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-bin[s], 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 @@ -613,6 +617,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 @@ -640,6 +646,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
20 changes: 20 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 @@ -215,6 +217,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 @@ -231,6 +235,10 @@ 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 @@ -397,6 +405,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 @@ -420,6 +430,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 @@ -444,6 +458,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 @@ -469,6 +487,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
42 changes: 32 additions & 10 deletions cargo/private/cargo_build_script_runner/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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-bin[s]`). 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 @@ -39,6 +46,10 @@ pub enum BuildScriptOutput {
Flags(String),
/// cargo::rustc-link-arg
LinkArg(String),
/// cargo::rustc-cdylib-link-arg
CdylibLinkArg(String),
/// cargo::rustc-link-arg-bin / cargo::rustc-link-arg-bins
BinLinkArg(String),
/// cargo::rustc-env
Env(String),
/// cargo::VAR=VALUE
Expand Down Expand Up @@ -100,16 +111,17 @@ 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-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]
);
None
}
// cargo::rustc-cdylib-link-arg=FLAG — linker flag applied only when the
// crate is built as a cdylib.
"rustc-cdylib-link-arg" => Some(BuildScriptOutput::CdylibLinkArg(param)),
// cargo::rustc-link-arg-bins=FLAG — linker flag applied to binary targets.
"rustc-link-arg-bins" => Some(BuildScriptOutput::BinLinkArg(param)),
// cargo::rustc-link-arg-bin=BIN=FLAG — linker flag for the binary BIN.
// Bazel builds one target per crate, so the BIN selector is dropped and
// the flag applies to the owning crate's binary.
"rustc-link-arg-bin" => Some(BuildScriptOutput::BinLinkArg(
param.split_once('=').map_or(param.clone(), |(_bin, flag)| flag.to_owned()),
)),
_ => {
// cargo::KEY=VALUE — Metadata, used by links scripts.
Some(BuildScriptOutput::DepEnv(format!(
Expand Down Expand Up @@ -208,12 +220,16 @@ 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 @@ -228,6 +244,8 @@ 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 @@ -336,6 +354,8 @@ mod tests {
.to_owned(),
link_flags: "-lsdfsdf".to_owned(),
link_search_paths: "-L${pwd}/bleh".to_owned(),
cdylib_link_flags: String::new(),
bin_link_flags: String::new(),
}
);
}
Expand Down Expand Up @@ -489,6 +509,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: String::new(),
bin_link_flags: String::new(),
}
);
}
Expand Down
2 changes: 2 additions & 0 deletions rust/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ CrateGroupInfo = provider(
BuildInfo = provider(
doc = "A provider containing `rustc` build settings for a given Crate.",
fields = {
"bin_link_flags": "Optional[File]: file of `-Clink-arg`s to pass to rustc only when the crate is built as a binary (`cargo::rustc-link-arg-bin[s]`).",
"cdylib_link_flags": "Optional[File]: file of `-Clink-arg`s to pass to rustc only when the crate is built as a cdylib (`cargo::rustc-cdylib-link-arg`); propagated transitively to cdylibs.",
"compile_data": "Depset[File]: Compile data provided by the build script that was not copied into `out_dir`.",
"dep_env": "Optional[File]: extra build script environment variables to be set to direct dependencies.",
"flags": "Optional[File]: file containing additional flags to pass to rustc",
Expand Down
15 changes: 15 additions & 0 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ def collect_inputs(
build_script_compile_inputs, out_dir, build_env_file, build_flags_files = _process_build_scripts(
build_info = build_info,
dep_info = dep_info,
crate_type = crate_info.type,
include_link_flags = include_link_flags,
include_transitive_data = not toolchain._incompatible_do_not_include_transitive_data_in_compile_inputs,
)
Expand Down Expand Up @@ -2253,6 +2254,7 @@ def add_edition_flags(args, crate):
def _process_build_scripts(
build_info,
dep_info,
crate_type,
include_link_flags = True,
include_transitive_data = False):
"""Gathers the outputs from a target's `cargo_build_script` action.
Expand Down Expand Up @@ -2297,6 +2299,12 @@ def _process_build_scripts(
build_flags_files.append(build_info.linker_flags)
direct_inputs.append(build_info.linker_flags)

# `cargo::rustc-link-arg-bin[s]` apply only to binary targets, and (like
# cargo) only from the crate's own build script — not transitively.
if crate_type == "bin" and getattr(build_info, "bin_link_flags", None):
build_flags_files.append(build_info.bin_link_flags)
direct_inputs.append(build_info.bin_link_flags)

transitive_inputs.append(build_info.compile_data)

# We include transitive dep build_infos because cargo build scripts may generate files which get linked into the final binary.
Expand All @@ -2306,6 +2314,13 @@ def _process_build_scripts(
direct_inputs.append(dep_build_info.out_dir)
transitive_inputs.append(dep_build_info.compile_data)

# `cargo::rustc-cdylib-link-arg` applies only to cdylib targets, and (like
# cargo, see rust-lang/cargo#9562) propagates transitively to them. The
# crate's own build script is included here via `transitive_build_infos`.
if crate_type in ("cdylib", "dylib") and getattr(dep_build_info, "cdylib_link_flags", None):
build_flags_files.append(dep_build_info.cdylib_link_flags)
direct_inputs.append(dep_build_info.cdylib_link_flags)

out_dir_compile_inputs = depset(
direct_inputs,
transitive = transitive_inputs,
Expand Down
Loading