bazelbuild / rules_go

Go rules for Bazel
Apache License 2.0
1.36k stars 636 forks source link

Linking with CGO dependencies fails in Go 1.23 due to missing linker arguments #3979

Open JacobOaks opened 3 days ago

JacobOaks commented 3 days ago

What version of rules_go are you using?

v0.48.0

What version of gazelle are you using?

v0.37.0

What version of Bazel are you using?

7.2.0

Does this issue reproduce with the latest releases of all the above?

Probably

What operating system and processor architecture are you using?

linux amd64

Any other potentially useful information about your toolchain?

This issue occurs when linking packages that use CGO w/ >= Go 1.23rc1.

What did you do?

main.go:

package main

// #include "unicode/uloc.h"
import "C"
import "fmt"

func main() {
        fmt.Println(C.uloc_getDefault())
}

BUILD.bazel:

load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
    name = "go_default_library",
    srcs = ["main.go"],
    cdeps = ["@icu4c//:icu4c"],
    cgo = True,
    importpath = "code.uber.internal/go/cgotest",
    visibility = ["//visibility:private"],
)

go_binary(
    name = "cgotest",
    embed = [":go_default_library"],
    visibility = ["//visibility:public"],
)

When using Go version 1.23rc1, run bazel build :cgotest

What did you expect to see?

Pass.

What did you see instead?

external/go_sdk/pkg/tool/linux_amd64/link: running external/zig_sdk/tools/x86_64-linux-gnu.2.19/c++ failed: exit status 1
external/zig_sdk/tools/x86_64-linux-gnu.2.19/c++ -m64 -s -o bazel-out/k8-fastbuild/bin/src/code.uber.internal/go/cgotest/cgotest_/cgotest -rdynamic -Qunused-arguments -Wl,--compress-debug-sections=zlib /tmp/go-link-3649824143/go.o /tmp/go-link-3649824143/000000.o /tmp/go-link-3649824143/000001.o /tmp/go-link-3649824143/000002.o /tmp/go-link-3649824143/000003.o /tmp/go-link-3649824143/000004.o /tmp/go-link-3649824143/000005.o /tmp/go-link-3649824143/000006.o /tmp/go-link-3649824143/000007.o /tmp/go-link-3649824143/000008.o /tmp/go-link-3649824143/000009.o /tmp/go-link-3649824143/000010.o /tmp/go-link-3649824143/000011.o /tmp/go-link-3649824143/000012.o /tmp/go-link-3649824143/000013.o /tmp/go-link-3649824143/000014.o /tmp/go-link-3649824143/000015.o -fno-lto -fsanitize-undefined-strip-path-components=-1 -pthread -lpthread -no-pie -fno-lto -fsanitize-undefined-strip-path-components=-1
ld.lld: error: undefined symbol: uloc_getDefault_70
>>> referenced by cgo-gcc-prolog:53
>>>               /tmp/go-link-3649824143/000001.o:(_cgo_4cb838639214_Cfunc_uloc_getDefault)

I did some debugging on this, and it seems like the go linker is not passing the libicu objects to the external linker. I.e., when I add these two arguments to the linker command above, linking succeeds: "bazel-out/k8-fastbuild/bin/external/icu4c/libicu-base.a", "bazel-out/k8-fastbuild/bin/external/icu4c/libicudata.a" (and these are present when using Go 1.22).

I believe this is because of https://go-review.googlesource.com/c/go/+/584655, which changes the cgo command to accept linker flags via command-line arg rather than env variable, while rules_go is still passing them as environment variables.

fmeum commented 2 days ago

Thanks for the root cause analysis! I followed up on https://github.com/golang/go/issues/66456 as this is a breaking change coming from upstream. I'll wait for recommendations from the Go team on how to handle this.