diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index f662495a1a1..1ba65031e97 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -46,7 +46,7 @@ use self::output_depinfo::output_depinfo; use self::unit_graph::UnitDep; pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; -use crate::core::profiles::{PanicStrategy, Profile}; +use crate::core::profiles::{PanicStrategy, Profile, Strip}; use crate::core::{Edition, Feature, InternedString, PackageId, Target}; use crate::util::errors::{self, CargoResult, CargoResultExt, ProcessError, VerboseError}; use crate::util::machine_message::Message; @@ -732,6 +732,7 @@ fn build_base_args( rpath, ref panic, incremental, + strip, .. } = unit.profile; let test = unit.mode.is_any_test(); @@ -910,6 +911,10 @@ fn build_base_args( opt(cmd, "-C", "incremental=", Some(dir)); } + if strip != Strip::None { + cmd.arg("-Z").arg(format!("strip={}", strip)); + } + if unit.is_std { // -Zforce-unstable-if-unmarked prevents the accidental use of // unstable crates within the sysroot (such as "extern crate libc" or diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 1c82a033d49..6a05b0f091f 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -214,6 +214,9 @@ features! { // Opt-in new-resolver behavior. [unstable] resolver: bool, + + // Allow to specify whether binaries should be stripped. + [unstable] strip: bool, } } diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index d4769389abd..fc5fe31bccb 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -565,6 +565,9 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) { if let Some(incremental) = toml.incremental { profile.incremental = incremental; } + if let Some(strip) = toml.strip { + profile.strip = strip; + } } /// The root profile (dev/release). @@ -595,6 +598,7 @@ pub struct Profile { pub rpath: bool, pub incremental: bool, pub panic: PanicStrategy, + pub strip: Strip, } impl Default for Profile { @@ -611,6 +615,7 @@ impl Default for Profile { rpath: false, incremental: false, panic: PanicStrategy::Unwind, + strip: Strip::None, } } } @@ -635,6 +640,7 @@ compact_debug! { rpath incremental panic + strip )] } } @@ -721,6 +727,7 @@ impl Profile { bool, bool, PanicStrategy, + Strip, ) { ( self.opt_level, @@ -732,6 +739,7 @@ impl Profile { self.rpath, self.incremental, self.panic, + self.strip, ) } } @@ -776,6 +784,30 @@ impl fmt::Display for PanicStrategy { } } +/// The setting for choosing which symbols to strip +#[derive( + Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, +)] +#[serde(rename_all = "lowercase")] +pub enum Strip { + /// Only strip debugging symbols + DebugInfo, + /// Don't remove any symbols + None, + /// Strip all non-exported symbols from the final binary + Symbols, +} + +impl fmt::Display for Strip { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Strip::DebugInfo => "debuginfo", + Strip::None => "abort", + Strip::Symbols => "symbols", + } + .fmt(f) + } +} /// Flags used in creating `Unit`s to indicate the purpose for the target, and /// to ensure the target's dependencies have the correct settings. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 246bd37f145..7cb2240e71f 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -15,6 +15,7 @@ use url::Url; use crate::core::dependency::DepKind; use crate::core::manifest::{ManifestMetadata, TargetSourcePath, Warnings}; +use crate::core::profiles::Strip; use crate::core::resolver::ResolveBehavior; use crate::core::{Dependency, InternedString, Manifest, PackageId, Summary, Target}; use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest, Workspace}; @@ -407,6 +408,7 @@ pub struct TomlProfile { pub build_override: Option>, pub dir_name: Option, pub inherits: Option, + pub strip: Option, } #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] @@ -522,6 +524,10 @@ impl TomlProfile { ); } } + + if self.strip.is_some() { + features.require(Feature::strip())?; + } Ok(()) } @@ -641,6 +647,10 @@ impl TomlProfile { if let Some(v) = &profile.dir_name { self.dir_name = Some(*v); } + + if let Some(v) = profile.strip { + self.strip = Some(v); + } } } diff --git a/tests/testsuite/profiles.rs b/tests/testsuite/profiles.rs index ad8bbe7db1a..1a51d20b0eb 100644 --- a/tests/testsuite/profiles.rs +++ b/tests/testsuite/profiles.rs @@ -2,7 +2,7 @@ use std::env; -use cargo_test_support::project; +use cargo_test_support::{is_nightly, project}; #[cargo_test] fn profile_overrides() { @@ -468,3 +468,111 @@ fn thin_lto_works() { ) .run(); } + +#[cargo_test] +fn strip_works() { + if !is_nightly() { + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["strip"] + + [package] + name = "foo" + version = "0.1.0" + + [profile.release] + strip = 'symbols' + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build --release -v") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo [..] +[RUNNING] `rustc [..] -Z strip=symbols [..]` +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn strip_requires_cargo_feature() { + if !is_nightly() { + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [profile.release] + strip = 'symbols' + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build --release -v") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + feature `strip` is required + +consider adding `cargo-features = [\"strip\"]` to the manifest +", + ) + .run(); +} +#[cargo_test] +fn strip_rejects_invalid_option() { + if !is_nightly() { + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["strip"] + + [package] + name = "foo" + version = "0.1.0" + + [profile.release] + strip = 'wrong' + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build --release -v") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + unknown variant `wrong`, expected one of `debuginfo`, `none`, `symbols` for key [..] +", + ) + .run(); +} diff --git a/tests/testsuite/unit_graph.rs b/tests/testsuite/unit_graph.rs index 878e7c3b4f5..2313a3ce6d5 100644 --- a/tests/testsuite/unit_graph.rs +++ b/tests/testsuite/unit_graph.rs @@ -75,7 +75,8 @@ fn simple() { "overflow_checks": true, "rpath": false, "incremental": false, - "panic": "unwind" + "panic": "unwind", + "strip": "none" }, "platform": null, "mode": "build", @@ -115,7 +116,8 @@ fn simple() { "overflow_checks": true, "rpath": false, "incremental": false, - "panic": "unwind" + "panic": "unwind", + "strip": "none" }, "platform": null, "mode": "build", @@ -155,7 +157,8 @@ fn simple() { "overflow_checks": true, "rpath": false, "incremental": false, - "panic": "unwind" + "panic": "unwind", + "strip": "none" }, "platform": null, "mode": "build", @@ -188,7 +191,8 @@ fn simple() { "overflow_checks": true, "rpath": false, "incremental": false, - "panic": "unwind" + "panic": "unwind", + "strip": "none" }, "platform": null, "mode": "build",