[short] skip
[!cgo] skip

# Set up fresh GOCACHE
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'

-- go.mod --
module main

go 1.18
-- main.go --
package main

import "C"
import (
	"debug/dwarf"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
)

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()
}
