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