From f9ea9831b97b973e40eed432cb39c58f3c2758d3 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 9 Jul 2023 12:46:38 -0700 Subject: [PATCH 1/5] feat(metadata): Add profiles information to `cargo metadata` This change adds profile information to the output of `cargo metadata`. I opted for serializing this information only when there is information present to minimize changes in the output. Signed-off-by: David Calavera --- src/cargo/core/package.rs | 4 + src/cargo/ops/cargo_output_metadata.rs | 11 +- src/cargo/util/toml/mod.rs | 17 ++ tests/testsuite/metadata.rs | 239 +++++++++++++++++++++++++ tests/testsuite/script.rs | 14 +- 5 files changed, 282 insertions(+), 3 deletions(-) diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 76f6c405bc3..16ecedc0bb5 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -31,6 +31,7 @@ use crate::util::network::http::http_handle_and_timeout; use crate::util::network::http::HttpTimeout; use crate::util::network::retry::{Retry, RetryResult}; use crate::util::network::sleep::SleepTracker; +use crate::util::toml::TomlProfiles; use crate::util::RustVersion; use crate::util::{self, internal, Config, Progress, ProgressStyle}; @@ -105,6 +106,8 @@ pub struct SerializedPackage { metabuild: Option>, default_run: Option, rust_version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + profiles: Option, } impl Package { @@ -264,6 +267,7 @@ impl Package { publish: self.publish().as_ref().cloned(), default_run: self.manifest().default_run().map(|s| s.to_owned()), rust_version: self.rust_version().cloned(), + profiles: self.manifest().profiles().cloned(), } } } diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index 83dae50ea8d..8b43be40571 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -3,9 +3,10 @@ use crate::core::compiler::{CompileKind, RustcTargetData}; use crate::core::dependency::DepKind; use crate::core::package::SerializedPackage; use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve}; -use crate::core::{Package, PackageId, Workspace}; +use crate::core::{MaybePackage, Package, PackageId, Workspace}; use crate::ops::{self, Packages}; use crate::util::interning::InternedString; +use crate::util::toml::TomlProfiles; use crate::util::CargoResult; use cargo_platform::Platform; use serde::Serialize; @@ -40,6 +41,11 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo (packages, Some(resolve)) }; + let workspace_profiles = match ws.root_maybe() { + MaybePackage::Virtual(vm) => vm.profiles().cloned(), + _ => None, // regular packages include the profile information under their package section + }; + Ok(ExportInfo { packages, workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), @@ -49,6 +55,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo version: VERSION, workspace_root: ws.root().to_path_buf(), metadata: ws.custom_metadata().cloned(), + workspace_profiles, }) } @@ -65,6 +72,8 @@ pub struct ExportInfo { version: u32, workspace_root: PathBuf, metadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + workspace_profiles: Option, } #[derive(Serialize)] diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 2e730b4e9fc..1ddceb2ddef 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -498,25 +498,42 @@ impl Display for TomlDebugInfo { #[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] #[serde(default, rename_all = "kebab-case")] pub struct TomlProfile { + #[serde(skip_serializing_if = "Option::is_none")] pub opt_level: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub lto: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub codegen_backend: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub codegen_units: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub debug: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub split_debuginfo: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub debug_assertions: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub rpath: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub panic: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub overflow_checks: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub incremental: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub dir_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub inherits: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub strip: Option, // Note that `rustflags` is used for the cargo-feature `profile_rustflags` + #[serde(skip_serializing_if = "Option::is_none")] pub rustflags: Option>, // These two fields must be last because they are sub-tables, and TOML // requires all non-tables to be listed first. + #[serde(skip_serializing_if = "Option::is_none")] pub package: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub build_override: Option>, } diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index fbead4dea97..ce76c774b0c 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -4257,3 +4257,242 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { ) .run(); } + +#[cargo_test] +fn library_metadata_with_profiles() { + let p = project() + .file("src/lib.rs", "") + .file( + "Cargo.toml", + r#" +[package] +name = "foo" +version = "0.5.0" + +[profile.release] +strip = "symbols" + +[profile.custom-lto] +lto = "thin" + "#, + ) + .build(); + + p.cargo("metadata") + .with_json( + r#" + { + "packages": [ + { + "authors": [], + "categories": [], + "default_run": null, + "name": "foo", + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "version": "0.5.0", + "rust_version": null, + "id": "foo[..]", + "keywords": [], + "source": null, + "dependencies": [], + "edition": "2015", + "license": null, + "license_file": null, + "links": null, + "description": null, + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "foo", + "src_path": "[..]/foo/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]Cargo.toml", + "metadata": null, + "publish": null, + "profiles": { + "custom-lto": { + "lto": "thin" + }, + "release": { + "strip": "symbols" + } + } + } + ], + "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], + "resolve": { + "nodes": [ + { + "dependencies": [], + "deps": [], + "features": [], + "id": "foo 0.5.0 (path+file:[..]foo)" + } + ], + "root": "foo 0.5.0 (path+file:[..]foo)" + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]/foo", + "metadata": null + }"#, + ) + .run(); +} + +#[cargo_test] +fn workspace_metadata_with_profiles() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar", "baz"] + + [profile.release] + strip = "symbols" + + [profile.custom-lto] + lto = "thin" + "#, + ) + .file("bar/Cargo.toml", &basic_lib_manifest("bar")) + .file("bar/src/lib.rs", "") + .file("baz/Cargo.toml", &basic_lib_manifest("baz")) + .file("baz/src/lib.rs", "") + .build(); + + p.cargo("metadata") + .with_json( + r#" + { + "packages": [ + { + "authors": [ + "wycats@example.com" + ], + "categories": [], + "default_run": null, + "name": "bar", + "version": "0.5.0", + "id": "bar[..]", + "readme": null, + "repository": null, + "rust_version": null, + "homepage": null, + "documentation": null, + "keywords": [], + "source": null, + "dependencies": [], + "license": null, + "license_file": null, + "links": null, + "description": null, + "edition": "2015", + "targets": [ + { + "kind": [ "lib" ], + "crate_types": [ "lib" ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "bar", + "src_path": "[..]bar/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]bar/Cargo.toml", + "metadata": null, + "publish": null + }, + { + "authors": [ + "wycats@example.com" + ], + "categories": [], + "default_run": null, + "name": "baz", + "readme": null, + "repository": null, + "rust_version": null, + "homepage": null, + "documentation": null, + "version": "0.5.0", + "id": "baz[..]", + "keywords": [], + "source": null, + "dependencies": [], + "license": null, + "license_file": null, + "links": null, + "description": null, + "edition": "2015", + "targets": [ + { + "kind": [ "lib" ], + "crate_types": [ "lib" ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "baz", + "src_path": "[..]baz/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]baz/Cargo.toml", + "metadata": null, + "publish": null + } + ], + "workspace_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "workspace_default_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "resolve": { + "nodes": [ + { + "dependencies": [], + "deps": [], + "features": [], + "id": "bar 0.5.0 (path+file:[..]bar)" + }, + { + "dependencies": [], + "deps": [], + "features": [], + "id": "baz 0.5.0 (path+file:[..]baz)" + } + ], + "root": null + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]/foo", + "metadata": null, + "workspace_profiles": { + "custom-lto": { + "lto": "thin" + }, + "release": { + "strip": "symbols" + } + } + }"#, + ) + .run(); +} diff --git a/tests/testsuite/script.rs b/tests/testsuite/script.rs index c869b43f7d6..409aaa96cba 100644 --- a/tests/testsuite/script.rs +++ b/tests/testsuite/script.rs @@ -1062,7 +1062,12 @@ fn cmd_metadata_with_embedded() { "features": {}, "manifest_path": "[..]script.rs", "metadata": null, - "publish": [] + "publish": [], + "profiles": { + "release": { + "strip": true + } + } } ], "workspace_members": ["script 0.0.0 (path+file:[..]foo)"], @@ -1137,7 +1142,12 @@ fn cmd_read_manifest_with_embedded() { "features":{}, "manifest_path":"[..]script.rs", "metadata": null, - "publish": [] + "publish": [], + "profiles": { + "release": { + "strip": true + } + } }"#, ) .with_stderr( From a83cca4347351fef12e31bbfce3aa56c635462e2 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Thu, 31 Aug 2023 20:15:50 -0700 Subject: [PATCH 2/5] Remove profiles information from the package structure. Signed-off-by: David Calavera --- src/cargo/core/package.rs | 4 ---- src/cargo/ops/cargo_output_metadata.rs | 11 +++-------- tests/testsuite/metadata.rs | 22 +++++++++++----------- tests/testsuite/script.rs | 21 ++++++++------------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 16ecedc0bb5..76f6c405bc3 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -31,7 +31,6 @@ use crate::util::network::http::http_handle_and_timeout; use crate::util::network::http::HttpTimeout; use crate::util::network::retry::{Retry, RetryResult}; use crate::util::network::sleep::SleepTracker; -use crate::util::toml::TomlProfiles; use crate::util::RustVersion; use crate::util::{self, internal, Config, Progress, ProgressStyle}; @@ -106,8 +105,6 @@ pub struct SerializedPackage { metabuild: Option>, default_run: Option, rust_version: Option, - #[serde(skip_serializing_if = "Option::is_none")] - profiles: Option, } impl Package { @@ -267,7 +264,6 @@ impl Package { publish: self.publish().as_ref().cloned(), default_run: self.manifest().default_run().map(|s| s.to_owned()), rust_version: self.rust_version().cloned(), - profiles: self.manifest().profiles().cloned(), } } } diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index 8b43be40571..cccf289372f 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -3,7 +3,7 @@ use crate::core::compiler::{CompileKind, RustcTargetData}; use crate::core::dependency::DepKind; use crate::core::package::SerializedPackage; use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve}; -use crate::core::{MaybePackage, Package, PackageId, Workspace}; +use crate::core::{Package, PackageId, Workspace}; use crate::ops::{self, Packages}; use crate::util::interning::InternedString; use crate::util::toml::TomlProfiles; @@ -41,11 +41,6 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo (packages, Some(resolve)) }; - let workspace_profiles = match ws.root_maybe() { - MaybePackage::Virtual(vm) => vm.profiles().cloned(), - _ => None, // regular packages include the profile information under their package section - }; - Ok(ExportInfo { packages, workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), @@ -55,7 +50,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo version: VERSION, workspace_root: ws.root().to_path_buf(), metadata: ws.custom_metadata().cloned(), - workspace_profiles, + profiles: ws.profiles().cloned(), }) } @@ -73,7 +68,7 @@ pub struct ExportInfo { workspace_root: PathBuf, metadata: Option, #[serde(skip_serializing_if = "Option::is_none")] - workspace_profiles: Option, + profiles: Option, } #[derive(Serialize)] diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index ce76c774b0c..9b9b2f0263a 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -4322,15 +4322,7 @@ lto = "thin" "features": {}, "manifest_path": "[..]Cargo.toml", "metadata": null, - "publish": null, - "profiles": { - "custom-lto": { - "lto": "thin" - }, - "release": { - "strip": "symbols" - } - } + "publish": null } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], @@ -4349,7 +4341,15 @@ lto = "thin" "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": { + "custom-lto": { + "lto": "thin" + }, + "release": { + "strip": "symbols" + } + } }"#, ) .run(); @@ -4484,7 +4484,7 @@ fn workspace_metadata_with_profiles() { "version": 1, "workspace_root": "[..]/foo", "metadata": null, - "workspace_profiles": { + "profiles": { "custom-lto": { "lto": "thin" }, diff --git a/tests/testsuite/script.rs b/tests/testsuite/script.rs index 409aaa96cba..710a261b50c 100644 --- a/tests/testsuite/script.rs +++ b/tests/testsuite/script.rs @@ -1062,12 +1062,7 @@ fn cmd_metadata_with_embedded() { "features": {}, "manifest_path": "[..]script.rs", "metadata": null, - "publish": [], - "profiles": { - "release": { - "strip": true - } - } + "publish": [] } ], "workspace_members": ["script 0.0.0 (path+file:[..]foo)"], @@ -1086,7 +1081,12 @@ fn cmd_metadata_with_embedded() { "target_directory": "[ROOT]/home/.cargo/target/[..]", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": { + "release": { + "strip": true + } + } }"#, ) .with_stderr( @@ -1142,12 +1142,7 @@ fn cmd_read_manifest_with_embedded() { "features":{}, "manifest_path":"[..]script.rs", "metadata": null, - "publish": [], - "profiles": { - "release": { - "strip": true - } - } + "publish": [] }"#, ) .with_stderr( From 285e01f7e17dee263f64192e616cb52a8f459dde Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 24 Sep 2023 17:54:29 -0700 Subject: [PATCH 3/5] Expose all profiles in the workspace. Implement a new method Profiles::all that returns all profiles in the workspace, including the root and predefined profiles. This new method follows Cargo resolution rules to resolve profile inheritance and ordering. Signed-off-by: David Calavera --- src/cargo/core/profiles.rs | 431 ++++++++++++++----------- src/cargo/ops/cargo_output_metadata.rs | 9 +- tests/testsuite/alt_registry.rs | 26 +- tests/testsuite/features_namespaced.rs | 10 +- tests/testsuite/git.rs | 6 +- tests/testsuite/metadata.rs | 387 +++++++++++++++++----- tests/testsuite/script.rs | 74 ++++- tests/testsuite/update.rs | 10 +- 8 files changed, 661 insertions(+), 292 deletions(-) diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index 1ad9ed5f725..30e01f0d085 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -8,8 +8,8 @@ //! //! - Create a `Profiles` by merging profiles from configs onto the profile //! from root manifest (see [`merge_config_profiles`]). -//! - Add built-in profiles onto it (see [`Profiles::add_root_profiles`]). -//! - Process profile inheritance for each profiles. (see [`Profiles::add_maker`]). +//! - Add built-in profiles onto it (see [`root_profiles`]). +//! - Process profile inheritance for each profiles. (see [`create_profile_maker`]). //! //! Then you can query a [`Profile`] via [`Profiles::get_profile`], which respects //! the profile overridden hierarchy described in below. The [`Profile`] you get @@ -31,6 +31,7 @@ use crate::util::toml::{ }; use crate::util::{closest_msg, config, CargoResult, Config}; use anyhow::{bail, Context as _}; +use std::collections::btree_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::Hash; use std::{cmp, fmt, hash}; @@ -62,196 +63,84 @@ pub struct Profiles { } impl Profiles { + /// Returns all the profiles defined in a workspace, including root and predefined profiles. + /// This function resolves inheritances between profiles. + pub fn all(ws: &Workspace<'_>) -> CargoResult> { + let mut definitions = merge_config_profiles(ws, None)?; + + merge_predefined_profiles(&mut definitions); + + let mut makers = HashMap::new(); + for (name, profile) in root_profiles(&definitions) { + makers.insert(name, profile); + } + + for (name, profile) in &definitions { + let name = *name; + if let Some(maker) = create_profile_maker(name, profile, &makers, &definitions)? { + makers.insert(name, maker); + } + } + + for (name, profile) in &definitions { + let name = *name; + if let Some(maker) = create_profile_maker(name, profile, &makers, &definitions)? { + makers.insert(name, maker); + } + } + + let mut profiles = HashMap::new(); + for (name, maker) in makers { + profiles.insert(name, maker.get_profile(name, None, true, false)); + } + + Ok(profiles) + } + + /// Returns all the profiles defined in a workspace, verifying that + /// the requested profile exists in the workspace. pub fn new(ws: &Workspace<'_>, requested_profile: InternedString) -> CargoResult { let config = ws.config(); let incremental = match config.get_env_os("CARGO_INCREMENTAL") { Some(v) => Some(v == "1"), None => config.build_config()?.incremental, }; - let mut profiles = merge_config_profiles(ws, requested_profile)?; + let mut profiles = merge_config_profiles(ws, Some(requested_profile))?; let rustc_host = ws.config().load_global_rustc(Some(ws))?.host; let mut profile_makers = Profiles { incremental, - dir_names: Self::predefined_dir_names(), + dir_names: predefined_dir_names(), by_name: HashMap::new(), original_profiles: profiles.clone(), requested_profile, rustc_host, }; - Self::add_root_profiles(&mut profile_makers, &profiles); - - // Merge with predefined profiles. - use std::collections::btree_map::Entry; - for (predef_name, mut predef_prof) in Self::predefined_profiles().into_iter() { - match profiles.entry(InternedString::new(predef_name)) { - Entry::Vacant(vac) => { - vac.insert(predef_prof); - } - Entry::Occupied(mut oc) => { - // Override predefined with the user-provided Toml. - let r = oc.get_mut(); - predef_prof.merge(r); - *r = predef_prof; - } - } + for (name, profile) in root_profiles(&profiles) { + profile_makers.by_name.insert(name, profile); } + merge_predefined_profiles(&mut profiles); + for (name, profile) in &profiles { - profile_makers.add_maker(*name, profile, &profiles)?; + let name = *name; + if let Some(dir_name) = profile.dir_name { + profile_makers.dir_names.insert(name, dir_name.to_owned()); + } + if let Some(maker) = + create_profile_maker(name, profile, &profile_makers.by_name, &profiles)? + { + profile_makers.by_name.insert(name, maker); + } } // Verify that the requested profile is defined *somewhere*. // This simplifies the API (no need for CargoResult), and enforces // assumptions about how config profiles are loaded. - profile_makers.get_profile_maker(requested_profile)?; + get_profile_maker(&profile_makers.by_name, requested_profile)?; Ok(profile_makers) } - /// Returns the hard-coded directory names for built-in profiles. - fn predefined_dir_names() -> HashMap { - [ - (InternedString::new("dev"), InternedString::new("debug")), - (InternedString::new("test"), InternedString::new("debug")), - (InternedString::new("bench"), InternedString::new("release")), - ] - .into() - } - - /// Initialize `by_name` with the two "root" profiles, `dev`, and - /// `release` given the user's definition. - fn add_root_profiles( - profile_makers: &mut Profiles, - profiles: &BTreeMap, - ) { - profile_makers.by_name.insert( - InternedString::new("dev"), - ProfileMaker::new(Profile::default_dev(), profiles.get("dev").cloned()), - ); - - profile_makers.by_name.insert( - InternedString::new("release"), - ProfileMaker::new(Profile::default_release(), profiles.get("release").cloned()), - ); - } - - /// Returns the built-in profiles (not including dev/release, which are - /// "root" profiles). - fn predefined_profiles() -> Vec<(&'static str, TomlProfile)> { - vec![ - ( - "bench", - TomlProfile { - inherits: Some(InternedString::new("release")), - ..TomlProfile::default() - }, - ), - ( - "test", - TomlProfile { - inherits: Some(InternedString::new("dev")), - ..TomlProfile::default() - }, - ), - ( - "doc", - TomlProfile { - inherits: Some(InternedString::new("dev")), - ..TomlProfile::default() - }, - ), - ] - } - - /// Creates a `ProfileMaker`, and inserts it into `self.by_name`. - fn add_maker( - &mut self, - name: InternedString, - profile: &TomlProfile, - profiles: &BTreeMap, - ) -> CargoResult<()> { - match &profile.dir_name { - None => {} - Some(dir_name) => { - self.dir_names.insert(name, dir_name.to_owned()); - } - } - - // dev/release are "roots" and don't inherit. - if name == "dev" || name == "release" { - if profile.inherits.is_some() { - bail!( - "`inherits` must not be specified in root profile `{}`", - name - ); - } - // Already inserted from `add_root_profiles`, no need to do anything. - return Ok(()); - } - - // Keep track for inherits cycles. - let mut set = HashSet::new(); - set.insert(name); - let maker = self.process_chain(name, profile, &mut set, profiles)?; - self.by_name.insert(name, maker); - Ok(()) - } - - /// Build a `ProfileMaker` by recursively following the `inherits` setting. - /// - /// * `name`: The name of the profile being processed. - /// * `profile`: The TOML profile being processed. - /// * `set`: Set of profiles that have been visited, used to detect cycles. - /// * `profiles`: Map of all TOML profiles. - /// - /// Returns a `ProfileMaker` to be used for the given named profile. - fn process_chain( - &mut self, - name: InternedString, - profile: &TomlProfile, - set: &mut HashSet, - profiles: &BTreeMap, - ) -> CargoResult { - let mut maker = match profile.inherits { - Some(inherits_name) if inherits_name == "dev" || inherits_name == "release" => { - // These are the root profiles added in `add_root_profiles`. - self.get_profile_maker(inherits_name).unwrap().clone() - } - Some(inherits_name) => { - if !set.insert(inherits_name) { - bail!( - "profile inheritance loop detected with profile `{}` inheriting `{}`", - name, - inherits_name - ); - } - - match profiles.get(&inherits_name) { - None => { - bail!( - "profile `{}` inherits from `{}`, but that profile is not defined", - name, - inherits_name - ); - } - Some(parent) => self.process_chain(inherits_name, parent, set, profiles)?, - } - } - None => { - bail!( - "profile `{}` is missing an `inherits` directive \ - (`inherits` is required for all profiles except `dev` or `release`)", - name - ); - } - }; - match &mut maker.toml { - Some(toml) => toml.merge(profile), - None => maker.toml = Some(profile.clone()), - }; - Ok(maker) - } - /// Retrieves the profile for a target. /// `is_member` is whether or not this package is a member of the /// workspace. @@ -263,8 +152,13 @@ impl Profiles { unit_for: UnitFor, kind: CompileKind, ) -> Profile { - let maker = self.get_profile_maker(self.requested_profile).unwrap(); - let mut profile = maker.get_profile(Some(pkg_id), is_member, unit_for.is_for_host()); + let maker = get_profile_maker(&self.by_name, self.requested_profile).unwrap(); + let mut profile = maker.get_profile( + self.requested_profile, + Some(pkg_id), + is_member, + unit_for.is_for_host(), + ); // Dealing with `panic=abort` and `panic=unwind` requires some special // treatment. Be sure to process all the various options here. @@ -302,7 +196,6 @@ impl Profiles { if !is_local { profile.incremental = false; } - profile.name = self.requested_profile; profile } @@ -325,8 +218,13 @@ impl Profiles { /// select for the package that was actually built. pub fn base_profile(&self) -> Profile { let profile_name = self.requested_profile; - let maker = self.get_profile_maker(profile_name).unwrap(); - maker.get_profile(None, /*is_member*/ true, /*is_for_host*/ false) + let maker = get_profile_maker(&self.by_name, profile_name).unwrap(); + maker.get_profile( + profile_name, + None, + /*is_member*/ true, + /*is_for_host*/ false, + ) } /// Gets the directory name for a profile, like `debug` or `release`. @@ -370,13 +268,170 @@ impl Profiles { } Ok(()) } +} + +/// Returns the hard-coded directory names for built-in profiles. +fn predefined_dir_names() -> HashMap { + [ + (InternedString::new("dev"), InternedString::new("debug")), + (InternedString::new("test"), InternedString::new("debug")), + (InternedString::new("bench"), InternedString::new("release")), + ] + .into() +} + +/// Returns the "root" profiles (dev/release) +fn root_profiles( + profiles: &BTreeMap, +) -> Vec<(InternedString, ProfileMaker)> { + vec![ + ( + InternedString::new("dev"), + ProfileMaker::new(Profile::default_dev(), profiles.get("dev").cloned()), + ), + ( + InternedString::new("release"), + ProfileMaker::new(Profile::default_release(), profiles.get("release").cloned()), + ), + ] +} + +/// Returns the built-in profiles (not including dev/release, which are +/// "root" profiles). +fn predefined_profiles() -> Vec<(&'static str, TomlProfile)> { + vec![ + ( + "bench", + TomlProfile { + inherits: Some(InternedString::new("release")), + ..TomlProfile::default() + }, + ), + ( + "test", + TomlProfile { + inherits: Some(InternedString::new("dev")), + ..TomlProfile::default() + }, + ), + ( + "doc", + TomlProfile { + inherits: Some(InternedString::new("dev")), + ..TomlProfile::default() + }, + ), + ] +} + +/// Merge a list of TOML profile definitions with the predefined list from Cargo. +fn merge_predefined_profiles(definitions: &mut BTreeMap) { + for (predef_name, mut predef_prof) in predefined_profiles().into_iter() { + match definitions.entry(InternedString::new(predef_name)) { + Entry::Vacant(vac) => { + vac.insert(predef_prof); + } + Entry::Occupied(mut oc) => { + // Override predefined with the user-provided Toml. + let r = oc.get_mut(); + predef_prof.merge(r); + *r = predef_prof; + } + } + } +} - /// Returns the profile maker for the given profile name. - fn get_profile_maker(&self, name: InternedString) -> CargoResult<&ProfileMaker> { - self.by_name - .get(&name) - .ok_or_else(|| anyhow::format_err!("profile `{}` is not defined", name)) +/// Creates a `ProfileMaker`. +fn create_profile_maker( + name: InternedString, + profile: &TomlProfile, + makers: &HashMap, + definitions: &BTreeMap, +) -> CargoResult> { + // dev/release are "roots" and don't inherit. + if name == "dev" || name == "release" { + if profile.inherits.is_some() { + bail!( + "`inherits` must not be specified in root profile `{}`", + name + ); + } + // Already inserted from `add_root_profiles`, no need to do anything. + return Ok(None); } + + // Keep track for inherits cycles. + let mut set = HashSet::new(); + set.insert(name); + let maker = process_chain(name, profile, &mut set, makers, definitions)?; + Ok(Some(maker)) +} + +/// Build a `ProfileMaker` by recursively following the `inherits` setting. +/// +/// * `name`: The name of the profile being processed. +/// * `profile`: The TOML profile being processed. +/// * `set`: Set of profiles that have been visited, used to detect cycles. +/// * `makers`: Map of all `ProfileMaker` already defined in the workspace. +/// * `definitions`: Map of all TOML profiles. +/// +/// Returns a `ProfileMaker` to be used for the given named profile. +fn process_chain( + name: InternedString, + profile: &TomlProfile, + set: &mut HashSet, + makers: &HashMap, + definitions: &BTreeMap, +) -> CargoResult { + let mut maker = match profile.inherits { + Some(inherits_name) if inherits_name == "dev" || inherits_name == "release" => { + // These are the root profiles. They must exist in the list of makers + // before calling `process_chain`. + get_profile_maker(makers, inherits_name)?.clone() + } + Some(inherits_name) => { + if !set.insert(inherits_name) { + bail!( + "profile inheritance loop detected with profile `{}` inheriting `{}`", + name, + inherits_name + ); + } + + match definitions.get(&inherits_name) { + None => { + bail!( + "profile `{}` inherits from `{}`, but that profile is not defined", + name, + inherits_name + ); + } + Some(parent) => process_chain(inherits_name, parent, set, makers, definitions)?, + } + } + None => { + bail!( + "profile `{}` is missing an `inherits` directive \ + (`inherits` is required for all profiles except `dev` or `release`)", + name + ); + } + }; + match &mut maker.toml { + Some(toml) => toml.merge(profile), + None => maker.toml = Some(profile.clone()), + }; + Ok(maker) +} + +/// Returns the profile maker for the given profile name. +fn get_profile_maker( + profiles: &HashMap, + name: InternedString, +) -> CargoResult<&ProfileMaker> { + profiles + .get(&name) + .ok_or_else(|| anyhow::format_err!("profile `{}` is not defined", name)) } /// An object used for handling the profile hierarchy. @@ -413,6 +468,7 @@ impl ProfileMaker { /// Generates a new `Profile`. fn get_profile( &self, + name: InternedString, pkg_id: Option, is_member: bool, is_for_host: bool, @@ -457,6 +513,7 @@ impl ProfileMaker { if let Some(toml) = &self.toml { merge_toml_overrides(pkg_id, is_member, is_for_host, &mut profile, toml); } + profile.name = name; profile } } @@ -849,9 +906,7 @@ 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, -)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Deserialize)] #[serde(rename_all = "lowercase")] pub enum Strip { /// Don't remove any symbols @@ -870,6 +925,18 @@ impl fmt::Display for Strip { } } +impl serde::ser::Serialize for Strip { + fn serialize(&self, s: S) -> Result + where + S: serde::ser::Serializer, + { + match self { + Strip::None => "none".serialize(s), + Strip::Named(n) => n.serialize(s), + } + } +} + /// Flags used in creating `Unit`s to indicate the purpose for the target, and /// to ensure the target's dependencies have the correct settings. /// @@ -1159,7 +1226,7 @@ impl UnitFor { /// Returns a new copy of the profile map with all the mergers complete. fn merge_config_profiles( ws: &Workspace<'_>, - requested_profile: InternedString, + requested_profile: Option, ) -> CargoResult> { let mut profiles = match ws.profiles() { Some(profiles) => profiles.get_all().clone(), @@ -1167,7 +1234,9 @@ fn merge_config_profiles( }; // Set of profile names to check if defined in config only. let mut check_to_add = HashSet::new(); - check_to_add.insert(requested_profile); + if let Some(requested_profile) = requested_profile { + check_to_add.insert(requested_profile); + } // Merge config onto manifest profiles. for (name, profile) in &mut profiles { if let Some(config_profile) = get_config_profile(ws, name)? { diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index cccf289372f..ac5627ccafc 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -2,15 +2,15 @@ use crate::core::compiler::artifact::match_artifacts_kind_with_targets; use crate::core::compiler::{CompileKind, RustcTargetData}; use crate::core::dependency::DepKind; use crate::core::package::SerializedPackage; +use crate::core::profiles::{Profile, Profiles}; use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve}; use crate::core::{Package, PackageId, Workspace}; use crate::ops::{self, Packages}; use crate::util::interning::InternedString; -use crate::util::toml::TomlProfiles; use crate::util::CargoResult; use cargo_platform::Platform; use serde::Serialize; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::path::PathBuf; const VERSION: u32 = 1; @@ -50,7 +50,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo version: VERSION, workspace_root: ws.root().to_path_buf(), metadata: ws.custom_metadata().cloned(), - profiles: ws.profiles().cloned(), + profiles: Profiles::all(ws)?, }) } @@ -67,8 +67,7 @@ pub struct ExportInfo { version: u32, workspace_root: PathBuf, metadata: Option, - #[serde(skip_serializing_if = "Option::is_none")] - profiles: Option, + profiles: HashMap, } #[derive(Serialize)] diff --git a/tests/testsuite/alt_registry.rs b/tests/testsuite/alt_registry.rs index d6d7dd531cc..0e4d6767743 100644 --- a/tests/testsuite/alt_registry.rs +++ b/tests/testsuite/alt_registry.rs @@ -6,6 +6,8 @@ use cargo_test_support::registry::{self, Package, RegistryBuilder}; use cargo_test_support::{basic_manifest, paths, project}; use std::fs; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn depend_on_alt_registry() { registry::alt_init(); @@ -844,7 +846,7 @@ fn alt_reg_metadata() { // iodep -> altdep2: alternative-registry p.cargo("metadata --format-version=1 --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -909,15 +911,17 @@ fn alt_reg_metadata() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); // --no-deps uses a different code path, make sure both work. p.cargo("metadata --format-version=1") .with_json( - r#" + &r#" { "packages": [ { @@ -1112,8 +1116,10 @@ fn alt_reg_metadata() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1160,7 +1166,7 @@ fn unknown_registry() { // bar -> baz registry = alternate p.cargo("metadata --format-version=1") .with_json( - r#" + &r#" { "packages": [ { @@ -1278,9 +1284,11 @@ fn unknown_registry() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } diff --git a/tests/testsuite/features_namespaced.rs b/tests/testsuite/features_namespaced.rs index f24186c1591..299bada3800 100644 --- a/tests/testsuite/features_namespaced.rs +++ b/tests/testsuite/features_namespaced.rs @@ -1,5 +1,7 @@ //! Tests for namespaced features. +use crate::metadata::DEFAULT_PROFILES; + use super::features2::switch_to_resolver_2; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::{project, publish}; @@ -576,7 +578,7 @@ fn json_exposed() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -614,9 +616,11 @@ fn json_exposed() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index e27315346c2..91591dc2e22 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -15,6 +15,8 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, main_file, path2url, project}; use cargo_test_support::{sleep_ms, t, Project}; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn cargo_compile_simple_git_dep() { let project = project(); @@ -3370,11 +3372,13 @@ fn metadata_master_consistency() { "target_directory": "[..]", "version": 1, "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("__BAR_SOURCE__", bar_source) .replace("__BAR_HASH__", &bar_hash) + .replace("$PROFILES", DEFAULT_PROFILES) }; let bar_source = format!("git+{}?branch=master", git_project.url()); diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index 9b9b2f0263a..d72b13c6328 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -6,6 +6,84 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, main_file, project, rustc_host}; use serde_json::json; +pub(crate) const DEFAULT_PROFILES: &str = r#"{ + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "release": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + } +}"#; + #[cargo_test] fn cargo_metadata_simple() { let p = project() @@ -15,7 +93,7 @@ fn cargo_metadata_simple() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -80,8 +158,10 @@ fn cargo_metadata_simple() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -117,7 +197,7 @@ crate-type = ["lib", "staticlib"] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -180,8 +260,10 @@ crate-type = ["lib", "staticlib"] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -207,7 +289,7 @@ optional_feat = [] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -277,8 +359,10 @@ optional_feat = [] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -313,7 +397,7 @@ fn cargo_metadata_with_deps_and_version() { p.cargo("metadata -q --format-version 1") .with_json( - r#" + &r#" { "packages": [ { @@ -594,8 +678,10 @@ fn cargo_metadata_with_deps_and_version() { "foo 0.5.0 (path+file:[..]foo)" ], "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -620,7 +706,7 @@ name = "ex" p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -691,8 +777,10 @@ name = "ex" "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -718,7 +806,7 @@ crate-type = ["rlib", "dylib"] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -789,8 +877,10 @@ crate-type = ["rlib", "dylib"] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -821,7 +911,7 @@ fn workspace_metadata() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -931,8 +1021,10 @@ fn workspace_metadata() { "foo": { "bar": 3 } - } - }"#, + }, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -972,7 +1064,7 @@ fn workspace_metadata_with_dependencies_no_deps() { p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "packages": [ { @@ -1145,8 +1237,10 @@ fn workspace_metadata_with_dependencies_no_deps() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1240,7 +1334,7 @@ fn workspace_metadata_with_dependencies_and_resolve() { p.cargo("metadata -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "metadata": null, "packages": [ @@ -1779,9 +1873,11 @@ fn workspace_metadata_with_dependencies_and_resolve() { "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" ], - "workspace_root": "[..]/foo" + "workspace_root": "[..]/foo", + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1991,7 +2087,8 @@ const MANIFEST_OUTPUT: &str = r#" "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES }"#; #[cargo_test] @@ -2003,7 +2100,7 @@ fn cargo_metadata_no_deps_path_to_cargo_toml_relative() { p.cargo("metadata --no-deps --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2017,7 +2114,7 @@ fn cargo_metadata_no_deps_path_to_cargo_toml_absolute() { p.cargo("metadata --no-deps --manifest-path") .arg(p.root().join("Cargo.toml")) .cwd(p.root().parent().unwrap()) - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2064,7 +2161,7 @@ fn cargo_metadata_no_deps_cwd() { .build(); p.cargo("metadata --no-deps") - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2135,7 +2232,7 @@ fn package_metadata() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -2186,8 +2283,10 @@ fn package_metadata() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2215,7 +2314,7 @@ fn package_publish() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -2262,8 +2361,10 @@ fn package_publish() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2290,7 +2391,7 @@ fn cargo_metadata_path_to_cargo_toml_project() { p.cargo("metadata --manifest-path") .arg(p.root().join("target/package/bar-0.5.0/Cargo.toml")) .with_json( - r#" + &r#" { "packages": [ { @@ -2357,9 +2458,11 @@ fn cargo_metadata_path_to_cargo_toml_project() { "bar 0.5.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2381,7 +2484,7 @@ fn package_edition_2018() { .build(); p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2448,9 +2551,11 @@ fn package_edition_2018() { "foo 0.1.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2518,7 +2623,7 @@ fn target_edition_2018() { .build(); p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2599,9 +2704,11 @@ fn target_edition_2018() { "foo 0.1.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2630,7 +2737,7 @@ fn rename_dependency() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2838,8 +2945,10 @@ fn rename_dependency() { "foo 0.0.1[..]" ], "workspace_root": "[..]", - "metadata": null -}"#, + "metadata": null, + "profiles": $PROFILES +}"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2862,7 +2971,7 @@ fn metadata_links() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2941,9 +3050,11 @@ fn metadata_links() { "foo 0.5.0 [..]" ], "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run() } @@ -2968,7 +3079,7 @@ fn deps_with_bin_only() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -3047,9 +3158,11 @@ fn deps_with_bin_only() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3499,7 +3612,8 @@ fn filter_platform() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$ALT_TRIPLE", alt_target) @@ -3508,7 +3622,8 @@ fn filter_platform() { .replace("$CFG_DEP", cfg_dep) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3585,13 +3700,15 @@ fn filter_platform() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$ALT_TRIPLE", alt_target) .replace("$ALT_DEP", alt_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3667,13 +3784,15 @@ fn filter_platform() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$HOST_TRIPLE", host_target) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3769,14 +3888,16 @@ fn filter_platform() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$HOST_TRIPLE", host_target) .replace("$CFG_DEP", cfg_dep) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3812,7 +3933,7 @@ fn dep_kinds() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": "{...}", "workspace_members": "{...}", @@ -3821,6 +3942,7 @@ fn dep_kinds() { "version": 1, "workspace_root": "{...}", "metadata": null, + "profiles": $PROFILES, "resolve": { "nodes": [ { @@ -3877,7 +3999,8 @@ fn dep_kinds() { "root": "foo 0.1.0 [..]" } } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3928,7 +4051,7 @@ fn dep_kinds_workspace() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": "{...}", "workspace_members": "{...}", @@ -3937,6 +4060,7 @@ fn dep_kinds_workspace() { "version": 1, "workspace_root": "[..]/foo", "metadata": null, + "profiles": $PROFILES, "resolve": { "nodes": [ { @@ -3989,7 +4113,8 @@ fn dep_kinds_workspace() { "root": "foo 0.1.0 (path+file://[..]/foo)" } } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -4057,9 +4182,10 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "metadata": null, + "profiles": $PROFILES, "packages": [ { "authors": [ @@ -4253,11 +4379,105 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { ], "workspace_root": "[..]/foo" } -"#, +"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } +const CUSTOM_PROFILES: &str = r#"{ + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "custom-lto": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "thin", + "name": "custom-lto", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "release": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + } +}"#; + #[cargo_test] fn library_metadata_with_profiles() { let p = project() @@ -4273,6 +4493,7 @@ version = "0.5.0" strip = "symbols" [profile.custom-lto] +inherits = "release" lto = "thin" "#, ) @@ -4280,7 +4501,7 @@ lto = "thin" p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -4342,15 +4563,9 @@ lto = "thin" "version": 1, "workspace_root": "[..]/foo", "metadata": null, - "profiles": { - "custom-lto": { - "lto": "thin" - }, - "release": { - "strip": "symbols" - } - } - }"#, + "profiles": $PROFILES + }"# + .replace("$PROFILES", CUSTOM_PROFILES), ) .run(); } @@ -4368,6 +4583,7 @@ fn workspace_metadata_with_profiles() { strip = "symbols" [profile.custom-lto] + inherits = "release" lto = "thin" "#, ) @@ -4379,7 +4595,7 @@ fn workspace_metadata_with_profiles() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -4484,15 +4700,8 @@ fn workspace_metadata_with_profiles() { "version": 1, "workspace_root": "[..]/foo", "metadata": null, - "profiles": { - "custom-lto": { - "lto": "thin" - }, - "release": { - "strip": "symbols" - } - } - }"#, + "profiles": $PROFILES + }"#.replace("$PROFILES", CUSTOM_PROFILES) ) .run(); } diff --git a/tests/testsuite/script.rs b/tests/testsuite/script.rs index 710a261b50c..12ccc9a0d89 100644 --- a/tests/testsuite/script.rs +++ b/tests/testsuite/script.rs @@ -1083,8 +1083,80 @@ fn cmd_metadata_with_embedded() { "workspace_root": "[..]/foo", "metadata": null, "profiles": { + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, "release": { - "strip": true + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" } } }"#, diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index fe1d86bd763..512b0c65946 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -3,6 +3,8 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project}; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn minor_update_two_places() { Package::new("log", "0.1.0").publish(); @@ -577,7 +579,7 @@ fn update_precise_first_run() { // Assert `cargo metadata` shows serde 0.2.0 p.cargo("metadata") .with_json( - r#"{ + &r#"{ "packages": [ { "authors": [], @@ -714,8 +716,10 @@ fn update_precise_first_run() { "bar 0.0.1 (path+file://[..]/foo)" ], "workspace_root": "[..]/foo", - "metadata": null -}"#, + "metadata": null, + "profiles": $PROFILES +}"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); From ffb24015444ffbd04dd82614ed340164cf806cfb Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 24 Sep 2023 19:33:20 -0700 Subject: [PATCH 4/5] Revert changes to TomlProfile Signed-off-by: David Calavera --- src/cargo/util/toml/mod.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1ddceb2ddef..2e730b4e9fc 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -498,42 +498,25 @@ impl Display for TomlDebugInfo { #[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] #[serde(default, rename_all = "kebab-case")] pub struct TomlProfile { - #[serde(skip_serializing_if = "Option::is_none")] pub opt_level: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub lto: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub codegen_backend: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub codegen_units: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub debug: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub split_debuginfo: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub debug_assertions: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub rpath: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub panic: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub overflow_checks: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub incremental: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub dir_name: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub inherits: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub strip: Option, // Note that `rustflags` is used for the cargo-feature `profile_rustflags` - #[serde(skip_serializing_if = "Option::is_none")] pub rustflags: Option>, // These two fields must be last because they are sub-tables, and TOML // requires all non-tables to be listed first. - #[serde(skip_serializing_if = "Option::is_none")] pub package: Option>, - #[serde(skip_serializing_if = "Option::is_none")] pub build_override: Option>, } From b2f9e3b11bd83821f6536655a7208b0f5d74e5e1 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 24 Sep 2023 20:35:39 -0700 Subject: [PATCH 5/5] Fix comment about root profiles. Signed-off-by: David Calavera --- src/cargo/core/profiles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index 30e01f0d085..2897dab42a5 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -356,7 +356,7 @@ fn create_profile_maker( name ); } - // Already inserted from `add_root_profiles`, no need to do anything. + // Already created in `root_profiles`, ignore them to prevent overwrites. return Ok(None); }