Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load(":duplicate_link_flags_test.bzl", "duplicate_link_flags_test_suite")

duplicate_link_flags_test_suite(name = "duplicate_link_flags_test_suite")
3 changes: 3 additions & 0 deletions cargo/tests/cargo_build_script/duplicate_link_flags/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-link-lib=static=example");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""Check when a package build script's native link flags reach a Rustc action."""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//cargo:defs.bzl", "cargo_build_script")
load("//rust:defs.bzl", "rust_binary", "rust_library")

def _link_flags_test_impl(ctx):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)
rustc_actions = [action for action in target.actions if action.mnemonic == "Rustc"]
asserts.equals(env, 1, len(rustc_actions))

if rustc_actions:
argv = rustc_actions[0].argv
link_flags = [
argv[i + 1]
for i in range(len(argv) - 1)
if argv[i] == "--arg-file" and argv[i + 1].endswith("shared_script.linkflags")
]
asserts.equals(env, ctx.attr.expected_count, len(link_flags))

return analysistest.end(env)

_link_flags_test = analysistest.make(
_link_flags_test_impl,
attrs = {"expected_count": attr.int(mandatory = True)},
)

def duplicate_link_flags_test_suite(name):
"""Verify a direct library owns its package build script's native flags."""
cargo_build_script(
name = "shared_script",
srcs = ["build.rs"],
)

rust_library(
name = "lib",
srcs = ["lib.rs"],
deps = [":shared_script"],
)

rust_binary(
name = "bin_with_lib",
srcs = ["main.rs"],
deps = [":lib", ":shared_script"],
)

rust_binary(
name = "bin_without_lib",
srcs = ["main.rs"],
deps = [":shared_script"],
)

_link_flags_test(
name = "lib_link_flags_test",
target_under_test = ":lib",
expected_count = 1,
)

_link_flags_test(
name = "bin_with_lib_link_flags_test",
target_under_test = ":bin_with_lib",
expected_count = 0,
)

_link_flags_test(
name = "bin_without_lib_link_flags_test",
target_under_test = ":bin_without_lib",
expected_count = 1,
)

native.test_suite(
name = name,
tests = [
":lib_link_flags_test",
":bin_with_lib_link_flags_test",
":bin_without_lib_link_flags_test",
],
)
3 changes: 3 additions & 0 deletions cargo/tests/cargo_build_script/duplicate_link_flags/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn value() -> i32 {
1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}
13 changes: 12 additions & 1 deletion rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2576,7 +2576,7 @@ def _process_build_scripts(
build_env_file = build_info.rustc_env
if build_info.flags:
build_flags_files.append(build_info.flags)
if build_info.linker_flags and include_link_flags:
if build_info.linker_flags and include_link_flags and not _build_script_linked_by_library(build_info, dep_info):
build_flags_files.append(build_info.linker_flags)
direct_inputs.append(build_info.linker_flags)

Expand All @@ -2600,6 +2600,17 @@ def _process_build_scripts(
depset(build_flags_files, transitive = [dep_info.link_search_path_files]),
)

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():
if crate.dep.type not in ("lib", "rlib", "dylib") or crate.dep.is_test:
continue
for dep in crate.dep.deps.to_list():
if dep.build_info == build_info and dep.build_info.linker_flags == build_info.linker_flags:
return True
return False

def _compute_rpaths(toolchain, output_dir, dep_info, use_pic, link_std_dylib, output_file = None, workspace_name = ""):
"""Determine the artifact's rpaths relative to the bazel root for runtime linking of shared libraries.

Expand Down