Skip to content

Commit 8f70e1f

Browse files
committed
cmd/go: do not install dependencies during "go install"
This CL makes "go install" behave the way many users expect: install only the things named on the command line. Future builds still run as fast, thanks to the new build cache (CL 75473). To install dependencies as well (the old behavior), use "go install -i". Actual definitions aside, what most users know and expect of "go install" is that (1) it installs what you asked, and (2) it's fast, unlike "go build". It was fast because it installed dependencies, but installing dependencies confused users repeatedly (see for example #5065, #6424, #10998, #12329, "go build" and "go test" so that they could be "fast" too, but that only created new opportunities for confusion. We also had to add -installsuffix and then -pkgdir, to allow "fast" even when dependencies could not be installed in the usual place. The recent introduction of precise content-based staleness logic means that the go command detects the need for rebuilding packages more often than it used to, with the consequence that "go install" rebuilds and reinstalls dependencies more than it used to. This will create more new opportunities for confusion and will certainly lead to more issues filed like the ones listed above. CL 75743 introduced a build cache, separate from the install locations. That cache makes all operations equally incremental and fast, whether or not the operation is "install" or "build", and whether or not "-i" is used. Installing dependencies is no longer necessary for speed, it has confused users in the past, and the more accurate rebuilds mean that it will confuse users even more often in the future. This CL aims to end all that confusion by not installing dependencies by default. By analogy with "go build -i" and "go test -i", which still install dependencies, this CL introduces "go install -i", which installs dependencies in addition to the things named on the command line. Fixes #5065. Fixes #6424. Fixes #10998. Fixes #12329. Fixes #18981. Fixes #22469. Another step toward #4719. Change-Id: I3d7bc145c3a680e2f26416e182fa0dcf1e2a15e5 Reviewed-on: https://go-review.googlesource.com/75850 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: David Crawshaw <[email protected]>
1 parent 0d18875 commit 8f70e1f

File tree

7 files changed

+110
-37
lines changed

7 files changed

+110
-37
lines changed

misc/cgo/testcarchive/carchive_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func TestInstall(t *testing.T) {
174174
testInstall(t, "./testp1"+exeSuffix,
175175
filepath.Join("pkg", libgodir, "libgo.a"),
176176
filepath.Join("pkg", libgodir, "libgo.h"),
177-
"go", "install", "-buildmode=c-archive", "libgo")
177+
"go", "install", "-i", "-buildmode=c-archive", "libgo")
178178

179179
// Test building libgo other than installing it.
180180
// Header files are now present.
@@ -491,7 +491,7 @@ func TestPIE(t *testing.T) {
491491
os.RemoveAll("pkg")
492492
}()
493493

