diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index a9b588c016c..a425a3bda26 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -477,6 +477,25 @@ fn rustc( paths::set_file_time_no_err(dep_info_loc, timestamp); } + // This mtime shift for .rmeta is a workaround as rustc incremental build + // since rust-lang/rust#114669 (1.90.0) skips unnecessary rmeta generation. + // + // The situation is like this: + // + // 1. When build script execution's external dependendies + // (rerun-if-changed, rerun-if-env-changed) got updated, + // the execution unit reran and got a newer mtime. + // 2. rustc type-checked the associated crate, though with incremental + // compilation, no rmeta regeneration. Its `.rmeta` stays old. + // 3. Run `cargo check` again. Cargo found build script execution had + // a new mtime than existing crate rmeta, so re-checking the crate. + // However the check is a no-op (input has no change), so stuck. + if mode.is_check() { + for output in outputs.iter() { + paths::set_file_time_no_err(&output.path, timestamp); + } + } + Ok(()) })); diff --git a/tests/testsuite/freshness.rs b/tests/testsuite/freshness.rs index 0cf673e4f7a..7d626bbb559 100644 --- a/tests/testsuite/freshness.rs +++ b/tests/testsuite/freshness.rs @@ -3184,3 +3184,63 @@ fn use_mtime_cache_in_cargo_home() { "#]]) .run(); } + +#[cargo_test] +fn incremental_build_script_execution_got_new_mtime_and_cargo_check() { + // See https://github.com/rust-lang/cargo/issues/16104 + let p = project() + .file("src/lib.rs", "") + .file("touch-me", "") + .file( + "build.rs", + r#"fn main() { println!("cargo::rerun-if-changed=touch-me") }"#, + ) + .build(); + + p.cargo("check") + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + if is_coarse_mtime() { + sleep_ms(1000); + } + + p.change_file("touch-me", "oops"); + + // The first one is expected to rerun build script + p.cargo("check -v") + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[DIRTY] foo v0.0.1 ([ROOT]/foo): the file `touch-me` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` +[RUNNING] `rustc --crate-name foo [..]` +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + // subsequent cargo check gets stuck... + p.cargo("check -v") + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[FRESH] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + p.cargo("check -v") + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[FRESH] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} diff --git a/tests/testsuite/freshness_checksum.rs b/tests/testsuite/freshness_checksum.rs index ffc94abb78c..eedc1f43de9 100644 --- a/tests/testsuite/freshness_checksum.rs +++ b/tests/testsuite/freshness_checksum.rs @@ -2963,3 +2963,63 @@ fn use_checksum_cache_in_cargo_home() { "#]]) .run(); } + +#[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] +fn incremental_build_script_execution_got_new_mtime_and_cargo_check() { + // See https://github.com/rust-lang/cargo/issues/16104 + let p = project() + .file("src/lib.rs", "") + .file("touch-me", "") + .file( + "build.rs", + r#"fn main() { println!("cargo::rerun-if-changed=touch-me") }"#, + ) + .build(); + + p.cargo("check -Zchecksum-freshness") + .masquerade_as_nightly_cargo(&["checksum-freshness"]) + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + p.change_file("touch-me", "oops"); + + // The first one is expected to rerun build script + p.cargo("check -Zchecksum-freshness -v") + .masquerade_as_nightly_cargo(&["checksum-freshness"]) + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[DIRTY] foo v0.0.1 ([ROOT]/foo): the file `touch-me` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) +[COMPILING] foo v0.0.1 ([ROOT]/foo) +[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` +[RUNNING] `rustc --crate-name foo [..]` +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + // subsequent cargo check gets stuck... + p.cargo("check -Zchecksum-freshness -v") + .masquerade_as_nightly_cargo(&["checksum-freshness"]) + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[FRESH] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + p.cargo("check -Zchecksum-freshness -v") + .masquerade_as_nightly_cargo(&["checksum-freshness"]) + .env("CARGO_INCREMENTAL", "1") + .with_stderr_data(str![[r#" +[FRESH] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +}