diff --git a/src/cargo/core/compiler/build_runner/compilation_files.rs b/src/cargo/core/compiler/build_runner/compilation_files.rs index a914dc7056d..e5f5efb8fb0 100644 --- a/src/cargo/core/compiler/build_runner/compilation_files.rs +++ b/src/cargo/core/compiler/build_runner/compilation_files.rs @@ -250,12 +250,16 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> { false => "-", }; let name = unit.pkg.package_id().name(); - let meta = self.metas[unit]; - let hash = meta + let hash = self.unit_hash(unit); + format!("{name}{separator}{hash}") + } + + /// The directory hash to use for a given unit + pub fn unit_hash(&self, unit: &Unit) -> String { + self.metas[unit] .pkg_dir() .map(|h| h.to_string()) - .unwrap_or_else(|| self.target_short_hash(unit)); - format!("{name}{separator}{hash}") + .unwrap_or_else(|| self.target_short_hash(unit)) } /// Returns the final artifact path for the host (`/…/target/debug`) @@ -296,6 +300,15 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> { self.layout(unit.kind).build_dir().fingerprint(&dir) } + /// The lock location for a given build unit. + pub fn build_unit_lock(&self, unit: &Unit) -> PathBuf { + let dir = self.pkg_dir(unit); + self.layout(unit.kind) + .build_dir() + .build_unit(&dir) + .join(".lock") + } + /// Directory where incremental output for the given unit should go. pub fn incremental_dir(&self, unit: &Unit) -> &Path { self.layout(unit.kind).build_dir().incremental() diff --git a/src/cargo/core/compiler/build_runner/mod.rs b/src/cargo/core/compiler/build_runner/mod.rs index 02f3c62267a..47e42a36cfc 100644 --- a/src/cargo/core/compiler/build_runner/mod.rs +++ b/src/cargo/core/compiler/build_runner/mod.rs @@ -6,6 +6,7 @@ use std::sync::{Arc, Mutex}; use crate::core::PackageId; use crate::core::compiler::compilation::{self, UnitOutput}; +use crate::core::compiler::locking::LockManager; use crate::core::compiler::{self, Unit, UserIntent, artifact}; use crate::util::cache_lock::CacheLockMode; use crate::util::errors::CargoResult; @@ -87,6 +88,9 @@ pub struct BuildRunner<'a, 'gctx> { /// because the target has a type error. This is in an Arc> /// because it is continuously updated as the job progresses. pub failed_scrape_units: Arc>>, + + /// Manages locks for build units when fine grain locking is enabled. + pub lock_manager: Arc, } impl<'a, 'gctx> BuildRunner<'a, 'gctx> { @@ -126,6 +130,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { lto: HashMap::new(), metadata_for_doc_units: HashMap::new(), failed_scrape_units: Arc::new(Mutex::new(HashSet::new())), + lock_manager: Arc::new(LockManager::new()), }) } @@ -417,7 +422,8 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { | UserIntent::Doctest | UserIntent::Bench => true, }; - let host_layout = Layout::new(self.bcx.ws, None, &dest, must_take_artifact_dir_lock)?; + let host_layout = + Layout::new(self.bcx.ws, None, &dest, must_take_artifact_dir_lock, false)?; let mut targets = HashMap::new(); for kind in self.bcx.all_kinds.iter() { if let CompileKind::Target(target) = *kind { @@ -426,6 +432,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { Some(target), &dest, must_take_artifact_dir_lock, + false, )?; targets.insert(target, layout); } diff --git a/src/cargo/core/compiler/job_queue/job.rs b/src/cargo/core/compiler/job_queue/job.rs index 71a9fc4184c..e518f3665c6 100644 --- a/src/cargo/core/compiler/job_queue/job.rs +++ b/src/cargo/core/compiler/job_queue/job.rs @@ -85,6 +85,12 @@ impl Job { let prev = mem::replace(&mut self.work, Work::noop()); self.work = next.then(prev); } + + /// Chains the given work by putting it after of our own unit of work. + pub fn after(&mut self, next: Work) { + let prev = mem::replace(&mut self.work, Work::noop()); + self.work = prev.then(next); + } } impl fmt::Debug for Job { diff --git a/src/cargo/core/compiler/job_queue/job_state.rs b/src/cargo/core/compiler/job_queue/job_state.rs index 66ccff0bd3f..06a672b611d 100644 --- a/src/cargo/core/compiler/job_queue/job_state.rs +++ b/src/cargo/core/compiler/job_queue/job_state.rs @@ -4,10 +4,11 @@ use std::{cell::Cell, marker, sync::Arc}; use cargo_util::ProcessBuilder; -use crate::CargoResult; use crate::core::compiler::future_incompat::FutureBreakageItem; +use crate::core::compiler::locking::LockKey; use crate::core::compiler::timings::SectionTiming; use crate::util::Queue; +use crate::{CargoResult, core::compiler::locking::LockManager}; use super::{Artifact, DiagDedupe, Job, JobId, Message}; @@ -47,6 +48,9 @@ pub struct JobState<'a, 'gctx> { /// sending a double message later on. rmeta_required: Cell, + /// Manages locks for build units when fine grain locking is enabled. + lock_manager: Arc, + // Historical versions of Cargo made use of the `'a` argument here, so to // leave the door open to future refactorings keep it here. _marker: marker::PhantomData<&'a ()>, @@ -58,12 +62,14 @@ impl<'a, 'gctx> JobState<'a, 'gctx> { messages: Arc>, output: Option<&'a DiagDedupe<'gctx>>, rmeta_required: bool, + lock_manager: Arc, ) -> Self { Self { id, messages, output, rmeta_required: Cell::new(rmeta_required), + lock_manager, _marker: marker::PhantomData, } } @@ -141,6 +147,14 @@ impl<'a, 'gctx> JobState<'a, 'gctx> { .push(Message::Finish(self.id, Artifact::Metadata, Ok(()))); } + pub fn lock_exclusive(&self, lock: &LockKey) -> CargoResult<()> { + self.lock_manager.lock(lock) + } + + pub fn downgrade_to_shared(&self, lock: &LockKey) -> CargoResult<()> { + self.lock_manager.downgrade_to_shared(lock) + } + pub fn on_section_timing_emitted(&self, section: SectionTiming) { self.messages.push(Message::SectionTiming(self.id, section)); } diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index de8b86f61bb..fdaceac904a 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -951,9 +951,10 @@ impl<'gctx> DrainState<'gctx> { let messages = self.messages.clone(); let is_fresh = job.freshness().is_fresh(); let rmeta_required = build_runner.rmeta_required(unit); + let lock_manager = build_runner.lock_manager.clone(); let doit = move |diag_dedupe| { - let state = JobState::new(id, messages, diag_dedupe, rmeta_required); + let state = JobState::new(id, messages, diag_dedupe, rmeta_required, lock_manager); state.run_to_finish(job); }; diff --git a/src/cargo/core/compiler/layout.rs b/src/cargo/core/compiler/layout.rs index e30d178eda4..3708c5eb473 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -128,6 +128,7 @@ impl Layout { target: Option, dest: &str, must_take_artifact_dir_lock: bool, + must_take_build_dir_lock_exclusively: bool, ) -> CargoResult { let is_new_layout = ws.gctx().cli_unstable().build_dir_new_layout; let mut root = ws.target_dir(); @@ -160,11 +161,20 @@ impl Layout { { None } else { - Some(build_dest.open_rw_exclusive_create( - ".cargo-lock", - ws.gctx(), - "build directory", - )?) + if ws.gctx().cli_unstable().fine_grain_locking && !must_take_build_dir_lock_exclusively + { + Some(build_dest.open_ro_shared_create( + ".cargo-lock", + ws.gctx(), + "build directory", + )?) + } else { + Some(build_dest.open_rw_exclusive_create( + ".cargo-lock", + ws.gctx(), + "build directory", + )?) + } }; let build_root = build_root.into_path_unlocked(); let build_dest = build_dest.as_path_unlocked(); diff --git a/src/cargo/core/compiler/locking.rs b/src/cargo/core/compiler/locking.rs new file mode 100644 index 00000000000..155a4dc364e --- /dev/null +++ b/src/cargo/core/compiler/locking.rs @@ -0,0 +1,108 @@ +//! This module handles the locking logic during compilation. + +use crate::{ + CargoResult, + core::compiler::{BuildRunner, Unit}, + util::{FileLock, Filesystem}, +}; +use anyhow::bail; +use std::{ + collections::HashMap, + fmt::{Display, Formatter}, + path::PathBuf, + sync::Mutex, +}; +use tracing::instrument; + +/// A struct to store the lock handles for build units during compilation. +pub struct LockManager { + locks: Mutex>, +} + +impl LockManager { + pub fn new() -> Self { + Self { + locks: Mutex::new(HashMap::new()), + } + } + + /// Takes a shared lock on a given [`Unit`] + /// This prevents other Cargo instances from compiling (writing) to + /// this build unit. + /// + /// This function returns a [`LockKey`] which can be used to + /// upgrade/unlock the lock. + #[instrument(skip_all, fields(key))] + pub fn lock_shared( + &self, + build_runner: &BuildRunner<'_, '_>, + unit: &Unit, + ) -> CargoResult { + let key = LockKey::from_unit(build_runner, unit); + tracing::Span::current().record("key", key.0.to_str()); + + let mut locks = self.locks.lock().unwrap(); + if let Some(lock) = locks.get_mut(&key) { + lock.file().lock_shared()?; + } else { + let fs = Filesystem::new(key.0.clone()); + let lock_msg = format!( + "{} ({})", + unit.pkg.name(), + build_runner.files().unit_hash(unit) + ); + let lock = fs.open_ro_shared_create(&key.0, build_runner.bcx.gctx, &lock_msg)?; + locks.insert(key.clone(), lock); + } + + Ok(key) + } + + #[instrument(skip(self))] + pub fn lock(&self, key: &LockKey) -> CargoResult<()> { + let mut locks = self.locks.lock().unwrap(); + if let Some(lock) = locks.get_mut(&key) { + lock.file().lock()?; + } else { + bail!("lock was not found in lock manager: {key}"); + } + + Ok(()) + } + + /// Upgrades an existing exclusive lock into a shared lock. + #[instrument(skip(self))] + pub fn downgrade_to_shared(&self, key: &LockKey) -> CargoResult<()> { + let mut locks = self.locks.lock().unwrap(); + let Some(lock) = locks.get_mut(key) else { + bail!("lock was not found in lock manager: {key}"); + }; + lock.file().lock_shared()?; + Ok(()) + } + + #[instrument(skip(self))] + pub fn unlock(&self, key: &LockKey) -> CargoResult<()> { + let mut locks = self.locks.lock().unwrap(); + if let Some(lock) = locks.get_mut(key) { + lock.file().unlock()?; + }; + + Ok(()) + } +} + +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct LockKey(PathBuf); + +impl LockKey { + fn from_unit(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Self { + Self(build_runner.files().build_unit_lock(unit)) + } +} + +impl Display for LockKey { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.display()) + } +} diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index cffa9a69cf6..1c5f79b0c1b 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -41,6 +41,7 @@ pub mod future_incompat; pub(crate) mod job_queue; pub(crate) mod layout; mod links; +mod locking; mod lto; mod output_depinfo; mod output_sbom; @@ -94,6 +95,7 @@ use self::output_sbom::build_sbom; use self::unit_graph::UnitDep; use crate::core::compiler::future_incompat::FutureIncompatReport; +use crate::core::compiler::locking::LockKey; use crate::core::compiler::timings::SectionTiming; pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; @@ -187,6 +189,12 @@ fn compile<'gctx>( return Ok(()); } + let lock = if build_runner.bcx.gctx.cli_unstable().fine_grain_locking { + Some(build_runner.lock_manager.lock_shared(build_runner, unit)?) + } else { + None + }; + // If we are in `--compile-time-deps` and the given unit is not a compile time // dependency, skip compiling the unit and jumps to dependencies, which still // have chances to be compile time dependencies @@ -228,6 +236,23 @@ fn compile<'gctx>( work.then(link_targets(build_runner, unit, true)?) }); + // If -Zfine-grain-locking is enabled, we wrap the job with an upgrade to exclusive + // lock before starting, then downgrade to a shared lock after the job is finished. + if build_runner.bcx.gctx.cli_unstable().fine_grain_locking && job.freshness().is_dirty() + { + if let Some(lock) = lock { + // Here we unlock the current shared lock to avoid deadlocking with other cargo + // processes. Then we configure our compile job to take an exclusive lock + // before starting. Once we are done compiling (including both rmeta and rlib) + // we downgrade to a shared lock to allow other cargo's to read the build unit. + // We will hold this shared lock for the remainder of compilation to prevent + // other cargo from re-compiling while we are still using the unit. + build_runner.lock_manager.unlock(&lock)?; + job.before(prebuild_lock_exclusive(lock.clone())); + job.after(downgrade_lock_to_shared(lock)); + } + } + job }; jobs.enqueue(build_runner, unit, job)?; @@ -589,6 +614,20 @@ fn verbose_if_simple_exit_code(err: Error) -> Error { } } +fn prebuild_lock_exclusive(lock: LockKey) -> Work { + Work::new(move |state| { + state.lock_exclusive(&lock)?; + Ok(()) + }) +} + +fn downgrade_lock_to_shared(lock: LockKey) -> Work { + Work::new(move |state| { + state.downgrade_to_shared(&lock)?; + Ok(()) + }) +} + /// Link the compiled target (often of form `foo-{metadata_hash}`) to the /// final target. This must happen during both "Fresh" and "Compile". fn link_targets( diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 82b4ce78356..edf02b00555 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -127,6 +127,7 @@ use std::str::FromStr; use anyhow::{Error, bail}; use cargo_util::ProcessBuilder; use serde::{Deserialize, Serialize}; +use tracing::debug; use crate::GlobalContext; use crate::core::resolver::ResolveBehavior; @@ -860,6 +861,7 @@ unstable_cli_options!( dual_proc_macros: bool = ("Build proc-macros for both the host and the target"), feature_unification: bool = ("Enable new feature unification modes in workspaces"), features: Option>, + fine_grain_locking: bool = ("Use fine grain locking instead of locking the entire build cache"), fix_edition: Option = ("Permanently unstable edition migration helper"), gc: bool = ("Track cache usage and \"garbage collect\" unused files"), #[serde(deserialize_with = "deserialize_git_features")] @@ -1244,6 +1246,9 @@ impl CliUnstable { if self.gitoxide.is_none() && cargo_use_gitoxide_instead_of_git2() { self.gitoxide = GitoxideFeatures::safe().into(); } + + self.implicitly_enable_features_if_needed(); + Ok(warnings) } @@ -1382,6 +1387,7 @@ impl CliUnstable { "direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?, "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, "feature-unification" => self.feature_unification = parse_empty(k, v)?, + "fine-grain-locking" => self.fine_grain_locking = parse_empty(k, v)?, "fix-edition" => { let fe = v .ok_or_else(|| anyhow::anyhow!("-Zfix-edition expected a value"))? @@ -1515,6 +1521,13 @@ impl CliUnstable { ); } } + + fn implicitly_enable_features_if_needed(&mut self) { + if self.fine_grain_locking && !self.build_dir_new_layout { + debug!("-Zbuild-dir-new-layout implicitly enabled by -Zfine-grain-locking"); + self.build_dir_new_layout = true; + } + } } /// Returns the current release channel ("stable", "beta", "nightly", "dev"). diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 7f445259dcc..6d63db2dbbb 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -118,13 +118,13 @@ fn clean_specs( let target_data = RustcTargetData::new(ws, &requested_kinds)?; let (pkg_set, resolve) = ops::resolve_ws(ws, dry_run)?; let prof_dir_name = profiles.get_dir_name(); - let host_layout = Layout::new(ws, None, &prof_dir_name, true)?; + let host_layout = Layout::new(ws, None, &prof_dir_name, true, true)?; // Convert requested kinds to a Vec of layouts. let target_layouts: Vec<(CompileKind, Layout)> = requested_kinds .into_iter() .filter_map(|kind| match kind { CompileKind::Target(target) => { - match Layout::new(ws, Some(target), &prof_dir_name, true) { + match Layout::new(ws, Some(target), &prof_dir_name, true, true) { Ok(layout) => Some(Ok((kind, layout))), Err(e) => Some(Err(e)), } diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index a24123a8d9c..16b5260222c 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -98,6 +98,7 @@ Each new feature described below should explain how to use it. * [open-namespaces](#open-namespaces) --- Allow multiple packages to participate in the same API namespace * [panic-immediate-abort](#panic-immediate-abort) --- Passes `-Cpanic=immediate-abort` to the compiler. * [compile-time-deps](#compile-time-deps) --- Perma-unstable feature for rust-analyzer + * [fine-grain-locking](#fine-grain-locking) --- Use fine grain locking instead of locking the entire build cache * rustdoc * [rustdoc-map](#rustdoc-map) --- Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/). * [scrape-examples](#scrape-examples) --- Shows examples within documentation. @@ -1664,6 +1665,14 @@ panic-immediate-abort = true panic = "immediate-abort" ``` +## fine-grain-locking + +* Tracking Issue: [#4282](https://github.com/rust-lang/cargo/issues/4282) + +Use fine grain locking instead of locking the entire build cache. + +Note: Fine grain locking implicitly enables [build-dir-new-layout](#build-dir-new-layout) as fine grain locking builds on that directory reoganization. + ## `[lints.cargo]` * Tracking Issue: [#12235](https://github.com/rust-lang/cargo/issues/12235) diff --git a/tests/testsuite/build_dir.rs b/tests/testsuite/build_dir.rs index 8c0e591dcaa..26441668200 100644 --- a/tests/testsuite/build_dir.rs +++ b/tests/testsuite/build_dir.rs @@ -29,7 +29,7 @@ fn binary_with_debug() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -46,6 +46,7 @@ fn binary_with_debug() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -74,7 +75,7 @@ fn binary_with_release() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build --release") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build --release") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -100,6 +101,7 @@ fn binary_with_release() { [ROOT]/foo/build-dir/release/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/release/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/release/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/release/build/foo/[HASH]/.lock "#]]); @@ -178,7 +180,7 @@ fn libs() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -194,7 +196,7 @@ fn should_default_to_target() { .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -211,6 +213,7 @@ fn should_default_to_target() { [ROOT]/foo/target/debug/build/foo/[HASH]/deps/foo[..].d [ROOT]/foo/target/debug/foo[EXE] [ROOT]/foo/target/debug/foo.d +[ROOT]/foo/target/debug/build/foo/[HASH]/.lock "#]]); } @@ -221,7 +224,7 @@ fn should_respect_env_var() { .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .env("CARGO_BUILD_BUILD_DIR", "build-dir") .enable_mac_dsym() @@ -237,6 +240,7 @@ fn should_respect_env_var() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); } @@ -267,7 +271,7 @@ fn build_script_should_output_to_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -296,6 +300,9 @@ fn build_script_should_output_to_build_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/build-script-execution/output [ROOT]/foo/build-dir/debug/build/foo/[HASH]/build-script-execution/root-output [ROOT]/foo/build-dir/debug/build/foo/[HASH]/build-script-execution/stderr +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); } @@ -327,7 +334,7 @@ fn cargo_tmpdir_should_output_to_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout test") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking test") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -353,6 +360,9 @@ fn cargo_tmpdir_should_output_to_build_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/dep-bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo.json +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock [ROOT]/foo/build-dir/tmp/foo.txt [ROOT]/foo/build-dir/.rustc_info.json @@ -383,7 +393,7 @@ fn examples_should_output_to_build_dir_and_uplift_to_target_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build --examples") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build --examples") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -398,6 +408,7 @@ fn examples_should_output_to_build_dir_and_uplift_to_target_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -427,7 +438,7 @@ fn benches_should_output_to_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build --bench=foo") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build --bench=foo") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -447,6 +458,8 @@ fn benches_should_output_to_build_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/dep-bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo.json +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock [ROOT]/foo/build-dir/.rustc_info.json "#]]); @@ -475,7 +488,7 @@ fn cargo_doc_should_output_to_target_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout doc") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking doc") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -500,7 +513,7 @@ fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout package") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking package") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -518,6 +531,7 @@ fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock [ROOT]/foo/build-dir/debug/foo[EXE] [ROOT]/foo/build-dir/debug/foo.d [ROOT]/foo/build-dir/package/foo-0.0.1/Cargo.lock @@ -554,7 +568,7 @@ fn cargo_publish_should_only_touch_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout publish") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking publish") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .replace_crates_io(registry.index_url()) .enable_mac_dsym() @@ -583,7 +597,7 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -598,6 +612,7 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -611,7 +626,7 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { "#]]); - p.cargo("-Zbuild-dir-new-layout clean") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking clean") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -652,7 +667,7 @@ fn cargo_clean_should_remove_correct_files() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -674,10 +689,12 @@ fn cargo_clean_should_remove_correct_files() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo.json [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/dep-bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp +[ROOT]/foo/build-dir/debug/build/bar/[HASH]/.lock +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); - p.cargo("-Zbuild-dir-new-layout clean -p bar") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking clean -p bar") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -692,6 +709,7 @@ fn cargo_clean_should_remove_correct_files() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo.json [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/dep-bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); } @@ -710,7 +728,7 @@ fn timings_report_should_output_to_target_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build --timings") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build --timings") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -735,7 +753,7 @@ fn future_incompat_should_output_to_build_dir() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .arg("--future-incompat-report") .env("RUSTFLAGS", "-Zfuture-incompat-test") @@ -758,7 +776,7 @@ fn template_should_error_for_invalid_variables() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .with_status(101) @@ -784,7 +802,7 @@ fn template_should_suggest_nearest_variable() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .with_status(101) .with_stderr_data(str![[r#" @@ -810,7 +828,7 @@ fn template_workspace_root() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -827,6 +845,7 @@ fn template_workspace_root() { [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -855,7 +874,7 @@ fn template_cargo_cache_home() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -874,6 +893,7 @@ fn template_cargo_cache_home() { [ROOT]/home/.cargo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/home/.cargo/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/home/.cargo/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/home/.cargo/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -912,7 +932,7 @@ fn template_workspace_path_hash() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -935,6 +955,7 @@ fn template_workspace_path_hash() { [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/foo[..][EXE] [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/foo[..].d +[ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -982,7 +1003,7 @@ fn template_workspace_path_hash_should_handle_symlink() { .build(); // Build from the non-symlinked directory - p.cargo("-Zbuild-dir-new-layout check") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking check") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .run(); @@ -1002,6 +1023,7 @@ fn template_workspace_path_hash_should_handle_symlink() { [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/fingerprint/lib-foo.json [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/foo-[HASH].d [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/libfoo-[HASH].rmeta +[ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -1020,7 +1042,7 @@ fn template_workspace_path_hash_should_handle_symlink() { foo_dir.rm_rf(); // Run cargo from the symlinked dir - p.cargo("-Zbuild-dir-new-layout check") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking check") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .enable_mac_dsym() .cwd(&symlinked_dir) @@ -1040,6 +1062,7 @@ fn template_workspace_path_hash_should_handle_symlink() { [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/fingerprint/lib-foo.json [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/foo-[HASH].d [ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/deps/libfoo-[HASH].rmeta +[ROOT]/foo/foo/[HASH]/build-dir/debug/build/foo/[HASH]/.lock "#]]); @@ -1065,7 +1088,7 @@ fn template_should_handle_reject_unmatched_brackets() { ) .build(); - p.cargo("-Zbuild-dir-new-layout build") + p.cargo("-Zbuild-dir-new-layout -Zfine-grain-locking build") .masquerade_as_nightly_cargo(&["new build-dir layout"]) .with_status(101) .with_stderr_data(str![[r#" diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index e3f325335e6..f5a3513c066 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ - +