From 06f4d93699ebbf05a500313c6b6ae6f80105d838 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sun, 3 Sep 2017 12:33:56 -0400 Subject: [PATCH] cmd/go: put computed GOROOT in built binaries As of CL 42533, cmd/go will recompute its GOROOT based on the location of its own executable. This CL plumbs that computed GOROOT into every binary it builds using the linker -X flag. This means binaries built with a moved cmd/go will report the GOROOT they were built in from runtime.GOROOT(). Fixes #21313 Change-Id: I6c2c559f40f2a0c867ab60cf47c6dbc73ae5e28a Reviewed-on: https://go-review.googlesource.com/61310 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/dist/buildruntime.go | 5 ++-- src/cmd/go/go_test.go | 39 ++++++++++++++++++++++++++++- src/cmd/go/internal/work/build.go | 3 +++ src/cmd/go/testdata/print_goroot.go | 11 ++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/cmd/go/testdata/print_goroot.go diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go index b885a79228..836b2ef31c 100644 --- a/src/cmd/dist/buildruntime.go +++ b/src/cmd/dist/buildruntime.go @@ -17,7 +17,8 @@ import ( // mkzversion writes zversion.go: // // package sys -// const DefaultGoroot = +// var DefaultGoroot = +// // const TheVersion = // const Goexperiment = // const StackGuardMultiplier = @@ -28,7 +29,7 @@ func mkzversion(dir, file string) { "\n"+ "package sys\n"+ "\n"+ - "const DefaultGoroot = `%s`\n"+ + "var DefaultGoroot = `%s`\n\n"+ "const TheVersion = `%s`\n"+ "const Goexperiment = `%s`\n"+ "const StackGuardMultiplier = %d\n\n", goroot_final, findgoversion(), os.Getenv("GOEXPERIMENT"), stackGuardMultiplier()) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 87810ad6cb..3908fe8823 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -4163,7 +4163,7 @@ func TestExecutableGOROOT(t *testing.T) { if err != nil { t.Fatal(err) } - m := regexp.MustCompile("const DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data)) + m := regexp.MustCompile("var DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data)) if m == nil { t.Fatal("cannot find DefaultGoroot in ../../runtime/internal/sys/zversion.go") } @@ -4188,6 +4188,43 @@ func TestExecutableGOROOT(t *testing.T) { } check(t, symGoTool, newRoot) }) + + tg.must(os.RemoveAll(tg.path("new/pkg"))) + + // Binaries built in the new tree should report the + // new tree when they call runtime.GOROOT(). + // This is implemented by having the go tool pass a -X option + // to the linker setting runtime/internal/sys.DefaultGoroot. + t.Run("RuntimeGoroot", func(t *testing.T) { + // Build a working GOROOT the easy way, with symlinks. + testenv.MustHaveSymlink(t) + if err := os.Symlink(filepath.Join(testGOROOT, "src"), tg.path("new/src")); err != nil { + t.Fatal(err) + } + if err := os.Symlink(filepath.Join(testGOROOT, "pkg"), tg.path("new/pkg")); err != nil { + t.Fatal(err) + } + + cmd := exec.Command(newGoTool, "run", "testdata/print_goroot.go") + cmd.Env = env + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%s run testdata/print_goroot.go: %v, %s", newGoTool, err, out) + } + goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out))) + if err != nil { + t.Fatal(err) + } + want, err := filepath.EvalSymlinks(tg.path("new")) + if err != nil { + t.Fatal(err) + } + if !strings.EqualFold(goroot, want) { + t.Errorf("go run testdata/print_goroot.go:\nhave %s\nwant %s", goroot, want) + } else { + t.Logf("go run testdata/print_goroot.go: %s", goroot) + } + }) } func TestNeedVersion(t *testing.T) { diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 6b9c511473..7cb11aa422 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -2536,6 +2536,9 @@ func (gcToolchain) ld(b *Builder, root *Action, out string, allactions []*Action if cfg.BuildBuildmode == "plugin" { ldflags = append(ldflags, "-pluginpath", load.PluginPath(root.Package)) } + if cfg.GOROOT != runtime.GOROOT() { + ldflags = append(ldflags, "-X=runtime/internal/sys.DefaultGoroot="+cfg.GOROOT) + } // If the user has not specified the -extld option, then specify the // appropriate linker. In case of C++ code, use the compiler named diff --git a/src/cmd/go/testdata/print_goroot.go b/src/cmd/go/testdata/print_goroot.go new file mode 100644 index 0000000000..5477291060 --- /dev/null +++ b/src/cmd/go/testdata/print_goroot.go @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +package main + +import "runtime" + +func main() { + println(runtime.GOROOT()) +}