// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package buildcfg provides access to the build configuration // described by the current environment. It is for use by build tools // such as cmd/go or cmd/compile and for setting up go/build's Default context. // // Note that it does NOT provide access to the build configuration used to // build the currently-running binary. For that, use runtime.GOOS etc // as well as internal/goexperiment.
package buildcfg import ( ) var ( GOROOT = os.Getenv("GOROOT") // cached for efficiency GOARCH = envOr("GOARCH", defaultGOARCH) GOOS = envOr("GOOS", defaultGOOS) GO386 = envOr("GO386", defaultGO386) GOAMD64 = goamd64() GOARM = goarm() GOARM64 = goarm64() GOMIPS = gomips() GOMIPS64 = gomips64() GOPPC64 = goppc64() GORISCV64 = goriscv64() GOWASM = gowasm() ToolTags = toolTags() GO_LDSO = defaultGO_LDSO Version = version ) // Error is one of the errors found (if any) in the build configuration. var Error error // Check exits the program with a fatal error if Error is non-nil. func () { if Error != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error) os.Exit(2) } } func envOr(, string) string { if := os.Getenv(); != "" { return } return } func goamd64() int { switch := envOr("GOAMD64", defaultGOAMD64); { case "v1": return 1 case "v2": return 2 case "v3": return 3 case "v4": return 4 } Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4") return int(defaultGOAMD64[len("v")] - '0') } type goarmFeatures struct { Version int SoftFloat bool } func ( goarmFeatures) () string { := strconv.Itoa(.Version) if .SoftFloat { += ",softfloat" } else { += ",hardfloat" } return } func goarm() ( goarmFeatures) { const ( = ",softfloat" = ",hardfloat" ) := defaultGOARM if GOOS == "android" && GOARCH == "arm" { // Android arm devices always support GOARM=7. = "7" } := envOr("GOARM", ) := false if strings.HasSuffix(, ) { .SoftFloat = true = true = [:len()-len()] } if strings.HasSuffix(, ) { = true = [:len()-len()] } switch { case "5": .Version = 5 case "6": .Version = 6 case "7": .Version = 7 default: Error = fmt.Errorf("invalid GOARM: must start with 5, 6, or 7, and may optionally end in either %q or %q", , ) .Version = int([0] - '0') } // 5 defaults to softfloat. 6 and 7 default to hardfloat. if ! && .Version == 5 { .SoftFloat = true } return } type Goarm64Features struct { Version string // Large Systems Extension LSE bool // ARM v8.0 Cryptographic Extension. It includes the following features: // * FEAT_AES, which includes the AESD and AESE instructions. // * FEAT_PMULL, which includes the PMULL, PMULL2 instructions. // * FEAT_SHA1, which includes the SHA1* instructions. // * FEAT_SHA256, which includes the SHA256* instructions. Crypto bool } func ( Goarm64Features) () string { := .Version if .LSE { += ",lse" } if .Crypto { += ",crypto" } return } func ( string) ( Goarm64Features, error) { const ( = ",lse" = ",crypto" ) .LSE = false .Crypto = false // We allow any combination of suffixes, in any order for { if strings.HasSuffix(, ) { .LSE = true = [:len()-len()] continue } if strings.HasSuffix(, ) { .Crypto = true = [:len()-len()] continue } break } switch { case "v8.0": .Version = case "v8.1", "v8.2", "v8.3", "v8.4", "v8.5", "v8.6", "v8.7", "v8.8", "v8.9", "v9.0", "v9.1", "v9.2", "v9.3", "v9.4", "v9.5": .Version = // LSE extension is mandatory starting from 8.1 .LSE = true default: = fmt.Errorf("invalid GOARM64: must start with v8.{0-9} or v9.{0-5} and may optionally end in %q and/or %q", , ) .Version = defaultGOARM64 } return } func goarm64() ( Goarm64Features) { , Error = ParseGoarm64(envOr("GOARM64", defaultGOARM64)) return } // Returns true if g supports giving ARM64 ISA // Note that this function doesn't accept / test suffixes (like ",lse" or ",crypto") func ( Goarm64Features) ( string) bool { // We only accept "v{8-9}.{0-9}. Everything else is malformed. if len() != 4 { return false } := [1] := [3] // We only accept "v{8-9}.{0-9}. Everything else is malformed. if < '8' || > '9' || < '0' || > '9' || [0] != 'v' || [2] != '.' { return false } := .Version[1] := .Version[3] if == { return <= } else if == '9' { // v9.0 diverged from v8.5. This means we should compare with g_minor increased by five. return <= +5 } else { return false } } func gomips() string { switch := envOr("GOMIPS", defaultGOMIPS); { case "hardfloat", "softfloat": return } Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat") return defaultGOMIPS } func gomips64() string { switch := envOr("GOMIPS64", defaultGOMIPS64); { case "hardfloat", "softfloat": return } Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat") return defaultGOMIPS64 } func goppc64() int { switch := envOr("GOPPC64", defaultGOPPC64); { case "power8": return 8 case "power9": return 9 case "power10": return 10 } Error = fmt.Errorf("invalid GOPPC64: must be power8, power9, power10") return int(defaultGOPPC64[len("power")] - '0') } func goriscv64() int { switch := envOr("GORISCV64", defaultGORISCV64); { case "rva20u64": return 20 case "rva22u64": return 22 } Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64") := defaultGORISCV64[len("rva"):] := strings.IndexFunc(, func( rune) bool { return < '0' || > '9' }) , := strconv.Atoi([:]) return } type gowasmFeatures struct { SatConv bool SignExt bool } func ( gowasmFeatures) () string { var []string if .SatConv { = append(, "satconv") } if .SignExt { = append(, "signext") } return strings.Join(, ",") } func gowasm() ( gowasmFeatures) { for , := range strings.Split(envOr("GOWASM", ""), ",") { switch { case "satconv": .SatConv = true case "signext": .SignExt = true case "": // ignore default: Error = fmt.Errorf("invalid GOWASM: no such feature %q", ) } } return } func () string { return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) } func toolTags() []string { := experimentTags() = append(, gogoarchTags()...) return } func experimentTags() []string { var []string // For each experiment that has been enabled in the toolchain, define a // build tag with the same name but prefixed by "goexperiment." which can be // used for compiling alternative files for the experiment. This allows // changes for the experiment, like extra struct fields in the runtime, // without affecting the base non-experiment code at all. for , := range Experiment.Enabled() { = append(, "goexperiment."+) } return } // GOGOARCH returns the name and value of the GO$GOARCH setting. // For example, if GOARCH is "amd64" it might return "GOAMD64", "v2". func () (, string) { switch GOARCH { case "386": return "GO386", GO386 case "amd64": return "GOAMD64", fmt.Sprintf("v%d", GOAMD64) case "arm": return "GOARM", GOARM.String() case "arm64": return "GOARM64", GOARM64.String() case "mips", "mipsle": return "GOMIPS", GOMIPS case "mips64", "mips64le": return "GOMIPS64", GOMIPS64 case "ppc64", "ppc64le": return "GOPPC64", fmt.Sprintf("power%d", GOPPC64) case "wasm": return "GOWASM", GOWASM.String() } return "", "" } func gogoarchTags() []string { switch GOARCH { case "386": return []string{GOARCH + "." + GO386} case "amd64": var []string for := 1; <= GOAMD64; ++ { = append(, fmt.Sprintf("%s.v%d", GOARCH, )) } return case "arm": var []string for := 5; <= GOARM.Version; ++ { = append(, fmt.Sprintf("%s.%d", GOARCH, )) } return case "arm64": var []string := int(GOARM64.Version[1] - '0') := int(GOARM64.Version[3] - '0') for := 0; <= ; ++ { = append(, fmt.Sprintf("%s.v%d.%d", GOARCH, , )) } // ARM64 v9.x also includes support of v8.x+5 (i.e. v9.1 includes v8.(1+5) = v8.6). if == 9 { for := 0; <= +5 && <= 9; ++ { = append(, fmt.Sprintf("%s.v%d.%d", GOARCH, 8, )) } } return case "mips", "mipsle": return []string{GOARCH + "." + GOMIPS} case "mips64", "mips64le": return []string{GOARCH + "." + GOMIPS64} case "ppc64", "ppc64le": var []string for := 8; <= GOPPC64; ++ { = append(, fmt.Sprintf("%s.power%d", GOARCH, )) } return case "riscv64": := []string{GOARCH + "." + "rva20u64"} if GORISCV64 >= 22 { = append(, GOARCH+"."+"rva22u64") } return case "wasm": var []string if GOWASM.SatConv { = append(, GOARCH+".satconv") } if GOWASM.SignExt { = append(, GOARCH+".signext") } return } return nil }