]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: respect $GOBIN always
authorRuss Cox <rsc@golang.org>
Tue, 27 Mar 2012 15:57:39 +0000 (11:57 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 27 Mar 2012 15:57:39 +0000 (11:57 -0400)
Another attempt at https://golang.org/cl/5754088.

Before, we only consulted $GOBIN for source code
found in $GOROOT, but that's confusing to explain
and less useful.  The new behavior lets users set
GOBIN=$HOME/bin and have all go-compiled binaries
installed there.

Tested a few cases in test.bash.

Ran all.bash with and without $GOBIN and it works.
Even so, I expect it to break the builders,
like it did last time, we can debug from there.

Fixes #3269 (again).
Fixes #3396.
Fixes #3397.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5927051

doc/install-source.html
src/cmd/go/build.go
src/cmd/go/doc.go
src/cmd/go/help.go
src/cmd/go/pkg.go
src/cmd/go/test.bash
src/cmd/go/testdata/src/go-cmd-test/helloworld.go [new file with mode: 0644]

index 82ff8e740d05c2510095426b4803a4bc6ba9851c..4673850f42d4c8ab23ca5d3de3715daf51d9c1f1 100644 (file)
@@ -393,11 +393,12 @@ For example, you should not set <code>$GOHOSTARCH</code> to
 
 <p><code>$GOBIN</code>
 <p>
-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 <code>$GOROOT/bin</code>.
 After installing, you will want to arrange to add this
 directory to your <code>$PATH</code>, so you can use the tools.
+If <code>$GOBIN</code> is set, the <a href="/cmd/go">go command</a>
+installs all commands there.
 </p>
 
 <p><code>$GOARM</code> (arm, default=6)</p>
index 16177c12772eda5e03a4dcb0b0608718f02939fd..4bb83f1618849aff4b38271bdc9eeb5b06cc183e 100644 (file)
@@ -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
        }
index 162eecfcc928f2b7f4303315f6e9b4f3e56a1a91..4bfd5236d8f706dfef61b98a7edb5d20d9f4f82f 100644 (file)
@@ -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:
 
index 26640d833c5489a8545374f188236bcf410c006e..47ea0c7110f87745d43f2a3090bc4e5b59622410 100644 (file)
@@ -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:
 
index 1a75019aca3ba30239e3372d8880023968745439..30bbfad55a9069b2f6c4c883407614278b38b342 100644 (file)
@@ -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)
index 541535101512cd0a4df9d86891bd3d172f86a500..fe186d4bbcb15c235b6838973d6da42a00f4cbb3 100755 (executable)
@@ -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 (file)
index 0000000..002a5c7
--- /dev/null
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+       println("hello world")
+}