Skip to content
Open
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
8 changes: 8 additions & 0 deletions cargo/private/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ def _cargo_build_script_impl(ctx):
flags_out = ctx.actions.declare_file(ctx.label.name + ".flags")
link_flags = ctx.actions.declare_file(ctx.label.name + ".linkflags")
link_search_paths = ctx.actions.declare_file(ctx.label.name + ".linksearchpaths") # rustc-link-search, propagated from transitive dependencies
cdylib_link_flags = ctx.actions.declare_file(ctx.label.name + ".cdyliblinkflags") # rustc-cdylib-link-arg, applied to cdylib crates (incl. transitively)
bin_link_flags = ctx.actions.declare_file(ctx.label.name + ".binlinkflags") # rustc-link-arg-bins, applied to binary crates
compilation_mode_opt_level = get_compilation_mode_opts(ctx, toolchain).opt_level

script_data = []
Expand Down Expand Up @@ -549,6 +551,8 @@ def _cargo_build_script_impl(ctx):
args.add(flags_out, format = "--flags_out=%s")
args.add(link_flags, format = "--link_flags=%s")
args.add(link_search_paths, format = "--link_search_paths=%s")
args.add(cdylib_link_flags, format = "--cdylib_link_flags=%s")
args.add(bin_link_flags, format = "--bin_link_flags=%s")
args.add(dep_env_out, format = "--dep_env_out=%s")
args.add(ctx.attr.rundir, format = "--rundir=%s")

