Commit 227fb116 authored by Russ Cox's avatar Russ Cox

cmd/go: clean up after 'go build' during 'go install'

If 'go install' (with no arguments, meaning the current directory)
succeeds, remove the executable written by 'go build', if present.
This avoids leaving a stale binary behind during a sequence like:

	go build
	<test, mostly works, make small change>
	go install

Before this CL, the current directory still has the stale binary
from 'go build'. If $PATH contains dot, running the name of
the program will find this stale binary instead of the new,
installed one.

Remove the 'go build' target during 'go install', both to clean
up the directory and to avoid accidentally running the stale binary.

Another way to view this CL is that it makes the go command
behave as if 'go install' is implemented by 'go build' followed by
moving the resulting binary to the install location.

See #9645 for discussion and objections.

Fixes #9645.

Change-Id: Ide109572f96bbb5a35be45dda17738317462a7d4
Reviewed-on: https://go-review.googlesource.com/10682Reviewed-by: default avatarRob Pike <r@golang.org>
parent 119daba9
......@@ -540,6 +540,30 @@ func runInstall(cmd *Command, args []string) {
}
}
b.do(a)
exitIfErrors()
// Success. If this command is 'go install' with no arguments
// and the current directory (the implicit argument) is a command,
// remove any leftover command binary from a previous 'go build'.
// The binary is installed; it's not needed here anymore.
// And worse it might be a stale copy, which you don't want to find
// instead of the installed one if $PATH contains dot.
// One way to view this behavior is that it is as if 'go install' first
// runs 'go build' and the moves the generated file to the install dir.
// See issue 9645.
if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
// Compute file 'go build' would have created.
// If it exists and is an executable file, remove it.
_, targ := filepath.Split(pkgs[0].ImportPath)
targ += exeSuffix
fi, err := os.Stat(targ)
if err == nil {
m := fi.Mode()
if m.IsRegular() && m&0111 != 0 {
os.Remove(targ)
}
}
}
}
// Global build parameters (used during package load)
......
......@@ -96,6 +96,55 @@ elif grep -q runtime $d/err.out; then
fi
rm -r $d
TEST 'go install cleans up after go build'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/mycmd
echo 'package main; func main(){}' >$d/src/mycmd/main.go
old=$(pwd)
cd $d/src/mycmd
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary"
ok=false
fi
"$old/testgo" install
if [ -e mycmd ]; then
echo "testgo install did not remove command binary"
ok=false
fi
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary (second time)"
ok=false
fi
# install with arguments does not remove the target,
# even in the same directory
"$old/testgo" install mycmd
if [ ! -e mycmd ]; then
echo "testgo install mycmd removed command binary when run in mycmd"
ok=false
fi
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary (third time)"
ok=false
fi
# and especially not outside the directory
cd $d
cp src/mycmd/mycmd .
"$old/testgo" install mycmd
if [ ! -e $d/src/mycmd/mycmd ]; then
echo "testgo install mycmd removed command binary from its source dir when run outside mycmd"
ok=false
fi
if [ ! -e $d/mycmd ]; then
echo "testgo install mycmd removed command binary from current dir when run outside mycmd"
ok=false
fi
cd "$old"
rm -r $d
TEST 'go install rebuilds stale packages in other GOPATH'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d/d1:$d/d2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment