+# Regression test for https://go.dev/issue/48319:
+# cgo builds should not include debug information from a stale GOROOT_FINAL.
+
[short] skip
[!cgo] skip
+[windows] skip # The Go Windows builders have an extremely out-of-date gcc that does not support reproducible builds; see https://go.dev/issue/50824.
-# Set up fresh GOCACHE
+# This test is sensitive to cache invalidation,
+# so use a separate build cache that we can control.
env GOCACHE=$WORK/gocache
mkdir $GOCACHE
-# 1. unset GOROOT_FINAL, Build a simple binary with cgo by origin go.
-# The DW_AT_comp_dir of runtime/cgo should have a prefix with origin goroot.
-env GOROOT_FINAL=
-# If using "go run", it is no debuginfo in binary. So use "go build".
-# And we can check the stderr to judge if the cache of "runtime/cgo"
-# was used or not.
-go build -o binary.exe
-exec ./binary.exe $TESTGO_GOROOT
-stdout 'cgo DW_AT_comp_dir is right in binary'
-
-
-# 2. GOROOT_FINAL will be changed, the runtime/cgo will be rebuild.
-env GOROOT_FINAL=$WORK/gorootfinal
-go build -x -o binary.exe
-stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
-exec ./binary.exe $GOROOT_FINAL
-stdout 'cgo DW_AT_comp_dir is right in binary'
-
-
-[!symlink] skip
-
-# Symlink the compiler to another path
-env GOROOT=$WORK/goroot
-symlink $GOROOT -> $TESTGO_GOROOT
-
-# 3. GOROOT_FINAL is same with 2, build with the other go
-# the runtime/cgo will not be rebuild.
-go build -x -o binary.exe
-! stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
-exec ./binary.exe $GOROOT_FINAL
-stdout 'cgo DW_AT_comp_dir is right in binary'
-
-
-# 4. unset GOROOT_FINAL, build with the other go
-# the runtime/cgo will be rebuild.
-env GOROOT_FINAL=
-go build -x -o binary.exe
-stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
-exec ./binary.exe $GOROOT
-stdout 'cgo DW_AT_comp_dir is right in binary'
+# Build a binary using a specific value of GOROOT_FINAL.
+env GOROOT_FINAL=$WORK${/}goroot1
+go build -o main.exe
+mv main.exe main1.exe
+
+# Now clean the cache and build using a different GOROOT_FINAL.
+# The resulting binaries should differ in their debug metadata.
+go clean -cache
+env GOROOT_FINAL=$WORK${/}goroot2
+go build -o main.exe
+mv main.exe main2.exe
+! cmp main2.exe main1.exe
+
+# Set GOROOT_FINAL back to the first value.
+# If the build is properly reproducible, the two binaries should match.
+env GOROOT_FINAL=$WORK${/}goroot1
+go build -o main.exe
+cmp -q main.exe main1.exe
-- go.mod --
module main
package main
import "C"
-import (
- "debug/dwarf"
- "fmt"
- "log"
- "os"
- "path/filepath"
- "strings"
-)
+
+import "runtime"
var _ C.int
func main() {
- dwarfData, err := readDWARF(os.Args[0])
- if err != nil {
- log.Fatal(err)
- }
- goroot := filepath.Join(os.Args[1], "src")
- dwarfReader := dwarfData.Reader()
- cgopackage := filepath.Join("runtime", "cgo")
- var hascgo bool
- for {
- e, err := dwarfReader.Next()
- if err != nil {
- log.Fatal(err)
- }
- if e == nil {
- break
- }
- field := e.AttrField(dwarf.AttrCompDir)
- if field == nil {
- continue
- }
- compdir := field.Val.(string)
- if strings.HasSuffix(compdir, cgopackage) {
- hascgo = true
- if !strings.HasPrefix(compdir, goroot) {
- fmt.Printf("cgo DW_AT_comp_dir %s contains incorrect path in binary.\n", compdir)
- return
- }
- }
- }
- if hascgo {
- fmt.Println("cgo DW_AT_comp_dir is right in binary")
- } else {
- fmt.Println("binary does not contain cgo")
- }
-}
--- read_darwin.go --
-package main
-
-import (
- "debug/dwarf"
- "debug/macho"
-)
-
-func readDWARF(exePath string) (*dwarf.Data, error) {
- machoFile, err := macho.Open(exePath)
- if err != nil {
- return nil, err
- }
- defer machoFile.Close()
- return machoFile.DWARF()
-}
--- read_elf.go --
-// +build android dragonfly freebsd illumos linux netbsd openbsd solaris
-
-package main
-
-import (
- "debug/dwarf"
- "debug/elf"
-)
-
-func readDWARF(exePath string) (*dwarf.Data, error) {
- elfFile, err := elf.Open(exePath)
- if err != nil {
- return nil, err
- }
- defer elfFile.Close()
- return elfFile.DWARF()
-}
--- read_windows.go --
-package main
-
-import (
- "debug/dwarf"
- "debug/pe"
-)
-
-func readDWARF(exePath string) (*dwarf.Data, error) {
- peFile, err := pe.Open(exePath)
- if err != nil {
- return nil, err
- }
- defer peFile.Close()
- return peFile.DWARF()
+ println(runtime.GOROOT())
}