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