-
Notifications
You must be signed in to change notification settings - Fork 504
Description
Summary
The _add_native_link_flags
function in rust/private/rustc.bzl
automatically generates both static (-lstatic=
) and dynamic (-l
) linking flags for cc_library dependencies. This prevents hermetic cross-compilation scenarios where only static libraries are available.
Problem Description
When cross-compiling a Rust binary that depends on cc_library targets, _add_native_link_flags
generates linking flags like:
-lstatic=mylib -lmylib
In hermetic cross-compilation environments (e.g., macOS host targeting Linux), only static libraries (.a
) are available, but the dynamic flags (-lmylib
) cause linker failures:
error: linking with `zig` failed: exit status: 1
= note: /usr/bin/ld: cannot find -lmylib: No such file or directory
Minimal Reproduction
A complete, self-contained reproduction is available at:
https://gist.github.com/punya/a013c30ea31ca4ef0386968e7f21849d
The reproduction demonstrates:
- A local cc_library that builds successfully (creating both .a and .so files)
- A rust_binary that fails during hermetic cross-compilation
- Evidence that even linkstatic=True doesn't solve the problem
- A working manual workaround using rustc_flags
- Why the workaround is insufficient for real-world use
Run ./test.sh
to see all scenarios in action.
Root Cause
The platform-specific link flag generators (e.g., _make_link_flags_default
for Linux) in _add_native_link_flags
are hardcoded to generate both static and dynamic flags for each cc_library dependency. There's no mechanism to generate only static flags.
Proposed Solutions (Ranked by Preference)
Option 1 (Preferred): Automatic Detection
Automatically detect when only static libraries are available and generate only static flags. The function could:
- Check if dynamic libraries (
.so
,.dylib
,.dll
) exist alongside static libraries - In hermetic cross-compilation, only static libraries are typically available
- Fall back to static-only linking when dynamic libraries are missing
Option 2: Add static_only_linking
attribute
Add a new attribute to rust_binary
and rust_library
rules:
rust_binary(
name = "my_binary",
static_only_linking = True, # Generate only -lstatic= flags
deps = [":mylib"],
)
Option 3: Use linking modifiers
Leverage Rust's native linking modifiers (RFC 2951) when available:
-l static:+whole-archive=mylib
Impact
This affects any project using:
- Hermetic cross-compilation with cc_library dependencies
- Static-only build environments
- Embedded targets where dynamic linking isn't available
- Container builds targeting minimal base images
- Projects currently forced to use cumbersome manual workarounds that don't scale
Current Workarounds
A manual workaround exists but is insufficient:
Manual rustc_flags workaround:
rust_binary(
name = "my_binary",
deps = [":mylib"],
rustc_flags = [
"-C", "link-arg=-Wl,-Bstatic",
"-C", "link-arg=-lmylib",
"-C", "link-arg=-Wl,-Bdynamic",
],
)
Limitations of this workaround:
- Requires manually specifying every library name
- Becomes unwieldy for complex dependency trees
- Defeats the purpose of Bazel's automatic dependency management
- Must be repeated for every rust_binary target
Other insufficient workarounds:
- Avoid cc_library dependencies in Rust targets
- Use cc_binary as the final linker instead of rust_binary
- Patch rules_rust locally
- Abandon hermetic cross-compilation
Additional Context
- Related to ongoing work on hermetic builds (Hermetic
build.rs
#490) - Could benefit from RFC 2951 (native-link-modifiers) implementation
- Similar challenges exist in other cross-compilation scenarios (Cross-compilation with Bzlmod not working #2518)
- The issue manifests in the
_make_link_flags_default
function which generates both flag types