Text file src/cmd/go/internal/cfg/cfg.go.orig
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.
4
5 // Package cfg holds configuration shared by multiple parts
6 // of the go command.
7 package cfg
8
9 import (
10 "bytes"
11 "fmt"
12 "go/build"
13 "internal/cfg"
14 "io/ioutil"
15 "os"
16 "path/filepath"
17 "runtime"
18 "strings"
19 "sync"
20
21 "cmd/internal/objabi"
22 )
23
24 // These are general "build flags" used by build and other commands.
25 var (
26 BuildA bool // -a flag
27 BuildBuildmode string // -buildmode flag
28 BuildContext = defaultContext()
29 BuildMod string // -mod flag
30 BuildI bool // -i flag
31 BuildLinkshared bool // -linkshared flag
32 BuildMSan bool // -msan flag
33 BuildN bool // -n flag
34 BuildO string // -o flag
35 BuildP = runtime.NumCPU() // -p flag
36 BuildPkgdir string // -pkgdir flag
37 BuildRace bool // -race flag
38 BuildToolexec []string // -toolexec flag
39 BuildToolchainName string
40 BuildToolchainCompiler func() string
41 BuildToolchainLinker func() string
42 BuildTrimpath bool // -trimpath flag
43 BuildV bool // -v flag
44 BuildWork bool // -work flag
45 BuildX bool // -x flag
46
47 CmdName string // "build", "install", "list", "mod tidy", etc.
48
49 DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
50 )
51
52 func defaultContext() build.Context {
53 ctxt := build.Default
54 ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
55
56 ctxt.GOROOT = findGOROOT()
57 if runtime.Compiler != "gccgo" {
58 // Note that we must use runtime.GOOS and runtime.GOARCH here,
59 // as the tool directory does not move based on environment
60 // variables. This matches the initialization of ToolDir in
61 // go/build, except for using ctxt.GOROOT rather than
62 // runtime.GOROOT.
63 build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
64 }
65
66 ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH)
67
68 // Override defaults computed in go/build with defaults
69 // from go environment configuration file, if known.
70 ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
71 ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
72
73 // The go/build rule for whether cgo is enabled is:
74 // 1. If $CGO_ENABLED is set, respect it.
75 // 2. Otherwise, if this is a cross-compile, disable cgo.
76 // 3. Otherwise, use built-in default for GOOS/GOARCH.
77 // Recreate that logic here with the new GOOS/GOARCH setting.
78 if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
79 ctxt.CgoEnabled = v[0] == '1'
80 } else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
81 ctxt.CgoEnabled = false
82 } else {
83 // Use built-in default cgo setting for GOOS/GOARCH.
84 // Note that ctxt.GOOS/GOARCH are derived from the preference list
85 // (1) environment, (2) go/env file, (3) runtime constants,
86 // while go/build.Default.GOOS/GOARCH are derived from the preference list
87 // (1) environment, (2) runtime constants.
88 // We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
89 // no matter how that happened, go/build.Default will make the
90 // same decision (either the environment variables are set explicitly
91 // to match the runtime constants, or else they are unset, in which
92 // case go/build falls back to the runtime constants), so
93 // go/build.Default.GOOS/GOARCH == runtime.GOOS/GOARCH.
94 // So ctxt.CgoEnabled (== go/build.Default.CgoEnabled) is correct
95 // as is and can be left unmodified.
96 // Nothing to do here.
97 }
98
99 return ctxt
100 }
101
102 func init() {
103 BuildToolchainCompiler = func() string { return "missing-compiler" }
104 BuildToolchainLinker = func() string { return "missing-linker" }
105 }
106
107 // An EnvVar is an environment variable Name=Value.
108 type EnvVar struct {
109 Name string
110 Value string
111 }
112
113 // OrigEnv is the original environment of the program at startup.
114 var OrigEnv []string
115
116 // CmdEnv is the new environment for running go tool commands.
117 // User binaries (during go test or go run) are run with OrigEnv,
118 // not CmdEnv.
119 var CmdEnv []EnvVar
120
121 // Global build parameters (used during package load)
122 var (
123 Goarch = BuildContext.GOARCH
124 Goos = BuildContext.GOOS
125
126 ExeSuffix = exeSuffix()
127
128 // ModulesEnabled specifies whether the go command is running
129 // in module-aware mode (as opposed to GOPATH mode).
130 // It is equal to modload.Enabled, but not all packages can import modload.
131 ModulesEnabled bool
132 )
133
134 func exeSuffix() string {
135 if Goos == "windows" {
136 return ".exe"
137 }
138 return ""
139 }
140
141 var envCache struct {
142 once sync.Once
143 m map[string]string
144 }
145
146 // EnvFile returns the name of the Go environment configuration file.
147 func EnvFile() (string, error) {
148 if file := os.Getenv("GOENV"); file != "" {
149 if file == "off" {
150 return "", fmt.Errorf("GOENV=off")
151 }
152 return file, nil
153 }
154 dir, err := os.UserConfigDir()
155 if err != nil {
156 return "", err
157 }
158 if dir == "" {
159 return "", fmt.Errorf("missing user-config dir")
160 }
161 return filepath.Join(dir, "go/env"), nil
162 }
163
164 func initEnvCache() {
165 envCache.m = make(map[string]string)
166 file, _ := EnvFile()
167 if file == "" {
168 return
169 }
170 data, err := ioutil.ReadFile(file)
171 if err != nil {
172 return
173 }
174
175 for len(data) > 0 {
176 // Get next line.
177 line := data
178 i := bytes.IndexByte(data, '\n')
179 if i >= 0 {
180 line, data = line[:i], data[i+1:]
181 } else {
182 data = nil
183 }
184
185 i = bytes.IndexByte(line, '=')
186 if i < 0 || line[0] < 'A' || 'Z' < line[0] {
187 // Line is missing = (or empty) or a comment or not a valid env name. Ignore.
188 // (This should not happen, since the file should be maintained almost
189 // exclusively by "go env -w", but better to silently ignore than to make
190 // the go command unusable just because somehow the env file has
191 // gotten corrupted.)
192 continue
193 }
194 key, val := line[:i], line[i+1:]
195 envCache.m[string(key)] = string(val)
196 }
197 }
198
199 // Getenv gets the value for the configuration key.
200 // It consults the operating system environment
201 // and then the go/env file.
202 // If Getenv is called for a key that cannot be set
203 // in the go/env file (for example GODEBUG), it panics.
204 // This ensures that CanGetenv is accurate, so that
205 // 'go env -w' stays in sync with what Getenv can retrieve.
206 func Getenv(key string) string {
207 if !CanGetenv(key) {
208 switch key {
209 case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW":
210 // used by internal/work/security_test.go; allow
211 default:
212 panic("internal error: invalid Getenv " + key)
213 }
214 }
215 val := os.Getenv(key)
216 if val != "" {
217 return val
218 }
219 envCache.once.Do(initEnvCache)
220 return envCache.m[key]
221 }
222
223 // CanGetenv reports whether key is a valid go/env configuration key.
224 func CanGetenv(key string) bool {
225 return strings.Contains(cfg.KnownEnv, "\t"+key+"\n")
226 }
227
228 var (
229 GOROOT = BuildContext.GOROOT
230 GOBIN = Getenv("GOBIN")
231 GOROOTbin = filepath.Join(GOROOT, "bin")
232 GOROOTpkg = filepath.Join(GOROOT, "pkg")
233 GOROOTsrc = filepath.Join(GOROOT, "src")
234 GOROOT_FINAL = findGOROOT_FINAL()
235
236 // Used in envcmd.MkEnv and build ID computations.
237 GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
238 GO386 = envOr("GO386", objabi.GO386)
239 GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
240 GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
241 GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
242 GOWASM = envOr("GOWASM", fmt.Sprint(objabi.GOWASM))
243
244 GOPROXY = envOr("GOPROXY", "https://proxy.golang.org,direct")
245 GOSUMDB = envOr("GOSUMDB", "sum.golang.org")
246 GOPRIVATE = Getenv("GOPRIVATE")
247 GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
248 GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
249 )
250
251 // GetArchEnv returns the name and setting of the
252 // GOARCH-specific architecture environment variable.
253 // If the current architecture has no GOARCH-specific variable,
254 // GetArchEnv returns empty key and value.
255 func GetArchEnv() (key, val string) {
256 switch Goarch {
257 case "arm":
258 return "GOARM", GOARM
259 case "386":
260 return "GO386", GO386
261 case "mips", "mipsle":
262 return "GOMIPS", GOMIPS
263 case "mips64", "mips64le":
264 return "GOMIPS64", GOMIPS64
265 case "ppc64", "ppc64le":
266 return "GOPPC64", GOPPC64
267 case "wasm":
268 return "GOWASM", GOWASM
269 }
270 return "", ""
271 }
272
273 // envOr returns Getenv(key) if set, or else def.
274 func envOr(key, def string) string {
275 val := Getenv(key)
276 if val == "" {
277 val = def
278 }
279 return val
280 }
281
282 // There is a copy of findGOROOT, isSameDir, and isGOROOT in
283 // x/tools/cmd/godoc/goroot.go.
284 // Try to keep them in sync for now.
285
286 // findGOROOT returns the GOROOT value, using either an explicitly
287 // provided environment variable, a GOROOT that contains the current
288 // os.Executable value, or else the GOROOT that the binary was built
289 // with from runtime.GOROOT().
290 //
291 // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
292 func findGOROOT() string {
293 if env := Getenv("GOROOT"); env != "" {
294 return filepath.Clean(env)
295 }
296 def := filepath.Clean(runtime.GOROOT())
297 if runtime.Compiler == "gccgo" {
298 // gccgo has no real GOROOT, and it certainly doesn't
299 // depend on the executable's location.
300 return def
301 }
302 exe, err := os.Executable()
303 if err == nil {
304 exe, err = filepath.Abs(exe)
305 if err == nil {
306 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
307 // If def (runtime.GOROOT()) and dir are the same
308 // directory, prefer the spelling used in def.
309 if isSameDir(def, dir) {
310 return def
311 }
312 return dir
313 }
314 exe, err = filepath.EvalSymlinks(exe)
315 if err == nil {
316 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
317 if isSameDir(def, dir) {
318 return def
319 }
320 return dir
321 }
322 }
323 }
324 }
325 return def
326 }
327
328 func findGOROOT_FINAL() string {
329 // $GOROOT_FINAL is only for use during make.bash
330 // so it is not settable using go/env, so we use os.Getenv here.
331 def := GOROOT
332 if env := os.Getenv("GOROOT_FINAL"); env != "" {
333 def = filepath.Clean(env)
334 }
335 return def
336 }
337
338 // isSameDir reports whether dir1 and dir2 are the same directory.
339 func isSameDir(dir1, dir2 string) bool {
340 if dir1 == dir2 {
341 return true
342 }
343 info1, err1 := os.Stat(dir1)
344 info2, err2 := os.Stat(dir2)
345 return err1 == nil && err2 == nil && os.SameFile(info1, info2)
346 }
347
348 // isGOROOT reports whether path looks like a GOROOT.
349 //
350 // It does this by looking for the path/pkg/tool directory,
351 // which is necessary for useful operation of the cmd/go tool,
352 // and is not typically present in a GOPATH.
353 //
354 // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
355 func isGOROOT(path string) bool {
356 stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
357 if err != nil {
358 return false
359 }
360 return stat.IsDir()
361 }
View as plain text