Auto merge of #1779 - RalfJung:cargo-miri-xargo, r=RalfJung

fix MIRI_BE_RUSTC value during sysroot build

`@hyd-dev` pointed out that `MIRI_BE_RUSTC` is set to an incorrect value during the xargo sysroot build. This fixes that.
This commit is contained in:
bors 2021-04-20 07:41:41 +00:00
commit 74ffda2dd7
2 changed files with 57 additions and 43 deletions

View File

@ -283,16 +283,17 @@ Moreover, Miri recognizes some environment variables:
architecture to test against. `miri` and `cargo miri` accept the `--target` architecture to test against. `miri` and `cargo miri` accept the `--target`
flag for the same purpose. flag for the same purpose.
The following environment variables are internal, but used to communicate between The following environment variables are *internal* and must not be used by
different Miri binaries, and as such worth documenting: anyone but Miri itself. They are used to communicate between different Miri
binaries, and as such worth documenting:
* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to * `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to
actually not interpret the code but compile it like rustc would. With `target`, Miri sets actually not interpret the code but compile it like rustc would. With `target`, Miri sets
some compiler flags to prepare the code for interpretation; with `host`, this is not done. some compiler flags to prepare the code for interpretation; with `host`, this is not done.
This environment variable is useful to be sure that the compiled `rlib`s are compatible This environment variable is useful to be sure that the compiled `rlib`s are compatible
with Miri. with Miri.
When set while running `cargo-miri`, it indicates that we are part of a sysroot * `MIRI_CALLED_FROM_XARGO` is set during the Miri-induced `xargo` sysroot build,
build (for which some crates need special treatment). which will re-invoke `cargo-miri` as the `rustc` to use for this build.
* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is * `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is
running as a child process of `rustdoc`, which invokes it twice for each doc-test running as a child process of `rustdoc`, which invokes it twice for each doc-test
and requires special treatment, most notably a check-only build before interpretation. and requires special treatment, most notably a check-only build before interpretation.

View File

