Skip to content

Commit 25117e3

Browse files
committed
Add support for build-dir layout v2
1 parent bafcd2a commit 25117e3

File tree

1 file changed

+121
-70
lines changed

1 file changed

+121
-70
lines changed

src/report.rs

Lines changed: 121 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -218,45 +218,64 @@ fn merge_profraw(cx: &Context) -> Result<()> {
218218
fn object_files(cx: &Context) -> Result<Vec<OsString>> {
219219
fn walk_target_dir<'a>(
220220
cx: &'a Context,
221-
build_script_re: &'a RegexVec,
221+
build_script_v1_layout_re: &'a RegexVec,
222+
build_script_v2_layout_re: &'a RegexVec,
222223
target_dir: &Utf8Path,
223224
) -> impl Iterator<Item = walkdir::DirEntry> + 'a {
225+
let build_dir = target_dir.join("build"); // <target>/{debug,release}/build
224226
WalkDir::new(target_dir)
225227
.into_iter()
226228
.filter_entry(move |e| {
227229
let p = e.path();
228-
// Refs: https://github.com/rust-lang/cargo/blob/0.85.0/src/cargo/core/compiler/layout.rs.
229-
if p.is_dir() {
230-
if p.file_name().is_some_and(|f| {
231-
f == "incremental"
232-
|| f == ".fingerprint"
233-
|| if cx.args.report.include_build_script {
234-
f == "out"
230+
// Note that Cargo has 2 file layouts. At the time of writing v2 is still unstable
231+
// but planned to replace the v1 layout.
232+
// v1: https://github.com/rust-lang/cargo/blob/0.85.0/src/cargo/core/compiler/layout.rs.
233+
// v2: https://github.com/rust-lang/cargo/blob/592bc40115849f2f16855f4adb6cc795c208765b/src/cargo/core/compiler/layout.rs
234+
if p.is_dir()
235+
&& p.file_name().is_some_and(|f| {
236+
f == "incremental" || f == ".fingerprint" || f == "fingerprint"
237+
})
238+
{
239+
// Ignore incremental compilation related files and Cargo fingerprints
240+
return false;
241+
}
242+
if let (Some(stem), Some(parent)) = (p.file_stem(), p.parent()) {
243+
if parent.starts_with(&build_dir) {
244+
if p.is_dir() && p.file_name().is_some_and(|f| f == "out") {
245+
let is_v2_layout = parent.join("fingerprint").exists();
246+
if is_v2_layout {
247+
// In the v2 layout, the `<target>/debug/$build-unit/out` dir is a
248+
// generic directory that may be the $OUT_DIR for build script
249+
// execution units or the compilation output.
250+
// We check this by seeing if a `run` directory is present which
251+
// indicates this is a build script run
252+
if parent.join("run").exists() {
253+
return false;
254+
}
235255
} else {
236-
f == "build"
256+
// In the v1 layout, `out` is always the build script $OUT_DIR
257+
// which we don't care about.
258+
return false;
237259
}
238-
}) {
239-
// Ignore incremental compilation related files and output from build scripts.
240-
return false;
241-
}
242-
} else if cx.args.report.include_build_script {
243-
if let (Some(stem), Some(p)) = (p.file_stem(), p.parent()) {
244-
fn in_build_dir(p: &Path) -> bool {
245-
let Some(p) = p.parent() else { return false };
246-
let Some(f) = p.file_name() else { return false };
247-
f == "build"
248260
}
249-
if in_build_dir(p) {
250-
if stem == "build-script-build"
251-
|| stem
252-
.to_str()
253-
.unwrap_or_default()
254-
.starts_with("build_script_build-")
255-
{
256-
// TODO: use os_str_to_str?
257-
let dir = p.file_name().unwrap().to_string_lossy();
258-
if !build_script_re.is_match(&dir) {
259-
return false;
261+
262+
if stem == "build-script-build"
263+
|| stem.to_str().unwrap_or_default().starts_with("build_script_build-")
264+
{
265+
if cx.args.report.include_build_script {
266+
let is_v2_layout =
267+
parent.parent().unwrap().join("fingerprint").exists();
268+
if is_v2_layout {
269+
let dir = parent.to_string_lossy();
270+
if !build_script_v2_layout_re.is_match(&dir) {
271+
return false;
272+
}
273+
} else {
274+
// TODO: use os_str_to_str?
275+
let dir = parent.file_name().unwrap().to_string_lossy();
276+
if !build_script_v1_layout_re.is_match(&dir) {
277+
return false;
278+
}
260279
}
261280
} else {
262281
return false;
@@ -273,7 +292,12 @@ fn object_files(cx: &Context) -> Result<Vec<OsString>> {
273292
// We check extension instead of using is_executable crate because it always return true on WSL:
274293
// - https://github.com/taiki-e/cargo-llvm-cov/issues/316
275294
// - https://github.com/taiki-e/cargo-llvm-cov/issues/342
276-
if ext == "d" || ext == "rlib" || ext == "rmeta" || f.ends_with(".cargo-lock") {
295+
if ext == "d"
296+
|| ext == "rlib"
297+
|| ext == "rmeta"
298+
|| f.ends_with(".cargo-lock")
299+
|| f.ends_with(".cargo-build-lock")
300+
{
277301
return false;
278302
}
279303
if cx.ws.target_is_windows
@@ -309,7 +333,8 @@ fn object_files(cx: &Context) -> Result<Vec<OsString>> {
309333
}
310334

311335
let re = pkg_hash_re(cx)?;
312-
let build_script_re = build_script_hash_re(cx);
336+
let build_script_v1_layout_re = build_script_hash_v1_layout_re(cx);
337+
let build_script_v2_layout_re = build_script_hash_v2_layout_re(cx);
313338
let mut files = vec![];
314339
let mut searched_dir = String::new();
315340
// To support testing binary crate like tests that use the CARGO_BIN_EXE
@@ -364,50 +389,58 @@ fn object_files(cx: &Context) -> Result<Vec<OsString>> {
364389
}
365390
}
366391

367-
let mut collect_target_dir =
368-
|mut target_dir: Utf8PathBuf, mut build_dir: Option<Utf8PathBuf>| -> Result<()> {
369-
if !auto_detect_profile {
370-
// https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#custom-profiles
371-
let profile = match cx.args.cargo_profile.as_deref() {
372-
None if cx.args.release => "release",
373-
Some("release" | "bench") => "release",
374-
None | Some("dev" | "test") => "debug",
375-
Some(p) => p,
376-
};
377-
target_dir.push(profile);
378-
if let Some(build_dir) = &mut build_dir {
379-
build_dir.push(profile);
380-
}
392+
let mut collect_target_dir = |mut target_dir: Utf8PathBuf,
393+
mut build_dir: Option<Utf8PathBuf>|
394+
-> Result<()> {
395+
if !auto_detect_profile {
396+
// https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#custom-profiles
397+
let profile = match cx.args.cargo_profile.as_deref() {
398+
None if cx.args.release => "release",
399+
Some("release" | "bench") => "release",
400+
None | Some("dev" | "test") => "debug",
401+
Some(p) => p,
402+
};
403+
target_dir.push(profile);
404+
if let Some(build_dir) = &mut build_dir {
405+
build_dir.push(profile);
381406
}
382-
for f in walk_target_dir(cx, &build_script_re, &target_dir) {
383-
let f = f.path();
384-
if is_object(cx, f) {
385-
if let Some(file_stem) = fs::file_stem_recursive(f).unwrap().to_str() {
386-
if re.is_match(file_stem) {
387-
files.push(make_relative(cx, f).to_owned().into_os_string());
388-
}
407+
}
408+
for f in
409+
walk_target_dir(cx, &build_script_v1_layout_re, &build_script_v2_layout_re, &target_dir)
410+
{
411+
let f = f.path();
412+
if is_object(cx, f) {
413+
if let Some(file_stem) = fs::file_stem_recursive(f).unwrap().to_str() {
414+
if re.is_match(file_stem) {
415+
files.push(make_relative(cx, f).to_owned().into_os_string());
389416
}
390417
}
391418
}
392-
searched_dir.push_str(target_dir.as_str());
393-
if let Some(build_dir) = &build_dir {
394-
if target_dir != *build_dir {
395-
for f in walk_target_dir(cx, &build_script_re, build_dir) {
396-
let f = f.path();
397-
if is_object(cx, f) {
398-
if let Some(file_stem) = fs::file_stem_recursive(f).unwrap().to_str() {
399-
if re.is_match(file_stem) {
400-
files.push(make_relative(cx, f).to_owned().into_os_string());
401-
}
419+
}
420+
searched_dir.push_str(target_dir.as_str());
421+
if let Some(build_dir) = &build_dir {
422+
if target_dir != *build_dir {
423+
for f in walk_target_dir(
424+
cx,
425+
&build_script_v1_layout_re,
426+
&build_script_v2_layout_re,
427+
build_dir,
428+
) {
429+
let f = f.path();
430+
if is_object(cx, f) {
431+
if let Some(file_stem) = fs::file_stem_recursive(f).unwrap().to_str() {
432+
if re.is_match(file_stem) {
433+
files.push(make_relative(cx, f).to_owned().into_os_string());
402434
}
403435
}
404436
}
405-
searched_dir.push(',');
406-
searched_dir.push_str(build_dir.as_str());
407437
}
438+
searched_dir.push(',');
439+
searched_dir.push_str(build_dir.as_str());
408440
}
409-
Ok(())
410-
};
441+
}
442+
Ok(())
443+
};
411444
// Check both host and target because proc-macro and build script are built for host.
412445
// https://doc.rust-lang.org/nightly/cargo/reference/build-cache.html
413446
if let Some(target) = &cx.args.target {
@@ -454,7 +487,12 @@ fn object_files(cx: &Context) -> Result<Vec<OsString>> {
454487
if !trybuild_targets.is_empty() {
455488
let re = Regex::new(&format!("^({})(-[0-9a-f]+)?$", trybuild_targets.join("|")))
456489
.unwrap();
457-
for entry in walk_target_dir(cx, &build_script_re, &trybuild_target_dir) {
490+
for entry in walk_target_dir(
491+
cx,
492+
&build_script_v1_layout_re,
493+
&build_script_v2_layout_re,
494+
&trybuild_target_dir,
495+
) {
458496
let path = make_relative(cx, entry.path());
459497
if let Some(file_stem) = fs::file_stem_recursive(path).unwrap().to_str() {
460498
if re.is_match(file_stem) {
@@ -483,7 +521,12 @@ fn object_files(cx: &Context) -> Result<Vec<OsString>> {
483521
let ui_test_target_dir = cx.ws.ui_test_target_dir();
484522
let mut collect_ui_test_target_dir = |ui_test_target_dir: Utf8PathBuf| -> Result<()> {
485523
if ui_test_target_dir.is_dir() {
486-
for entry in walk_target_dir(cx, &build_script_re, &ui_test_target_dir) {
524+
for entry in walk_target_dir(
525+
cx,
526+
&build_script_v1_layout_re,
527+
&build_script_v2_layout_re,
528+
&ui_test_target_dir,
529+
) {
487530
let path = make_relative(cx, entry.path());
488531
if is_object(cx, path) {
489532
files.push(path.to_owned().into_os_string());
@@ -526,14 +569,22 @@ fn pkg_hash_re(cx: &Context) -> Result<RegexVec> {
526569
re.build()
527570
}
528571

529-
fn build_script_hash_re(cx: &Context) -> RegexVec {
572+
fn build_script_hash_v1_layout_re(cx: &Context) -> RegexVec {
530573
let mut re = RegexVecBuilder::new("^(", ")-[0-9a-f]+$");
531574
for &id in &cx.workspace_members.included {
532575
re.or(&cx.ws.metadata[id].name);
533576
}
534577
re.build().unwrap()
535578
}
536579

580+
fn build_script_hash_v2_layout_re(cx: &Context) -> RegexVec {
581+
let mut re = RegexVecBuilder::new("build/(", ")/[0-9a-f]+/out$");
582+
for &id in &cx.workspace_members.included {
583+
re.or(&cx.ws.metadata[id].name);
584+
}
585+
re.build().unwrap()
586+
}
587+
537588
/// Collects metadata for packages generated by trybuild. If the trybuild test
538589
/// directory is not found, it returns an empty vector.
539590
fn trybuild_metadata(ws: &Workspace, target_dir: &Utf8Path) -> Result<Vec<Metadata>> {

0 commit comments

Comments
 (0)