1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package cfg holds configuration shared by multiple parts
24 "cmd/go/internal/fsys"
27 // Global build parameters (used during package load)
29 Goos = envOr("GOOS", build.Default.GOOS)
30 Goarch = envOr("GOARCH", build.Default.GOARCH)
32 ExeSuffix = exeSuffix()
34 // ModulesEnabled specifies whether the go command is running
35 // in module-aware mode (as opposed to GOPATH mode).
36 // It is equal to modload.Enabled, but not all packages can import modload.
40 func exeSuffix() string {
41 if Goos == "windows" {
47 // Configuration for tools installed to GOROOT/bin.
48 // Normally these match runtime.GOOS and runtime.GOARCH,
49 // but when testing a cross-compiled cmd/go they will
50 // indicate the GOOS and GOARCH of the installed cmd/go
51 // rather than the test binary.
54 installedGOARCH string
57 // ToolExeSuffix returns the suffix for executables installed
59 func ToolExeSuffix() string {
60 if installedGOOS == "windows" {
66 // These are general "build flags" used by build and other commands.
68 BuildA bool // -a flag
69 BuildBuildmode string // -buildmode flag
70 BuildBuildvcs = "auto" // -buildvcs flag: "true", "false", or "auto"
71 BuildContext = defaultContext()
72 BuildMod string // -mod flag
73 BuildModExplicit bool // whether -mod was set explicitly
74 BuildModReason string // reason -mod was set, if set by default
75 BuildLinkshared bool // -linkshared flag
76 BuildMSan bool // -msan flag
77 BuildASan bool // -asan flag
78 BuildCover bool // -cover flag
79 BuildCoverMode string // -covermode flag
80 BuildCoverPkg []string // -coverpkg flag
81 BuildN bool // -n flag
82 BuildO string // -o flag
83 BuildP = runtime.GOMAXPROCS(0) // -p flag
84 BuildPGO string // -pgo flag
85 BuildPkgdir string // -pkgdir flag
86 BuildRace bool // -race flag
87 BuildToolexec []string // -toolexec flag
88 BuildToolchainName string
89 BuildToolchainCompiler func() string
90 BuildToolchainLinker func() string
91 BuildTrimpath bool // -trimpath flag
92 BuildV bool // -v flag
93 BuildWork bool // -work flag
94 BuildX bool // -x flag
96 ModCacheRW bool // -modcacherw flag
97 ModFile string // -modfile flag
99 CmdName string // "build", "install", "list", "mod tidy", etc.
101 DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
102 DebugTrace string // -debug-trace flag
103 DebugRuntimeTrace string // -debug-runtime-trace flag (undocumented, unstable)
105 // GoPathError is set when GOPATH is not set. it contains an
106 // explanation why GOPATH is unset.
110 func defaultContext() build.Context {
111 ctxt := build.Default
113 ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
115 // Override defaults computed in go/build with defaults
116 // from go environment configuration file, if known.
117 ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
121 // Clear the GOEXPERIMENT-based tool tags, which we will recompute later.
123 for _, tag := range ctxt.ToolTags {
124 if !strings.HasPrefix(tag, "goexperiment.") {
125 save = append(save, tag)
130 // The go/build rule for whether cgo is enabled is:
131 // 1. If $CGO_ENABLED is set, respect it.
132 // 2. Otherwise, if this is a cross-compile, disable cgo.
133 // 3. Otherwise, use built-in default for GOOS/GOARCH.
134 // Recreate that logic here with the new GOOS/GOARCH setting.
135 if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
136 ctxt.CgoEnabled = v[0] == '1'
137 } else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
138 ctxt.CgoEnabled = false
140 // Use built-in default cgo setting for GOOS/GOARCH.
141 // Note that ctxt.GOOS/GOARCH are derived from the preference list
142 // (1) environment, (2) go/env file, (3) runtime constants,
143 // while go/build.Default.GOOS/GOARCH are derived from the preference list
144 // (1) environment, (2) runtime constants.
146 // We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
147 // no matter how that happened, go/build.Default will make the
148 // same decision (either the environment variables are set explicitly
149 // to match the runtime constants, or else they are unset, in which
150 // case go/build falls back to the runtime constants), so
151 // go/build.Default.GOOS/GOARCH == runtime.GOOS/GOARCH.
152 // So ctxt.CgoEnabled (== go/build.Default.CgoEnabled) is correct
153 // as is and can be left unmodified.
155 // All that said, starting in Go 1.20 we layer one more rule
156 // on top of the go/build decision: if CC is unset and
157 // the default C compiler we'd look for is not in the PATH,
158 // we automatically default cgo to off.
159 // This makes go builds work automatically on systems
160 // without a C compiler installed.
162 if os.Getenv("CC") == "" {
163 cc := DefaultCC(ctxt.GOOS, ctxt.GOARCH)
164 if _, err := exec.LookPath(cc); err != nil {
165 ctxt.CgoEnabled = false
171 ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
172 return fsys.Open(path)
174 ctxt.ReadDir = fsys.ReadDir
175 ctxt.IsDir = func(path string) bool {
176 isDir, err := fsys.IsDir(path)
177 return err == nil && isDir
184 SetGOROOT(Getenv("GOROOT"), false)
185 BuildToolchainCompiler = func() string { return "missing-compiler" }
186 BuildToolchainLinker = func() string { return "missing-linker" }
189 // SetGOROOT sets GOROOT and associated variables to the given values.
191 // If isTestGo is true, build.ToolDir is set based on the TESTGO_GOHOSTOS and
192 // TESTGO_GOHOSTARCH environment variables instead of runtime.GOOS and
194 func SetGOROOT(goroot string, isTestGo bool) {
195 BuildContext.GOROOT = goroot
203 GOROOTbin = filepath.Join(goroot, "bin")
204 GOROOTpkg = filepath.Join(goroot, "pkg")
205 GOROOTsrc = filepath.Join(goroot, "src")
207 GOROOT_FINAL = findGOROOT_FINAL(goroot)
209 installedGOOS = runtime.GOOS
210 installedGOARCH = runtime.GOARCH
212 if testOS := os.Getenv("TESTGO_GOHOSTOS"); testOS != "" {
213 installedGOOS = testOS
215 if testArch := os.Getenv("TESTGO_GOHOSTARCH"); testArch != "" {
216 installedGOARCH = testArch
220 if runtime.Compiler != "gccgo" {
224 // Note that we must use the installed OS and arch here: the tool
225 // directory does not move based on environment variables, and even if we
226 // are testing a cross-compiled cmd/go all of the installed packages and
227 // tools would have been built using the native compiler and linker (and
228 // would spuriously appear stale if we used a cross-compiled compiler and
231 // This matches the initialization of ToolDir in go/build, except for
232 // using ctxt.GOROOT and the installed GOOS and GOARCH rather than the
233 // GOROOT, GOOS, and GOARCH reported by the runtime package.
234 build.ToolDir = filepath.Join(GOROOTpkg, "tool", installedGOOS+"_"+installedGOARCH)
239 // Experiment configuration.
241 // RawGOEXPERIMENT is the GOEXPERIMENT value set by the user.
242 RawGOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)
243 // CleanGOEXPERIMENT is the minimal GOEXPERIMENT value needed to reproduce the
244 // experiments enabled by RawGOEXPERIMENT.
245 CleanGOEXPERIMENT = RawGOEXPERIMENT
247 Experiment *buildcfg.ExperimentFlags
252 Experiment, ExperimentErr = buildcfg.ParseGOEXPERIMENT(Goos, Goarch, RawGOEXPERIMENT)
253 if ExperimentErr != nil {
257 // GOEXPERIMENT is valid, so convert it to canonical form.
258 CleanGOEXPERIMENT = Experiment.String()
260 // Add build tags based on the experiments in effect.
261 exps := Experiment.Enabled()
262 expTags := make([]string, 0, len(exps)+len(BuildContext.ToolTags))
263 for _, exp := range exps {
264 expTags = append(expTags, "goexperiment."+exp)
266 BuildContext.ToolTags = append(expTags, BuildContext.ToolTags...)
269 // An EnvVar is an environment variable Name=Value.
275 // OrigEnv is the original environment of the program at startup.
278 // CmdEnv is the new environment for running go tool commands.
279 // User binaries (during go test or go run) are run with OrigEnv,
283 var envCache struct {
288 // EnvFile returns the name of the Go environment configuration file.
289 func EnvFile() (string, error) {
290 if file := os.Getenv("GOENV"); file != "" {
292 return "", fmt.Errorf("GOENV=off")
296 dir, err := os.UserConfigDir()
301 return "", fmt.Errorf("missing user-config dir")
303 return filepath.Join(dir, "go/env"), nil
306 func initEnvCache() {
307 envCache.m = make(map[string]string)
308 if file, _ := EnvFile(); file != "" {
309 readEnvFile(file, "user")
311 goroot := findGOROOT(envCache.m["GOROOT"])
313 readEnvFile(filepath.Join(goroot, "go.env"), "GOROOT")
316 // Save the goroot for func init calling SetGOROOT,
317 // and also overwrite anything that might have been in go.env.
318 // It makes no sense for GOROOT/go.env to specify
319 // a different GOROOT.
320 envCache.m["GOROOT"] = goroot
323 func readEnvFile(file string, source string) {
327 data, err := os.ReadFile(file)
335 i := bytes.IndexByte(data, '\n')
337 line, data = line[:i], data[i+1:]
342 i = bytes.IndexByte(line, '=')
343 if i < 0 || line[0] < 'A' || 'Z' < line[0] {
344 // Line is missing = (or empty) or a comment or not a valid env name. Ignore.
345 // This should not happen in the user file, since the file should be maintained almost
346 // exclusively by "go env -w", but better to silently ignore than to make
347 // the go command unusable just because somehow the env file has
349 // In the GOROOT/go.env file, we expect comments.
352 key, val := line[:i], line[i+1:]
354 if source == "GOROOT" {
355 // In the GOROOT/go.env file, do not overwrite fields loaded from the user's go/env file.
356 if _, ok := envCache.m[string(key)]; ok {
360 envCache.m[string(key)] = string(val)
364 // Getenv gets the value for the configuration key.
365 // It consults the operating system environment
366 // and then the go/env file.
367 // If Getenv is called for a key that cannot be set
368 // in the go/env file (for example GODEBUG), it panics.
369 // This ensures that CanGetenv is accurate, so that
370 // 'go env -w' stays in sync with what Getenv can retrieve.
371 func Getenv(key string) string {
374 case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW":
375 // used by internal/work/security_test.go; allow
377 panic("internal error: invalid Getenv " + key)
380 val := os.Getenv(key)
384 envCache.once.Do(initEnvCache)
385 return envCache.m[key]
388 // CanGetenv reports whether key is a valid go/env configuration key.
389 func CanGetenv(key string) bool {
390 envCache.once.Do(initEnvCache)
391 if _, ok := envCache.m[key]; ok {
392 // Assume anything in the user file or go.env file is valid.
395 return strings.Contains(cfg.KnownEnv, "\t"+key+"\n")
401 // Either empty or produced by filepath.Join(GOROOT, …).
408 GOBIN = Getenv("GOBIN")
409 GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod"))
411 // Used in envcmd.MkEnv and build ID computations.
412 GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
413 GO386 = envOr("GO386", buildcfg.GO386)
414 GOAMD64 = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
415 GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
416 GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
417 GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
418 GOWASM = envOr("GOWASM", fmt.Sprint(buildcfg.GOWASM))
420 GOPROXY = envOr("GOPROXY", "")
421 GOSUMDB = envOr("GOSUMDB", "")
422 GOPRIVATE = Getenv("GOPRIVATE")
423 GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
424 GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
425 GOINSECURE = Getenv("GOINSECURE")
426 GOVCS = Getenv("GOVCS")
429 var SumdbDir = gopathDir("pkg/sumdb")
431 // GetArchEnv returns the name and setting of the
432 // GOARCH-specific architecture environment variable.
433 // If the current architecture has no GOARCH-specific variable,
434 // GetArchEnv returns empty key and value.
435 func GetArchEnv() (key, val string) {
438 return "GOARM", GOARM
440 return "GO386", GO386
442 return "GOAMD64", GOAMD64
443 case "mips", "mipsle":
444 return "GOMIPS", GOMIPS
445 case "mips64", "mips64le":
446 return "GOMIPS64", GOMIPS64
447 case "ppc64", "ppc64le":
448 return "GOPPC64", GOPPC64
450 return "GOWASM", GOWASM
455 // envOr returns Getenv(key) if set, or else def.
456 func envOr(key, def string) string {
464 // There is a copy of findGOROOT, isSameDir, and isGOROOT in
465 // x/tools/cmd/godoc/goroot.go.
466 // Try to keep them in sync for now.
468 // findGOROOT returns the GOROOT value, using either an explicitly
469 // provided environment variable, a GOROOT that contains the current
470 // os.Executable value, or else the GOROOT that the binary was built
471 // with from runtime.GOROOT().
473 // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
474 func findGOROOT(env string) string {
476 // Not using Getenv because findGOROOT is called
477 // to find the GOROOT/go.env file. initEnvCache
478 // has passed in the setting from the user go/env file.
479 env = os.Getenv("GOROOT")
482 return filepath.Clean(env)
485 if r := runtime.GOROOT(); r != "" {
486 def = filepath.Clean(r)
488 if runtime.Compiler == "gccgo" {
489 // gccgo has no real GOROOT, and it certainly doesn't
490 // depend on the executable's location.
493 exe, err := os.Executable()
495 exe, err = filepath.Abs(exe)
497 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
498 // If def (runtime.GOROOT()) and dir are the same
499 // directory, prefer the spelling used in def.
500 if isSameDir(def, dir) {
505 exe, err = filepath.EvalSymlinks(exe)
507 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
508 if isSameDir(def, dir) {
519 func findGOROOT_FINAL(goroot string) string {
520 // $GOROOT_FINAL is only for use during make.bash
521 // so it is not settable using go/env, so we use os.Getenv here.
523 if env := os.Getenv("GOROOT_FINAL"); env != "" {
524 def = filepath.Clean(env)
529 // isSameDir reports whether dir1 and dir2 are the same directory.
530 func isSameDir(dir1, dir2 string) bool {
534 info1, err1 := os.Stat(dir1)
535 info2, err2 := os.Stat(dir2)
536 return err1 == nil && err2 == nil && os.SameFile(info1, info2)
539 // isGOROOT reports whether path looks like a GOROOT.
541 // It does this by looking for the path/pkg/tool directory,
542 // which is necessary for useful operation of the cmd/go tool,
543 // and is not typically present in a GOPATH.
545 // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
546 func isGOROOT(path string) bool {
547 stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
554 func gopathDir(rel string) string {
555 list := filepath.SplitList(BuildContext.GOPATH)
556 if len(list) == 0 || list[0] == "" {
559 return filepath.Join(list[0], rel)
562 func gopath(ctxt build.Context) string {
563 if len(ctxt.GOPATH) > 0 {
567 if runtime.GOOS == "windows" {
569 } else if runtime.GOOS == "plan9" {
572 if home := os.Getenv(env); home != "" {
573 def := filepath.Join(home, "go")
574 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
575 GoPathError = "cannot set GOROOT as GOPATH"
579 GoPathError = fmt.Sprintf("%s is not set", env)
583 // WithBuildXWriter returns a Context in which BuildX output is written
584 // to given io.Writer.
585 func WithBuildXWriter(ctx context.Context, xLog io.Writer) context.Context {
586 return context.WithValue(ctx, buildXContextKey{}, xLog)
589 type buildXContextKey struct{}
591 // BuildXWriter returns nil if BuildX is false, or
592 // the writer to which BuildX output should be written otherwise.
593 func BuildXWriter(ctx context.Context) (io.Writer, bool) {
597 if v := ctx.Value(buildXContextKey{}); v != nil {
598 return v.(io.Writer), true
600 return os.Stderr, true