@ -413,14 +413,14 @@ path = "lib.rs"
// for target crates. // for target crates.
// We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags
// for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves).
// The `MIRI_BE_RUSTC` will mean we dispatch to `phase_setup_rustc`. // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`.
let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_miri_path = std::env::current_exe().expect("current executable path invalid");
if env::var_os("RUSTC_STAGE").is_some() { if env::var_os("RUSTC_STAGE").is_some() {
command.env("RUSTC_REAL", &cargo_miri_path); command.env("RUSTC_REAL", &cargo_miri_path);
} else { } else {
command.env("RUSTC", &cargo_miri_path); command.env("RUSTC", &cargo_miri_path);
} }
command.env("MIRI_BE_RUSTC", "target"); command.env("MIRI_CALLED_FROM_XARGO", "1");
// Make sure there are no other wrappers or flags getting in our way // Make sure there are no other wrappers or flags getting in our way
// (Cc https://github.com/rust-lang/miri/issues/1421). // (Cc https://github.com/rust-lang/miri/issues/1421).
// This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS`
@ -450,21 +450,6 @@ path = "lib.rs"
} }
} }
fn phase_setup_rustc(args: env::Args) {
// Mostly we just forward everything.
// `MIRI_BE_RUST` is already set.
let mut cmd = miri();
cmd.args(args);
// Patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does).
if get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") {
cmd.arg("-C").arg("panic=abort");
}
// Run it!
exec(cmd);
}
fn phase_cargo_miri(mut args: env::Args) { fn phase_cargo_miri(mut args: env::Args) {
// Check for version and help flags even when invoked as `cargo-miri`. // Check for version and help flags even when invoked as `cargo-miri`.
if has_arg_flag("--help") || has_arg_flag("-h") { if has_arg_flag("--help") || has_arg_flag("-h") {
@ -598,7 +583,17 @@ fn phase_cargo_miri(mut args: env::Args) {
exec(cmd) exec(cmd)
} }
fn phase_cargo_rustc(mut args: env::Args) { #[derive(Debug, Copy, Clone, PartialEq)]
enum RustcPhase {
/// `rustc` called via `xargo` for sysroot build.
Setup,
/// `rustc` called by `cargo` for regular build.
Build,
/// `rustc` called by `rustdoc` for doctest.
Rustdoc,
}
fn phase_rustc(mut args: env::Args, phase: RustcPhase) {
/// Determines if we are being invoked (as rustc) to build a crate for /// Determines if we are being invoked (as rustc) to build a crate for
/// the "target" architecture, in contrast to the "host" architecture. /// the "target" architecture, in contrast to the "host" architecture.
/// Host crates are for build scripts and proc macros and still need to /// Host crates are for build scripts and proc macros and still need to
@ -644,7 +639,7 @@ fn phase_cargo_rustc(mut args: env::Args) {
let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
let target_crate = is_target_crate(); let target_crate = is_target_crate();
let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos
let store_json = |info: CrateRunInfo| { let store_json = |info: CrateRunInfo| {
// Create a stub .d file to stop Cargo from "rebuilding" the crate: // Create a stub .d file to stop Cargo from "rebuilding" the crate:
@ -669,7 +664,8 @@ fn phase_cargo_rustc(mut args: env::Args) {
let runnable_crate = !print && is_runnable_crate(); let runnable_crate = !print && is_runnable_crate();
if runnable_crate && target_crate { if runnable_crate && target_crate {
let inside_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); assert!(phase != RustcPhase::Setup, "there should be no interpretation during sysroot build");
let inside_rustdoc = phase == RustcPhase::Rustdoc;
// This is the binary or test crate that we want to interpret under Miri. // This is the binary or test crate that we want to interpret under Miri.
// But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not
// like we want them. // like we want them.
@ -749,8 +745,15 @@ fn phase_cargo_rustc(mut args: env::Args) {
} }
} }
// Use our custom sysroot. // Use our custom sysroot (but not if that is what we are currently building).
if phase != RustcPhase::Setup {
forward_miri_sysroot(&mut cmd); forward_miri_sysroot(&mut cmd);
}
// During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does).
if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") {
cmd.arg("-C").arg("panic=abort");
}
} else { } else {
// For host crates or when we are printing, just forward everything. // For host crates or when we are printing, just forward everything.
cmd.args(args); cmd.args(args);
@ -783,7 +786,15 @@ fn phase_cargo_rustc(mut args: env::Args) {
} }
} }
fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { #[derive(Debug, Copy, Clone, PartialEq)]
enum RunnerPhase {
/// `cargo` is running a binary
Cargo,
/// `rustdoc` is running a binary
Rustdoc,
}
fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) {
let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
let file = File::open(&binary) let file = File::open(&binary)
@ -840,8 +851,8 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
cmd.arg(arg); cmd.arg(arg);
} }
} }
if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() {
// Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`).
if phase != RunnerPhase::Rustdoc {
forward_miri_sysroot(&mut cmd); forward_miri_sysroot(&mut cmd);
} }
// Respect `MIRIFLAGS`. // Respect `MIRIFLAGS`.
@ -869,14 +880,17 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
eprintln!("[cargo-miri runner] {:?}", cmd); eprintln!("[cargo-miri runner] {:?}", cmd);
} }
if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { match phase {
RunnerPhase::Rustdoc => {
exec_with_pipe(cmd, &info.stdin) exec_with_pipe(cmd, &info.stdin)
} else { }
RunnerPhase::Cargo => {
exec(cmd) exec(cmd)
} }
} }
}
fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { fn phase_rustdoc(fst_arg: &str, mut args: env::Args) {
let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
// phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here;
@ -950,15 +964,14 @@ fn main() {
args.next().unwrap(); args.next().unwrap();
// Dispatch running as part of sysroot compilation. // Dispatch running as part of sysroot compilation.
if env::var_os("MIRI_BE_RUSTC").is_some() { if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() {
phase_setup_rustc(args); phase_rustc(args, RustcPhase::Setup);
return; return;
} }
// The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the
// arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate.
let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() {
if invoked_by_rustdoc {
// ...however, we then also see this variable when rustdoc invokes us as the testrunner! // ...however, we then also see this variable when rustdoc invokes us as the testrunner!
// The runner is invoked as `$runtool ($runtool-arg)* output_file`; // The runner is invoked as `$runtool ($runtool-arg)* output_file`;
// since we don't specify any runtool-args, and rustdoc supplies multiple arguments to // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to
@ -967,12 +980,12 @@ fn main() {
let arg = args.next().unwrap(); let arg = args.next().unwrap();
let binary = Path::new(&arg); let binary = Path::new(&arg);
if binary.exists() { if binary.exists() {
phase_cargo_runner(binary, args); phase_runner(binary, args, RunnerPhase::Rustdoc);
} else { } else {
show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg));
} }
} else { } else {
phase_cargo_rustc(args); phase_rustc(args, RustcPhase::Rustdoc);
} }
return; return;
@ -988,7 +1001,7 @@ fn main() {
// On top of that, we are also called as RUSTDOC, but that is just a stub currently. // On top of that, we are also called as RUSTDOC, but that is just a stub currently.
match args.next().as_deref() { match args.next().as_deref() {
Some("miri") => phase_cargo_miri(args), Some("miri") => phase_cargo_miri(args),
Some("rustc") => phase_cargo_rustc(args), Some("rustc") => phase_rustc(args, RustcPhase::Build),
Some(arg) => { Some(arg) => {
// We have to distinguish the "runner" and "rustdoc" cases. // We have to distinguish the "runner" and "rustdoc" cases.
// As runner, the first argument is the binary (a file that should exist, with an absolute path); // As runner, the first argument is the binary (a file that should exist, with an absolute path);
@ -996,9 +1009,9 @@ fn main() {
let binary = Path::new(arg); let binary = Path::new(arg);
if binary.exists() { if binary.exists() {
assert!(!arg.starts_with("--")); // not a flag assert!(!arg.starts_with("--")); // not a flag
phase_cargo_runner(binary, args); phase_runner(binary, args, RunnerPhase::Cargo);
} else if arg.starts_with("--") { } else if arg.starts_with("--") {
phase_cargo_rustdoc(arg, args); phase_rustdoc(arg, args);
} else { } else {
show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg));
} }