From 9a2150b2f3c757f57236c9437e39af42fdd9060e Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Wed, 15 Apr 2026 00:49:25 +0900 Subject: [PATCH] fix: Always take a shared lock on `.cargo-lock` This commit changes the behavior to always take a shared lock on `.cargo-lock` to ensure backwards compatiblity with older versions of cargo that do not lock `.cargo-build-lock`. To allow `cargo check` and `cargo build` to continue running concurrently `.cargo-artifact-lock` was added with the original behavior of `.cargo-lock`. --- src/cargo/core/compiler/layout.rs | 13 ++++++++++++- tests/testsuite/build_dir.rs | 14 ++++++++++++++ tests/testsuite/build_dir_legacy.rs | 14 ++++++++++++++ tests/testsuite/check.rs | 10 ++++++++-- tests/testsuite/clean.rs | 7 +++++-- tests/testsuite/clean_new_layout.rs | 7 +++++-- 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/cargo/core/compiler/layout.rs b/src/cargo/core/compiler/layout.rs index b7fab8f113c..2bfd03c3232 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -220,6 +220,7 @@ use std::path::{Path, PathBuf}; pub struct Layout { artifact_dir: Option, build_dir: BuildDirLayout, + _lock: Option, } impl Layout { @@ -281,6 +282,15 @@ impl Layout { let deps = build_dest.join("deps"); let artifact = deps.join("artifact"); + // We take a shared lock on `.cargo-lock` to make sure we don't run currently with + // older versions of Cargo (including tools that use Cargo as a library) that don't support + // `.cargo-build-lock`. + let lock = if is_on_nfs_mount(root.as_path_unlocked()) { + None + } else { + Some(dest.open_ro_shared_create(".cargo-lock", ws.gctx(), "artifact directory")?) + }; + let artifact_dir = if must_take_artifact_dir_lock { // For now we don't do any more finer-grained locking on the artifact // directory, so just lock the entire thing for the duration of this @@ -289,7 +299,7 @@ impl Layout { None } else { Some(dest.open_rw_exclusive_create( - ".cargo-lock", + ".cargo-artifact-lock", ws.gctx(), "artifact directory", )?) @@ -320,6 +330,7 @@ impl Layout { _lock: build_dir_lock, is_new_layout, }, + _lock: lock, }) } diff --git a/tests/testsuite/build_dir.rs b/tests/testsuite/build_dir.rs index 3da1f31265f..cde8c5cb003 100644 --- a/tests/testsuite/build_dir.rs +++ b/tests/testsuite/build_dir.rs @@ -55,6 +55,7 @@ fn binary_with_debug() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -110,6 +111,7 @@ fn binary_with_release() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/release/.cargo-lock +[ROOT]/foo/target-dir/release/.cargo-artifact-lock [ROOT]/foo/target-dir/release/foo[EXE] [ROOT]/foo/target-dir/release/foo.d @@ -205,6 +207,7 @@ fn should_default_to_target() { [ROOT]/foo/target/.rustc_info.json [ROOT]/foo/target/CACHEDIR.TAG [ROOT]/foo/target/debug/.cargo-lock +[ROOT]/foo/target/debug/.cargo-artifact-lock [ROOT]/foo/target/debug/.cargo-build-lock [ROOT]/foo/target/debug/build/foo/[HASH]/fingerprint/bin-foo [ROOT]/foo/target/debug/build/foo/[HASH]/fingerprint/bin-foo.json @@ -373,6 +376,7 @@ fn cargo_tmpdir_should_output_to_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] "#]]); @@ -419,6 +423,7 @@ fn examples_should_output_to_build_dir_and_uplift_to_target_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/examples/foo[EXE] [ROOT]/foo/target-dir/debug/examples/foo.d @@ -471,6 +476,7 @@ fn benches_should_output_to_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] "#]]); @@ -528,6 +534,7 @@ fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() { p.root().join("build-dir").assert_build_dir_layout(str![[r#" [ROOT]/foo/build-dir/.rustc_info.json [ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.cargo-artifact-lock [ROOT]/foo/build-dir/debug/.cargo-build-lock [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo [ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/bin-foo.json @@ -625,6 +632,7 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -858,6 +866,7 @@ fn template_workspace_root() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -906,6 +915,7 @@ fn template_cargo_cache_home() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -968,6 +978,7 @@ fn template_workspace_path_hash() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -1033,6 +1044,7 @@ fn template_workspace_path_hash_should_handle_symlink() { p.root().join("target").assert_build_dir_layout(str![[r#" [ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock "#]]); @@ -1072,6 +1084,7 @@ fn template_workspace_path_hash_should_handle_symlink() { p.root().join("target").assert_build_dir_layout(str![[r#" [ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock "#]]); @@ -1213,6 +1226,7 @@ CARGO_BIN_FILE_BAR_bar=[ROOT]/foo/build-dir/debug/build/bar/[HASH]/artifact/bin/ .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d diff --git a/tests/testsuite/build_dir_legacy.rs b/tests/testsuite/build_dir_legacy.rs index ff708525fef..1b4b6b0bcd7 100644 --- a/tests/testsuite/build_dir_legacy.rs +++ b/tests/testsuite/build_dir_legacy.rs @@ -51,6 +51,7 @@ fn binary_with_debug() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -102,6 +103,7 @@ fn binary_with_release() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/release/.cargo-lock +[ROOT]/foo/target-dir/release/.cargo-artifact-lock [ROOT]/foo/target-dir/release/foo[EXE] [ROOT]/foo/target-dir/release/foo.d @@ -191,6 +193,7 @@ fn should_default_to_target() { [ROOT]/foo/target/.rustc_info.json [ROOT]/foo/target/CACHEDIR.TAG [ROOT]/foo/target/debug/.cargo-lock +[ROOT]/foo/target/debug/.cargo-artifact-lock [ROOT]/foo/target/debug/.cargo-build-lock [ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/bin-foo [ROOT]/foo/target/debug/.fingerprint/foo-[HASH]/bin-foo.json @@ -345,6 +348,7 @@ fn cargo_tmpdir_should_output_to_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] "#]]); @@ -385,6 +389,7 @@ fn examples_should_output_to_build_dir_and_uplift_to_target_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/examples/foo[EXE] [ROOT]/foo/target-dir/debug/examples/foo.d @@ -432,6 +437,7 @@ fn benches_should_output_to_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] "#]]); @@ -483,6 +489,7 @@ fn cargo_package_should_build_in_build_dir_and_output_to_target_dir() { p.root().join("build-dir").assert_build_dir_layout(str![[r#" [ROOT]/foo/build-dir/.rustc_info.json [ROOT]/foo/build-dir/debug/.cargo-lock +[ROOT]/foo/build-dir/debug/.cargo-artifact-lock [ROOT]/foo/build-dir/debug/.cargo-build-lock [ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo [ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/bin-foo.json @@ -574,6 +581,7 @@ fn cargo_clean_should_clean_the_target_dir_and_build_dir() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -785,6 +793,7 @@ fn template_workspace_root() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -829,6 +838,7 @@ fn template_cargo_cache_home() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -887,6 +897,7 @@ fn template_workspace_path_hash() { .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d @@ -948,6 +959,7 @@ fn template_workspace_path_hash_should_handle_symlink() { p.root().join("target").assert_build_dir_layout(str![[r#" [ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock "#]]); @@ -982,6 +994,7 @@ fn template_workspace_path_hash_should_handle_symlink() { p.root().join("target").assert_build_dir_layout(str![[r#" [ROOT]/foo/target/CACHEDIR.TAG +[ROOT]/foo/target/debug/.cargo-lock "#]]); @@ -1122,6 +1135,7 @@ CARGO_BIN_FILE_BAR_bar=[ROOT]/foo/build-dir/debug/deps/artifact/bar-[HASH]/bin/b .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG [ROOT]/foo/target-dir/debug/.cargo-lock +[ROOT]/foo/target-dir/debug/.cargo-artifact-lock [ROOT]/foo/target-dir/debug/foo[EXE] [ROOT]/foo/target-dir/debug/foo.d diff --git a/tests/testsuite/check.rs b/tests/testsuite/check.rs index aa55ff34ae7..34293a27c3a 100644 --- a/tests/testsuite/check.rs +++ b/tests/testsuite/check.rs @@ -1715,6 +1715,7 @@ fn check_build_should_not_output_files_to_artifact_dir() { .join("target-dir") .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock "#]]); } @@ -1745,8 +1746,12 @@ fn check_build_should_not_lock_artifact_dir_when_build_dir_is_not_same_dir() { p.cargo("check").enable_mac_dsym().run(); - // Verify we did NOT take the build-dir lock - assert!(!p.root().join("target-dir/debug/.cargo-lock").exists()); + // Verify we did NOT take the artifact-dir lock + assert!( + !p.root() + .join("target-dir/debug/.cargo-artifact-lock") + .exists() + ); // Verify we did take the build-dir lock assert!(p.root().join("build-dir/debug/.cargo-build-lock").exists()); } @@ -1838,6 +1843,7 @@ fn check_build_should_not_uplift_proc_macro_dylib_deps() { .join("target-dir") .assert_build_dir_layout(str![[r#" [ROOT]/foo/target-dir/CACHEDIR.TAG +[ROOT]/foo/target-dir/debug/.cargo-lock "#]]); } diff --git a/tests/testsuite/clean.rs b/tests/testsuite/clean.rs index cd598626e63..0ad0ed2869b 100644 --- a/tests/testsuite/clean.rs +++ b/tests/testsuite/clean.rs @@ -736,8 +736,11 @@ fn assert_all_clean(build_dir: &Path) { }) { let entry = entry.unwrap(); let path = entry.path(); - if let ".rustc_info.json" | ".cargo-lock" | ".cargo-build-lock" | "CACHEDIR.TAG" = - path.file_name().unwrap().to_str().unwrap() + if let ".rustc_info.json" + | ".cargo-lock" + | ".cargo-build-lock" + | ".cargo-artifact-lock" + | "CACHEDIR.TAG" = path.file_name().unwrap().to_str().unwrap() { continue; } diff --git a/tests/testsuite/clean_new_layout.rs b/tests/testsuite/clean_new_layout.rs index 635cb6deabf..0dd9c0149e7 100644 --- a/tests/testsuite/clean_new_layout.rs +++ b/tests/testsuite/clean_new_layout.rs @@ -702,8 +702,11 @@ fn assert_all_clean(build_dir: &Path) { }) { let entry = entry.unwrap(); let path = entry.path(); - if let ".rustc_info.json" | ".cargo-lock" | ".cargo-build-lock" | "CACHEDIR.TAG" = - path.file_name().unwrap().to_str().unwrap() + if let ".rustc_info.json" + | ".cargo-lock" + | ".cargo-build-lock" + | ".cargo-artifact-lock" + | "CACHEDIR.TAG" = path.file_name().unwrap().to_str().unwrap() { continue; }