]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go, cmd/link: make builds deterministic
authorDamien Neil <dneil@google.com>
Tue, 9 Feb 2016 01:20:59 +0000 (17:20 -0800)
committerDamien Neil <dneil@google.com>
Thu, 18 Feb 2016 20:56:29 +0000 (20:56 +0000)
Add the following flags when supported by the compiler:
  -gno-record-gcc-switches
  -fdebug-prefix-map=$WORK=/tmp/go-build

Add an empty NAME symbol to the ELF .symtab. GNU ld will add a NAME
symbol when one is not present; including one of our own prevents it
from adding a reference to the link tempdir.

Fixes #13247 for compilers that support -fdebug-prefix-map. (gcc, clang
in the near future.)

Change-Id: I221c71fc59cd23ee8c99bcc038793ff4623c9ffc
Reviewed-on: https://go-review.googlesource.com/19363
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>

src/cmd/go/build.go
src/cmd/go/go_test.go
src/cmd/link/internal/ld/symtab.go

index f2a2a6014f2b134ce2375846663818e7f956e56f..1932f324eaa73afe76d14fd8153a0ce1d96605ed 100644 (file)
@@ -686,6 +686,7 @@ type builder struct {
        work        string               // the temporary work directory (ends in filepath.Separator)
        actionCache map[cacheKey]*action // a cache of already-constructed actions
        mkdirCache  map[string]bool      // a cache of created directories
+       flagCache   map[string]bool      // a cache of supported compiler flags
        print       func(args ...interface{}) (int, error)
 
        output    sync.Mutex
@@ -2927,6 +2928,14 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
        // disable word wrapping in error messages
        a = append(a, "-fmessage-length=0")
 
+       // Tell gcc not to include the work directory in object files.
+       if b.gccSupportsFlag("-fdebug-prefix-map=a=b") {
+               // -gno-record-gcc-switches is supported by all gcc/clang
+               // versions that support -fdebug-prefix-map.
+               a = append(a, "-gno-record-gcc-switches")
+               a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build")
+       }
+
        // On OS X, some of the compilers behave as if -fno-common
        // is always set, and the Mach-O linker in 6l/8l assumes this.
        // See https://golang.org/issue/3253.
@@ -2941,19 +2950,24 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 // -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is
 // not supported by all compilers.
 func (b *builder) gccSupportsNoPie() bool {
-       if goos != "linux" {
-               // On some BSD platforms, error messages from the
-               // compiler make it to the console despite cmd.Std*
-               // all being nil. As -no-pie is only required on linux
-               // systems so far, we only test there.
-               return false
+       return b.gccSupportsFlag("-no-pie")
+}
+
+// gccSupportsFlag checks to see if the compiler supports a flag.
+func (b *builder) gccSupportsFlag(flag string) bool {
+       b.exec.Lock()
+       defer b.exec.Unlock()
+       if b, ok := b.flagCache[flag]; ok {
+               return b
        }
-       src := filepath.Join(b.work, "trivial.c")
-       if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
-               return false
+       if b.flagCache == nil {
+               src := filepath.Join(b.work, "trivial.c")
+               if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+                       return false
+               }
+               b.flagCache = make(map[string]bool)
        }
-       cmdArgs := b.gccCmd(b.work)
-       cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c")
+       cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c")
        if buildN || buildX {
                b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
                if buildN {
@@ -2964,7 +2978,9 @@ func (b *builder) gccSupportsNoPie() bool {
        cmd.Dir = b.work
        cmd.Env = envForDir(cmd.Dir, os.Environ())
        out, err := cmd.CombinedOutput()
-       return err == nil && !bytes.Contains(out, []byte("unrecognized"))
+       supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+       b.flagCache[flag] = supported
+       return supported
 }
 
 // gccArchArgs returns arguments to pass to gcc based on the architecture.
index 39e0f3e56d58b25a6dc4365bf41650fb47e4a70d..e55fc360de4ce79ff499b4d9241827eb3566fc87 100644 (file)
@@ -2759,3 +2759,30 @@ func TestParallelTest(t *testing.T) {
        tg.setenv("GOPATH", tg.path("."))
        tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
 }
+
+func TestCgoConsistentResults(t *testing.T) {
+       if !canCgo {
+               t.Skip("skipping because cgo not enabled")
+       }
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+       exe1 := tg.path("cgotest1" + exeSuffix)
+       exe2 := tg.path("cgotest2" + exeSuffix)
+       tg.run("build", "-o", exe1, "cgotest")
+       tg.run("build", "-x", "-o", exe2, "cgotest")
+       b1, err := ioutil.ReadFile(exe1)
+       tg.must(err)
+       b2, err := ioutil.ReadFile(exe2)
+       tg.must(err)
+
+       if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) {
+               t.Skip("skipping because C compiler does not support -fdebug-prefix-map")
+       }
+       if !bytes.Equal(b1, b2) {
+               t.Error("building cgotest twice did not produce the same output")
+       }
+}
index 3e6169e453210b913316889bd327e92ceda07269..b87ca810074f4d3a087dee1ea6fd9d04e2077823 100644 (file)
@@ -215,6 +215,11 @@ func Asmelfsym() {
 
        dwarfaddelfsectionsyms()
 
+       // Some linkers will add a FILE sym if one is not present.
+       // Avoid having the working directory inserted into the symbol table.
+       putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+       numelfsym++
+
        elfbind = STB_LOCAL
        genasmsym(putelfsym)