Skip to content

Conversation

@electronjoe
Copy link

@electronjoe electronjoe commented Jan 28, 2026

Closes #243

The -u SYMBOL flag tells the linker to treat SYMBOL as undefined, forcing it to be resolved from archives or shared libraries. This is a standard linker feature used to:

  • Force inclusion of specific archive members (e.g., static initializers, plugin registration, constructor functions)
  • Pull in coverage/profiling runtime symbols (e.g., __llvm_profile_runtime)
  • Ensure weak symbol overrides are linked
  • Implement plugin architectures that require specific entry points

Currently, Zig's cc/c++ driver misinterprets -u SYMBOL - it attempts to open SYMBOL as a filename rather than passing it to the linker. This breaks any toolchain or build system that relies on this flag.

This is a known Zig bug tracked at:
https://codeberg.org/ziglang/zig/issues/30613

The fix (https://codeberg.org/ziglang/zig/pulls/30749) is pending merge. I'll post on the issue and merge request at Zig just to +1 the need for a fix - and I'm not sure whether you want to integrate a work around here in hermetic_cc_toolchain or not vs waiting for an upstream fix.

This patch works around the issue by transforming -u SYMBOL into -Wl,-u,SYMBOL, which explicitly passes the flag through to the linker.

Discovered while debugging bazel coverage failures in a mixed C++/Rust repository (minimal reproduction at https://github.com/electronjoe/bazel-cpp-rust-codecov). This repo uses hermetic_cc_compiler and rules_rust -> rustc passes -u __llvm_profile_runtime for coverage instrumentation. If you would like to reproduce the original issue, you can open a codespace from the repo, bazel coverage //..., observe success - then roll back this patch in the repo and try again to observe the failure mode.

The `-u SYMBOL` flag tells the linker to treat SYMBOL as undefined,
forcing it to be resolved from archives or shared libraries. This is a
standard linker feature used to:

- Force inclusion of specific archive members (e.g., static initializers,
  plugin registration, constructor functions)
- Pull in coverage/profiling runtime symbols (e.g., __llvm_profile_runtime)
- Ensure weak symbol overrides are linked
- Implement plugin architectures that require specific entry points

Currently, Zig's cc/c++ driver misinterprets `-u SYMBOL` - it attempts
to open SYMBOL as a filename rather than passing it to the linker. This
breaks any toolchain or build system that relies on this flag.

This is a known Zig bug tracked at:
  https://codeberg.org/ziglang/zig/issues/30613

The fix (https://codeberg.org/ziglang/zig/pulls/30749) is pending merge.

This patch works around the issue by transforming `-u SYMBOL` into
`-Wl,-u,SYMBOL`, which explicitly passes the flag through to the linker.

Discovered while debugging `bazel coverage` failures in a mixed C++/Rust
repository (https://github.com/electronjoe/bazel-cpp-rust-codecov), where
rustc passes `-u __llvm_profile_runtime` for coverage instrumentation.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@CLAassistant
Copy link

CLAassistant commented Jan 28, 2026

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bazel coverage fails for Rust targets: -u linker flag incorrectly parsed as filename

2 participants