diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index 22a07a601fc..e147ac03d86 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -1254,20 +1254,24 @@ fn calculate(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult, unit: &Unit) -> CargoResult { - // Recursively calculate the fingerprint for all of our dependencies. - // - // Skip fingerprints of binaries because they don't actually induce a - // recompile, they're just dependencies in the sense that they need to be - // built. - // - // Create Vec since mutable cx is needed in closure. - let deps = Vec::from(cx.unit_deps(unit)); - let mut deps = deps - .into_iter() - .filter(|dep| !dep.unit.target.is_bin()) - .map(|dep| DepFingerprint::new(cx, unit, &dep)) - .collect::>>()?; - deps.sort_by(|a, b| a.pkg_id.cmp(&b.pkg_id)); + let deps = { + // Recursively calculate the fingerprint for all of our dependencies. + // + // Skip fingerprints of binaries because they don't actually induce a + // recompile, they're just dependencies in the sense that they need to be + // built. The only exception here are artifact dependencies, + // which is an actual dependency that needs a recompile. + // + // Create Vec since mutable cx is needed in closure. + let deps = Vec::from(cx.unit_deps(unit)); + let mut deps = deps + .into_iter() + .filter(|dep| !dep.unit.target.is_bin() || dep.unit.artifact.is_true()) + .map(|dep| DepFingerprint::new(cx, unit, &dep)) + .collect::>>()?; + deps.sort_by(|a, b| a.pkg_id.cmp(&b.pkg_id)); + deps + }; // Afterwards calculate our own fingerprint information. let target_root = target_root(cx); diff --git a/tests/testsuite/artifact_dep.rs b/tests/testsuite/artifact_dep.rs index 6f41dd21a04..0665df649fd 100644 --- a/tests/testsuite/artifact_dep.rs +++ b/tests/testsuite/artifact_dep.rs @@ -2276,3 +2276,69 @@ fn build_script_features_for_shared_dependency() { .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } + +#[cargo_test] +fn calc_bin_artifact_fingerprint() { + // See rust-lang/cargo#10527 + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + resolver = "2" + + [dependencies] + bar = { path = "bar/", artifact = "bin" } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { + let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); + } + "#, + ) + .file("bar/Cargo.toml", &basic_bin_manifest("bar")) + .file("bar/src/main.rs", r#"fn main() { println!("foo") }"#) + .build(); + p.cargo("check -Z bindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr( + "\ +[COMPILING] bar v0.5.0 ([CWD]/bar) +[CHECKING] foo v0.1.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); + + p.change_file("bar/src/main.rs", r#"fn main() { println!("bar") }"#); + // Change in artifact bin dep `bar` propagates to `foo`, triggering recompile. + p.cargo("check -v -Z bindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr( + "\ +[COMPILING] bar v0.5.0 ([CWD]/bar) +[RUNNING] `rustc --crate-name bar [..]` +[CHECKING] foo v0.1.0 ([CWD]) +[RUNNING] `rustc --crate-name foo [..]` +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); + + // All units are fresh. No recompile. + p.cargo("check -v -Z bindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr( + "\ +[FRESH] bar v0.5.0 ([CWD]/bar) +[FRESH] foo v0.1.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +}