Skip to content

Commit 86f227a

Browse files
committed
cmd/cgo: use --no-gc-sections if available
zig cc passes `--gc-sections` to the underlying linker, which then causes undefined symbol errors when compiling with cgo but without C code. Add `-Wl,--no-gc-sections` to make it work with zig cc. Minimal example: **main.go** package main import _ "runtime/cgo" func main() {} Run (works after the patch, doesn't work before): CC="zig cc" go build main.go Among the existing code, `src/runtime/testdata/testprognet` fails to build: src/runtime/testdata/testprognet$ CC="zig cc" go build . net(.text): relocation target __errno_location not defined net(.text): relocation target getaddrinfo not defined net(.text): relocation target freeaddrinfo not defined net(.text): relocation target gai_strerror not defined runtime/cgo(.text): relocation target stderr not defined runtime/cgo(.text): relocation target fwrite not defined runtime/cgo(.text): relocation target vfprintf not defined runtime/cgo(.text): relocation target fputc not defined runtime/cgo(.text): relocation target abort not defined runtime/cgo(.text): relocation target pthread_create not defined runtime/cgo(.text): relocation target nanosleep not defined runtime/cgo(.text): relocation target pthread_detach not defined runtime/cgo(.text): relocation target stderr not defined runtime/cgo(.text): relocation target strerror not defined runtime/cgo(.text): relocation target fprintf not defined runtime/cgo(.text): relocation target abort not defined runtime/cgo(.text): relocation target pthread_mutex_lock not defined runtime/cgo(.text): relocation target pthread_cond_wait not defined runtime/cgo(.text): relocation target pthread_mutex_unlock not defined runtime/cgo(.text): relocation target pthread_cond_broadcast not defined runtime/cgo(.text): relocation target malloc not defined With the patch both examples build as expected. @ianlancetaylor suggested: > It would be fine with me if somebody wants to send a cgo patch that passes -Wl,--no-gc-sections, with a fallback if that option is not supported. ... and this is what we are doing. Tested with zig 0.10.0-dev.2252+a4369918b This is a continuation of CL 405414: the original one broke AIX and iOS builds. To fix that, added `unknown option` to the list of strings under lookup. Fixes #52690
1 parent 61fc5df commit 86f227a

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

src/cmd/go/internal/work/exec.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,6 +2528,13 @@ func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []strin
25282528
a = append(a, "-Qunused-arguments")
25292529
}
25302530

2531+
// zig cc passes --gc-sections to the underlying linker, which then causes
2532+
// undefined symbol errors when compiling with cgo but without C code.
2533+
// https://github.com/golang/go/issues/52690
2534+
if b.gccSupportsFlag(compiler, "-Wl,--no-gc-sections") {
2535+
a = append(a, "-Wl,--no-gc-sections")
2536+
}
2537+
25312538
// disable word wrapping in error messages
25322539
a = append(a, "-fmessage-length=0")
25332540

@@ -2584,7 +2591,12 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
25842591
}
25852592

25862593
tmp := os.DevNull
2587-
if runtime.GOOS == "windows" {
2594+
2595+
// On the iOS builder the command
2596+
// $CC -Wl,--no-gc-sections -x c - -o /dev/null < /dev/null
2597+
// is failing with:
2598+
// Unable to remove existing file: Invalid argument
2599+
if runtime.GOOS == "windows" || runtime.GOOS == "ios" {
25882600
f, err := os.CreateTemp(b.WorkDir, "")
25892601
if err != nil {
25902602
return false
@@ -2594,13 +2606,21 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
25942606
defer os.Remove(tmp)
25952607
}
25962608

2597-
// We used to write an empty C file, but that gets complicated with
2598-
// go build -n. We tried using a file that does not exist, but that
2599-
// fails on systems with GCC version 4.2.1; that is the last GPLv2
2600-
// version of GCC, so some systems have frozen on it.
2601-
// Now we pass an empty file on stdin, which should work at least for
2602-
// GCC and clang.
2603-
cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", tmp)
2609+
// We used to write an empty C file, but that gets complicated with go
2610+
// build -n. We tried using a file that does not exist, but that fails on
2611+
// systems with GCC version 4.2.1; that is the last GPLv2 version of GCC,
2612+
// so some systems have frozen on it. Now we pass an empty file on stdin,
2613+
// which should work at least for GCC and clang.
2614+
//
2615+
// If the argument is "-Wl,", then it's testing the linker. In that case,
2616+
// skip "-c". If it's not "-Wl,", then we are testing the compiler and
2617+
// can emit the linking step with "-c".
2618+
cmdArgs := str.StringList(compiler, flag)
2619+
if !strings.HasPrefix(flag, "-Wl,") /* linker flag */ {
2620+
cmdArgs = append(cmdArgs, "-c")
2621+
}
2622+
cmdArgs = append(cmdArgs, "-x", "c", "-", "-o", tmp)
2623+
26042624
if cfg.BuildN || cfg.BuildX {
26052625
b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
26062626
if cfg.BuildN {
@@ -2613,12 +2633,16 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
26132633
out, _ := cmd.CombinedOutput()
26142634
// GCC says "unrecognized command line option".
26152635
// clang says "unknown argument".
2636+
// tcc says "unsupported"
2637+
// AIX says "not recognized"
26162638
// Older versions of GCC say "unrecognised debug output level".
26172639
// For -fsplit-stack GCC says "'-fsplit-stack' is not supported".
26182640
supported := !bytes.Contains(out, []byte("unrecognized")) &&
26192641
!bytes.Contains(out, []byte("unknown")) &&
26202642
!bytes.Contains(out, []byte("unrecognised")) &&
2621-
!bytes.Contains(out, []byte("is not supported"))
2643+
!bytes.Contains(out, []byte("is not supported")) &&
2644+
!bytes.Contains(out, []byte("not recognized")) &&
2645+
!bytes.Contains(out, []byte("unsupported"))
26222646
b.flagCache[key] = supported
26232647
return supported
26242648
}

0 commit comments

Comments
 (0)