diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 1587f100eae..0360c088888 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -25,7 +25,7 @@ pub struct BuildOutput { /// Names and link kinds of libraries, suitable for the `-l` flag. pub library_links: Vec, /// Linker arguments suitable to be passed to `-C link-arg=` - pub linker_args: Vec<(Option, String)>, + pub linker_args: Vec<(LinkType, String)>, /// Various `--cfg` flags to pass to the compiler. pub cfgs: Vec, /// Additional environment variables to run the compiler with. @@ -562,18 +562,36 @@ impl BuildOutput { "rustc-link-lib" => library_links.push(value.to_string()), "rustc-link-search" => library_paths.push(PathBuf::from(value)), "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => { - linker_args.push((Some(LinkType::Cdylib), value)) + linker_args.push((LinkType::Cdylib, value)) } "rustc-link-arg-bins" => { if extra_link_arg { - linker_args.push((Some(LinkType::Bin), value)); + linker_args.push((LinkType::Bin, value)); + } else { + warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key)); + } + } + "rustc-link-arg-bin" => { + if extra_link_arg { + let parts = value.splitn(2, "=").collect::>(); + if parts.len() == 2 { + linker_args.push(( + LinkType::SingleBin(parts[0].to_string()), + parts[1].to_string(), + )); + } else { + warnings.push(format!( + "cargo:{} has invalid syntax: expected `cargo:{}=BIN=ARG`", + key, key + )); + } } else { warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key)); } } "rustc-link-arg" => { if extra_link_arg { - linker_args.push((None, value)); + linker_args.push((LinkType::All, value)); } else { warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key)); } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 969e5996180..5079046e767 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -62,29 +62,27 @@ use cargo_util::{paths, ProcessBuilder, ProcessError}; const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; -#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub enum LinkType { + All, Cdylib, Bin, + SingleBin(String), Test, Bench, Example, } -impl From<&super::Target> for Option { - fn from(value: &super::Target) -> Self { - if value.is_cdylib() { - Some(LinkType::Cdylib) - } else if value.is_bin() { - Some(LinkType::Bin) - } else if value.is_test() { - Some(LinkType::Test) - } else if value.is_bench() { - Some(LinkType::Bench) - } else if value.is_exe_example() { - Some(LinkType::Example) - } else { - None +impl LinkType { + pub fn applies_to(&self, target: &Target) -> bool { + match self { + LinkType::All => true, + LinkType::Cdylib => target.is_cdylib(), + LinkType::Bin => target.is_bin(), + LinkType::SingleBin(name) => target.is_bin() && target.name() == name, + LinkType::Test => target.is_test(), + LinkType::Bench => target.is_bench(), + LinkType::Example => target.is_exe_example(), } } } @@ -227,7 +225,6 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc) -> Car // If we are a binary and the package also contains a library, then we // don't pass the `-l` flags. let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib()); - let link_type = (&unit.target).into(); let dep_info_name = if cx.files().use_extra_filename(unit) { format!( @@ -280,7 +277,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc) -> Car &script_outputs, &build_scripts, pass_l_flag, - link_type, + &target, current_id, )?; add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?; @@ -371,7 +368,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc) -> Car build_script_outputs: &BuildScriptOutputs, build_scripts: &BuildScripts, pass_l_flag: bool, - link_type: Option, + target: &Target, current_id: PackageId, ) -> CargoResult<()> { for key in build_scripts.to_link.iter() { @@ -396,11 +393,9 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc) -> Car } } - if link_type.is_some() { - for (lt, arg) in &output.linker_args { - if lt.is_none() || *lt == link_type { - rustc.arg("-C").arg(format!("link-arg={}", arg)); - } + for (lt, arg) in &output.linker_args { + if lt.applies_to(&target) { + rustc.arg("-C").arg(format!("link-arg={}", arg)); } } } diff --git a/src/cargo/util/config/target.rs b/src/cargo/util/config/target.rs index e22cab92ee5..304679854ff 100644 --- a/src/cargo/util/config/target.rs +++ b/src/cargo/util/config/target.rs @@ -134,13 +134,13 @@ fn parse_links_overrides( } "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => { let args = value.list(key)?; - let args = args.iter().map(|v| (Some(LinkType::Cdylib), v.0.clone())); + let args = args.iter().map(|v| (LinkType::Cdylib, v.0.clone())); output.linker_args.extend(args); } "rustc-link-arg-bins" => { if extra_link_arg { let args = value.list(key)?; - let args = args.iter().map(|v| (Some(LinkType::Bin), v.0.clone())); + let args = args.iter().map(|v| (LinkType::Bin, v.0.clone())); output.linker_args.extend(args); } else { config.shell().warn(format!( @@ -152,7 +152,7 @@ fn parse_links_overrides( "rustc-link-arg" => { if extra_link_arg { let args = value.list(key)?; - let args = args.iter().map(|v| (None, v.0.clone())); + let args = args.iter().map(|v| (LinkType::All, v.0.clone())); output.linker_args.extend(args); } else { config.shell().warn(format!( diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 348936aba86..e4befbccd69 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -137,11 +137,13 @@ Cargo _or_ Rust features can be used. * Tracking Issue: [#9426](https://github.com/rust-lang/cargo/issues/9426) * Original Pull Request: [#7811](https://github.com/rust-lang/cargo/pull/7811) -The `-Z extra-link-arg` flag makes the following two instructions available +The `-Z extra-link-arg` flag makes the following instructions available in build scripts: * [`cargo:rustc-link-arg-bins=FLAG`](#rustc-link-arg-bins) – Passes custom flags to a linker for binaries. +* [`cargo:rustc-link-arg-bin=BIN=FLAG`](#rustc-link-arg-bin) – Passes custom + flags to a linker for the binary `BIN`. * [`cargo:rustc-link-arg=FLAG`](#rustc-link-arg) – Passes custom flags to a linker for benchmarks, binaries, `cdylib` crates, examples, and tests. @@ -155,6 +157,16 @@ to set a linker script or other linker options. [link-arg]: ../../rustc/codegen-options/index.md#link-arg + +#### `cargo:rustc-link-arg-bin=BIN=FLAG` + +The `rustc-link-arg-bin` instruction tells Cargo to pass the [`-C +link-arg=FLAG` option][link-arg] to the compiler, but only when building +the binary target with name `BIN`. Its usage is highly platform specific. It is useful +to set a linker script or other linker options. + +[link-arg]: ../../rustc/codegen-options/index.md#link-arg + #### `cargo:rustc-link-arg=FLAG` diff --git a/tests/testsuite/build_script_extra_link_arg.rs b/tests/testsuite/build_script_extra_link_arg.rs index e655414924e..afd8e085aef 100644 --- a/tests/testsuite/build_script_extra_link_arg.rs +++ b/tests/testsuite/build_script_extra_link_arg.rs @@ -26,6 +26,49 @@ fn build_script_extra_link_arg_bin() { .run(); } +#[cargo_test] +fn build_script_extra_link_arg_bin_single() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + + name = "foobar" + version = "0.5.0" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + [[bin]] + name = "bar" + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "build.rs", + r#" + fn main() { + println!("cargo:rustc-link-arg-bins=--bogus-flag-all"); + println!("cargo:rustc-link-arg-bin=foo=--bogus-flag-foo"); + println!("cargo:rustc-link-arg-bin=bar=--bogus-flag-bar"); + } + "#, + ) + .build(); + + p.cargo("build -Zextra-link-arg -v") + .masquerade_as_nightly_cargo() + .without_status() + .with_stderr_contains( + "[RUNNING] `rustc --crate-name foo [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-foo[..]", + ) + .with_stderr_contains( + "[RUNNING] `rustc --crate-name bar [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-bar[..]", + ) + .run(); +} + #[cargo_test] fn build_script_extra_link_arg() { let p = project()