diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 86c39b2bef9..8e782b5dee0 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -448,7 +448,7 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu let export_dir = cx.files().export_dir(); let package_id = unit.pkg.package_id(); let manifest_path = PathBuf::from(unit.pkg.manifest_path()); - let profile = unit.profile; + let profile = unit.profile.clone(); let unit_mode = unit.mode; let features = unit.features.iter().map(|s| s.to_string()).collect(); let json_messages = bcx.build_config.emit_json(); @@ -853,8 +853,9 @@ fn build_base_args( ref panic, incremental, strip, + rustflags, .. - } = unit.profile; + } = unit.profile.clone(); let test = unit.mode.is_any_test(); cmd.arg("--crate-name").arg(&unit.target.crate_name()); @@ -904,6 +905,10 @@ fn build_base_args( cmd.arg("-C").arg(&format!("opt-level={}", opt_level)); } + if !rustflags.is_empty() { + cmd.args(&rustflags); + } + if *panic != PanicStrategy::Unwind { cmd.arg("-C").arg(format!("panic={}", panic)); } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 968290a380e..85eae245d36 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -409,6 +409,9 @@ features! { // Allow specifying different binary name apart from the crate name (unstable, different_binary_name, "", "reference/unstable.html#different-binary-name"), + + // Allow specifying rustflags directly in a profile + (unstable, profile_rustflags, "", "reference/unstable.html#profile-rustflags-option"), } pub struct Feature { diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index fe88e724e28..eafc00a64c6 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -500,7 +500,7 @@ impl ProfileMaker { is_member: bool, unit_for: UnitFor, ) -> Profile { - let mut profile = self.default; + let mut profile = self.default.clone(); // First apply profile-specific settings, things like // `[profile.release]` @@ -626,6 +626,9 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) { if let Some(incremental) = toml.incremental { profile.incremental = incremental; } + if let Some(flags) = &toml.rustflags { + profile.rustflags = flags.clone(); + } profile.strip = match toml.strip { Some(StringOrBool::Bool(true)) => Strip::Named(InternedString::new("symbols")), None | Some(StringOrBool::Bool(false)) => Strip::None, @@ -647,7 +650,7 @@ pub enum ProfileRoot { /// Profile settings used to determine which compiler flags to use for a /// target. -#[derive(Clone, Copy, Eq, PartialOrd, Ord, serde::Serialize)] +#[derive(Clone, Eq, PartialOrd, Ord, serde::Serialize)] pub struct Profile { pub name: InternedString, pub opt_level: InternedString, @@ -666,6 +669,9 @@ pub struct Profile { pub incremental: bool, pub panic: PanicStrategy, pub strip: Strip, + #[serde(skip_serializing_if = "Vec::is_empty")] // remove when `rustflags` is stablized + // Note that `rustflags` is used for the cargo-feature `profile_rustflags` + pub rustflags: Vec, } impl Default for Profile { @@ -685,6 +691,7 @@ impl Default for Profile { incremental: false, panic: PanicStrategy::Unwind, strip: Strip::None, + rustflags: vec![], } } } @@ -712,6 +719,7 @@ compact_debug! { incremental panic strip + rustflags )] } } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index fc78dbfc63b..a21cf4f429b 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -1606,7 +1606,7 @@ fn traverse_and_share( let new_unit = interner.intern( &unit.pkg, &unit.target, - unit.profile, + unit.profile.clone(), new_kind, unit.mode, unit.features.clone(), diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 39835c75285..b955d460d21 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -413,6 +413,8 @@ pub struct TomlProfile { pub dir_name: Option, pub inherits: Option, pub strip: Option, + // Note that `rustflags` is used for the cargo-feature `profile_rustflags` + pub rustflags: Option>, // These two fields must be last because they are sub-tables, and TOML // requires all non-tables to be listed first. pub package: Option>, @@ -530,6 +532,10 @@ impl TomlProfile { } } + if self.rustflags.is_some() { + features.require(Feature::profile_rustflags())?; + } + if let Some(codegen_backend) = &self.codegen_backend { features.require(Feature::codegen_backend())?; if codegen_backend.contains(|c: char| !c.is_ascii_alphanumeric() && c != '_') { @@ -691,6 +697,10 @@ impl TomlProfile { self.incremental = Some(v); } + if let Some(v) = &profile.rustflags { + self.rustflags = Some(v.clone()); + } + if let Some(other_package) = &profile.package { match &mut self.package { Some(self_package) => { diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index ff29e8f2bc5..b1c06e567e9 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -89,6 +89,7 @@ Each new feature described below should explain how to use it. * [rustdoc-map](#rustdoc-map) — Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/). * `Cargo.toml` extensions * [Profile `strip` option](#profile-strip-option) — Forces the removal of debug information and symbols from executables. + * [Profile `rustflags` option](#profile-rustflags-option) — Passed directly to rustc. * [per-package-target](#per-package-target) — Sets the `--target` to use for each individual package. * Information and metadata * [Build-plan](#build-plan) — Emits JSON information on which commands will be run. @@ -820,6 +821,24 @@ The following is a description of the JSON structure: } ``` +### Profile `rustflags` option +* Original Issue: [rust-lang/cargo#7878](https://github.com/rust-lang/cargo/issues/7878) +* Tracking Issue: [rust-lang/cargo#10271](https://github.com/rust-lang/cargo/issues/10271) + +This feature provides a new option in the `[profile]` section to specify flags +that are passed directly to rustc. +This can be enabled like so: + +```toml +cargo-features = ["profile-rustflags"] + +[package] +# ... + +[profile.release] +rustflags = [ "-C", "..." ] +``` + ### rustdoc-map * Tracking Issue: [#8296](https://github.com/rust-lang/cargo/issues/8296) diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs index e6576eee2b0..95549cfc387 100644 --- a/tests/testsuite/config.rs +++ b/tests/testsuite/config.rs @@ -1484,6 +1484,7 @@ fn all_profile_options() { strip: Some(toml::StringOrBool::String("symbols".to_string())), package: None, build_override: None, + rustflags: None, }; let mut overrides = BTreeMap::new(); let key = toml::ProfilePackageSpec::Spec(PackageIdSpec::parse("foo").unwrap()); diff --git a/tests/testsuite/profiles.rs b/tests/testsuite/profiles.rs index 4f5ed76644e..97246776505 100644 --- a/tests/testsuite/profiles.rs +++ b/tests/testsuite/profiles.rs @@ -595,3 +595,101 @@ fn strip_accepts_false_to_disable_strip() { .with_stderr_does_not_contain("-C strip") .run(); } + +#[cargo_test] +fn rustflags_works() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["profile-rustflags"] + + [profile.dev] + rustflags = ["-C", "link-dead-code=yes"] + + [package] + name = "foo" + version = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo [..] +[RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn rustflags_works_with_env() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["profile-rustflags"] + + [package] + name = "foo" + version = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v") + .env("CARGO_PROFILE_DEV_RUSTFLAGS", "-C link-dead-code=yes") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo [..] +[RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn rustflags_requires_cargo_feature() { + let p = project() + .file( + "Cargo.toml", + r#" + [profile.dev] + rustflags = ["-C", "link-dead-code=yes"] + + [package] + name = "foo" + version = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + feature `profile-rustflags` is required + + The package requires the Cargo feature called `profile-rustflags`, but that feature is \ + not stabilized in this version of Cargo (1.[..]). + Consider adding `cargo-features = [\"profile-rustflags\"]` to the top of Cargo.toml \ + (above the [package] table) to tell Cargo you are opting in to use this unstable feature. + See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option \ + for more information about the status of this feature. +", + ) + .run(); +}