Skip to content

Commit 7438770

Browse files
committed
Revert always computing filename Metadata.
When a unit does not have Metadata, the computation of fingerprints depends on reusing the same fingerprint file to detect if the output needs to be rebuilt. The previous change that put each unit's fingerprint into a separate directory was wrong, and broke change detection in this case (for example, executables on MSVC). Instead, use a different approach to deal with compiler output caching by using the same naming convention as the fingerprint file itself.
1 parent bd5f563 commit 7438770

File tree

6 files changed

+73
-48
lines changed

6 files changed

+73
-48
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub struct CompilationFiles<'a, 'cfg> {
8585
roots: Vec<Unit>,
8686
ws: &'a Workspace<'cfg>,
8787
/// Metadata hash to use for each unit.
88-
metas: HashMap<Unit, Metadata>,
88+
metas: HashMap<Unit, Option<Metadata>>,
8989
/// For each Unit, a list all files produced.
9090
outputs: HashMap<Unit, LazyCell<Arc<Vec<OutputFile>>>>,
9191
}
@@ -154,12 +154,8 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
154154
///
155155
/// Returns `None` if the unit should not use a metadata hash (like
156156
/// rustdoc, or some dylibs).
157-
pub fn metadata(&self, bcx: &BuildContext<'_, '_>, unit: &Unit) -> Option<Metadata> {
158-
if should_use_metadata(bcx, unit) {
159-
Some(self.metas[unit])
160-
} else {
161-
None
162-
}
157+
pub fn metadata(&self, unit: &Unit) -> Option<Metadata> {
158+
self.metas[unit]
163159
}
164160

165161
/// Gets the short hash based only on the `PackageId`.
@@ -192,10 +188,14 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
192188

193189
/// Directory name to use for a package in the form `NAME-HASH`.
194190
///
195-
/// The hash is unique per Unit.
196-
pub fn pkg_dir(&self, unit: &Unit) -> String {
191+
/// Note that some units may share the same directory, so care should be
192+
/// taken in those cases!
193+
fn pkg_dir(&self, unit: &Unit) -> String {
197194
let name = unit.pkg.package_id().name();
198-
format!("{}-{}", name, self.metas[unit])
195+
match self.metas[unit] {
196+
Some(ref meta) => format!("{}-{}", name, meta),
197+
None => format!("{}-{}", name, self.target_short_hash(unit)),
198+
}
199199
}
200200

201201
/// Returns the root of the build output tree for the host
@@ -220,9 +220,29 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
220220
self.layout(unit.kind).fingerprint().join(dir)
221221
}
222222

223+
/// Returns the path for a file in the fingerprint directory.
224+
///
225+
/// The "prefix" should be something to distinguish the file from other
226+
/// files in the fingerprint directory.
227+
pub fn fingerprint_file_path(&self, unit: &Unit, prefix: &str) -> PathBuf {
228+
// Different targets need to be distinguished in the
229+
let kind = unit.target.kind().description();
230+
let flavor = if unit.mode.is_any_test() {
231+
"test-"
232+
} else if unit.mode.is_doc() {
233+
"doc-"
234+
} else if unit.mode.is_run_custom_build() {
235+
"run-"
236+
} else {
237+
""
238+
};
239+
let name = format!("{}{}{}-{}", prefix, flavor, kind, unit.target.name());
240+
self.fingerprint_dir(unit).join(name)
241+
}
242+
223243
/// Path where compiler output is cached.
224244
pub fn message_cache_path(&self, unit: &Unit) -> PathBuf {
225-
self.fingerprint_dir(unit).join("output")
245+
self.fingerprint_file_path(unit, "output-")
226246
}
227247

228248
/// Returns the directory where a compiled build script is stored.
@@ -414,7 +434,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
414434
// Convert FileType to OutputFile.
415435
let mut outputs = Vec::new();
416436
for file_type in file_types {
417-
let meta = self.metadata(bcx, unit).map(|m| m.to_string());
437+
let meta = self.metadata(unit).map(|m| m.to_string());
418438
let path = out_dir.join(file_type.output_filename(&unit.target, meta.as_deref()));
419439
let hardlink = self.uplift_to(unit, &file_type, &path);
420440
let export_path = if unit.target.is_custom_build() {
@@ -437,7 +457,11 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
437457
}
438458
}
439459

440-
fn metadata_of(unit: &Unit, cx: &Context<'_, '_>, metas: &mut HashMap<Unit, Metadata>) -> Metadata {
460+
fn metadata_of(
461+
unit: &Unit,
462+
cx: &Context<'_, '_>,
463+
metas: &mut HashMap<Unit, Option<Metadata>>,
464+
) -> Option<Metadata> {
441465
if !metas.contains_key(unit) {
442466
let meta = compute_metadata(unit, cx, metas);
443467
metas.insert(unit.clone(), meta);
@@ -451,9 +475,12 @@ fn metadata_of(unit: &Unit, cx: &Context<'_, '_>, metas: &mut HashMap<Unit, Meta
451475
fn compute_metadata(
452476
unit: &Unit,
453477
cx: &Context<'_, '_>,
454-
metas: &mut HashMap<Unit, Metadata>,
455-
) -> Metadata {
478+
metas: &mut HashMap<Unit, Option<Metadata>>,
479+
) -> Option<Metadata> {
456480
let bcx = &cx.bcx;
481+
if !should_use_metadata(bcx, unit) {
482+
return None;
483+
}
457484
let mut hasher = SipHasher::new();
458485

459486
// This is a generic version number that can be changed to make
@@ -526,7 +553,7 @@ fn compute_metadata(
526553
// with user dependencies.
527554
unit.is_std.hash(&mut hasher);
528555

529-
Metadata(hasher.finish())
556+
Some(Metadata(hasher.finish()))
530557
}
531558

532559
fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut SipHasher) {

src/cargo/core/compiler/context/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
377377
pub fn get_run_build_script_metadata(&self, unit: &Unit) -> Metadata {
378378
assert!(unit.mode.is_run_custom_build());
379379
self.files()
380-
.metadata(self.bcx, unit)
380+
.metadata(unit)
381381
.expect("build script should always have hash")
382382
}
383383

src/cargo/core/compiler/fingerprint.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@
4343
//! The `Metadata` hash is a hash added to the output filenames to isolate
4444
//! each unit. See the documentation in the `compilation_files` module for
4545
//! more details. NOTE: Not all output files are isolated via filename hashes
46-
//! (like dylibs), but the fingerprint directory always has the `Metadata`
47-
//! hash in its directory name.
46+
//! (like dylibs). The fingerprint directory uses a hash, but sometimes units
47+
//! share the same fingerprint directory (when they don't have Metadata) so
48+
//! care should be taken to handle this!
4849
//!
4950
//! Fingerprints and Metadata are similar, and track some of the same things.
5051
//! The Metadata contains information that is required to keep Units separate.
@@ -352,8 +353,7 @@ pub fn prepare_target(cx: &mut Context<'_, '_>, unit: &Unit, force: bool) -> Car
352353
unit.target.name()
353354
));
354355
let bcx = cx.bcx;
355-
let new = cx.files().fingerprint_dir(unit);
356-
let loc = new.join(&filename(unit));
356+
let loc = cx.files().fingerprint_file_path(unit, "");
357357

358358
debug!("fingerprint at: {}", loc.display());
359359

@@ -1522,9 +1522,7 @@ pub fn prepare_init(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<()> {
15221522
/// Returns the location that the dep-info file will show up at for the `unit`
15231523
/// specified.
15241524
pub fn dep_info_loc(cx: &mut Context<'_, '_>, unit: &Unit) -> PathBuf {
1525-
cx.files()
1526-
.fingerprint_dir(unit)
1527-
.join(&format!("dep-{}", filename(unit)))
1525+
cx.files().fingerprint_file_path(unit, "dep-")
15281526
}
15291527

15301528
/// Returns an absolute path that target directory.
@@ -1680,21 +1678,6 @@ where
16801678
None
16811679
}
16821680

1683-
/// Returns the filename used for the fingerprint file.
1684-
fn filename(unit: &Unit) -> String {
1685-
let kind = unit.target.kind().description();
1686-
let flavor = if unit.mode.is_any_test() {
1687-
"test-"
1688-
} else if unit.mode.is_doc() {
1689-
"doc-"
1690-
} else if unit.mode.is_run_custom_build() {
1691-
"run-"
1692-
} else {
1693-
""
1694-
};
1695-
format!("{}{}-{}", flavor, kind, unit.target.name())
1696-
}
1697-
16981681
#[repr(u8)]
16991682
enum DepInfoPathType {
17001683
// src/, e.g. src/lib.rs

src/cargo/core/compiler/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
//! lib-$targetname.json
4040
//! # The console output from the compiler. This is cached
4141
//! # so that warnings can be redisplayed for "fresh" units.
42-
//! output
42+
//! output-lib-$targetname
4343
//!
4444
//! # This is the root directory for all rustc artifacts except build
4545
//! # scripts, examples, and test and bench executables. Almost every

src/cargo/core/compiler/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
194194
let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib());
195195
let pass_cdylib_link_args = unit.target.is_cdylib();
196196

197-
let dep_info_name = match cx.files().metadata(cx.bcx, unit) {
197+
let dep_info_name = match cx.files().metadata(unit) {
198198
Some(metadata) => format!("{}-{}.d", unit.target.crate_name(), metadata),
199199
None => format!("{}.d", unit.target.crate_name()),
200200
};
@@ -870,7 +870,7 @@ fn build_base_args(
870870
cmd.arg("--cfg").arg(&format!("feature=\"{}\"", feat));
871871
}
872872

873-
match cx.files().metadata(cx.bcx, unit) {
873+
match cx.files().metadata(unit) {
874874
Some(m) => {
875875
cmd.arg("-C").arg(&format!("metadata={}", m));
876876
cmd.arg("-C").arg(&format!("extra-filename=-{}", m));

tests/testsuite/cache_messages.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ fn clears_cache_after_fix() {
194194
// Fill the cache.
195195
p.cargo("check").with_stderr_contains("[..]asdf[..]").run();
196196
let cpath = p
197-
.glob("target/debug/.fingerprint/foo-*/output")
197+
.glob("target/debug/.fingerprint/foo-*/output-*")
198198
.next()
199199
.unwrap()
200200
.unwrap();
@@ -215,7 +215,10 @@ fn clears_cache_after_fix() {
215215
",
216216
)
217217
.run();
218-
assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 0);
218+
assert_eq!(
219+
p.glob("target/debug/.fingerprint/foo-*/output-*").count(),
220+
0
221+
);
219222

220223
// And again, check the cache is correct.
221224
p.cargo("check")
@@ -253,7 +256,10 @@ fn rustdoc() {
253256
let rustdoc_stderr = as_str(&rustdoc_output.stderr);
254257
assert!(rustdoc_stderr.contains("private"));
255258
assert!(rustdoc_stderr.contains("\x1b["));
256-
assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 1);
259+
assert_eq!(
260+
p.glob("target/debug/.fingerprint/foo-*/output-*").count(),
261+
1
262+
);
257263

258264
// Check the cached output.
259265
let rustdoc_output = p
@@ -331,14 +337,23 @@ fn doesnt_create_extra_files() {
331337

332338
p.cargo("build").run();
333339

334-
assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 0);
335-
assert_eq!(p.glob("target/debug/.fingerprint/dep-*/output").count(), 0);
340+
assert_eq!(
341+
p.glob("target/debug/.fingerprint/foo-*/output-*").count(),
342+
0
343+
);
344+
assert_eq!(
345+
p.glob("target/debug/.fingerprint/dep-*/output-*").count(),
346+
0
347+
);
336348
if is_coarse_mtime() {
337349
sleep_ms(1000);
338350
}
339351
p.change_file("src/lib.rs", "fn unused() {}");
340352
p.cargo("build").run();
341-
assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 1);
353+
assert_eq!(
354+
p.glob("target/debug/.fingerprint/foo-*/output-*").count(),
355+
1
356+
);
342357
}
343358

344359
#[cargo_test]

0 commit comments

Comments
 (0)