diff --git a/doc/install-source.html b/doc/install-source.html
index 82ff8e740d0..4673850f42d 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -393,11 +393,12 @@ For example, you should not set $GOHOSTARCH
to
$GOBIN
-The location where binaries from the main repository will be installed.
-XXX THIS MAY CHANGE TO BE AN OVERRIDE EVEN FOR GOPATH ENTRIES XXX
+The location where Go binaries will be installed.
The default is $GOROOT/bin
.
After installing, you will want to arrange to add this
directory to your $PATH
, so you can use the tools.
+If $GOBIN
is set, the go command
+installs all commands there.
$GOARM
(arm, default=6)
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 16177c12772..4bb83f16188 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -74,6 +74,8 @@ The build flags are shared by the build, install, run, and test commands:
more information about build tags.
For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+see 'go help gopath'.
See also: go install, go get, go clean.
`,
@@ -304,19 +306,13 @@ const (
var (
goroot = filepath.Clean(runtime.GOROOT())
- gobin = defaultGobin()
+ gobin = os.Getenv("GOBIN")
+ gorootBin = filepath.Join(goroot, "bin")
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
-func defaultGobin() string {
- if s := os.Getenv("GOBIN"); s != "" {
- return s
- }
- return filepath.Join(goroot, "bin")
-}
-
func (b *builder) init() {
var err error
b.print = fmt.Print
@@ -388,17 +384,23 @@ func goFilesPackage(gofiles []string) *Package {
pkg.load(&stk, bp, err)
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
+ pkg.target = ""
- if *buildO == "" {
- if pkg.Name == "main" {
- _, elem := filepath.Split(gofiles[0])
- *buildO = elem[:len(elem)-len(".go")] + exeSuffix
- } else {
+ if pkg.Name == "main" {
+ _, elem := filepath.Split(gofiles[0])
+ exe := elem[:len(elem)-len(".go")] + exeSuffix
+ if *buildO == "" {
+ *buildO = exe
+ }
+ if gobin != "" {
+ pkg.target = filepath.Join(gobin, exe)
+ }
+ } else {
+ if *buildO == "" {
*buildO = pkg.Name + ".a"
}
}
- pkg.target = ""
- pkg.Target = ""
+ pkg.Target = pkg.target
pkg.Stale = true
computeStale(pkg)
@@ -463,7 +465,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
return a
}
- if p.local {
+ if p.local && p.target == "" {
// Imported via local path. No permanent target.
mode = modeBuild
}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 162eecfcc92..4bfd5236d8f 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -91,6 +91,8 @@ The build flags are shared by the build, install, run, and test commands:
more information about build tags.
For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+see 'go help gopath'.
See also: go install, go get, go clean.
@@ -461,7 +463,9 @@ the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
-installed commands.
+installed commands. If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
Here's an example directory layout:
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 26640d833c5..47ea0c7110f 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -209,7 +209,9 @@ the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
-installed commands.
+installed commands. If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
Here's an example directory layout:
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 1a75019aca3..30bbfad55a9 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -222,6 +222,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
// See issue 3268 for mistakes to avoid.
bp, err := buildContext.Import(path, srcDir, 0)
bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
pos := importPos[0]
@@ -552,7 +555,10 @@ func loadPackage(arg string, stk *importStack) *Package {
bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
- bp.BinDir = gobin
+ bp.BinDir = gorootBin
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
bp.Root = goroot
bp.SrcRoot = gorootSrc
p := new(Package)
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 54153510151..fe186d4bbcb 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -8,6 +8,9 @@ go build -o testgo
ok=true
+unset GOPATH
+unset GOBIN
+
# Test that error messages have file:line information
# at beginning of line.
for i in testdata/errmsg/*.go
@@ -80,6 +83,42 @@ if ! ./testgo test ./testdata/testimport/*.go; then
ok=false
fi
+# Test that without $GOBIN set, binaries get installed
+# into the GOPATH bin directory.
+rm -rf testdata/bin
+if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
+ ok=false
+fi
+
+# And with $GOBIN set, binaries get installed to $GOBIN.
+if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin1/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
+ ok=false
+fi
+
+# Without $GOBIN set, installing a program outside $GOPATH should fail
+# (there is nowhere to install it).
+if ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
+ ok=false
+fi
+
+# With $GOBIN set, should install there.
+if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go failed"
+ ok=false
+elif ! test -x testdata/bin1/helloworld; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
+ ok=false
+fi
+
if $ok; then
echo PASS
else
diff --git a/src/cmd/go/testdata/src/go-cmd-test/helloworld.go b/src/cmd/go/testdata/src/go-cmd-test/helloworld.go
new file mode 100644
index 00000000000..002a5c740c7
--- /dev/null
+++ b/src/cmd/go/testdata/src/go-cmd-test/helloworld.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("hello world")
+}