bazel-contrib / bazel-contrib/rules_go
cgo: `-lstdc++` being stripped out of linkopts
- Dominant language
- Go
- Stars
- 1.5k
- Forks
- 760
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 12
Description
### What version of rules_go are you using?
0.48.1
### What version of gazelle are you using?
n/a
### What version of Bazel are you using?
7.4.1
### Does this issue reproduce with the latest releases of all the above?
Yes
### What operating system and processor architecture are you using?
Linux/amd64
### Any other potentially useful information about your toolchain?
Custom c++ toolchain configuration including
```starlark
link_flags = [
"-static-libstdc++",
"-fuse-ld=gold",
"-Wl,-z,relro,-z,now",
"-no-canonical-prefixes",
"-Wl,--warn-execstack",
],
link_libs = [
"-Wl,--push-state,-as-needed,-Bstatic",
"-lstdc++",
"-Bdynamic",
"-lm",
"-Wl,--pop-state",
],
```
### What did you do?
Try to compile a cgo executable with a transitive dependency on c++ `cc_library`.
### What did you expect to see?
Successful linking with the toolchain-provided link flags.
### What did you see instead?
The `-lstdc++` is stripped out from the link line, so we get
```
bazel-out/k8-opt-exec-ST-9082f79b1d9e/bin/external/go_sdk/builder_reset/builder link ... -extldflags '-static-libstdc++ -fuse-ld=gold ... -Wl,--push-state,-as-needed,-Bstatic -Wl,-Bdynamic -lm -Wl,--pop-state -Wl,--push-state,-as-needed,-Bstatic -Wl,-Bdynamic -lm -Wl,--pop-state'
...
external/go_sdk/pkg/tool/linux_amd64/link: running /gcc failed: exit status 1
gcc -m64 -s ... bazel-out/k8-fastbuild/bin/external/com_googlesource_code_re2/libre2.a ... -static-libstdc++ -fuse-ld=gold -Wl,--push-state,-as-needed,-Bstatic -Wl,-Bdynamic -lm -Wl,--pop-state -Wl,--push-state,-as-needed,-Bstatic -Wl,-Bdynamic -lm -Wl,--pop-state ...
bazel-out/k8-fastbuild/bin/external/com_googlesource_code_re2/libre2.a(re2.pic.o):re2.cc:function re2::trunc(std::basic_string_view >):(.text+0x4b1): error: undefined reference to 'std::__cxx11::basic_string, std::allocator >::basic_string(char const*, unsigned long, std::allocator const&)'
```
Up until recently we'd been using a wrapper script around the linker which just injected `-lc++` no matter how broken the build system was being, but now I need to support compilation against either `libc++` or `libstdc++`, so that's no longer an option.
This seems to be caused by I think
https://github.com/bazel-contrib/rules_go/blob/5200a61dbf7f566586b027b7c5cc36a4bced3bfc/go/private/actions/link.bzl#L55-L58
which strips it out assuming that it'll be in `CGO_LDFLAGS` if needed except, leaving aside that `_cgo_codegen` doesn't seem to be a thing any more, I'm not sure how it's supposed to do that, because the go library doesn't have a direct dependency on the c++ library, and the go library doesn't use `#cgo LDFLAGS` directives because it wouldn't work anyway because the library it needs to link to doesn't exist outside of bazel. Adding
```golang
// #cgo LDFLAGS: -lstdc++
```
in the code is out of the question because this has to build with either `libstdc++` or `libc++` (including on linux).
The comment also seems somewhat at odds with
https://github.com/bazel-contrib/rules_go/blob/5200a61dbf7f566586b027b7c5cc36a4bced3bfc/go/tools/builders/cgo2.go#L50-L52
I'm not 100% sure that
https://github.com/bazel-contrib/rules_go/blob/5200a61dbf7f566586b027b7c5cc36a4bced3bfc/go/private/rules/cgo.bzl#L63-L69
isn't involved as well.
It may be possible to set it explicitly in the linkopts for the `go_library`, by configuring complicated `select()`s to infer which c++ standard library should be in use, but frankly I went to the trouble of configuring my c++ toolchain correctly so that I wouldn't have to do that.
Now that I've tracked down the cause of this issue, I do have a workaround, which is to change my toolchain configuration's linkopts to use `-Wl,-Bstatic,-lstdc++` to defeat the string matching, but it does seem like a case of the go rules trying to outsmart the c++ toolchain configuration and failing.
Contributor guide
Research direction
Start with the linkopts handling in go/private/actions/link.bzl at the referenced lines, then compare the cgo paths in go/tools/builders/cgo2.go and go/private/rules/cgo.bzl. Reproduce the cgo executable link with the custom C++ toolchain and trace why -lstdc++ is removed; done means the toolchain-provided library remains available and linking succeeds without a hard-coded libc++ or libstdc++ directive.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, go
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100