1
2
3
4
5
6
7 package cfg
8
9 import (
10 "bytes"
11 "fmt"
12 "go/build"
13 "internal/buildcfg"
14 "internal/cfg"
15 "io"
16 "os"
17 "path/filepath"
18 "runtime"
19 "strings"
20 "sync"
21
22 "cmd/go/internal/fsys"
23 )
24
25
26 var (
27 BuildA bool
28 BuildBuildmode string
29 BuildBuildvcs = "auto"
30 BuildContext = defaultContext()
31 BuildMod string
32 BuildModExplicit bool
33 BuildModReason string
34 BuildI bool
35 BuildLinkshared bool
36 BuildMSan bool
37 BuildASan bool
38 BuildN bool
39 BuildO string
40 BuildP = runtime.GOMAXPROCS(0)
41 BuildPkgdir string
42 BuildRace bool
43 BuildToolexec []string
44 BuildToolchainName string
45 BuildToolchainCompiler func() string
46 BuildToolchainLinker func() string
47 BuildTrimpath bool
48 BuildV bool
49 BuildWork bool
50 BuildX bool
51
52 ModCacheRW bool
53 ModFile string
54
55 CmdName string
56
57 DebugActiongraph string
58 DebugTrace string
59
60
61
62 GoPathError string
63
64 GOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)
65 )
66
67 func defaultContext() build.Context {
68 ctxt := build.Default
69
70 ctxt.JoinPath = filepath.Join
71
72 ctxt.GOROOT = findGOROOT()
73 if runtime.Compiler != "gccgo" {
74
75
76
77
78
79 build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
80 }
81
82 ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
83
84
85
86 ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
87 ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
88
89
90
91 buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, GOEXPERIMENT)
92 ctxt.ToolTags = nil
93 for _, exp := range buildcfg.EnabledExperiments() {
94 ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
95 }
96
97
98
99
100
101
102 if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
103 ctxt.CgoEnabled = v[0] == '1'
104 } else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
105 ctxt.CgoEnabled = false
106 } else {
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 }
122
123 ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
124 return fsys.Open(path)
125 }
126 ctxt.ReadDir = fsys.ReadDir
127 ctxt.IsDir = func(path string) bool {
128 isDir, err := fsys.IsDir(path)
129 return err == nil && isDir
130 }
131
132 return ctxt
133 }
134
135 func init() {
136 BuildToolchainCompiler = func() string { return "missing-compiler" }
137 BuildToolchainLinker = func() string { return "missing-linker" }
138 }
139
140
141 type EnvVar struct {
142 Name string
143 Value string
144 }
145
146
147 var OrigEnv []string
148
149
150
151
152 var CmdEnv []EnvVar
153
154
155 var (
156 Goarch = BuildContext.GOARCH
157 Goos = BuildContext.GOOS
158
159 ExeSuffix = exeSuffix()
160
161
162
163
164 ModulesEnabled bool
165 )
166
167 func exeSuffix() string {
168 if Goos == "windows" {
169 return ".exe"
170 }
171 return ""
172 }
173
174 var envCache struct {
175 once sync.Once
176 m map[string]string
177 }
178
179
180 func EnvFile() (string, error) {
181 if file := os.Getenv("GOENV"); file != "" {
182 if file == "off" {
183 return "", fmt.Errorf("GOENV=off")
184 }
185 return file, nil
186 }
187 dir, err := os.UserConfigDir()
188 if err != nil {
189 return "", err
190 }
191 if dir == "" {
192 return "", fmt.Errorf("missing user-config dir")
193 }
194 return filepath.Join(dir, "go/env"), nil
195 }
196
197 func initEnvCache() {
198 envCache.m = make(map[string]string)
199 file, _ := EnvFile()
200 if file == "" {
201 return
202 }
203 data, err := os.ReadFile(file)
204 if err != nil {
205 return
206 }
207
208 for len(data) > 0 {
209
210 line := data
211 i := bytes.IndexByte(data, '\n')
212 if i >= 0 {
213 line, data = line[:i], data[i+1:]
214 } else {
215 data = nil
216 }
217
218 i = bytes.IndexByte(line, '=')
219 if i < 0 || line[0] < 'A' || 'Z' < line[0] {
220
221
222
223
224
225 continue
226 }
227 key, val := line[:i], line[i+1:]
228 envCache.m[string(key)] = string(val)
229 }
230 }
231
232
233
234
235
236
237
238
239 func Getenv(key string) string {
240 if !CanGetenv(key) {
241 switch key {
242 case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW":
243
244 default:
245 panic("internal error: invalid Getenv " + key)
246 }
247 }
248 val := os.Getenv(key)
249 if val != "" {
250 return val
251 }
252 envCache.once.Do(initEnvCache)
253 return envCache.m[key]
254 }
255
256
257 func CanGetenv(key string) bool {
258 return strings.Contains(cfg.KnownEnv, "\t"+key+"\n")
259 }
260
261 var (
262 GOROOT = BuildContext.GOROOT
263 GOBIN = Getenv("GOBIN")
264 GOROOTbin = filepath.Join(GOROOT, "bin")
265 GOROOTpkg = filepath.Join(GOROOT, "pkg")
266 GOROOTsrc = filepath.Join(GOROOT, "src")
267 GOROOT_FINAL = findGOROOT_FINAL()
268 GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod"))
269
270
271 GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
272 GO386 = envOr("GO386", buildcfg.GO386)
273 GOAMD64 = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
274 GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
275 GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
276 GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
277 GOWASM = envOr("GOWASM", fmt.Sprint(buildcfg.GOWASM))
278
279 GOPROXY = envOr("GOPROXY", "https://proxy.golang.org,direct")
280 GOSUMDB = envOr("GOSUMDB", "sum.golang.org")
281 GOPRIVATE = Getenv("GOPRIVATE")
282 GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
283 GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
284 GOINSECURE = Getenv("GOINSECURE")
285 GOVCS = Getenv("GOVCS")
286 )
287
288 var SumdbDir = gopathDir("pkg/sumdb")
289
290
291
292
293
294 func GetArchEnv() (key, val string) {
295 switch Goarch {
296 case "arm":
297 return "GOARM", GOARM
298 case "386":
299 return "GO386", GO386
300 case "amd64":
301 return "GOAMD64", GOAMD64
302 case "mips", "mipsle":
303 return "GOMIPS", GOMIPS
304 case "mips64", "mips64le":
305 return "GOMIPS64", GOMIPS64
306 case "ppc64", "ppc64le":
307 return "GOPPC64", GOPPC64
308 case "wasm":
309 return "GOWASM", GOWASM
310 }
311 return "", ""
312 }
313
314
315 func envOr(key, def string) string {
316 val := Getenv(key)
317 if val == "" {
318 val = def
319 }
320 return val
321 }
322
323
324
325
326
327
328
329
330
331
332
333 func findGOROOT() string {
334 if env := Getenv("GOROOT"); env != "" {
335 return filepath.Clean(env)
336 }
337 def := filepath.Clean(runtime.GOROOT())
338 if runtime.Compiler == "gccgo" {
339
340
341 return def
342 }
343 exe, err := os.Executable()
344 if err == nil {
345 exe, err = filepath.Abs(exe)
346 if err == nil {
347 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
348
349
350 if isSameDir(def, dir) {
351 return def
352 }
353 return dir
354 }
355 exe, err = filepath.EvalSymlinks(exe)
356 if err == nil {
357 if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
358 if isSameDir(def, dir) {
359 return def
360 }
361 return dir
362 }
363 }
364 }
365 }
366 return def
367 }
368
369 func findGOROOT_FINAL() string {
370
371
372 def := GOROOT
373 if env := os.Getenv("GOROOT_FINAL"); env != "" {
374 def = filepath.Clean(env)
375 }
376 return def
377 }
378
379
380 func isSameDir(dir1, dir2 string) bool {
381 if dir1 == dir2 {
382 return true
383 }
384 info1, err1 := os.Stat(dir1)
385 info2, err2 := os.Stat(dir2)
386 return err1 == nil && err2 == nil && os.SameFile(info1, info2)
387 }
388
389
390
391
392
393
394
395
396 func isGOROOT(path string) bool {
397 stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
398 if err != nil {
399 return false
400 }
401 return stat.IsDir()
402 }
403
404 func gopathDir(rel string) string {
405 list := filepath.SplitList(BuildContext.GOPATH)
406 if len(list) == 0 || list[0] == "" {
407 return ""
408 }
409 return filepath.Join(list[0], rel)
410 }
411
412 func gopath(ctxt build.Context) string {
413 if len(ctxt.GOPATH) > 0 {
414 return ctxt.GOPATH
415 }
416 env := "HOME"
417 if runtime.GOOS == "windows" {
418 env = "USERPROFILE"
419 } else if runtime.GOOS == "plan9" {
420 env = "home"
421 }
422 if home := os.Getenv(env); home != "" {
423 def := filepath.Join(home, "go")
424 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
425 GoPathError = "cannot set GOROOT as GOPATH"
426 }
427 return ""
428 }
429 GoPathError = fmt.Sprintf("%s is not set", env)
430 return ""
431 }
432
View as plain text