Description
Binaries built with "go build" that use cgo or include packages that use cgo contain references to a temporary directory. Multiple builds for the same binary will produce inconsistent results.
Simple reproduction:
// foo.go
package main
// #include <math.h>
// #cgo LDFLAGS: -lm
import "C"
import "fmt"
func main() {
fmt.Println(C.sqrt(4))
}
$ go build foo.go && md5sum foo
d4cc4febe540953e8115417476adc4a4 foo
$ go build foo.go && md5sum foo
28f5f670a48e6f72a2f31405d9fbf2cc foo
$ strings foo | grep go-build
/tmp/go-build847878379/command-line-arguments/_obj/_cgo_export.c
/tmp/go-build847878379/command-line-arguments/_obj/foo.cgo2.c
/tmp/go-build988195549/runtime/cgo/_obj/_cgo_export.c
/tmp/go-build988195549/runtime/cgo/_obj/cgo.cgo2.c
Some build systems require reproducible results: The same inputs should produce precisely the same outputs. The above behavior violates that requirement.
The problem appears to be that the gcc command invoked by "go build" includes the absolute path of the source file in $WORKDIR, which gcc then bakes into the resulting object file.
One fix might be to execute gcc from within $WORKDIR. There is, however, a comment in cmd/go/build.go indicating that the current behavior is intentional: "We always pass absolute paths of source files so that the error messages will include the full path to a file in need of attention."
Another possibility might be to use -fdebug-prefix-map to elide $WORKDIR from the debugging information written by gcc. I don't know if this can be generalized to other compilers.