mirror of
https://github.com/golang/go
synced 2024-11-23 02:00:03 -07:00
cmd/go: add env -w and env -u to set and unset default env vars
Setting environment variables for go command configuration is too difficult and system-specific. This CL adds go env -w, to change the default settings more easily, in a portable way. It also adds go env -u, to unset those changes. See https://golang.org/design/30411-env for details. Fixes #30411. Change-Id: I36e83f55b666459f8f7f482432a4a6ee015da71d Reviewed-on: https://go-review.googlesource.com/c/go/+/171137 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
parent
e40dffe55a
commit
f0e9754696
@ -368,7 +368,7 @@
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go env [-json] [var ...]
|
||||
// go env [-json] [-u] [-w] [var ...]
|
||||
//
|
||||
// Env prints Go environment information.
|
||||
//
|
||||
@ -380,6 +380,14 @@
|
||||
// The -json flag prints the environment in JSON format
|
||||
// instead of as a shell script.
|
||||
//
|
||||
// The -u flag requires one or more arguments and unsets
|
||||
// the default setting for the named environment variables,
|
||||
// if one has been set with 'go env -w'.
|
||||
//
|
||||
// The -w flag requires one or more arguments of the
|
||||
// form NAME=VALUE and changes the default settings
|
||||
// of the named environment variables to the given values.
|
||||
//
|
||||
// For more about environment variables, see 'go help environment'.
|
||||
//
|
||||
//
|
||||
@ -1485,10 +1493,17 @@
|
||||
//
|
||||
// Environment variables
|
||||
//
|
||||
// The go command, and the tools it invokes, examine a few different
|
||||
// environment variables. For many of these, you can see the default
|
||||
// value of on your system by running 'go env NAME', where NAME is the
|
||||
// name of the variable.
|
||||
// The go command and the tools it invokes consult environment variables
|
||||
// for configuration. If an environment variable is unset, the go command
|
||||
// uses a sensible default setting. To see the effective setting of the
|
||||
// variable <NAME>, run 'go env <NAME>'. To change the default setting,
|
||||
// run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
|
||||
// are recorded in a Go environment configuration file stored in the
|
||||
// per-user configuration directory, as reported by os.UserConfigDir.
|
||||
// The location of the configuration file can be changed by setting
|
||||
// the environment variable GOENV, and 'go env GOENV' prints the
|
||||
// effective location, but 'go env -w' cannot change the default location.
|
||||
// See 'go help env' for details.
|
||||
//
|
||||
// General-purpose environment variables:
|
||||
//
|
||||
@ -1502,10 +1517,15 @@
|
||||
// GOCACHE
|
||||
// The directory where the go command will store cached
|
||||
// information for reuse in future builds.
|
||||
// GOENV
|
||||
// The location of the Go environment configuration file.
|
||||
// Cannot be set using 'go env -w'.
|
||||
// GOFLAGS
|
||||
// A space-separated list of -flag=value settings to apply
|
||||
// to go commands by default, when the given flag is known by
|
||||
// the current command. Flags listed on the command line
|
||||
// the current command. Each entry must be a standalone flag.
|
||||
// Because the entries are space-separated, flag values must
|
||||
// not contain spaces. Flags listed on the command line
|
||||
// are applied after this list and therefore override it.
|
||||
// GOOS
|
||||
// The operating system for which to compile code.
|
||||
@ -1514,21 +1534,18 @@
|
||||
// For more details see: 'go help gopath'.
|
||||
// GOPROXY
|
||||
// URL of Go module proxy. See 'go help goproxy'.
|
||||
// GORACE
|
||||
// Options for the race detector.
|
||||
// See https://golang.org/doc/articles/race_detector.html.
|
||||
// GOROOT
|
||||
// The root of the go tree.
|
||||
// GOTMPDIR
|
||||
// The directory where the go command will write
|
||||
// temporary source files, packages, and binaries.
|
||||
//
|
||||
// Each entry in the GOFLAGS list must be a standalone flag.
|
||||
// Because the entries are space-separated, flag values must
|
||||
// not contain spaces.
|
||||
//
|
||||
// Environment variables for use with cgo:
|
||||
//
|
||||
// AR
|
||||
// The command to use to manipulate library archives when
|
||||
// building with the gccgo compiler.
|
||||
// The default is 'ar'.
|
||||
// CC
|
||||
// The command to use to compile C code.
|
||||
// CGO_ENABLED
|
||||
@ -1558,12 +1575,10 @@
|
||||
// but for the linker.
|
||||
// CXX
|
||||
// The command to use to compile C++ code.
|
||||
// FC
|
||||
// The command to use to compile Fortran code.
|
||||
// PKG_CONFIG
|
||||
// Path to pkg-config tool.
|
||||
// AR
|
||||
// The command to use to manipulate library archives when
|
||||
// building with the gccgo compiler.
|
||||
// The default is 'ar'.
|
||||
//
|
||||
// Architecture-specific environment variables:
|
||||
//
|
||||
@ -1598,9 +1613,11 @@
|
||||
// when using -linkmode=auto with code that uses cgo.
|
||||
// Set to 0 to disable external linking mode, 1 to enable it.
|
||||
// GIT_ALLOW_PROTOCOL
|
||||
// Defined by Git. A colon-separated list of schemes that are allowed to be used
|
||||
// with git fetch/clone. If set, any scheme not explicitly mentioned will be
|
||||
// considered insecure by 'go get'.
|
||||
// Defined by Git. A colon-separated list of schemes that are allowed
|
||||
// to be used with git fetch/clone. If set, any scheme not explicitly
|
||||
// mentioned will be considered insecure by 'go get'.
|
||||
// Because the variable is defined by Git, the default value cannot
|
||||
// be set using 'go env -w'.
|
||||
//
|
||||
// Additional information available from 'go env' but not read from the environment:
|
||||
//
|
||||
|
@ -6,8 +6,6 @@ package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/internal/sys"
|
||||
"context"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
@ -28,6 +26,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/internal/sys"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -119,6 +121,8 @@ var testCtx = context.Background()
|
||||
// The TestMain function creates a go command for testing purposes and
|
||||
// deletes it after the tests have been run.
|
||||
func TestMain(m *testing.M) {
|
||||
// $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc.
|
||||
// It is not a standard go command flag; use os.Getenv, not cfg.Getenv.
|
||||
if os.Getenv("GO_GCFLAGS") != "" {
|
||||
fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go
|
||||
fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n")
|
||||
@ -256,6 +260,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
}
|
||||
// Don't let these environment variables confuse the test.
|
||||
os.Setenv("GOENV", "off")
|
||||
os.Unsetenv("GOBIN")
|
||||
os.Unsetenv("GOPATH")
|
||||
os.Unsetenv("GIT_ALLOW_PROTOCOL")
|
||||
@ -264,7 +269,7 @@ func TestMain(m *testing.M) {
|
||||
// Setting HOME to a non-existent directory will break
|
||||
// those systems. Disable ccache and use real compiler. Issue 17668.
|
||||
os.Setenv("CCACHE_DISABLE", "1")
|
||||
if os.Getenv("GOCACHE") == "" {
|
||||
if cfg.Getenv("GOCACHE") == "" {
|
||||
os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone
|
||||
}
|
||||
|
||||
@ -5258,7 +5263,7 @@ func TestCacheVet(t *testing.T) {
|
||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
||||
t.Skip("GODEBUG gocacheverify")
|
||||
}
|
||||
if os.Getenv("GOCACHE") == "off" {
|
||||
if cfg.Getenv("GOCACHE") == "off" {
|
||||
tooSlow(t)
|
||||
tg.makeTempdir()
|
||||
tg.setenv("GOCACHE", tg.path("cache"))
|
||||
|
@ -7,7 +7,6 @@ package base
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@ -62,7 +61,7 @@ func InitGOFLAGS() {
|
||||
// (Both will show the GOFLAGS setting if let succeed.)
|
||||
hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug"
|
||||
|
||||
goflags = strings.Fields(os.Getenv("GOFLAGS"))
|
||||
goflags = strings.Fields(cfg.Getenv("GOFLAGS"))
|
||||
if goflags == nil {
|
||||
goflags = []string{} // avoid work on later InitGOFLAGS call
|
||||
}
|
||||
|
3
src/cmd/go/internal/cache/default.go
vendored
3
src/cmd/go/internal/cache/default.go
vendored
@ -12,6 +12,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
)
|
||||
|
||||
// Default returns the default cache to use, or nil if no cache should be used.
|
||||
@ -73,7 +74,7 @@ func DefaultDir() string {
|
||||
// otherwise distinguish between an explicit "off" and a UserCacheDir error.
|
||||
|
||||
defaultDirOnce.Do(func() {
|
||||
defaultDir = os.Getenv("GOCACHE")
|
||||
defaultDir = cfg.Getenv("GOCACHE")
|
||||
if filepath.IsAbs(defaultDir) || defaultDir == "off" {
|
||||
return
|
||||
}
|
||||
|
@ -7,11 +7,15 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/internal/objabi"
|
||||
)
|
||||
@ -46,6 +50,50 @@ var (
|
||||
func defaultContext() build.Context {
|
||||
ctxt := build.Default
|
||||
ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
|
||||
|
||||
ctxt.GOROOT = findGOROOT()
|
||||
if runtime.Compiler != "gccgo" {
|
||||
// Note that we must use runtime.GOOS and runtime.GOARCH here,
|
||||
// as the tool directory does not move based on environment
|
||||
// variables. This matches the initialization of ToolDir in
|
||||
// go/build, except for using ctxt.GOROOT rather than
|
||||
// runtime.GOROOT.
|
||||
build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
|
||||
}
|
||||
|
||||
ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH)
|
||||
|
||||
// Override defaults computed in go/build with defaults
|
||||
// from go environment configuration file, if known.
|
||||
ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
|
||||
ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
|
||||
|
||||
// The go/build rule for whether cgo is enabled is:
|
||||
// 1. If $CGO_ENABLED is set, respect it.
|
||||
// 2. Otherwise, if this is a cross-compile, disable cgo.
|
||||
// 3. Otherwise, use built-in default for GOOS/GOARCH.
|
||||
// Recreate that logic here with the new GOOS/GOARCH setting.
|
||||
if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
|
||||
ctxt.CgoEnabled = v[0] == '1'
|
||||
} else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
|
||||
ctxt.CgoEnabled = false
|
||||
} else {
|
||||
// Use built-in default cgo setting for GOOS/GOARCH.
|
||||
// Note that ctxt.GOOS/GOARCH are derived from the preference list
|
||||
// (1) environment, (2) go/env file, (3) runtime constants,
|
||||
// while go/build.Default.GOOS/GOARCH are derived from the preference list
|
||||
// (1) environment, (2) runtime constants.
|
||||
// We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
|
||||
// no matter how that happened, go/build.Default will make the
|
||||
// same decision (either the environment variables are set explicitly
|
||||
// to match the runtime constants, or else they are unset, in which
|
||||
// case go/build falls back to the runtime constants), so
|
||||
// go/build.Default.GOOS/GOARCH == runtime.GOOS/GOARCH.
|
||||
// So ctxt.CgoEnabled (== go/build.Default.CgoEnabled) is correct
|
||||
// as is and can be left unmodified.
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
return ctxt
|
||||
}
|
||||
|
||||
@ -70,9 +118,10 @@ var CmdEnv []EnvVar
|
||||
|
||||
// Global build parameters (used during package load)
|
||||
var (
|
||||
Goarch = BuildContext.GOARCH
|
||||
Goos = BuildContext.GOOS
|
||||
ExeSuffix string
|
||||
Goarch = BuildContext.GOARCH
|
||||
Goos = BuildContext.GOOS
|
||||
|
||||
ExeSuffix = exeSuffix()
|
||||
|
||||
// ModulesEnabled specifies whether the go command is running
|
||||
// in module-aware mode (as opposed to GOPATH mode).
|
||||
@ -85,40 +134,195 @@ var (
|
||||
GoModInGOPATH string
|
||||
)
|
||||
|
||||
func init() {
|
||||
func exeSuffix() string {
|
||||
if Goos == "windows" {
|
||||
ExeSuffix = ".exe"
|
||||
return ".exe"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var envCache struct {
|
||||
once sync.Once
|
||||
m map[string]string
|
||||
}
|
||||
|
||||
// EnvFile returns the name of the Go environment configuration file.
|
||||
func EnvFile() (string, error) {
|
||||
if file := os.Getenv("GOENV"); file != "" {
|
||||
if file == "off" {
|
||||
return "", fmt.Errorf("GOENV=off")
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
dir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if dir == "" {
|
||||
return "", fmt.Errorf("missing user-config dir")
|
||||
}
|
||||
return filepath.Join(dir, "go/env"), nil
|
||||
}
|
||||
|
||||
func initEnvCache() {
|
||||
envCache.m = make(map[string]string)
|
||||
file, _ := EnvFile()
|
||||
if file == "" {
|
||||
return
|
||||
}
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for len(data) > 0 {
|
||||
// Get next line.
|
||||
line := data
|
||||
i := bytes.IndexByte(data, '\n')
|
||||
if i >= 0 {
|
||||
line, data = line[:i], data[i+1:]
|
||||
} else {
|
||||
data = nil
|
||||
}
|
||||
|
||||
i = bytes.IndexByte(line, '=')
|
||||
if i < 0 || line[0] < 'A' || 'Z' < line[0] {
|
||||
// Line is missing = (or empty) or a comment or not a valid env name. Ignore.
|
||||
// (This should not happen, since the file should be maintained almost
|
||||
// exclusively by "go env -w", but better to silently ignore than to make
|
||||
// the go command unusable just because somehow the env file has
|
||||
// gotten corrupted.)
|
||||
continue
|
||||
}
|
||||
key, val := line[:i], line[i+1:]
|
||||
envCache.m[string(key)] = string(val)
|
||||
}
|
||||
}
|
||||
|
||||
// Getenv gets the value for the configuration key.
|
||||
// It consults the operating system environment
|
||||
// and then the go/env file.
|
||||
// If Getenv is called for a key that cannot be set
|
||||
// in the go/env file (for example GODEBUG), it panics.
|
||||
// This ensures that CanGetenv is accurate, so that
|
||||
// 'go env -w' stays in sync with what Getenv can retrieve.
|
||||
func Getenv(key string) string {
|
||||
if !CanGetenv(key) {
|
||||
switch key {
|
||||
case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW":
|
||||
// used by internal/work/security_test.go; allow
|
||||
default:
|
||||
panic("internal error: invalid Getenv " + key)
|
||||
}
|
||||
}
|
||||
val := os.Getenv(key)
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
envCache.once.Do(initEnvCache)
|
||||
return envCache.m[key]
|
||||
}
|
||||
|
||||
// CanGetenv reports whether key is a valid go/env configuration key.
|
||||
func CanGetenv(key string) bool {
|
||||
return strings.Contains(knownEnv, "\t"+key+"\n")
|
||||
}
|
||||
|
||||
var knownEnv = `
|
||||
AR
|
||||
CC
|
||||
CGO_CFLAGS
|
||||
CGO_CFLAGS_ALLOW
|
||||
CGO_CFLAGS_DISALLOW
|
||||
CGO_CPPFLAGS
|
||||
CGO_CPPFLAGS_ALLOW
|
||||
CGO_CPPFLAGS_DISALLOW
|
||||
CGO_CXXFLAGS
|
||||
CGO_CXXFLAGS_ALLOW
|
||||
CGO_CXXFLAGS_DISALLOW
|
||||
CGO_ENABLED
|
||||
CGO_FFLAGS
|
||||
CGO_FFLAGS_ALLOW
|
||||
CGO_FFLAGS_DISALLOW
|
||||
CGO_LDFLAGS
|
||||
CGO_LDFLAGS_ALLOW
|
||||
CGO_LDFLAGS_DISALLOW
|
||||
CXX
|
||||
FC
|
||||
GCCGO
|
||||
GO111MODULE
|
||||
GO386
|
||||
GOARCH
|
||||
GOARM
|
||||
GOBIN
|
||||
GOCACHE
|
||||
GOENV
|
||||
GOEXE
|
||||
GOFLAGS
|
||||
GOGCCFLAGS
|
||||
GOHOSTARCH
|
||||
GOHOSTOS
|
||||
GOMIPS
|
||||
GOMIPS64
|
||||
GONOVERIFY
|
||||
GOOS
|
||||
GOPATH
|
||||
GOPPC64
|
||||
GOPROXY
|
||||
GOROOT
|
||||
GOTMPDIR
|
||||
GOTOOLDIR
|
||||
GOWASM
|
||||
GO_EXTLINK_ENABLED
|
||||
PKG_CONFIG
|
||||
`
|
||||
|
||||
var (
|
||||
GOROOT = findGOROOT()
|
||||
GOBIN = os.Getenv("GOBIN")
|
||||
GOROOT = BuildContext.GOROOT
|
||||
GOBIN = Getenv("GOBIN")
|
||||
GOROOTbin = filepath.Join(GOROOT, "bin")
|
||||
GOROOTpkg = filepath.Join(GOROOT, "pkg")
|
||||
GOROOTsrc = filepath.Join(GOROOT, "src")
|
||||
GOROOT_FINAL = findGOROOT_FINAL()
|
||||
|
||||
// Used in envcmd.MkEnv and build ID computations.
|
||||
GOARM = fmt.Sprint(objabi.GOARM)
|
||||
GO386 = objabi.GO386
|
||||
GOMIPS = objabi.GOMIPS
|
||||
GOMIPS64 = objabi.GOMIPS64
|
||||
GOPPC64 = fmt.Sprintf("%s%d", "power", objabi.GOPPC64)
|
||||
GOWASM = objabi.GOWASM
|
||||
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
||||
GO386 = envOr("GO386", objabi.GO386)
|
||||
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
||||
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
||||
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
||||
GOWASM = envOr("GOWASM", fmt.Sprint(objabi.GOWASM))
|
||||
)
|
||||
|
||||
// Update build context to use our computed GOROOT.
|
||||
func init() {
|
||||
BuildContext.GOROOT = GOROOT
|
||||
if runtime.Compiler != "gccgo" {
|
||||
// Note that we must use runtime.GOOS and runtime.GOARCH here,
|
||||
// as the tool directory does not move based on environment
|
||||
// variables. This matches the initialization of ToolDir in
|
||||
// go/build, except for using GOROOT rather than
|
||||
// runtime.GOROOT.
|
||||
build.ToolDir = filepath.Join(GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
|
||||
// GetArchEnv returns the name and setting of the
|
||||
// GOARCH-specific architecture environment variable.
|
||||
// If the current architecture has no GOARCH-specific variable,
|
||||
// GetArchEnv returns empty key and value.
|
||||
func GetArchEnv() (key, val string) {
|
||||
switch Goarch {
|
||||
case "arm":
|
||||
return "GOARM", GOARM
|
||||
case "386":
|
||||
return "GO386", GO386
|
||||
case "mips", "mipsle":
|
||||
return "GOMIPS", GOMIPS
|
||||
case "mips64", "mips64le":
|
||||
return "GOMIPS64", GOMIPS64
|
||||
case "ppc64", "ppc64le":
|
||||
return "GOPPC64", GOPPC64
|
||||
case "wasm":
|
||||
return "GOWASM", GOWASM
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// envOr returns Getenv(key) if set, or else def.
|
||||
func envOr(key, def string) string {
|
||||
val := Getenv(key)
|
||||
if val == "" {
|
||||
val = def
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// There is a copy of findGOROOT, isSameDir, and isGOROOT in
|
||||
@ -132,7 +336,7 @@ func init() {
|
||||
//
|
||||
// There is a copy of this code in x/tools/cmd/godoc/goroot.go.
|
||||
func findGOROOT() string {
|
||||
if env := os.Getenv("GOROOT"); env != "" {
|
||||
if env := Getenv("GOROOT"); env != "" {
|
||||
return filepath.Clean(env)
|
||||
}
|
||||
def := filepath.Clean(runtime.GOROOT())
|
||||
@ -168,6 +372,8 @@ func findGOROOT() string {
|
||||
}
|
||||
|
||||
func findGOROOT_FINAL() string {
|
||||
// $GOROOT_FINAL is only for use during make.bash
|
||||
// so it is not settable using go/env, so we use os.Getenv here.
|
||||
def := GOROOT
|
||||
if env := os.Getenv("GOROOT_FINAL"); env != "" {
|
||||
def = filepath.Clean(env)
|
||||
|
@ -10,6 +10,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"unicode/utf8"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@ -22,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
var CmdEnv = &base.Command{
|
||||
UsageLine: "go env [-json] [var ...]",
|
||||
UsageLine: "go env [-json] [-u] [-w] [var ...]",
|
||||
Short: "print Go environment information",
|
||||
Long: `
|
||||
Env prints Go environment information.
|
||||
@ -35,6 +38,14 @@ each named variable on its own line.
|
||||
The -json flag prints the environment in JSON format
|
||||
instead of as a shell script.
|
||||
|
||||
The -u flag requires one or more arguments and unsets
|
||||
the default setting for the named environment variables,
|
||||
if one has been set with 'go env -w'.
|
||||
|
||||
The -w flag requires one or more arguments of the
|
||||
form NAME=VALUE and changes the default settings
|
||||
of the named environment variables to the given values.
|
||||
|
||||
For more about environment variables, see 'go help environment'.
|
||||
`,
|
||||
}
|
||||
@ -43,26 +54,31 @@ func init() {
|
||||
CmdEnv.Run = runEnv // break init cycle
|
||||
}
|
||||
|
||||
var envJson = CmdEnv.Flag.Bool("json", false, "")
|
||||
var (
|
||||
envJson = CmdEnv.Flag.Bool("json", false, "")
|
||||
envU = CmdEnv.Flag.Bool("u", false, "")
|
||||
envW = CmdEnv.Flag.Bool("w", false, "")
|
||||
)
|
||||
|
||||
func MkEnv() []cfg.EnvVar {
|
||||
var b work.Builder
|
||||
b.Init()
|
||||
|
||||
envFile, _ := cfg.EnvFile()
|
||||
env := []cfg.EnvVar{
|
||||
{Name: "GOARCH", Value: cfg.Goarch},
|
||||
{Name: "GOBIN", Value: cfg.GOBIN},
|
||||
{Name: "GOCACHE", Value: cache.DefaultDir()},
|
||||
{Name: "GOENV", Value: envFile},
|
||||
{Name: "GOEXE", Value: cfg.ExeSuffix},
|
||||
{Name: "GOFLAGS", Value: os.Getenv("GOFLAGS")},
|
||||
{Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")},
|
||||
{Name: "GOHOSTARCH", Value: runtime.GOARCH},
|
||||
{Name: "GOHOSTOS", Value: runtime.GOOS},
|
||||
{Name: "GOOS", Value: cfg.Goos},
|
||||
{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
|
||||
{Name: "GOPROXY", Value: os.Getenv("GOPROXY")},
|
||||
{Name: "GORACE", Value: os.Getenv("GORACE")},
|
||||
{Name: "GOPROXY", Value: cfg.Getenv("GOPROXY")},
|
||||
{Name: "GOROOT", Value: cfg.GOROOT},
|
||||
{Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")},
|
||||
{Name: "GOTMPDIR", Value: cfg.Getenv("GOTMPDIR")},
|
||||
{Name: "GOTOOLDIR", Value: base.ToolDir},
|
||||
}
|
||||
|
||||
@ -72,29 +88,20 @@ func MkEnv() []cfg.EnvVar {
|
||||
env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName})
|
||||
}
|
||||
|
||||
switch cfg.Goarch {
|
||||
case "arm":
|
||||
env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM})
|
||||
case "386":
|
||||
env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
|
||||
case "mips", "mipsle":
|
||||
env = append(env, cfg.EnvVar{Name: "GOMIPS", Value: cfg.GOMIPS})
|
||||
case "mips64", "mips64le":
|
||||
env = append(env, cfg.EnvVar{Name: "GOMIPS64", Value: cfg.GOMIPS64})
|
||||
case "ppc64", "ppc64le":
|
||||
env = append(env, cfg.EnvVar{Name: "GOPPC64", Value: cfg.GOPPC64})
|
||||
case "wasm":
|
||||
env = append(env, cfg.EnvVar{Name: "GOWASM", Value: cfg.GOWASM.String()})
|
||||
key, val := cfg.GetArchEnv()
|
||||
if key != "" {
|
||||
env = append(env, cfg.EnvVar{Name: key, Value: val})
|
||||
}
|
||||
|
||||
cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
|
||||
if env := strings.Fields(os.Getenv("CC")); len(env) > 0 {
|
||||
if env := strings.Fields(cfg.Getenv("CC")); len(env) > 0 {
|
||||
cc = env[0]
|
||||
}
|
||||
cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
|
||||
if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 {
|
||||
if env := strings.Fields(cfg.Getenv("CXX")); len(env) > 0 {
|
||||
cxx = env[0]
|
||||
}
|
||||
env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")})
|
||||
env = append(env, cfg.EnvVar{Name: "CC", Value: cc})
|
||||
env = append(env, cfg.EnvVar{Name: "CXX", Value: cxx})
|
||||
|
||||
@ -107,6 +114,14 @@ func MkEnv() []cfg.EnvVar {
|
||||
return env
|
||||
}
|
||||
|
||||
func envOr(name, def string) string {
|
||||
val := cfg.Getenv(name)
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func findEnv(env []cfg.EnvVar, name string) string {
|
||||
for _, e := range env {
|
||||
if e.Name == name {
|
||||
@ -154,7 +169,25 @@ func ExtraEnvVarsCostly() []cfg.EnvVar {
|
||||
}
|
||||
}
|
||||
|
||||
// argKey returns the KEY part of the arg KEY=VAL, or else arg itself.
|
||||
func argKey(arg string) string {
|
||||
i := strings.Index(arg, "=")
|
||||
if i < 0 {
|
||||
return arg
|
||||
}
|
||||
return arg[:i]
|
||||
}
|
||||
|
||||
func runEnv(cmd *base.Command, args []string) {
|
||||
if *envJson && *envU {
|
||||
base.Fatalf("go env: cannot use -json with -u")
|
||||
}
|
||||
if *envJson && *envW {
|
||||
base.Fatalf("go env: cannot use -json with -w")
|
||||
}
|
||||
if *envU && *envW {
|
||||
base.Fatalf("go env: cannot use -u with -w")
|
||||
}
|
||||
env := cfg.CmdEnv
|
||||
env = append(env, ExtraEnvVars()...)
|
||||
|
||||
@ -165,7 +198,7 @@ func runEnv(cmd *base.Command, args []string) {
|
||||
if len(args) > 0 {
|
||||
needCostly = false
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
switch argKey(arg) {
|
||||
case "CGO_CFLAGS",
|
||||
"CGO_CPPFLAGS",
|
||||
"CGO_CXXFLAGS",
|
||||
@ -181,6 +214,55 @@ func runEnv(cmd *base.Command, args []string) {
|
||||
env = append(env, ExtraEnvVarsCostly()...)
|
||||
}
|
||||
|
||||
if *envW {
|
||||
// Process and sanity-check command line.
|
||||
if len(args) == 0 {
|
||||
base.Fatalf("go env -w: no KEY=VALUE arguments given")
|
||||
}
|
||||
osEnv := make(map[string]string)
|
||||
for _, e := range cfg.OrigEnv {
|
||||
if i := strings.Index(e, "="); i >= 0 {
|
||||
osEnv[e[:i]] = e[i+1:]
|
||||
}
|
||||
}
|
||||
add := make(map[string]string)
|
||||
for _, arg := range args {
|
||||
i := strings.Index(arg, "=")
|
||||
if i < 0 {
|
||||
base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
|
||||
}
|
||||
key, val := arg[:i], arg[i+1:]
|
||||
if err := checkEnvWrite(key, val, env); err != nil {
|
||||
base.Fatalf("go env -w: %v", err)
|
||||
}
|
||||
if _, ok := add[key]; ok {
|
||||
base.Fatalf("go env -w: multiple values for key: %s", key)
|
||||
}
|
||||
add[key] = val
|
||||
if osVal := osEnv[key]; osVal != "" && osVal != val {
|
||||
fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key)
|
||||
}
|
||||
}
|
||||
updateEnvFile(add, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if *envU {
|
||||
// Process and sanity-check command line.
|
||||
if len(args) == 0 {
|
||||
base.Fatalf("go env -u: no arguments given")
|
||||
}
|
||||
del := make(map[string]bool)
|
||||
for _, arg := range args {
|
||||
if err := checkEnvWrite(arg, "", env); err != nil {
|
||||
base.Fatalf("go env -u: %v", err)
|
||||
}
|
||||
del[arg] = true
|
||||
}
|
||||
updateEnvFile(nil, del)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
if *envJson {
|
||||
var es []cfg.EnvVar
|
||||
@ -239,6 +321,118 @@ func printEnvAsJSON(env []cfg.EnvVar) {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", "\t")
|
||||
if err := enc.Encode(m); err != nil {
|
||||
base.Fatalf("%s", err)
|
||||
base.Fatalf("go env -json: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func checkEnvWrite(key, val string, env []cfg.EnvVar) error {
|
||||
switch key {
|
||||
case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOTOOLDIR":
|
||||
return fmt.Errorf("%s cannot be modified", key)
|
||||
case "GOENV":
|
||||
return fmt.Errorf("%s can only be set using the OS environment", key)
|
||||
}
|
||||
|
||||
// To catch typos and the like, check that we know the variable.
|
||||
if !cfg.CanGetenv(key) {
|
||||
return fmt.Errorf("unknown go command variable %s", key)
|
||||
}
|
||||
|
||||
if !utf8.ValidString(val) {
|
||||
return fmt.Errorf("invalid UTF-8 in %s=... value", key)
|
||||
}
|
||||
if strings.Contains(val, "\x00") {
|
||||
return fmt.Errorf("invalid NUL in %s=... value", key)
|
||||
}
|
||||
if strings.ContainsAny(val, "\v\r\n") {
|
||||
return fmt.Errorf("invalid newline in %s=... value", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateEnvFile(add map[string]string, del map[string]bool) {
|
||||
file, err := cfg.EnvFile()
|
||||
if file == "" {
|
||||
base.Fatalf("go env: cannot find go env config: %v", err)
|
||||
}
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil && (!os.IsNotExist(err) || len(add) == 0) {
|
||||
base.Fatalf("go env: reading go env config: %v", err)
|
||||
}
|
||||
|
||||
lines := strings.SplitAfter(string(data), "\n")
|
||||
if lines[len(lines)-1] == "" {
|
||||
lines = lines[:len(lines)-1]
|
||||
} else {
|
||||
lines[len(lines)-1] += "\n"
|
||||
}
|
||||
|
||||
// Delete all but last copy of any duplicated variables,
|
||||
// since the last copy is the one that takes effect.
|
||||
prev := make(map[string]int)
|
||||
for l, line := range lines {
|
||||
if key := lineToKey(line); key != "" {
|
||||
if p, ok := prev[key]; ok {
|
||||
lines[p] = ""
|
||||
}
|
||||
prev[key] = l
|
||||
}
|
||||
}
|
||||
|
||||
// Add variables (go env -w). Update existing lines in file if present, add to end otherwise.
|
||||
for key, val := range add {
|
||||
if p, ok := prev[key]; ok {
|
||||
lines[p] = key + "=" + val + "\n"
|
||||
delete(add, key)
|
||||
}
|
||||
}
|
||||
for key, val := range add {
|
||||
lines = append(lines, key + "=" + val + "\n")
|
||||
}
|
||||
|
||||
// Delete requested variables (go env -u).
|
||||
for key := range del {
|
||||
if p, ok := prev[key]; ok {
|
||||
lines[p] = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Sort runs of KEY=VALUE lines
|
||||
// (that is, blocks of lines where blocks are separated
|
||||
// by comments, blank lines, or invalid lines).
|
||||
start := 0
|
||||
for i := 0; i <= len(lines); i++ {
|
||||
if i == len(lines) || lineToKey(lines[i]) == "" {
|
||||
sortKeyValues(lines[start:i])
|
||||
start = i+1
|
||||
}
|
||||
}
|
||||
|
||||
data = []byte(strings.Join(lines, ""))
|
||||
err = ioutil.WriteFile(file, data, 0666)
|
||||
if err != nil {
|
||||
// Try creating directory.
|
||||
os.MkdirAll(filepath.Dir(file), 0777)
|
||||
err = ioutil.WriteFile(file, data, 0666)
|
||||
if err != nil {
|
||||
base.Fatalf("go env: writing go env config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lineToKey returns the KEY part of the line KEY=VALUE or else an empty string.
|
||||
func lineToKey(line string) string {
|
||||
i := strings.Index(line, "=")
|
||||
if i < 0 || strings.Contains(line[:i], "#") {
|
||||
return ""
|
||||
}
|
||||
return line[:i]
|
||||
}
|
||||
|
||||
// sortKeyValues sorts a sequence of lines by key.
|
||||
// It differs from sort.Strings in that GO386= sorts after GO=.
|
||||
func sortKeyValues(lines []string) {
|
||||
sort.Slice(lines, func(i, j int) bool {
|
||||
return lineToKey(lines[i]) < lineToKey(lines[j])
|
||||
})
|
||||
}
|
||||
|
@ -469,10 +469,17 @@ var HelpEnvironment = &base.Command{
|
||||
Short: "environment variables",
|
||||
Long: `
|
||||
|
||||
The go command, and the tools it invokes, examine a few different
|
||||
environment variables. For many of these, you can see the default
|
||||
value of on your system by running 'go env NAME', where NAME is the
|
||||
name of the variable.
|
||||
The go command and the tools it invokes consult environment variables
|
||||
for configuration. If an environment variable is unset, the go command
|
||||
uses a sensible default setting. To see the effective setting of the
|
||||
variable <NAME>, run 'go env <NAME>'. To change the default setting,
|
||||
run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
|
||||
are recorded in a Go environment configuration file stored in the
|
||||
per-user configuration directory, as reported by os.UserConfigDir.
|
||||
The location of the configuration file can be changed by setting
|
||||
the environment variable GOENV, and 'go env GOENV' prints the
|
||||
effective location, but 'go env -w' cannot change the default location.
|
||||
See 'go help env' for details.
|
||||
|
||||
General-purpose environment variables:
|
||||
|
||||
@ -486,10 +493,15 @@ General-purpose environment variables:
|
||||
GOCACHE
|
||||
The directory where the go command will store cached
|
||||
information for reuse in future builds.
|
||||
GOENV
|
||||
The location of the Go environment configuration file.
|
||||
Cannot be set using 'go env -w'.
|
||||
GOFLAGS
|
||||
A space-separated list of -flag=value settings to apply
|
||||
to go commands by default, when the given flag is known by
|
||||
the current command. Flags listed on the command line
|
||||
the current command. Each entry must be a standalone flag.
|
||||
Because the entries are space-separated, flag values must
|
||||
not contain spaces. Flags listed on the command line
|
||||
are applied after this list and therefore override it.
|
||||
GOOS
|
||||
The operating system for which to compile code.
|
||||
@ -498,21 +510,18 @@ General-purpose environment variables:
|
||||
For more details see: 'go help gopath'.
|
||||
GOPROXY
|
||||
URL of Go module proxy. See 'go help goproxy'.
|
||||
GORACE
|
||||
Options for the race detector.
|
||||
See https://golang.org/doc/articles/race_detector.html.
|
||||
GOROOT
|
||||
The root of the go tree.
|
||||
GOTMPDIR
|
||||
The directory where the go command will write
|
||||
temporary source files, packages, and binaries.
|
||||
|
||||
Each entry in the GOFLAGS list must be a standalone flag.
|
||||
Because the entries are space-separated, flag values must
|
||||
not contain spaces.
|
||||
|
||||
Environment variables for use with cgo:
|
||||
|
||||
AR
|
||||
The command to use to manipulate library archives when
|
||||
building with the gccgo compiler.
|
||||
The default is 'ar'.
|
||||
CC
|
||||
The command to use to compile C code.
|
||||
CGO_ENABLED
|
||||
@ -542,12 +551,10 @@ Environment variables for use with cgo:
|
||||
but for the linker.
|
||||
CXX
|
||||
The command to use to compile C++ code.
|
||||
FC
|
||||
The command to use to compile Fortran code.
|
||||
PKG_CONFIG
|
||||
Path to pkg-config tool.
|
||||
AR
|
||||
The command to use to manipulate library archives when
|
||||
building with the gccgo compiler.
|
||||
The default is 'ar'.
|
||||
|
||||
Architecture-specific environment variables:
|
||||
|
||||
@ -582,9 +589,11 @@ Special-purpose environment variables:
|
||||
when using -linkmode=auto with code that uses cgo.
|
||||
Set to 0 to disable external linking mode, 1 to enable it.
|
||||
GIT_ALLOW_PROTOCOL
|
||||
Defined by Git. A colon-separated list of schemes that are allowed to be used
|
||||
with git fetch/clone. If set, any scheme not explicitly mentioned will be
|
||||
considered insecure by 'go get'.
|
||||
Defined by Git. A colon-separated list of schemes that are allowed
|
||||
to be used with git fetch/clone. If set, any scheme not explicitly
|
||||
mentioned will be considered insecure by 'go get'.
|
||||
Because the variable is defined by Git, the default value cannot
|
||||
be set using 'go env -w'.
|
||||
|
||||
Additional information available from 'go env' but not read from the environment:
|
||||
|
||||
|
@ -6,11 +6,11 @@ package modfetch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/get"
|
||||
"cmd/go/internal/module"
|
||||
)
|
||||
@ -67,7 +67,7 @@ func useNotary(mod module.Version) bool {
|
||||
if get.Insecure {
|
||||
return false
|
||||
}
|
||||
wantNotary, err := notaryShouldVerify(mod.Path, os.Getenv("GONOVERIFY"))
|
||||
wantNotary, err := notaryShouldVerify(mod.Path, cfg.Getenv("GONOVERIFY"))
|
||||
if err != nil {
|
||||
base.Fatalf("%v", err)
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modfetch/codehost"
|
||||
"cmd/go/internal/module"
|
||||
"cmd/go/internal/semver"
|
||||
@ -85,7 +85,7 @@ cached module versions with GOPROXY=https://example.com/proxy.
|
||||
`,
|
||||
}
|
||||
|
||||
var proxyURL = os.Getenv("GOPROXY")
|
||||
var proxyURL = cfg.Getenv("GOPROXY")
|
||||
|
||||
// SetProxy sets the proxy to use when fetching modules.
|
||||
// It accepts the same syntax as the GOPROXY environment variable,
|
||||
|
@ -6,6 +6,18 @@ package modload
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/lazyregexp"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
@ -18,17 +30,6 @@ import (
|
||||
"cmd/go/internal/mvs"
|
||||
"cmd/go/internal/renameio"
|
||||
"cmd/go/internal/search"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/lazyregexp"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -90,7 +91,7 @@ func Init() {
|
||||
}
|
||||
initialized = true
|
||||
|
||||
env := os.Getenv("GO111MODULE")
|
||||
env := cfg.Getenv("GO111MODULE")
|
||||
switch env {
|
||||
default:
|
||||
base.Fatalf("go: unknown environment setting GO111MODULE=%s", env)
|
||||
@ -294,7 +295,7 @@ func die() {
|
||||
if printStackInDie {
|
||||
debug.PrintStack()
|
||||
}
|
||||
if os.Getenv("GO111MODULE") == "off" {
|
||||
if cfg.Getenv("GO111MODULE") == "off" {
|
||||
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
|
||||
}
|
||||
if inGOPATH && !mustUseModules {
|
||||
|
@ -226,7 +226,7 @@ func (b *Builder) Init() {
|
||||
if cfg.BuildN {
|
||||
b.WorkDir = "$WORK"
|
||||
} else {
|
||||
tmp, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build")
|
||||
tmp, err := ioutil.TempDir(cfg.Getenv("GOTMPDIR"), "go-build")
|
||||
if err != nil {
|
||||
base.Fatalf("go: creating work dir: %v", err)
|
||||
}
|
||||
|
@ -224,12 +224,16 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
||||
if len(p.SFiles) > 0 {
|
||||
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
|
||||
}
|
||||
|
||||
// GO386, GOARM, GOMIPS, etc.
|
||||
baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
|
||||
key, val := cfg.GetArchEnv()
|
||||
fmt.Fprintf(h, "%s=%s\n", key, val)
|
||||
|
||||
// TODO(rsc): Convince compiler team not to add more magic environment variables,
|
||||
// or perhaps restrict the environment variables passed to subprocesses.
|
||||
// Because these are clumsy, undocumented special-case hacks
|
||||
// for debugging the compiler, they are not settable using 'go env -w',
|
||||
// and so here we use os.Getenv, not cfg.Getenv.
|
||||
magic := []string{
|
||||
"GOCLOBBERDEADHASH",
|
||||
"GOSSAFUNC",
|
||||
@ -1115,21 +1119,16 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
|
||||
if p != nil {
|
||||
fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags)
|
||||
}
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
|
||||
|
||||
// GO386, GOARM, GOMIPS, etc.
|
||||
key, val := cfg.GetArchEnv()
|
||||
fmt.Fprintf(h, "%s=%s\n", key, val)
|
||||
|
||||
// The linker writes source file paths that say GOROOT_FINAL.
|
||||
fmt.Fprintf(h, "GOROOT=%s\n", cfg.GOROOT_FINAL)
|
||||
|
||||
// TODO(rsc): Convince linker team not to add more magic environment variables,
|
||||
// or perhaps restrict the environment variables passed to subprocesses.
|
||||
magic := []string{
|
||||
"GO_EXTLINK_ENABLED",
|
||||
}
|
||||
for _, env := range magic {
|
||||
if x := os.Getenv(env); x != "" {
|
||||
fmt.Fprintf(h, "magic %s=%s\n", env, x)
|
||||
}
|
||||
}
|
||||
// GO_EXTLINK_ENABLED controls whether the external linker is used.
|
||||
fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED"))
|
||||
|
||||
// TODO(rsc): Do cgo settings and flags need to be included?
|
||||
// Or external linker settings and flags?
|
||||
@ -2192,8 +2191,8 @@ func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string,
|
||||
|
||||
// Grab these before main helpfully overwrites them.
|
||||
var (
|
||||
origCC = os.Getenv("CC")
|
||||
origCXX = os.Getenv("CXX")
|
||||
origCC = cfg.Getenv("CC")
|
||||
origCXX = cfg.Getenv("CXX")
|
||||
)
|
||||
|
||||
// gccCmd returns a gcc command line prefix
|
||||
@ -2225,7 +2224,7 @@ func (b *Builder) cxxExe() []string {
|
||||
|
||||
// fcExe returns the FC compiler setting without all the extra flags we add implicitly.
|
||||
func (b *Builder) fcExe() []string {
|
||||
return b.compilerExe(os.Getenv("FC"), "gfortran")
|
||||
return b.compilerExe(cfg.Getenv("FC"), "gfortran")
|
||||
}
|
||||
|
||||
// compilerExe returns the compiler to use given an
|
||||
@ -2391,7 +2390,7 @@ func (b *Builder) gccArchArgs() []string {
|
||||
// envList returns the value of the given environment variable broken
|
||||
// into fields, using the default value when the variable is empty.
|
||||
func envList(key, def string) []string {
|
||||
v := os.Getenv(key)
|
||||
v := cfg.Getenv(key)
|
||||
if v == "" {
|
||||
v = def
|
||||
}
|
||||
@ -2448,7 +2447,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
// Support gfortran out of the box and let others pass the correct link options
|
||||
// via CGO_LDFLAGS
|
||||
if len(ffiles) > 0 {
|
||||
fc := os.Getenv("FC")
|
||||
fc := cfg.Getenv("FC")
|
||||
if fc == "" {
|
||||
fc = "gfortran"
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ var GccgoName, GccgoBin string
|
||||
var gccgoErr error
|
||||
|
||||
func init() {
|
||||
GccgoName = os.Getenv("GCCGO")
|
||||
GccgoName = cfg.Getenv("GCCGO")
|
||||
if GccgoName == "" {
|
||||
GccgoName = "gccgo"
|
||||
}
|
||||
@ -44,7 +44,7 @@ func (gccgoToolchain) linker() string {
|
||||
}
|
||||
|
||||
func (gccgoToolchain) ar() string {
|
||||
ar := os.Getenv("AR")
|
||||
ar := cfg.Getenv("AR")
|
||||
if ar == "" {
|
||||
ar = "ar"
|
||||
}
|
||||
@ -479,7 +479,7 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
|
||||
ldflags = append(ldflags, "-lobjc")
|
||||
}
|
||||
if fortran {
|
||||
fc := os.Getenv("FC")
|
||||
fc := cfg.Getenv("FC")
|
||||
if fc == "" {
|
||||
fc = "gfortran"
|
||||
}
|
||||
|
@ -30,12 +30,13 @@
|
||||
package work
|
||||
|
||||
import (
|
||||
"cmd/go/internal/load"
|
||||
"fmt"
|
||||
"internal/lazyregexp"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/load"
|
||||
)
|
||||
|
||||
var re = lazyregexp.New
|
||||
@ -229,14 +230,14 @@ func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp,
|
||||
allow *regexp.Regexp
|
||||
disallow *regexp.Regexp
|
||||
)
|
||||
if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
|
@ -122,8 +122,14 @@ func main() {
|
||||
os.Exit(2)
|
||||
}
|
||||
if !filepath.IsAbs(p) {
|
||||
fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
|
||||
os.Exit(2)
|
||||
if cfg.Getenv("GOPATH") == "" {
|
||||
// We inferred $GOPATH from $HOME and did a bad job at it.
|
||||
// Instead of dying, uninfer it.
|
||||
cfg.BuildContext.GOPATH = ""
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
87
src/cmd/go/testdata/script/env_write.txt
vendored
Normal file
87
src/cmd/go/testdata/script/env_write.txt
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
env GO111MODULE=off
|
||||
|
||||
# go env should default to the right places
|
||||
env AppData=$HOME/windowsappdata
|
||||
env home=$HOME/plan9home
|
||||
go env GOENV
|
||||
[aix] stdout $HOME/.config/go/env
|
||||
[darwin] stdout $HOME/Library/Preferences/go/env
|
||||
[freebsd] stdout $HOME/.config/go/env
|
||||
[linux] stdout $HOME/.config/go/env
|
||||
[netbsd] stdout $HOME/.config/go/env
|
||||
[openbsd] stdout $HOME/.config/go/env
|
||||
[plan9] stdout $HOME/plan9home/lib/go/env
|
||||
[windows] stdout $HOME\\windowsappdata\\go\\env
|
||||
|
||||
# Now override it to something writable.
|
||||
env GOENV=$WORK/envdir/go/env
|
||||
go env GOENV
|
||||
stdout envdir[\\/]go[\\/]env
|
||||
|
||||
# go env shows all variables
|
||||
go env
|
||||
stdout GOARCH=
|
||||
stdout GOOS=
|
||||
stdout GOROOT=
|
||||
|
||||
# go env -w changes default setting
|
||||
env root=
|
||||
[windows] env root=c:
|
||||
env GOPATH=
|
||||
go env -w GOPATH=$root/non-exist/gopath
|
||||
! stderr .+
|
||||
grep GOPATH=$root/non-exist/gopath $WORK/envdir/go/env
|
||||
go env GOPATH
|
||||
stdout /non-exist/gopath
|
||||
|
||||
# go env -w does not override OS environment, and warns about that
|
||||
env GOPATH=$root/other
|
||||
go env -w GOPATH=$root/non-exist/gopath2
|
||||
stderr 'warning: go env -w GOPATH=... does not override conflicting OS environment variable'
|
||||
go env GOPATH
|
||||
stdout $root/other
|
||||
|
||||
# but go env -w does do the update, and unsetting the env var exposes the change
|
||||
env GOPATH=
|
||||
go env GOPATH
|
||||
stdout $root/non-exist/gopath2
|
||||
|
||||
# unsetting with go env -u does not warn about OS environment overrides,
|
||||
# nor does it warn about variables that haven't been set by go env -w.
|
||||
env GOPATH=$root/other
|
||||
go env -u GOPATH
|
||||
! stderr .+
|
||||
go env -u GOPATH
|
||||
! stderr .+
|
||||
|
||||
# go env -w rejects unknown or bad variables
|
||||
! go env -w GODEBUG=gctrace=1
|
||||
stderr 'unknown go command variable GODEBUG'
|
||||
! go env -w GOEXE=.bat
|
||||
stderr 'GOEXE cannot be modified'
|
||||
! go env -w GOENV=/env
|
||||
stderr 'GOENV can only be set using the OS environment'
|
||||
|
||||
# go env -w can set multiple variables
|
||||
env CC=
|
||||
go env CC
|
||||
! stdout ^xyc$
|
||||
go env -w GOOS=$GOOS CC=xyc
|
||||
grep CC=xyc $GOENV
|
||||
# file is maintained in sorted order
|
||||
grep 'CC=xyc\nGOOS=' $GOENV
|
||||
go env CC
|
||||
stdout ^xyc$
|
||||
|
||||
# go env -u unsets effect of go env -w.
|
||||
go env -u CC
|
||||
go env CC
|
||||
! stdout ^xyc$
|
||||
|
||||
# go env -w rejects double-set variables
|
||||
! go env -w GOOS=$GOOS GOOS=$GOOS
|
||||
stderr 'multiple values for key: GOOS'
|
||||
|
||||
# go env -w rejects missing variables
|
||||
! go env -w GOOS
|
||||
stderr 'arguments must be KEY=VALUE: invalid argument: GOOS'
|
@ -87,7 +87,7 @@ type gowasmFeatures struct {
|
||||
SatConv bool
|
||||
}
|
||||
|
||||
func (f *gowasmFeatures) String() string {
|
||||
func (f gowasmFeatures) String() string {
|
||||
var flags []string
|
||||
if f.SatConv {
|
||||
flags = append(flags, "satconv")
|
||||
|
@ -65,6 +65,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
export GOENV=off
|
||||
unset GOBIN # Issue 14340
|
||||
unset GOFLAGS
|
||||
unset GO111MODULE
|
||||
|
@ -46,13 +46,14 @@ if x%4==x--no-local goto nolocal
|
||||
setlocal
|
||||
:nolocal
|
||||
|
||||
set GOENV=off
|
||||
set GOBUILDFAIL=0
|
||||
set GOFLAGS=
|
||||
set GO111MODULE=
|
||||
|
||||
if exist make.bat goto ok
|
||||
echo Must run make.bat from Go src directory.
|
||||
goto fail
|
||||
goto fail
|
||||
:ok
|
||||
|
||||
:: Clean old generated file that will cause problems in the build.
|
||||
|
@ -47,6 +47,7 @@ if(~ $1 -v) {
|
||||
shift
|
||||
}
|
||||
|
||||
GOENV=off
|
||||
GOFLAGS=()
|
||||
GO111MODULE=()
|
||||
GOROOT = `{cd .. && pwd}
|
||||
|
@ -136,6 +136,9 @@ that can be blocked in system calls on behalf of Go code; those do not count aga
|
||||
the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes
|
||||
the limit.
|
||||
|
||||
The GORACE variable configures the race detector, for programs built using -race.
|
||||
See https://golang.org/doc/articles/race_detector.html for details.
|
||||
|
||||
The GOTRACEBACK variable controls the amount of output generated when a Go
|
||||
program fails due to an unrecovered panic or an unexpected runtime condition.
|
||||
By default, a failure prints a stack trace for the current goroutine,
|
||||
|
Loading…
Reference in New Issue
Block a user