Expand Down Expand Up @@ -623,6 +627,8 @@ def _cargo_build_script_impl(ctx):
flags_out,
link_flags,
link_search_paths,
cdylib_link_flags,
bin_link_flags,
dep_env_out,
runfiles_dir,
] + extra_output,
Expand Down Expand Up @@ -650,6 +656,8 @@ def _cargo_build_script_impl(ctx):
flags = flags_out,
linker_flags = link_flags,
link_search_paths = link_search_paths,
cdylib_link_flags = cdylib_link_flags,
bin_link_flags = bin_link_flags,
compile_data = depset([runfiles_dir] + extra_output, transitive = script_data),
),
OutputGroupInfo(
Expand Down
24 changes: 24 additions & 0 deletions cargo/private/cargo_build_script_runner/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ fn run_buildrs() -> Result<(), String> {
compile_flags_file,
link_flags_file,
link_search_paths_file,
cdylib_link_flags_file,
bin_link_flags_file,
output_dep_env_path,
stdout_path,
stderr_path,
Expand Down Expand Up @@ -219,6 +221,8 @@ fn run_buildrs() -> Result<(), String> {
compile_flags,
link_flags,
link_search_paths,
cdylib_link_flags,
bin_link_flags,
} = BuildScriptOutput::outputs_to_flags(
&buildrs_outputs,
&exec_root.to_string_lossy(),
Expand All @@ -235,6 +239,14 @@ fn run_buildrs() -> Result<(), String> {
link_search_paths_file, e
)
});
write(&cdylib_link_flags_file, cdylib_link_flags.as_bytes()).unwrap_or_else(|e| {
panic!(
"Unable to write file {:?}: {:#?}",
cdylib_link_flags_file, e
)
});
write(&bin_link_flags_file, bin_link_flags.as_bytes())
.unwrap_or_else(|e| panic!("Unable to write file {:?}: {:#?}", bin_link_flags_file, e));

if !exec_root_links.is_empty() {
for link in exec_root_links {
Expand Down Expand Up @@ -401,6 +413,8 @@ struct Args {
compile_flags_file: String,
link_flags_file: String,
link_search_paths_file: String,
cdylib_link_flags_file: String,
bin_link_flags_file: String,
output_dep_env_path: String,
stdout_path: Option<String>,
stderr_path: Option<String>,
Expand All @@ -424,6 +438,10 @@ impl Args {
Err("Argument `link_flags_file` not provided".to_owned());
let mut link_search_paths_file: Result<String, String> =
Err("Argument `link_search_paths_file` not provided".to_owned());
let mut cdylib_link_flags_file: Result<String, String> =
Err("Argument `cdylib_link_flags_file` not provided".to_owned());
let mut bin_link_flags_file: Result<String, String> =
Err("Argument `bin_link_flags_file` not provided".to_owned());
let mut output_dep_env_path: Result<String, String> =
Err("Argument `output_dep_env_path` not provided".to_owned());
let mut stdout_path = None;
Expand All @@ -448,6 +466,10 @@ impl Args {
link_flags_file = Ok(arg.split_off("--link_flags=".len()));
} else if arg.starts_with("--link_search_paths=") {
link_search_paths_file = Ok(arg.split_off("--link_search_paths=".len()));
} else if arg.starts_with("--cdylib_link_flags=") {
cdylib_link_flags_file = Ok(arg.split_off("--cdylib_link_flags=".len()));
} else if arg.starts_with("--bin_link_flags=") {
bin_link_flags_file = Ok(arg.split_off("--bin_link_flags=".len()));
} else if arg.starts_with("--dep_env_out=") {
output_dep_env_path = Ok(arg.split_off("--dep_env_out=".len()));
} else if arg.starts_with("--stdout=") {
Expand All @@ -473,6 +495,8 @@ impl Args {
compile_flags_file: compile_flags_file.unwrap(),
link_flags_file: link_flags_file.unwrap(),
link_search_paths_file: link_search_paths_file.unwrap(),
cdylib_link_flags_file: cdylib_link_flags_file.unwrap(),
bin_link_flags_file: bin_link_flags_file.unwrap(),
output_dep_env_path: output_dep_env_path.unwrap(),
stdout_path,
stderr_path,
Expand Down
72 changes: 65 additions & 7 deletions cargo/private/cargo_build_script_runner/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ pub struct CompileAndLinkFlags {
pub compile_flags: String,
pub link_flags: String,
pub link_search_paths: String,
/// `-Clink-arg`s that apply only when the crate is built as a cdylib
/// (`cargo::rustc-cdylib-link-arg`). The consuming rule gates these on the
/// crate type, and propagates them transitively to cdylibs (matching cargo).
pub cdylib_link_flags: String,
/// `-Clink-arg`s that apply only when the crate is built as a binary
/// (`cargo::rustc-link-arg-bins`). Gated on the crate type by the rule.
pub bin_link_flags: String,
}

/// Enum containing all the considered return value from the script
Expand All @@ -41,6 +48,10 @@ pub enum BuildScriptOutput {
Flags(String),
/// cargo::rustc-link-arg
LinkArg(String),
/// cargo::rustc-cdylib-link-arg
CdylibLinkArg(String),
/// cargo::rustc-link-arg-bins
BinLinkArg(String),
/// cargo::rustc-env
Env(String),
/// cargo::VAR=VALUE
Expand Down Expand Up @@ -98,14 +109,18 @@ impl BuildScriptOutput {
Some(BuildScriptOutput::DepEnv(format!("METADATA={}", param)))
}
}
"rustc-cdylib-link-arg" | "rustc-link-arg-bin" | "rustc-link-arg-bins" => {
// cargo::rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
// cargo::rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
"rustc-cdylib-link-arg" => Some(BuildScriptOutput::CdylibLinkArg(param)),
// cargo::rustc-link-arg-bins=FLAG – Passes custom flags to a linker for binaries.
"rustc-link-arg-bins" => Some(BuildScriptOutput::BinLinkArg(param)),
"rustc-link-arg-bin" => {
// cargo::rustc-link-arg-bin=BIN=FLAG – Passes custom flags to a linker for the binary BIN.
// cargo::rustc-link-arg-bins=FLAG – Passes custom flags to a linker for binaries.
eprint!(
"Warning: build script returned unsupported directive `{}`",
split[0]
);
if emit_warnings {
eprint!(
"Warning: build script returned unsupported directive `{}`",
split[0]
);
}
None
}
_ => {
Expand Down Expand Up @@ -210,12 +225,18 @@ impl BuildScriptOutput {
let mut compile_flags = Vec::new();
let mut link_flags = Vec::new();
let mut link_search_paths = Vec::new();
let mut cdylib_link_flags = Vec::new();
let mut bin_link_flags = Vec::new();

for flag in outputs {
match flag {
BuildScriptOutput::Cfg(e) => compile_flags.push(format!("--cfg={e}")),
BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()),
BuildScriptOutput::LinkArg(e) => compile_flags.push(format!("-Clink-arg={e}")),
BuildScriptOutput::CdylibLinkArg(e) => {
cdylib_link_flags.push(format!("-Clink-arg={e}"))
}
BuildScriptOutput::BinLinkArg(e) => bin_link_flags.push(format!("-Clink-arg={e}")),
BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{e}")),
BuildScriptOutput::LinkSearch(e) => link_search_paths.push(format!("-L{e}")),
_ => {}
Expand All @@ -230,6 +251,12 @@ impl BuildScriptOutput {
exec_root,
out_dir,
),
cdylib_link_flags: Self::redact_flags(
&cdylib_link_flags.join("\n"),
exec_root,
out_dir,
),
bin_link_flags: Self::redact_flags(&bin_link_flags.join("\n"), exec_root, out_dir),
}
}

Expand Down Expand Up @@ -338,6 +365,8 @@ mod tests {
.to_owned(),
link_flags: "-lsdfsdf".to_owned(),
link_search_paths: "-L${pwd}/bleh".to_owned(),
cdylib_link_flags: "".to_owned(),
bin_link_flags: "".to_owned(),
}
);
}
Expand Down Expand Up @@ -366,6 +395,33 @@ non-assignment-instructions-are-ignored",
from_read_buffer_to_env_and_flags_test_impl(buff);
}

#[test]
fn test_cdylib_and_bin_link_args() {
let buff = Cursor::new(
"
cargo::rustc-cdylib-link-arg=-undefined
cargo::rustc-link-arg-bins=-Wl,--whole-archive
cargo::rustc-link-arg-bin=mybin=-Wl,--per-bin",
);
let result = BuildScriptOutput::outputs_from_reader(BufReader::new(buff), false);

// `rustc-link-arg-bin` (the per-binary form) is unsupported and dropped.
assert_eq!(
result,
vec![
BuildScriptOutput::CdylibLinkArg("-undefined".to_owned()),
BuildScriptOutput::BinLinkArg("-Wl,--whole-archive".to_owned()),
]
);

let flags = BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path", "");
assert_eq!(flags.cdylib_link_flags, "-Clink-arg=-undefined".to_owned());
assert_eq!(
flags.bin_link_flags,
"-Clink-arg=-Wl,--whole-archive".to_owned()
);
}

/// Demonstrate that the old style single colon flags are all parsable
#[test]
fn test_legacy_from_read_buffer_to_env_and_flags() {
Expand Down Expand Up @@ -503,6 +559,8 @@ cargo::rustc-link-search=/abs/exec_root/other/path
link_flags: "".to_owned(),
link_search_paths:
"-L${pwd}/${bazel-out/cfg/bin/pkg/_bs.out_dir}\n-L${pwd}/other/path".to_owned(),
cdylib_link_flags: "".to_owned(),
bin_link_flags: "".to_owned(),
}
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load(":cdylib_bin_link_args_test.bzl", "cdylib_bin_link_args_test_suite")

cdylib_bin_link_args_test_suite(name = "cdylib_bin_link_args_test_suite")
1 change: 1 addition & 0 deletions cargo/tests/cargo_build_script/cdylib_bin_link_args/bin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}
13 changes: 13 additions & 0 deletions cargo/tests/cargo_build_script/cdylib_bin_link_args/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fn main() {
// Emit a benign linker flag (an extra library search path) as the cdylib/bin
// link arg. It exercises the real pipeline end to end -- the consumers below
// link with it applied -- while being a no-op that doesn't break any linker.
let out_dir = std::env::var("OUT_DIR").unwrap();
let search = if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
format!("/LIBPATH:{out_dir}")
} else {
format!("-L{out_dir}")
};
println!("cargo::rustc-cdylib-link-arg={search}");
println!("cargo::rustc-link-arg-bins={search}");
}
Loading
Loading