1
2
3
4
5
6
7
8
9
10
11
12 package buildcfg
13
14 import (
15 "fmt"
16 "os"
17 "path/filepath"
18 "strconv"
19 "strings"
20 )
21
22 var (
23 GOROOT = os.Getenv("GOROOT")
24 GOARCH = envOr("GOARCH", defaultGOARCH)
25 GOOS = envOr("GOOS", defaultGOOS)
26 GO386 = envOr("GO386", DefaultGO386)
27 GOAMD64 = goamd64()
28 GOARM = goarm()
29 GOARM64 = goarm64()
30 GOMIPS = gomips()
31 GOMIPS64 = gomips64()
32 GOPPC64 = goppc64()
33 GORISCV64 = goriscv64()
34 GOWASM = gowasm()
35 ToolTags = toolTags()
36 GO_LDSO = defaultGO_LDSO
37 GOFIPS140 = gofips140()
38 Version = version
39 )
40
41
42 var Error error
43
44
45 func Check() {
46 if Error != nil {
47 fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error)
48 os.Exit(2)
49 }
50 }
51
52 func envOr(key, value string) string {
53 if x := os.Getenv(key); x != "" {
54 return x
55 }
56 return value
57 }
58
59 func goamd64() int {
60 switch v := envOr("GOAMD64", DefaultGOAMD64); v {
61 case "v1":
62 return 1
63 case "v2":
64 return 2
65 case "v3":
66 return 3
67 case "v4":
68 return 4
69 }
70 Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4")
71 return int(DefaultGOAMD64[len("v")] - '0')
72 }
73
74 func gofips140() string {
75 v := envOr("GOFIPS140", DefaultGOFIPS140)
76 switch v {
77 case "off", "latest", "inprocess", "certified":
78 return v
79 }
80 if isFIPSVersion(v) {
81 return v
82 }
83 Error = fmt.Errorf("invalid GOFIPS140: must be off, latest, inprocess, certified, or v1.Y.Z")
84 return DefaultGOFIPS140
85 }
86
87
88
89 func isFIPSVersion(v string) bool {
90 v, ok := strings.CutPrefix(v, "v1.")
91 if !ok {
92 return false
93 }
94 if v, ok = cutNum(v); !ok {
95 return false
96 }
97 if v, ok = strings.CutPrefix(v, "."); !ok {
98 return false
99 }
100 if v, ok = cutNum(v); !ok {
101 return false
102 }
103 if v == "" {
104 return true
105 }
106 if v, ok = strings.CutPrefix(v, "-rc"); ok {
107 v, ok = cutNum(v)
108 return ok && v == ""
109 }
110 if v, ok = strings.CutPrefix(v, "-"); ok {
111 return len(v) == 8
112 }
113 return false
114 }
115
116
117
118 func cutNum(s string) (rest string, ok bool) {
119 i := 0
120 for i < len(s) && '0' <= s[i] && s[i] <= '9' {
121 i++
122 }
123 return s[i:], i > 0
124 }
125
126 type GoarmFeatures struct {
127 Version int
128 SoftFloat bool
129 }
130
131 func (g GoarmFeatures) String() string {
132 armStr := strconv.Itoa(g.Version)
133 if g.SoftFloat {
134 armStr += ",softfloat"
135 } else {
136 armStr += ",hardfloat"
137 }
138 return armStr
139 }
140
141 func goarm() (g GoarmFeatures) {
142 const (
143 softFloatOpt = ",softfloat"
144 hardFloatOpt = ",hardfloat"
145 )
146 def := DefaultGOARM
147 if GOOS == "android" && GOARCH == "arm" {
148
149 def = "7"
150 }
151 v := envOr("GOARM", def)
152
153 floatSpecified := false
154 if strings.HasSuffix(v, softFloatOpt) {
155 g.SoftFloat = true
156 floatSpecified = true
157 v = v[:len(v)-len(softFloatOpt)]
158 }
159 if strings.HasSuffix(v, hardFloatOpt) {
160 floatSpecified = true
161 v = v[:len(v)-len(hardFloatOpt)]
162 }
163
164 switch v {
165 case "5":
166 g.Version = 5
167 case "6":
168 g.Version = 6
169 case "7":
170 g.Version = 7
171 default:
172 Error = fmt.Errorf("invalid GOARM: must start with 5, 6, or 7, and may optionally end in either %q or %q", hardFloatOpt, softFloatOpt)
173 g.Version = int(def[0] - '0')
174 }
175
176
177 if !floatSpecified && g.Version == 5 {
178 g.SoftFloat = true
179 }
180 return
181 }
182
183 type Goarm64Features struct {
184 Version string
185
186 LSE bool
187
188
189
190
191
192 Crypto bool
193 }
194
195 func (g Goarm64Features) String() string {
196 arm64Str := g.Version
197 if g.LSE {
198 arm64Str += ",lse"
199 }
200 if g.Crypto {
201 arm64Str += ",crypto"
202 }
203 return arm64Str
204 }
205
206 func ParseGoarm64(v string) (g Goarm64Features, e error) {
207 const (
208 lseOpt = ",lse"
209 cryptoOpt = ",crypto"
210 )
211
212 g.LSE = false
213 g.Crypto = false
214
215 for {
216 if strings.HasSuffix(v, lseOpt) {
217 g.LSE = true
218 v = v[:len(v)-len(lseOpt)]
219 continue
220 }
221
222 if strings.HasSuffix(v, cryptoOpt) {
223 g.Crypto = true
224 v = v[:len(v)-len(cryptoOpt)]
225 continue
226 }
227
228 break
229 }
230
231 switch v {
232 case "v8.0":
233 g.Version = v
234 case "v8.1", "v8.2", "v8.3", "v8.4", "v8.5", "v8.6", "v8.7", "v8.8", "v8.9",
235 "v9.0", "v9.1", "v9.2", "v9.3", "v9.4", "v9.5":
236 g.Version = v
237
238 g.LSE = true
239 default:
240 e = fmt.Errorf("invalid GOARM64: must start with v8.{0-9} or v9.{0-5} and may optionally end in %q and/or %q",
241 lseOpt, cryptoOpt)
242 g.Version = DefaultGOARM64
243 }
244
245 return
246 }
247
248 func goarm64() (g Goarm64Features) {
249 g, Error = ParseGoarm64(envOr("GOARM64", DefaultGOARM64))
250 return
251 }
252
253
254
255 func (g Goarm64Features) Supports(s string) bool {
256
257 if len(s) != 4 {
258 return false
259 }
260
261 major := s[1]
262 minor := s[3]
263
264
265 if major < '8' || major > '9' ||
266 minor < '0' || minor > '9' ||
267 s[0] != 'v' || s[2] != '.' {
268 return false
269 }
270
271 g_major := g.Version[1]
272 g_minor := g.Version[3]
273
274 if major == g_major {
275 return minor <= g_minor
276 } else if g_major == '9' {
277
278 return minor <= g_minor+5
279 } else {
280 return false
281 }
282 }
283
284 func gomips() string {
285 switch v := envOr("GOMIPS", DefaultGOMIPS); v {
286 case "hardfloat", "softfloat":
287 return v
288 }
289 Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat")
290 return DefaultGOMIPS
291 }
292
293 func gomips64() string {
294 switch v := envOr("GOMIPS64", DefaultGOMIPS64); v {
295 case "hardfloat", "softfloat":
296 return v
297 }
298 Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat")
299 return DefaultGOMIPS64
300 }
301
302 func goppc64() int {
303 switch v := envOr("GOPPC64", DefaultGOPPC64); v {
304 case "power8":
305 return 8
306 case "power9":
307 return 9
308 case "power10":
309 return 10
310 }
311 Error = fmt.Errorf("invalid GOPPC64: must be power8, power9, power10")
312 return int(DefaultGOPPC64[len("power")] - '0')
313 }
314
315 func goriscv64() int {
316 switch v := envOr("GORISCV64", DefaultGORISCV64); v {
317 case "rva20u64":
318 return 20
319 case "rva22u64":
320 return 22
321 case "rva23u64":
322 return 23
323 }
324 Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64, rva23u64")
325 v := DefaultGORISCV64[len("rva"):]
326 i := strings.IndexFunc(v, func(r rune) bool {
327 return r < '0' || r > '9'
328 })
329 year, _ := strconv.Atoi(v[:i])
330 return year
331 }
332
333 type gowasmFeatures struct {
334
335
336
337 }
338
339 func (f gowasmFeatures) String() string {
340 var flags []string
341 return strings.Join(flags, ",")
342 }
343
344 func gowasm() (f gowasmFeatures) {
345 for opt := range strings.SplitSeq(envOr("GOWASM", ""), ",") {
346 switch opt {
347 case "satconv":
348
349 case "signext":
350
351 case "":
352
353 default:
354 Error = fmt.Errorf("invalid GOWASM: no such feature %q", opt)
355 }
356 }
357 return
358 }
359
360 func Getgoextlinkenabled() string {
361 return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
362 }
363
364 func toolTags() []string {
365 tags := experimentTags()
366 tags = append(tags, gogoarchTags()...)
367 return tags
368 }
369
370 func experimentTags() []string {
371 var list []string
372
373
374
375
376
377 for _, exp := range Experiment.Enabled() {
378 list = append(list, "goexperiment."+exp)
379 }
380 return list
381 }
382
383
384
385 func GOGOARCH() (name, value string) {
386 switch GOARCH {
387 case "386":
388 return "GO386", GO386
389 case "amd64":
390 return "GOAMD64", fmt.Sprintf("v%d", GOAMD64)
391 case "arm":
392 return "GOARM", GOARM.String()
393 case "arm64":
394 return "GOARM64", GOARM64.String()
395 case "mips", "mipsle":
396 return "GOMIPS", GOMIPS
397 case "mips64", "mips64le":
398 return "GOMIPS64", GOMIPS64
399 case "ppc64", "ppc64le":
400 return "GOPPC64", fmt.Sprintf("power%d", GOPPC64)
401 case "riscv64":
402 return "GORISCV64", fmt.Sprintf("rva%du64", GORISCV64)
403 case "wasm":
404 return "GOWASM", GOWASM.String()
405 }
406 return "", ""
407 }
408
409 func gogoarchTags() []string {
410 switch GOARCH {
411 case "386":
412 return []string{GOARCH + "." + GO386}
413 case "amd64":
414 var list []string
415 for i := 1; i <= GOAMD64; i++ {
416 list = append(list, fmt.Sprintf("%s.v%d", GOARCH, i))
417 }
418 return list
419 case "arm":
420 var list []string
421 for i := 5; i <= GOARM.Version; i++ {
422 list = append(list, fmt.Sprintf("%s.%d", GOARCH, i))
423 }
424 return list
425 case "arm64":
426 var list []string
427 major := int(GOARM64.Version[1] - '0')
428 minor := int(GOARM64.Version[3] - '0')
429 for i := 0; i <= minor; i++ {
430 list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, major, i))
431 }
432
433 if major == 9 {
434 for i := 0; i <= minor+5 && i <= 9; i++ {
435 list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, 8, i))
436 }
437 }
438 return list
439 case "mips", "mipsle":
440 return []string{GOARCH + "." + GOMIPS}
441 case "mips64", "mips64le":
442 return []string{GOARCH + "." + GOMIPS64}
443 case "ppc64", "ppc64le":
444 var list []string
445 for i := 8; i <= GOPPC64; i++ {
446 list = append(list, fmt.Sprintf("%s.power%d", GOARCH, i))
447 }
448 return list
449 case "riscv64":
450 list := []string{GOARCH + "." + "rva20u64"}
451 if GORISCV64 >= 22 {
452 list = append(list, GOARCH+"."+"rva22u64")
453 }
454 if GORISCV64 >= 23 {
455 list = append(list, GOARCH+"."+"rva23u64")
456 }
457 return list
458 case "wasm":
459 var list []string
460
461 list = append(list, GOARCH+".satconv")
462
463 list = append(list, GOARCH+".signext")
464 return list
465 }
466 return nil
467 }
468
View as plain text