Commit 8c3005c4 authored by Russ Cox's avatar Russ Cox

cmd/go: make build -a skip standard packages in Go releases

Today, 'go build -a my/pkg' and 'go install -a my/pkg'
recompile not just my/pkg and all its dependencies that
you wrote but also the standard library packages.
Recompiling the standard library is problematic on
some systems because the installed copy is not writable.

The -a behavior means that you can't use 'go install -a all'
or 'go install -a my/...' to rebuild everything after a Go
release - the rebuild stops early when it cannot overwrite
the installed standard library.

During development work, however, you do want install -a
to rebuild everything, because anything might have changed.

Resolve the conflict by making the behavior of -a depend
on whether we are using a released copy of Go or a devel copy.
In the release copies, -a no longer applies to the standard library.
In the devel copies, it still does.

This is the latest in a long line of refinements to the
"do I build this or not" logic. It is surely not the last.

Fixes #8290.

LGTM=r
R=golang-codereviews, r, tracey.brendan
CC=adg, golang-codereviews, iant
https://golang.org/cl/151730045
parent e5afecbd
...@@ -57,6 +57,7 @@ and test commands: ...@@ -57,6 +57,7 @@ and test commands:
-a -a
force rebuilding of packages that are already up-to-date. force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n -n
print the commands but do not run them. print the commands but do not run them.
-p n -p n
......
...@@ -76,6 +76,7 @@ and test commands: ...@@ -76,6 +76,7 @@ and test commands:
-a -a
force rebuilding of packages that are already up-to-date. force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n -n
print the commands but do not run them. print the commands but do not run them.
-p n -p n
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"os" "os"
pathpkg "path" pathpkg "path"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
"time" "time"
...@@ -685,6 +686,12 @@ func computeStale(pkgs ...*Package) { ...@@ -685,6 +686,12 @@ func computeStale(pkgs ...*Package) {
} }
} }
// The runtime version string takes one of two forms:
// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
// Determine whether we are in a released copy by
// inspecting the version.
var isGoRelease = !strings.HasPrefix(runtime.Version(), "go1")
// isStale reports whether package p needs to be rebuilt. // isStale reports whether package p needs to be rebuilt.
func isStale(p *Package, topRoot map[string]bool) bool { func isStale(p *Package, topRoot map[string]bool) bool {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
...@@ -705,7 +712,16 @@ func isStale(p *Package, topRoot map[string]bool) bool { ...@@ -705,7 +712,16 @@ func isStale(p *Package, topRoot map[string]bool) bool {
return false return false
} }
if buildA || p.target == "" || p.Stale { // If we are running a release copy of Go, do not rebuild the standard packages.
// They may not be writable anyway, but they are certainly not changing.
// This makes 'go build -a' skip the standard packages when using an official release.
// See issue 4106 and issue 8290.
pkgBuildA := buildA
if p.Standard && isGoRelease {
pkgBuildA = false
}
if pkgBuildA || p.target == "" || p.Stale {
return true return true
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
set -e set -e
go build -o testgo go build -tags testgo -o testgo
go() { go() {
echo TEST ERROR: ran go, not testgo: go "$@" >&2 echo TEST ERROR: ran go, not testgo: go "$@" >&2
exit 2 exit 2
...@@ -71,6 +71,32 @@ if ! grep -q "/tool/.*/$linker" $d/err.out; then ...@@ -71,6 +71,32 @@ if ! grep -q "/tool/.*/$linker" $d/err.out; then
fi fi
rm -r $d rm -r $d
TEST 'go build -a in dev branch'
./testgo install math || ok=false # should be up to date already but just in case
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then
cat $d/err.out
ok=false
elif ! grep -q runtime $d/err.out; then
echo "testgo build -a math in dev branch DID NOT build runtime, but should have"
cat $d/err.out
ok=false
fi
rm -r $d
TEST 'go build -a in release branch'
./testgo install math || ok=false # should be up to date already but just in case
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then
cat $d/err.out
ok=false
elif grep -q runtime $d/err.out; then
echo "testgo build -a math in dev branch DID build runtime, but should NOT have"
cat $d/err.out
ok=false
fi
rm -r $d
# Test local (./) imports. # Test local (./) imports.
testlocal() { testlocal() {
local="$1" local="$1"
......
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains extra hooks for testing the go command.
// It is compiled into the Go binary only when building the
// test copy; it does not get compiled into the standard go
// command, so these testing hooks are not present in the
// go command that everyone uses.
// +build testgo
package main
import "os"
func init() {
if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
isGoRelease = v == "1"
}
}
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