diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 446f9959b..789acc8a3 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -38,7 +38,6 @@ pub struct BuildContext<'a, 'cfg: 'a> { pub target_config: TargetConfig, pub target_info: TargetInfo, pub host_info: TargetInfo, - pub incremental_env: Option, } impl<'a, 'cfg> BuildContext<'a, 'cfg> { @@ -51,11 +50,6 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { profiles: &'a Profiles, extra_compiler_args: HashMap, Vec>, ) -> CargoResult> { - let incremental_env = match env::var("CARGO_INCREMENTAL") { - Ok(v) => Some(v == "1"), - Err(_) => None, - }; - let rustc = config.rustc(Some(ws))?; let host_config = TargetConfig::new(config, &rustc.host)?; let target_config = match build_config.requested_target.as_ref() { @@ -84,7 +78,6 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { host_info, build_config, profiles, - incremental_env, extra_compiler_args, }) } diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index cbd88fc27..27f8adb20 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -386,61 +386,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> { deps } - pub fn incremental_args(&self, unit: &Unit<'_>) -> CargoResult> { - // There's a number of ways to configure incremental compilation right - // now. In order of descending priority (first is highest priority) we - // have: - // - // * `CARGO_INCREMENTAL` - this is blanket used unconditionally to turn - // on/off incremental compilation for any cargo subcommand. We'll - // respect this if set. - // * `build.incremental` - in `.cargo/config` this blanket key can - // globally for a system configure whether incremental compilation is - // enabled. Note that setting this to `true` will not actually affect - // all builds though. For example a `true` value doesn't enable - // release incremental builds, only dev incremental builds. This can - // be useful to globally disable incremental compilation like - // `CARGO_INCREMENTAL`. - // * `profile.dev.incremental` - in `Cargo.toml` specific profiles can - // be configured to enable/disable incremental compilation. This can - // be primarily used to disable incremental when buggy for a package. - // * Finally, each profile has a default for whether it will enable - // incremental compilation or not. Primarily development profiles - // have it enabled by default while release profiles have it disabled - // by default. - let global_cfg = self - .bcx - .config - .get_bool("build.incremental")? - .map(|c| c.val); - let incremental = match ( - self.bcx.incremental_env, - global_cfg, - unit.profile.incremental, - ) { - (Some(v), _, _) => v, - (None, Some(false), _) => false, - (None, _, other) => other, - }; - - if !incremental { - return Ok(Vec::new()); - } - - // Only enable incremental compilation for sources the user can - // modify (aka path sources). For things that change infrequently, - // non-incremental builds yield better performance in the compiler - // itself (aka crates.io / git dependencies) - // - // (see also https://github.com/rust-lang/cargo/issues/3972) - if !unit.pkg.package_id().source_id().is_path() { - return Ok(Vec::new()); - } - - let dir = self.files().layout(unit.kind).incremental().display(); - Ok(vec!["-C".to_string(), format!("incremental={}", dir)]) - } - pub fn is_primary_package(&self, unit: &Unit<'a>) -> bool { self.primary_packages.contains(&unit.pkg.package_id()) } diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index 6781ba2a3..4e23fb0fd 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -492,12 +492,7 @@ fn calculate<'a, 'cfg>( } else { bcx.rustflags_args(unit)? }; - let profile_hash = util::hash_u64(&( - &unit.profile, - unit.mode, - bcx.extra_args_for(unit), - cx.incremental_args(unit)?, - )); + let profile_hash = util::hash_u64(&(&unit.profile, unit.mode, bcx.extra_args_for(unit))); let fingerprint = Arc::new(Fingerprint { rustc: util::hash_u64(&bcx.rustc.verbose_version), target: util::hash_u64(&unit.target), diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index af1c1250d..0ab2ac8e7 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -760,6 +760,7 @@ fn build_base_args<'a, 'cfg>( overflow_checks, rpath, ref panic, + incremental, .. } = unit.profile; let test = unit.mode.is_any_test(); @@ -902,8 +903,10 @@ fn build_base_args<'a, 'cfg>( "linker=", bcx.linker(unit.kind).map(|s| s.as_ref()), ); - cmd.args(&cx.incremental_args(unit)?); - + if incremental { + let dir = cx.files().layout(unit.kind).incremental().as_os_str(); + opt(cmd, "-C", "incremental=", Some(dir)); + } Ok(()) } diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index bcd5ed5a6..4fdbe65fa 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -66,6 +66,7 @@ pub struct VirtualManifest { workspace: WorkspaceConfig, profiles: Profiles, warnings: Warnings, + features: Features, } /// General metadata about a package which is just blindly uploaded to the @@ -541,6 +542,7 @@ impl VirtualManifest { patch: HashMap>, workspace: WorkspaceConfig, profiles: Profiles, + features: Features, ) -> VirtualManifest { VirtualManifest { replace, @@ -548,6 +550,7 @@ impl VirtualManifest { workspace, profiles, warnings: Warnings::new(), + features, } } @@ -574,6 +577,10 @@ impl VirtualManifest { pub fn warnings(&self) -> &Warnings { &self.warnings } + + pub fn features(&self) -> &Features { + &self.features + } } impl Target { diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index b806f72d2..18355b9b4 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -1,5 +1,5 @@ use std::collections::HashSet; -use std::{cmp, fmt, hash}; +use std::{cmp, env, fmt, hash}; use serde::Deserialize; @@ -19,6 +19,10 @@ pub struct Profiles { test: ProfileMaker, bench: ProfileMaker, doc: ProfileMaker, + /// Incremental compilation can be overridden globally via: + /// - `CARGO_INCREMENTAL` environment variable. + /// - `build.incremental` config value. + incremental: Option, } impl Profiles { @@ -33,7 +37,11 @@ impl Profiles { } let config_profiles = config.profiles()?; - config_profiles.validate(features, warnings)?; + + let incremental = match env::var_os("CARGO_INCREMENTAL") { + Some(v) => Some(v == "1"), + None => config.get::>("build.incremental")?, + }; Ok(Profiles { dev: ProfileMaker { @@ -61,6 +69,7 @@ impl Profiles { toml: profiles.and_then(|p| p.doc.clone()), config: None, }, + incremental, }) } @@ -100,10 +109,25 @@ impl Profiles { CompileMode::Doc { .. } => &self.doc, }; let mut profile = maker.get_profile(Some(pkg_id), is_member, unit_for); - // `panic` should not be set for tests/benches, or any of their dependencies. + // `panic` should not be set for tests/benches, or any of their + // dependencies. if !unit_for.is_panic_ok() || mode.is_any_test() { profile.panic = None; } + + // Incremental can be globally overridden. + if let Some(v) = self.incremental { + profile.incremental = v; + } + // Only enable incremental compilation for sources the user can + // modify (aka path sources). For things that change infrequently, + // non-incremental builds yield better performance in the compiler + // itself (aka crates.io / git dependencies) + // + // (see also https://github.com/rust-lang/cargo/issues/3972) + if !pkg_id.source_id().is_path() { + profile.incremental = false; + } profile } diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index e74f751f7..76bedfaf3 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -237,13 +237,9 @@ impl<'cfg> Workspace<'cfg> { } pub fn profiles(&self) -> &Profiles { - let root = self - .root_manifest - .as_ref() - .unwrap_or(&self.current_manifest); - match *self.packages.get(root) { - MaybePackage::Package(ref p) => p.manifest().profiles(), - MaybePackage::Virtual(ref vm) => vm.profiles(), + match self.root_maybe() { + MaybePackage::Package(p) => p.manifest().profiles(), + MaybePackage::Virtual(vm) => vm.profiles(), } } @@ -260,6 +256,15 @@ impl<'cfg> Workspace<'cfg> { .unwrap() } + /// Returns the root Package or VirtualManifest. + fn root_maybe(&self) -> &MaybePackage { + let root = self + .root_manifest + .as_ref() + .unwrap_or(&self.current_manifest); + self.packages.get(root) + } + pub fn target_dir(&self) -> Filesystem { self.target_dir .clone() @@ -270,13 +275,9 @@ impl<'cfg> Workspace<'cfg> { /// /// This may be from a virtual crate or an actual crate. pub fn root_replace(&self) -> &[(PackageIdSpec, Dependency)] { - let path = match self.root_manifest { - Some(ref p) => p, - None => &self.current_manifest, - }; - match *self.packages.get(path) { - MaybePackage::Package(ref p) => p.manifest().replace(), - MaybePackage::Virtual(ref vm) => vm.replace(), + match self.root_maybe() { + MaybePackage::Package(p) => p.manifest().replace(), + MaybePackage::Virtual(vm) => vm.replace(), } } @@ -284,13 +285,9 @@ impl<'cfg> Workspace<'cfg> { /// /// This may be from a virtual crate or an actual crate. pub fn root_patch(&self) -> &HashMap> { - let path = match self.root_manifest { - Some(ref p) => p, - None => &self.current_manifest, - }; - match *self.packages.get(path) { - MaybePackage::Package(ref p) => p.manifest().patch(), - MaybePackage::Virtual(ref vm) => vm.patch(), + match self.root_maybe() { + MaybePackage::Package(p) => p.manifest().patch(), + MaybePackage::Virtual(vm) => vm.patch(), } } @@ -524,6 +521,18 @@ impl<'cfg> Workspace<'cfg> { /// 2. All workspace members agree on this one root as the root. /// 3. The current crate is a member of this workspace. fn validate(&mut self) -> CargoResult<()> { + // Validate config profiles only once per workspace. + let features = match self.root_maybe() { + MaybePackage::Package(p) => p.manifest().features(), + MaybePackage::Virtual(vm) => vm.features(), + }; + let mut warnings = Vec::new(); + self.config.profiles()?.validate(features, &mut warnings)?; + for warning in warnings { + self.config.shell().warn(&warning)?; + } + + // The rest of the checks require a VirtualManifest or multiple members. if self.root_manifest.is_none() { return Ok(()); } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 15cd67bd4..eb1354bf2 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1137,7 +1137,7 @@ impl TomlManifest { } }; Ok(( - VirtualManifest::new(replace, patch, workspace_config, profiles), + VirtualManifest::new(replace, patch, workspace_config, profiles, features), nested_paths, )) } diff --git a/src/doc/src/reference/config.md b/src/doc/src/reference/config.md index 56b804a06..fb2da971b 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -129,6 +129,8 @@ target-dir = "target" # path of where to place all generated artifacts rustflags = ["..", ".."] # custom flags to pass to all compiler invocations rustdocflags = ["..", ".."] # custom flags to pass to rustdoc incremental = true # whether or not to enable incremental compilation + # If `incremental` is not set, then the value from + # the profile is used. dep-info-basedir = ".." # full path for the base directory for targets in depfiles [term] diff --git a/src/doc/src/reference/manifest.md b/src/doc/src/reference/manifest.md index 6a29944b5..7aa649136 100644 --- a/src/doc/src/reference/manifest.md +++ b/src/doc/src/reference/manifest.md @@ -374,6 +374,9 @@ codegen-units = 16 # if > 1 enables parallel code generation which improves # Passes `-C codegen-units`. panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort' incremental = true # whether or not incremental compilation is enabled + # This can be overridden globally with the CARGO_INCREMENTAL + # environment variable or `build.incremental` config + # variable. Incremental is only used for path sources. overflow-checks = true # use overflow checks for integer arithmetic. # Passes the `-C overflow-checks=...` flag to the compiler. diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index beae1562d..d2a5d15bd 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -37,7 +37,7 @@ fn cargo_fail_with_no_stderr() { } /// Checks that the `CARGO_INCREMENTAL` environment variable results in -/// `rustc` getting `-Zincremental` passed to it. +/// `rustc` getting `-C incremental` passed to it. #[test] fn cargo_compile_incremental() { let p = project() diff --git a/tests/testsuite/profile_config.rs b/tests/testsuite/profile_config.rs index 8a46cff70..8b6bdab4b 100644 --- a/tests/testsuite/profile_config.rs +++ b/tests/testsuite/profile_config.rs @@ -1,4 +1,4 @@ -use crate::support::{basic_lib_manifest, paths, project}; +use crate::support::{basic_lib_manifest, is_nightly, paths, project}; #[test] fn profile_config_gated() { @@ -138,10 +138,7 @@ fn profile_config_validate_errors() { .with_status(101) .with_stderr( "\ -[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` - -Caused by: - config profile `profile.dev` is not valid +[ERROR] config profile `profile.dev` is not valid Caused by: `panic` may not be specified in a profile override. @@ -233,10 +230,14 @@ found profile override specs: bar, bar:0.5.0", #[test] fn profile_config_all_options() { + if !is_nightly() { + // May be removed once 1.34 is stable (added support for incremental-LTO). + return; + } + // Ensure all profile options are supported. let p = project() - .file("Cargo.toml", &basic_lib_manifest("foo")) - .file("src/lib.rs", "") + .file("src/main.rs", "fn main() {}") .file( ".cargo/config", r#" @@ -256,17 +257,20 @@ fn profile_config_all_options() { p.cargo("build --release -v -Z config-profile") .masquerade_as_nightly_cargo() + .env_remove("CARGO_INCREMENTAL") .with_stderr( "\ [COMPILING] foo [..] [RUNNING] `rustc --crate-name foo [..] \ -C opt-level=1 \ -C panic=abort \ + -C lto \ -C codegen-units=2 \ -C debuginfo=2 \ -C debug-assertions=on \ -C overflow-checks=off [..]\ - -C rpath [..] + -C rpath [..]\ + -C incremental=[..] [FINISHED] release [optimized + debuginfo] [..] ", )