Skip to content

rust: avoid duplicate native flags from direct build scripts - #4276

Open
jrandolf wants to merge 2 commits into
bazelbuild:mainfrom
jrandolf:codex/upstream-native-link-flags
Open

jrandolf wants to merge 2 commits into
bazelbuild:mainfrom
jrandolf:codex/upstream-native-link-flags

Conversation

@jrandolf

@jrandolf jrandolf commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

A package binary can need its build script directly for cfg flags, rustc-env, and generated files in OUT_DIR, even when it also depends on the package library. Cargo applies rustc-link-lib to the library in that situation; the binary links the native dependency through the library.

Record each crate's direct build script in DepInfo and decide native-link flag ownership during the existing dependency collection pass. A matching library dependency suppresses only the duplicate native-link flag file. The binary keeps its compiler flags, environment, generated output, and link search paths. This avoids flattening dependency sets to rediscover the library's build script.

The regression fixtures require build-script output to compile the binary. Five analysis cases cover the library, a binary sharing its script, a standalone binary, a shared script through an intermediate library, and a library with a different script.

Validation: all five analysis tests and the real fixture builds pass locally on macOS arm64 with Bazel 9.2.0 at 1fba2fb (bazel test //cargo/tests/cargo_build_script/duplicate_link_flags:all). Both suites also pass together on fork main 8242dfc, where all four binary fixtures run successfully. Formatting checks also pass.

Closes #4291.

@UebelAndre UebelAndre left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'm not quite sure how I feel about this situation. My initial instinct is to say the build script being a direct dependency of both the rust_library and rust_binary is a configuration error and the build script should only be on the rust_library. Can you explain more about why the dep is needed on both? And do you know how Cargo handles this situation?

Comment thread rust/private/rustc.bzl Outdated
def _build_script_linked_by_library(build_info, dep_info):
# Cargo applies rustc-link-lib to the package library when one exists.
# Binaries that depend on that library already link its native archives.
for crate in dep_info.direct_crates.to_list():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about the to_list() here. Is there another way we can identify this pattern?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked this in f2ced4f. collect_deps now records each crate's directly attached BuildInfo in DepInfo and checks eligible library dependencies during its existing loop. It compares the complete BuildInfo after collecting the dependencies and carries the resulting native-link flag file separately as build_script_linker_flags.

Both added to_list() calls and the nested helper are gone. The original build-script provider is preserved so a shared script is still recognized through an intermediate library.

@jrandolf

jrandolf commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor Author

The binary needs the direct build-script dependency when it consumes the script's rustc-cfg, rustc-env, or generated files through OUT_DIR. A dependency on the Rust library does not pass those compile settings to the binary. The expanded fixture now requires all three, so removing :shared_script from the binary would leave it unable to compile.

Cargo makes a separate decision for native libraries: its rustc-link-lib documentation says the library target receives -l when the package has a library, and all targets receive it when there is no library. The rustc-env section describes environment values used when compiling the package.

Updated in f2ced4f: only the duplicate native-link flag file is omitted. The cfg flags, environment, OUT_DIR, and search paths remain attached to the binary. The analysis cases also cover an intermediate library sharing the script and an unrelated library with a different script. All five analysis tests and the real fixture builds now pass locally on macOS arm64 with Bazel 9.2.0 at f2ced4f. Both suites also pass together on fork main e9abbb5, and all four binary fixtures run successfully there.

@jrandolf
jrandolf requested a review from UebelAndre September 28, 2026 19:14
@jrandolf
jrandolf force-pushed the codex/upstream-native-link-flags branch from f2ced4f to 1fba2fb Compare September 28, 2026 19:15

This branch has not been deployed

No deployments
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.

Native link flags repeat when a binary and its library share a build script

2 participants