From ab0f48227df28648f83da33b24000f9ecffb3a62 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Fri, 17 Jan 2020 10:50:37 -0500 Subject: [PATCH 1/2] Add rustc-bin-link-arg and rustc-link-arg custom build options Both are similar to rustc-cdylib-link-arg. The rustc-bin-link-arg option adds -C link-arg=... on binary targets. The rustc-link-arg option adds -C link-arg=... on all supported targets (currently only binaries and cdylib libraries). --- src/cargo/core/compiler/custom_build.rs | 8 +++--- src/cargo/core/compiler/mod.rs | 34 +++++++++++++++++++++---- src/cargo/util/config/target.rs | 15 +++++++++-- src/doc/src/reference/build-scripts.md | 26 +++++++++++++++++++ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index c35df661dd6..e33249c81db 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -1,5 +1,5 @@ use super::job::{Freshness, Job, Work}; -use super::{fingerprint, CompileKind, Context, Unit}; +use super::{fingerprint, CompileKind, Context, LinkType, Unit}; use crate::core::compiler::job_queue::JobState; use crate::core::{profiles::ProfileRoot, PackageId}; use crate::util::errors::{CargoResult, CargoResultExt}; @@ -20,7 +20,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, + pub linker_args: Vec<(Option, String)>, /// Various `--cfg` flags to pass to the compiler. pub cfgs: Vec, /// Additional environment variables to run the compiler with. @@ -478,7 +478,9 @@ impl BuildOutput { } "rustc-link-lib" => library_links.push(value.to_string()), "rustc-link-search" => library_paths.push(PathBuf::from(value)), - "rustc-cdylib-link-arg" => linker_args.push(value.to_string()), + "rustc-cdylib-link-arg" => linker_args.push((Some(LinkType::Cdylib), value)), + "rustc-bin-link-arg" => linker_args.push((Some(LinkType::Bin), value)), + "rustc-link-arg" => linker_args.push((None, value)), "rustc-cfg" => cfgs.push(value.to_string()), "rustc-env" => env.push(BuildOutput::parse_rustc_env(&value, &whence)?), "warning" => warnings.push(value.to_string()), diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 29805bb3e0e..4854880245e 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -49,6 +49,24 @@ use crate::util::machine_message::Message; use crate::util::{self, machine_message, ProcessBuilder}; use crate::util::{internal, join_paths, paths, profile}; +#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] +pub enum LinkType { + Cdylib, + Bin, +} + +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 { + None + } + } +} + /// A glorified callback for executing calls to rustc. Rather than calling rustc /// directly, we'll use an `Executor`, giving clients an opportunity to intercept /// the build calls. @@ -191,7 +209,7 @@ fn rustc<'a, 'cfg>( // 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 pass_cdylib_link_args = unit.target.is_cdylib(); + let link_type = unit.target.into(); let do_rename = unit.target.allows_underscores() && !unit.mode.is_any_test(); let real_name = unit.target.name().to_string(); let crate_name = unit.target.crate_name(); @@ -242,7 +260,7 @@ fn rustc<'a, 'cfg>( &script_outputs, &build_scripts, pass_l_flag, - pass_cdylib_link_args, + link_type, current_id, )?; add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?; @@ -336,7 +354,7 @@ fn rustc<'a, 'cfg>( build_script_outputs: &BuildScriptOutputs, build_scripts: &BuildScripts, pass_l_flag: bool, - pass_cdylib_link_args: bool, + link_type: Option, current_id: PackageId, ) -> CargoResult<()> { for key in build_scripts.to_link.iter() { @@ -358,8 +376,14 @@ fn rustc<'a, 'cfg>( rustc.arg("-l").arg(name); } } - if pass_cdylib_link_args { - for arg in output.linker_args.iter() { + + if link_type.is_some() { + for arg in output + .linker_args + .iter() + .filter(|x| x.0.is_none() || x.0 == link_type) + .map(|x| &x.1) + { let link_arg = format!("link-arg={}", arg); rustc.arg("-C").arg(link_arg); } diff --git a/src/cargo/util/config/target.rs b/src/cargo/util/config/target.rs index 1ea39abb732..5398c542311 100644 --- a/src/cargo/util/config/target.rs +++ b/src/cargo/util/config/target.rs @@ -1,5 +1,5 @@ use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV}; -use crate::core::compiler::BuildOutput; +use crate::core::compiler::{BuildOutput, LinkType}; use crate::util::CargoResult; use serde::Deserialize; use std::collections::{BTreeMap, HashMap}; @@ -131,7 +131,18 @@ fn parse_links_overrides( } "rustc-cdylib-link-arg" => { let args = value.list(key)?; - output.linker_args.extend(args.iter().map(|v| v.0.clone())); + let args = args.iter().map(|v| (Some(LinkType::Cdylib), v.0.clone())); + output.linker_args.extend(args); + } + "rustc-bin-link-arg" => { + let args = value.list(key)?; + let args = args.iter().map(|v| (Some(LinkType::Bin), v.0.clone())); + output.linker_args.extend(args); + } + "rustc-link-arg" => { + let args = value.list(key)?; + let args = args.iter().map(|v| (None, v.0.clone())); + output.linker_args.extend(args); } "rustc-cfg" => { let list = value.list(key)?; diff --git a/src/doc/src/reference/build-scripts.md b/src/doc/src/reference/build-scripts.md index 3bdbb6254f2..36ba3424d45 100644 --- a/src/doc/src/reference/build-scripts.md +++ b/src/doc/src/reference/build-scripts.md @@ -105,6 +105,10 @@ one detailed below. * [`cargo:rustc-env=VAR=VALUE`](#rustc-env) — Sets an environment variable. * [`cargo:rustc-cdylib-link-arg=FLAG`](#rustc-cdylib-link-arg) — Passes custom flags to a linker for cdylib crates. +* [`cargo:rustc-bin-link-arg=FLAG`](#rustc-bin-link-arg) — Passes custom + flags to a linker for bin crates. +* [`cargo:rustc-link-arg=FLAG`](#rustc-link-arg) — Passes custom + flags to a linker for all supported crates. * [`cargo:warning=MESSAGE`](#cargo-warning) — Displays a warning on the terminal. * [`cargo:KEY=VALUE`](#the-links-manifest-key) — Metadata, used by `links` @@ -205,6 +209,26 @@ to set the shared library version or the runtime-path. [link-arg]: ../../rustc/codegen-options/index.md#link-arg + +#### `cargo:rustc-bin-link-arg=FLAG` + +The `rustc-bin-link-arg` instruction tells Cargo to pass the [`-C +link-arg=FLAG` option][link-arg] to the compiler, but only when building a +binary target. 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` + +The `rustc-link-arg` instruction tells Cargo to pass the [`-C link-arg=FLAG` +option][link-arg] to the compiler, but only when building a supported target +(currently a binary or `cdylib` library). Its usage is highly platform +specific. It is useful to set the shared library version or linker script. + +[link-arg]: ../../rustc/codegen-options/index.md#link-arg + #### `cargo:warning=MESSAGE` @@ -372,6 +396,8 @@ rustc-flags = "-L /some/path" rustc-cfg = ['key="value"'] rustc-env = {key = "value"} rustc-cdylib-link-arg = ["…"] +rustc-bin-link-arg = ["…"] +rustc-link-arg = ["…"] metadata_key1 = "value" metadata_key2 = "value" ``` From ee2870cacc37f7a6e611fe4b5419efc7805171e6 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Fri, 24 Jan 2020 17:53:51 -0500 Subject: [PATCH 2/2] Add -Z extra-link-arg This hides the new rustc-bin-link-arg and rustc-link-arg build script configuration items behind an unstable flag. --- src/cargo/core/compiler/mod.rs | 15 ++++++++------- src/cargo/core/features.rs | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 4854880245e..117abf73bbe 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -213,6 +213,7 @@ fn rustc<'a, 'cfg>( let do_rename = unit.target.allows_underscores() && !unit.mode.is_any_test(); let real_name = unit.target.name().to_string(); let crate_name = unit.target.crate_name(); + let extra_link_arg = cx.bcx.config.cli_unstable().extra_link_arg; // Rely on `target_filenames` iterator as source of truth rather than rederiving filestem. let rustc_dep_info_loc = if do_rename && cx.files().metadata(unit).is_none() { @@ -261,6 +262,7 @@ fn rustc<'a, 'cfg>( &build_scripts, pass_l_flag, link_type, + extra_link_arg, current_id, )?; add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?; @@ -355,6 +357,7 @@ fn rustc<'a, 'cfg>( build_scripts: &BuildScripts, pass_l_flag: bool, link_type: Option, + extra_link_arg: bool, current_id: PackageId, ) -> CargoResult<()> { for key in build_scripts.to_link.iter() { @@ -376,17 +379,15 @@ fn rustc<'a, 'cfg>( rustc.arg("-l").arg(name); } } - if link_type.is_some() { - for arg in output + output .linker_args .iter() .filter(|x| x.0.is_none() || x.0 == link_type) - .map(|x| &x.1) - { - let link_arg = format!("link-arg={}", arg); - rustc.arg("-C").arg(link_arg); - } + .filter(|x| x.0 == Some(LinkType::Cdylib) || extra_link_arg) + .for_each(|x| { + rustc.arg("-C").arg(format!("link-arg={}", x.1)); + }); } } } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index c2ea6622fa8..d579f51224a 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -342,6 +342,7 @@ pub struct CliUnstable { pub doctest_xcompile: bool, pub panic_abort_tests: bool, pub jobserver_per_rustc: bool, + pub extra_link_arg: bool, } impl CliUnstable { @@ -411,6 +412,7 @@ impl CliUnstable { "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?, "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?, "jobserver-per-rustc" => self.jobserver_per_rustc = parse_empty(k, v)?, + "extra-link-arg" => self.extra_link_arg = parse_empty(k, v)?, _ => bail!("unknown `-Z` flag specified: {}", k), }