Skip to content

Commit

Permalink
cmd/go: make build -a skip standard packages in Go releases
Browse files Browse the repository at this point in the history
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 golang#8290.

LGTM=r
R=golang-codereviews, r, tracey.brendan
CC=adg, golang-codereviews, iant
https://golang.org/cl/151730045
  • Loading branch information
rsc committed Sep 26, 2014
1 parent e5afecb commit 8c3005c
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/cmd/go/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
Expand Down
1 change: 1 addition & 0 deletions src/cmd/go/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
Expand Down
18 changes: 17 additions & 1 deletion src/cmd/go/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os"
pathpkg "path"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -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.
func isStale(p *Package, topRoot map[string]bool) bool {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
Expand All @@ -705,7 +712,16 @@ func isStale(p *Package, topRoot map[string]bool) bool {
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
}

Expand Down
28 changes: 27 additions & 1 deletion src/cmd/go/test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.

set -e
go build -o testgo
go build -tags testgo -o testgo
go() {
echo TEST ERROR: ran go, not testgo: go "$@" >&2
exit 2
Expand Down Expand Up @@ -71,6 +71,32 @@ if ! grep -q "/tool/.*/$linker" $d/err.out; then
fi
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.
testlocal() {
local="$1"
Expand Down
21 changes: 21 additions & 0 deletions src/cmd/go/testgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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"
}
}

0 comments on commit 8c3005c

Please sign in to comment.