diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 7b43fd27d999..4340a4d89351 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -603,9 +603,13 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu } if json_messages { + let debuginfo = profile.debuginfo.to_option().map(|d| match d.parse() { + Ok(n) => machine_message::ArtifactDebuginfo::Int(n), + Err(_) => machine_message::ArtifactDebuginfo::Named(d.to_string()), + }); let art_profile = machine_message::ArtifactProfile { opt_level: profile.opt_level.as_str(), - debuginfo: profile.debuginfo.to_option(), + debuginfo, debug_assertions: profile.debug_assertions, overflow_checks: profile.overflow_checks, test: unit_mode.is_any_test(), diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index 51d19e32e627..9500e32c201f 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -26,7 +26,9 @@ use crate::core::dependency::Artifact; use crate::core::resolver::features::FeaturesFor; use crate::core::{PackageId, PackageIdSpec, Resolve, Shell, Target, Workspace}; use crate::util::interning::InternedString; -use crate::util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool}; +use crate::util::toml::{ + ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBoolOrString, +}; use crate::util::{closest_msg, config, CargoResult, Config}; use anyhow::{bail, Context as _}; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -276,15 +278,13 @@ impl Profiles { // platform which has a stable `-Csplit-debuginfo` option for rustc, // and it's typically much faster than running `dsymutil` on all builds // in incremental cases. - if let Some(debug) = profile.debuginfo.to_option() { - if profile.split_debuginfo.is_none() && debug > 0 { - let target = match &kind { - CompileKind::Host => self.rustc_host.as_str(), - CompileKind::Target(target) => target.short_name(), - }; - if target.contains("-apple-") { - profile.split_debuginfo = Some(InternedString::new("unpacked")); - } + if profile.debuginfo.is_turned_on() && profile.split_debuginfo.is_none() { + let target = match &kind { + CompileKind::Host => self.rustc_host.as_str(), + CompileKind::Target(target) => target.short_name(), + }; + if target.contains("-apple-") { + profile.split_debuginfo = Some(InternedString::new("unpacked")); } } @@ -529,9 +529,12 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) { profile.codegen_units = toml.codegen_units; } match toml.debug { - Some(U32OrBool::U32(debug)) => profile.debuginfo = DebugInfo::Explicit(debug), - Some(U32OrBool::Bool(true)) => profile.debuginfo = DebugInfo::Explicit(2), - Some(U32OrBool::Bool(false)) => profile.debuginfo = DebugInfo::None, + Some(U32OrBoolOrString::U32(debug)) => { + profile.debuginfo = DebugInfo::Explicit(debug.to_string().into()) + } + Some(U32OrBoolOrString::Bool(true)) => profile.debuginfo = DebugInfo::Explicit("2".into()), + Some(U32OrBoolOrString::Bool(false)) => profile.debuginfo = DebugInfo::None, + Some(U32OrBoolOrString::String(ref s)) => profile.debuginfo = DebugInfo::Explicit(s.into()), None => {} } if let Some(debug_assertions) = toml.debug_assertions { @@ -683,7 +686,7 @@ impl Profile { Profile { name: InternedString::new("dev"), root: ProfileRoot::Debug, - debuginfo: DebugInfo::Explicit(2), + debuginfo: DebugInfo::Explicit("2".into()), debug_assertions: true, overflow_checks: true, incremental: true, @@ -743,7 +746,7 @@ pub enum DebugInfo { /// No debuginfo level was set. None, /// A debuginfo level that is explicitly set, by a profile or a user. - Explicit(u32), + Explicit(InternedString), /// For internal purposes: a deferred debuginfo level that can be optimized /// away, but has this value otherwise. /// @@ -753,22 +756,25 @@ pub enum DebugInfo { /// faster to build (see [DebugInfo::weaken]). /// /// In all other situations, this level value will be the one to use. - Deferred(u32), + Deferred(InternedString), } impl DebugInfo { /// The main way to interact with this debuginfo level, turning it into an Option. - pub fn to_option(&self) -> Option { + pub fn to_option(self) -> Option { match self { DebugInfo::None => None, - DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(*v), + DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(v), } } /// Returns true if the debuginfo level is high enough (at least 1). Helper /// for a common operation on the usual `Option` representation. pub(crate) fn is_turned_on(&self) -> bool { - self.to_option().unwrap_or(0) != 0 + match self.to_option().as_deref() { + None | Some("0") | Some("none") => false, + Some(_) => true, + } } pub(crate) fn is_deferred(&self) -> bool { diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs index baef5167b367..a96a84ae1256 100644 --- a/src/cargo/util/machine_message.rs +++ b/src/cargo/util/machine_message.rs @@ -55,12 +55,20 @@ impl<'a> Message for Artifact<'a> { #[derive(Serialize)] pub struct ArtifactProfile { pub opt_level: &'static str, - pub debuginfo: Option, + pub debuginfo: Option, pub debug_assertions: bool, pub overflow_checks: bool, pub test: bool, } +/// Internally this is just a string, but keep using 0/1/2 as integers for compatibility. +#[derive(Serialize)] +#[serde(untagged)] +pub enum ArtifactDebuginfo { + Int(u32), + Named(String), +} + #[derive(Serialize)] pub struct BuildScript<'a> { pub package_id: PackageId, diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 9e7c6f63e20a..9ed61aff9591 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -443,10 +443,11 @@ impl ser::Serialize for TomlOptLevel { } #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged, expecting = "expected a boolean or an integer")] -pub enum U32OrBool { +#[serde(untagged, expecting = "expected a boolean, integer, or string")] +pub enum U32OrBoolOrString { U32(u32), Bool(bool), + String(String), } #[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] @@ -456,7 +457,7 @@ pub struct TomlProfile { pub lto: Option, pub codegen_backend: Option, pub codegen_units: Option, - pub debug: Option, + pub debug: Option, pub split_debuginfo: Option, pub debug_assertions: Option, pub rpath: Option, diff --git a/tests/testsuite/bad_config.rs b/tests/testsuite/bad_config.rs index ca51b101e39d..3e736a6797a0 100644 --- a/tests/testsuite/bad_config.rs +++ b/tests/testsuite/bad_config.rs @@ -1313,6 +1313,37 @@ fn bad_debuginfo() { .file("src/lib.rs", "") .build(); + p.cargo("check") + .with_status(101) + .with_stderr( + "\ +[CHECKING] foo v0.0.0 ([CWD]) +error: incorrect value `a` for codegen option `debuginfo` [..] + +error: could not compile `foo` (lib) due to previous error +", + ) + .run(); +} + +#[cargo_test] +fn bad_debuginfo2() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [profile.dev] + debug = 3.6 + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("check") .with_status(101) .with_stderr( @@ -1320,7 +1351,7 @@ fn bad_debuginfo() { error: failed to parse manifest at `[..]` Caused by: - expected a boolean or an integer + expected a boolean, integer, or string in `profile.dev.debug` ", ) diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs index 92e1f42643c7..b2b9f7811cf4 100644 --- a/tests/testsuite/config.rs +++ b/tests/testsuite/config.rs @@ -401,7 +401,7 @@ lto = false opt_level: Some(cargo_toml::TomlOptLevel("s".to_string())), lto: Some(cargo_toml::StringOrBool::Bool(true)), codegen_units: Some(5), - debug: Some(cargo_toml::U32OrBool::Bool(true)), + debug: Some(cargo_toml::U32OrBoolOrString::Bool(true)), debug_assertions: Some(true), rpath: Some(true), panic: Some("abort".to_string()), @@ -444,7 +444,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, None); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::U32OrBoolOrString::U32(1))); let config = ConfigBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG_ASSERTIONS", "false") @@ -452,7 +452,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, Some(false)); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::U32OrBoolOrString::U32(1))); } #[cargo_test] @@ -1511,7 +1511,7 @@ fn all_profile_options() { lto: Some(cargo_toml::StringOrBool::String("thin".to_string())), codegen_backend: Some(InternedString::new("example")), codegen_units: Some(123), - debug: Some(cargo_toml::U32OrBool::U32(1)), + debug: Some(cargo_toml::U32OrBoolOrString::U32(1)), split_debuginfo: Some("packed".to_string()), debug_assertions: Some(true), rpath: Some(true), diff --git a/tests/testsuite/profile_config.rs b/tests/testsuite/profile_config.rs index c59ed7a97f59..05ae1c55dde8 100644 --- a/tests/testsuite/profile_config.rs +++ b/tests/testsuite/profile_config.rs @@ -436,7 +436,7 @@ fn named_config_profile() { assert_eq!(p.name, "foo"); assert_eq!(p.codegen_units, Some(2)); // "foo" from config assert_eq!(p.opt_level, "1"); // "middle" from manifest - assert_eq!(p.debuginfo.to_option(), Some(1)); // "bar" from config + assert_eq!(p.debuginfo.to_option(), Some("1".into())); // "bar" from config assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override) assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override) @@ -445,7 +445,7 @@ fn named_config_profile() { assert_eq!(bo.name, "foo"); assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config assert_eq!(bo.opt_level, "0"); // default to zero - assert_eq!(bo.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(bo.debuginfo.to_option(), Some("1".into())); // SAME as normal assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest assert_eq!(bo.overflow_checks, true); // SAME as normal @@ -454,7 +454,7 @@ fn named_config_profile() { assert_eq!(po.name, "foo"); assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config assert_eq!(po.opt_level, "1"); // SAME as normal - assert_eq!(po.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(po.debuginfo.to_option(), Some("1".into())); // SAME as normal assert_eq!(po.debug_assertions, true); // SAME as normal assert_eq!(po.overflow_checks, false); // "middle" package override from manifest } diff --git a/tests/testsuite/unit_graph.rs b/tests/testsuite/unit_graph.rs index 91451177a516..32d00476df56 100644 --- a/tests/testsuite/unit_graph.rs +++ b/tests/testsuite/unit_graph.rs @@ -72,7 +72,7 @@ fn simple() { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, - "debuginfo": 2, + "debuginfo": "2", "incremental": false, "lto": "false", "name": "dev", @@ -117,7 +117,7 @@ fn simple() { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, - "debuginfo": 2, + "debuginfo": "2", "incremental": false, "lto": "false", "name": "dev", @@ -155,7 +155,7 @@ fn simple() { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, - "debuginfo": 2, + "debuginfo": "2", "incremental": false, "lto": "false", "name": "dev", @@ -198,7 +198,7 @@ fn simple() { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, - "debuginfo": 2, + "debuginfo": "2", "incremental": false, "lto": "false", "name": "dev",