diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index a4edd85..78cbbb9 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -460,7 +460,7 @@
GOROOTpkg string
GOROOTsrc string
- GOBIN = Getenv("GOBIN")
+ GOBIN, GOBINChanged = EnvOrAndChanged("GOBIN", "")
GOCACHEPROG, GOCACHEPROGChanged = EnvOrAndChanged("GOCACHEPROG", "")
GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod"))
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index e950c65..1c54fc6 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -83,7 +83,6 @@
{Name: "GO111MODULE", Value: cfg.Getenv("GO111MODULE")},
{Name: "GOARCH", Value: cfg.Goarch, Changed: cfg.Goarch != runtime.GOARCH},
{Name: "GOAUTH", Value: cfg.GOAUTH, Changed: cfg.GOAUTHChanged},
- {Name: "GOBIN", Value: cfg.GOBIN},
{Name: "GOCACHE"},
{Name: "GOCACHEPROG", Value: cfg.GOCACHEPROG, Changed: cfg.GOCACHEPROGChanged},
{Name: "GODEBUG", Value: os.Getenv("GODEBUG")},
@@ -126,7 +125,7 @@
if env[i].Value != "on" && env[i].Value != "" {
env[i].Changed = true
}
- case "GOBIN", "GOEXPERIMENT", "GOFLAGS", "GOINSECURE", "GOPRIVATE", "GOTMPDIR", "GOVCS":
+ case "GOEXPERIMENT", "GOFLAGS", "GOINSECURE", "GOPRIVATE", "GOTMPDIR", "GOVCS":
if env[i].Value != "" {
env[i].Changed = true
}
@@ -203,9 +202,30 @@
if cfg.Getenv("GOWORK") == "off" {
gowork = "off"
}
+ gobin := cfg.GOBIN
+ if gobin == "" && cfg.ModulesEnabled {
+ gobin = modload.BinDir(ld)
+ } else if gobin == "" {
+ // Best effort guess of where the binary will be installed.
+ // go.dev/issue/23439
+ wd, err := os.Getwd()
+ if err == nil {
+ gopaths := filepath.SplitList(cfg.BuildContext.GOPATH)
+ gopath := gopaths[0]
+ for _, p := range gopaths {
+ if strings.HasPrefix(wd, p) {
+ gopath = p
+ break
+ }
+ }
+ gobin = filepath.Join(gopath, "bin")
+ }
+ }
+
return []cfg.EnvVar{
{Name: "GOMOD", Value: gomod},
{Name: "GOWORK", Value: gowork},
+ {Name: "GOBIN", Value: gobin, Changed: cfg.GOBINChanged},
}
}
diff --git a/src/cmd/go/testdata/script/env_gobin.txt b/src/cmd/go/testdata/script/env_gobin.txt
new file mode 100644
index 0000000..0e0efb9
--- /dev/null
+++ b/src/cmd/go/testdata/script/env_gobin.txt
@@ -0,0 +1,44 @@
+
+go env GOBIN
+stdout $WORK${/}gopath${/}bin
+go env -changed GOBIN
+! stdout $WORK
+
+# report explicit settings
+env GOBIN=/tmp/gobin
+go env GOBIN
+stdout /tmp/gobin
+go env -changed GOBIN
+stdout /tmp/gobin
+
+# reset
+env GOBIN=
+go env -changed GOBIN
+! stdout $WORK
+
+# In GOPATH mode
+# the default install directory depends on the GOPATH
+# technically it also depends on the install target
+# but that's not something we can report.
+env GO111MODULE=off
+env GOPATH=$WORK/a${:}$WORK/b
+
+# report GOPATH[0]/bin outside of GOPATH
+cd $WORK
+go env GOBIN
+stdout $WORK${/}a${/}bin
+
+# report the current GOPATH/bin inside of a GOPATH
+cd $WORK/a/src/example1.com
+go env GOBIN
+stdout $WORK${/}a${/}bin
+
+cd $WORK/b/src/example2.com
+go env GOBIN
+stdout $WORK${/}b${/}bin
+
+-- $WORK/a/src/example1.com/main.go --
+package main
+
+-- $WORK/b/src/example2.com/main.go --
+package main