diff --git a/go/tools/builders/cgo2.go b/go/tools/builders/cgo2.go index 36103ae2fb..f088a8415b 100644 --- a/go/tools/builders/cgo2.go +++ b/go/tools/builders/cgo2.go @@ -197,7 +197,30 @@ func cgo2(goenv *env, goSrcs, cgoSrcs, cSrcs, cxxSrcs, objcSrcs, objcxxSrcs, sSr args = append([]string{cc, "-o", mainBin, mainObj}, cObjs...) args = append(args, combinedLdFlags...) if err := goenv.runCommand(args); err != nil { - return "", nil, nil, err + // If linking the binary for cgo fails, this is usually because the + // object files reference external symbols that can't be resolved yet. + // Since the binary is only produced to have its symbols read by the cgo + // command, there is no harm in trying to build it allowing unresolved + // symbols - the real link that happens at the end will fail if they + // rightfully can't be resolved. + var allowUnresolvedSymbolsLdFlag string + switch os.Getenv("GOOS") { + case "windows": + // MinGW's linker doesn't seem to support --unresolved-symbols + // and MSVC isn't supported at all. + return "", nil, nil, err + case "darwin", "ios": + allowUnresolvedSymbolsLdFlag = "-Wl,-undefined,dynamic_lookup" + default: + allowUnresolvedSymbolsLdFlag = "-Wl,--unresolved-symbols=ignore-all" + } + if err2 := goenv.runCommand(append(args, allowUnresolvedSymbolsLdFlag)); err2 != nil { + // Return the original error if we can't link the binary with the + // additional linker flags as they may simply be incorrect for the + // particular compiler/linker pair and would obscure the true reason + // for the failure of the original command. + return "", nil, nil, err + } } cgoImportsGo := filepath.Join(workDir, "_cgo_imports.go") diff --git a/tests/core/cgo/BUILD.bazel b/tests/core/cgo/BUILD.bazel index 7f39f6b29a..cefa1b9812 100644 --- a/tests/core/cgo/BUILD.bazel +++ b/tests/core/cgo/BUILD.bazel @@ -414,3 +414,23 @@ go_bazel_test( name = "external_includes_test", srcs = ["external_includes_test.go"], ) + +go_library( + name = "use_external_symbol", + srcs = ["use_external_symbol.go"], + cgo = True, + importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/use_external_symbol", + tags = ["manual"], +) + +go_binary( + name = "provide_external_symbol", + srcs = ["provide_external_symbol.go"], + cgo = True, + target_compatible_with = select({ + "@platforms//os:osx": [], + "@platforms//os:linux": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + deps = [":use_external_symbol"], +) diff --git a/tests/core/cgo/provide_external_symbol.go b/tests/core/cgo/provide_external_symbol.go new file mode 100644 index 0000000000..68d9fce1e0 --- /dev/null +++ b/tests/core/cgo/provide_external_symbol.go @@ -0,0 +1,12 @@ +package main + +import "C" + +import "github.com/bazelbuild/rules_go/tests/core/cgo/use_external_symbol" + +//export external_symbol +func external_symbol() {} + +func main() { + use_external_symbol.UseExternalSymbol() +} diff --git a/tests/core/cgo/use_external_symbol.go b/tests/core/cgo/use_external_symbol.go new file mode 100644 index 0000000000..70980ea7db --- /dev/null +++ b/tests/core/cgo/use_external_symbol.go @@ -0,0 +1,10 @@ +package use_external_symbol + +/* +void external_symbol(); +*/ +import "C" + +func UseExternalSymbol() { + C.external_symbol() +}