494-
cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
494+
cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "libgo")
495495
cmd.Env = gopathEnv
496496
if out, err := cmd.CombinedOutput(); err != nil {
497497
t.Logf("%s", out)

misc/cgo/testcshared/cshared_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ func runCC(t *testing.T, args ...string) string {
216216
}
217217

218218
func createHeaders() error {
219-
args := []string{"go", "install", "-buildmode=c-shared",
219+
args := []string{"go", "install", "-i", "-buildmode=c-shared",
220220
"-installsuffix", "testcshared", "libgo"}
221221
cmd := exec.Command(args[0], args[1:]...)
222222
cmd.Env = gopathEnv

src/cmd/dist/build.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ func cmdbootstrap() {
11571157
// chosen $CC_FOR_TARGET in this case.
11581158
os.Setenv("CC", defaultcctarget)
11591159
}
1160-
goInstall(goBootstrap, toolchain...)
1160+
goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
11611161
if debug {
11621162
run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
11631163
run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
@@ -1185,7 +1185,7 @@ func cmdbootstrap() {
11851185
xprintf("\n")
11861186
}
11871187
xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1188-
goInstall(goBootstrap, append([]string{"-a"}, toolchain...)...)
1188+
goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...)
11891189
if debug {
11901190
run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
11911191
run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))

src/cmd/dist/test.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,25 @@ func (t *tester) run() {
116116

117117
if t.rebuild {
118118
t.out("Building packages and commands.")
119-
// Rebuilding is a shortened bootstrap.
120-
// See cmdbootstrap for a description of the overall process.
121-
goInstall("go", toolchain...)
122-
goInstall("go", toolchain...)
119+
// Force rebuild the whole toolchain.
120+
goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
121+
}
122+
123+
// Complete rebuild bootstrap, even with -no-rebuild.
124+
// If everything is up-to-date, this is a no-op.
125+
// If everything is not up-to-date, the first checkNotStale
126+
// during the test process will kill the tests, so we might
127+
// as well install the world.
128+
// Now that for example "go install cmd/compile" does not
129+
// also install runtime (you need "go install -i cmd/compile"
130+
// for that), it's easy for previous workflows like
131+
// "rebuild the compiler and then run run.bash"
132+
// to break if we don't automatically refresh things here.
133+
// Rebuilding is a shortened bootstrap.
134+
// See cmdbootstrap for a description of the overall process.
135+
if !t.listMode {
136+
goInstall("go", append([]string{"-i"}, toolchain...)...)
137+
goInstall("go", append([]string{"-i"}, toolchain...)...)
123138
goInstall("go", "std", "cmd")
124139
checkNotStale("go", "std", "cmd")
125140
}

src/cmd/go/go_test.go

+43-6
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,7 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
960960
func F() {}`)
961961
sep := string(filepath.ListSeparator)
962962
tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
963-
tg.run("install", "p1")
963+
tg.run("install", "-i", "p1")
964964
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
965965
tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly")
966966
tg.sleep()
@@ -974,7 +974,7 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
974974
tg.wantStale("p2", "build ID mismatch", "./testgo list claims p2 is NOT stale, incorrectly")
975975
tg.wantStale("p1", "stale dependency: p2", "./testgo list claims p1 is NOT stale, incorrectly")
976976

977-
tg.run("install", "p1")
977+
tg.run("install", "-i", "p1")
978978
tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
979979
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
980980
}
@@ -3296,10 +3296,11 @@ func TestGoInstallPkgdir(t *testing.T) {
32963296
tg.makeTempdir()
32973297
pkg := tg.path(".")
32983298
tg.run("install", "-pkgdir", pkg, "errors")
3299-
_, err := os.Stat(filepath.Join(pkg, "errors.a"))
3300-
tg.must(err)
3301-
_, err = os.Stat(filepath.Join(pkg, "runtime.a"))
3302-
tg.must(err)
3299+
tg.mustExist(filepath.Join(pkg, "errors.a"))
3300+
tg.mustNotExist(filepath.Join(pkg, "runtime.a"))
3301+
tg.run("install", "-i", "-pkgdir", pkg, "errors")
3302+
tg.mustExist(filepath.Join(pkg, "errors.a"))
3303+
tg.mustExist(filepath.Join(pkg, "runtime.a"))
33033304
}
33043305

33053306
func TestGoTestRaceInstallCgo(t *testing.T) {
@@ -4869,3 +4870,39 @@ func TestTestVet(t *testing.T) {
48694870
tg.run("test", "-vet=off", filepath.Join(tg.tempdir, "p1.go"))
48704871
tg.grepStdout(`\[no test files\]`, "did not print test summary")
48714872
}
4873+
4874+
func TestInstallDeps(t *testing.T) {
4875+
tg := testgo(t)
4876+
defer tg.cleanup()
4877+
tg.parallel()
4878+
tg.makeTempdir()
4879+
tg.setenv("GOPATH", tg.tempdir)
4880+
4881+
tg.tempFile("src/p1/p1.go", "package p1\nvar X = 1\n")
4882+
tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\n")
4883+
tg.tempFile("src/main1/main.go", "package main\nimport _ \"p2\"\nfunc main() {}\n")
4884+
4885+
tg.run("list", "-f={{.Target}}", "p1")
4886+
p1 := strings.TrimSpace(tg.getStdout())
4887+
tg.run("list", "-f={{.Target}}", "p2")
4888+
p2 := strings.TrimSpace(tg.getStdout())
4889+
tg.run("list", "-f={{.Target}}", "main1")
4890+
main1 := strings.TrimSpace(tg.getStdout())
4891+
4892+
tg.run("install", "main1")
4893+
4894+
tg.mustExist(main1)
4895+
tg.mustNotExist(p2)
4896+
tg.mustNotExist(p1)
4897+
4898+
tg.run("install", "p2")
4899+
tg.mustExist(p2)
4900+
tg.mustNotExist(p1)
4901+
4902+
tg.run("install", "-i", "main1")
4903+
tg.mustExist(p1)
4904+
tg.must(os.Remove(p1))
4905+
4906+
tg.run("install", "-i", "p2")
4907+
tg.mustExist(p1)
4908+
}

src/cmd/go/internal/work/action.go

+32-18
Original file line numberDiff line numberDiff line change
@@ -390,17 +390,6 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
390390
a1.needVet = true
391391
a.Func = (*Builder).vet
392392

393-
// If there might be an install action, make it depend on vet,
394-
// so that the temporary files generated by the build step
395-
// are not deleted before vet can use them.
396-
// If nothing was going to install p, calling b.CompileAction with
397-
// ModeInstall here creates the action, but nothing links it into the
398-
// graph, so it will still not be installed.
399-
install := b.CompileAction(ModeInstall, depMode, p)
400-
if install != a1 {
401-
install.Deps = append(install.Deps, a)
402-
}
403-
404393
return a
405394
})
406395
return a
@@ -466,6 +455,13 @@ func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action {
466455

467456
// installAction returns the action for installing the result of a1.
468457
func (b *Builder) installAction(a1 *Action) *Action {
458+
// Because we overwrite the build action with the install action below,
459+
// a1 may already be an install action fetched from the "build" cache key,
460+
// and the caller just doesn't realize.
461+
if strings.HasSuffix(a1.Mode, "-install") {
462+
return a1
463+
}
464+
469465
// If there's no actual action to build a1,
470466
// there's nothing to install either.
471467
// This happens if a1 corresponds to reusing an already-built object.
@@ -475,18 +471,36 @@ func (b *Builder) installAction(a1 *Action) *Action {
475471

476472
p := a1.Package
477473
return b.cacheAction(a1.Mode+"-install", p, func() *Action {
478-
a := &Action{
479-
Mode: a1.Mode + "-install",
474+
// The install deletes the temporary build result,
475+
// so we need all other actions, both past and future,
476+
// that attempt to depend on the build to depend instead
477+
// on the install.
478+
479+
// Make a private copy of a1 (the build action),
480+
// no longer accessible to any other rules.
481+
buildAction := new(Action)
482+
*buildAction = *a1
483+
484+
// Overwrite a1 with the install action.
485+
// This takes care of updating past actions that
486+
// point at a1 for the build action; now they will
487+
// point at a1 and get the install action.
488+
// We also leave a1 in the action cache as the result
489+
// for "build", so that actions not yet created that
490+
// try to depend on the build will instead depend
491+
// on the install.
492+
*a1 = Action{
493+
Mode: buildAction.Mode + "-install",
480494
Func: BuildInstallFunc,
481495
Package: p,
482-
Objdir: a1.Objdir,
483-
Deps: []*Action{a1},
496+
Objdir: buildAction.Objdir,
497+
Deps: []*Action{buildAction},
484498
Target: p.Target,
485499
built: p.Target,
486500
}
487501

488-
b.addInstallHeaderAction(a)
489-
return a
502+
b.addInstallHeaderAction(a1)
503+
return a1
490504
})
491505
}
492506

@@ -514,7 +528,7 @@ func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) {
514528
a1 := workq[i]
515529
for _, a2 := range a1.Deps {
516530
// TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles.
517-
if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build" && a2.Mode != "use installed") || haveDep[a2.Package.ImportPath] {
531+
if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] {
518532
continue
519533
}
520534
haveDep[a2.Package.ImportPath] = true

src/cmd/go/internal/work/build.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ func init() {
141141
CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "")
142142
CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file")
143143

144+
CmdInstall.Flag.BoolVar(&cfg.BuildI, "i", false, "")
145+
144146
AddBuildFlags(CmdBuild)
145147
AddBuildFlags(CmdInstall)
146148
}
@@ -464,11 +466,12 @@ func runBuild(cmd *base.Command, args []string) {
464466
}
465467

466468
var CmdInstall = &base.Command{
467-
UsageLine: "install [build flags] [packages]",
469+
UsageLine: "install [-i] [build flags] [packages]",
468470
Short: "compile and install packages and dependencies",
469471
Long: `
470-
Install compiles and installs the packages named by the import paths,
471-
along with their dependencies.
472+
Install compiles and installs the packages named by the import paths.
473+
474+
The -i flag installs the dependencies of the named packages as well.
472475
473476
For more about the build flags, see 'go help build'.
474477
For more about specifying packages, see 'go help packages'.
@@ -565,6 +568,10 @@ func InstallPackages(args []string, forGet bool) {
565568

566569
var b Builder
567570
b.Init()
571+
depMode := ModeBuild
572+
if cfg.BuildI {
573+
depMode = ModeInstall
574+
}
568575
a := &Action{Mode: "go install"}
569576
var tools []*Action
570577
for _, p := range pkgs {
@@ -576,7 +583,7 @@ func InstallPackages(args []string, forGet bool) {
576583
// If p is a tool, delay the installation until the end of the build.
577584
// This avoids installing assemblers/compilers that are being executed
578585
// by other steps in the build.
579-
a1 := b.AutoAction(ModeInstall, ModeInstall, p)
586+
a1 := b.AutoAction(ModeInstall, depMode, p)
580587
if load.InstallTargetDir(p) == load.ToTool {
581588
a.Deps = append(a.Deps, a1.Deps...)
582589
a1.Deps = append(a1.Deps, a)

0 commit comments

Comments
 (0)