Skip to content

Commit b29145e

Browse files
committed
add 'x.py miri', and make it work for 'library/{core,alloc,std}'
1 parent 829aadc commit b29145e

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ binaries, and as such worth documenting:
507507
crate currently being compiled.
508508
* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the
509509
value of `RUSTDOC` from before it was overwritten.
510+
* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap
511+
run the standard library tests in Miri.
510512
* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to
511513
perform verbose logging.
512514
* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host*

cargo-miri/src/phases.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::env;
44
use std::fs::{self, File};
55
use std::io::BufReader;
6-
use std::path::PathBuf;
6+
use std::path::{Path, PathBuf};
77
use std::process::Command;
88

99
use rustc_version::VersionMeta;
@@ -412,9 +412,25 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
412412
// Arguments are treated very differently depending on whether this crate is
413413
// for interpretation by Miri, or for use by a build script / proc macro.
414414
if target_crate {
415-
// Forward arguments, but remove "link" from "--emit" to make this a check-only build.
415+
// Forward arguments, but patched.
416416
let emit_flag = "--emit";
417+
// This hack helps bootstrap run standard library tests in Miri. The issue is as follows:
418+
// when running `cargo miri test` on libcore, cargo builds a local copy of core and makes it
419+
// a dependency of the integration test crate. This copy duplicates all the lang items, so
420+
// the build fails. (Regular testing avoids this because the sysroot is a literal copy of
421+
// what `cargo build` produces, but since Miri builds its own sysroot this does not work for
422+
// us.) So we need to make it so that the locally built libcore contains all the items from
423+
// `core`, but does not re-define them -- we want to replace the entire crate but a
424+
// re-export of the sysroot crate. We do this by swapping out the source file: if
425+
// `MIRI_REPLACE_LIBRS_IF_NOT_TEST` is set and we are building a `lib.rs` file, and a
426+
// `lib.miri.rs` file exists in the same folder, we build that instead. But crucially we
427+
// only do that for the library, not the unit test crate (which would be runnable) or
428+
// rustdoc (which would have a different `phase`).
429+
let replace_librs = env::var_os("MIRI_REPLACE_LIBRS_IF_NOT_TEST").is_some()
430+
&& !runnable_crate
431+
&& phase == RustcPhase::Build;
417432
while let Some(arg) = args.next() {
433+
// Patch `--emit`: remove "link" from "--emit" to make this a check-only build.
418434
if let Some(val) = arg.strip_prefix(emit_flag) {
419435
// Patch this argument. First, extract its value.
420436
let val =
@@ -429,13 +445,36 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
429445
}
430446
}
431447
cmd.arg(format!("{emit_flag}={}", val.join(",")));
432-
} else if arg == "--extern" {
433-
// Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files:
434-
// https://github.com/rust-lang/miri/issues/1705
448+
continue;
449+
}
450+
// Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files:
451+
// https://github.com/rust-lang/miri/issues/1705
452+
if arg == "--extern" {
435453
forward_patched_extern_arg(&mut args, &mut cmd);
436-
} else {
437-
cmd.arg(arg);
454+
continue;
438455
}
456+
// If the REPLACE_LIBRS hack is enabled and we are building a `lib.rs` file, and a
457+
// `lib.miri.rs` file exists, then build that instead. We only consider relative paths
458+
// as cargo uses those for files in the workspace; dependencies from crates.io get
459+
// absolute paths.
460+
if replace_librs {
461+
let path = Path::new(&arg);
462+
if path.is_relative()
463+
&& path.file_name().is_some_and(|f| f == "lib.rs")
464+
&& path.is_file()
465+
{
466+
let miri_rs = Path::new(&arg).with_extension("miri.rs");
467+
if miri_rs.is_file() {
468+
if verbose > 0 {
469+
eprintln!("Performing REPLACE_LIBRS hack: {arg:?} -> {miri_rs:?}");
470+
}
471+
cmd.arg(miri_rs);
472+
continue;
473+
}
474+
}
475+
}
476+
// Fallback: just propagate the argument.
477+
cmd.arg(arg);
439478
}
440479

441480
// During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does).

0 commit comments

Comments
 (0)