From: Alex Brainman Date: Wed, 10 Aug 2016 01:06:46 +0000 (+1000) Subject: cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end X-Git-Tag: go1.8beta1~1545 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=dfbbe06a205e7048a8541c4c97b250c24c40db96;p=gostls13.git cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end cmd/go links mingwex and mingw32 libraries to every package it builds. This breaks when 2 different packages call same gcc standard library function pow. gcc linker appends pow implementation to the compiled package, and names that function "pow". But when these 2 compiled packages are linked together into the final executable, linker complains, because it finds two "pow" functions with the same name. This CL stops linking of mingwex and mingw32 during package build - that leaves pow function reference unresolved. pow reference gets resolved as final executable is built, by having both internal and external linker use mingwex and mingw32 libraries. Fixes #8756 Change-Id: I50ddc79529ea5463c67118d668488345ecf069bc Reviewed-on: https://go-review.googlesource.com/26670 Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 8a95b02ac3..6440747208 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -70,5 +70,6 @@ func Test12030(t *testing.T) { test12030(t) } func TestGCC68255(t *testing.T) { testGCC68255(t) } func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) } func Test14838(t *testing.T) { test14838(t) } +func Test8756(t *testing.T) { test8756(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/misc/cgo/test/issue8756.go b/misc/cgo/test/issue8756.go new file mode 100644 index 0000000000..d8ee3b8213 --- /dev/null +++ b/misc/cgo/test/issue8756.go @@ -0,0 +1,17 @@ +package cgotest + +/* +#cgo LDFLAGS: -lm +#include +*/ +import "C" +import ( + "testing" + + "./issue8756" +) + +func test8756(t *testing.T) { + issue8756.Pow() + C.pow(1, 2) +} diff --git a/misc/cgo/test/issue8756/issue8756.go b/misc/cgo/test/issue8756/issue8756.go new file mode 100644 index 0000000000..5f6b7778ff --- /dev/null +++ b/misc/cgo/test/issue8756/issue8756.go @@ -0,0 +1,11 @@ +package issue8756 + +/* +#cgo LDFLAGS: -lm +#include +*/ +import "C" + +func Pow() { + C.pow(1, 2) +} diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 6e7f54d996..3d0326b967 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -3268,7 +3268,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi outGo = append(outGo, gofiles...) // gcc - cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) for _, cfile := range cfiles { ofile := obj + cfile[:len(cfile)-1] + "o" @@ -3421,12 +3420,6 @@ func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []st ldflags = append(ldflags, "-Wl,-r", "-nostdlib") - if goos == "windows" { - // libmingw32 and libmingwex have some inter-dependencies, - // so must use linker groups. - ldflags = append(ldflags, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group") - } - if b.gccSupportsNoPie() { ldflags = append(ldflags, "-no-pie") } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 9f906080e9..0df49a7271 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -372,6 +372,33 @@ func loadinternal(ctxt *Link, name string) { } } +// findLibPathCmd uses cmd command to find gcc library libname. +// It returns library full path if found, or "none" if not found. +func (ctxt *Link) findLibPathCmd(cmd, libname string) string { + if *flagExtld == "" { + *flagExtld = "gcc" + } + args := hostlinkArchArgs() + args = append(args, cmd) + if ctxt.Debugvlog != 0 { + ctxt.Logf("%s %v\n", *flagExtld, args) + } + out, err := exec.Command(*flagExtld, args...).Output() + if err != nil { + if ctxt.Debugvlog != 0 { + ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out) + } + return "none" + } + return strings.TrimSpace(string(out)) +} + +// findLibPath searches for library libname. +// It returns library full path if found, or "none" if not found. +func (ctxt *Link) findLibPath(libname string) string { + return ctxt.findLibPathCmd("--print-file-name="+libname, libname) +} + func (ctxt *Link) loadlib() { switch Buildmode { case BuildmodeCShared: @@ -573,28 +600,27 @@ func (ctxt *Link) loadlib() { } if any { if *flagLibGCC == "" { - if *flagExtld == "" { - *flagExtld = "gcc" - } - args := hostlinkArchArgs() - args = append(args, "--print-libgcc-file-name") - if ctxt.Debugvlog != 0 { - ctxt.Logf("%s %v\n", *flagExtld, args) - } - out, err := exec.Command(*flagExtld, args...).Output() - if err != nil { - if ctxt.Debugvlog != 0 { - ctxt.Logf("not using a libgcc file because compiler failed\n%v\n%s\n", err, out) - } - *flagLibGCC = "none" - } else { - *flagLibGCC = strings.TrimSpace(string(out)) - } + *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc") } - if *flagLibGCC != "none" { hostArchive(ctxt, *flagLibGCC) } + if HEADTYPE == obj.Hwindows { + if p := ctxt.findLibPath("libmingwex.a"); p != "none" { + hostArchive(ctxt, p) + } + if p := ctxt.findLibPath("libmingw32.a"); p != "none" { + hostArchive(ctxt, p) + } + // TODO: maybe do something similar to peimporteddlls to collect all lib names + // and try link them all to final exe just like libmingwex.a and libmingw32.a: + /* + for: + #cgo windows LDFLAGS: -lmsvcrt -lm + import: + libmsvcrt.a libm.a + */ + } } } else { hostlinksetup() @@ -1145,6 +1171,9 @@ func (l *Link) hostlink() { } } if HEADTYPE == obj.Hwindows { + // libmingw32 and libmingwex have some inter-dependencies, + // so must use linker groups. + argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group") argv = append(argv, peimporteddlls()...) }