Skip to content

Commit 4eaf05c

Browse files
committed
Auto merge of #1404 - RalfJung:cargo-miri-host-detect, r=RalfJung
re-do cargo-miri host/target detection logic to match rustbuild @oli-obk I think that's better than looking at `--emit` like we did before... what do you think?
2 parents 17f740e + 024cc43 commit 4eaf05c

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed

src/bin/cargo-miri.rs

+43-39
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::io::{self, BufRead, Write};
66
use std::ops::Not;
77
use std::path::{Path, PathBuf};
88
use std::process::Command;
9+
use std::ffi::OsString;
910

1011
const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20);
1112

@@ -85,29 +86,23 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
8586
}
8687
}
8788

88-
/// Returns the path to the `miri` binary
89-
fn find_miri() -> PathBuf {
89+
/// Returns a command for the right `miri` binary.
90+
fn miri() -> Command {
9091
let mut path = std::env::current_exe().expect("current executable path invalid");
9192
path.set_file_name("miri");
92-
path
93+
Command::new(path)
9394
}
9495

9596
fn cargo() -> Command {
96-
if let Ok(val) = std::env::var("CARGO") {
97-
// Bootstrap tells us where to find cargo
98-
Command::new(val)
99-
} else {
100-
Command::new("cargo")
101-
}
97+
Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo")))
10298
}
10399

104100
fn xargo_check() -> Command {
105-
if let Ok(val) = std::env::var("XARGO_CHECK") {
106-
// Bootstrap tells us where to find xargo
107-
Command::new(val)
108-
} else {
109-
Command::new("xargo-check")
110-
}
101+
Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check")))
102+
}
103+
104+
fn rustc() -> Command {
105+
Command::new(env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")))
111106
}
112107

113108
fn list_targets() -> impl Iterator<Item = cargo_metadata::Target> {
@@ -188,8 +183,8 @@ fn test_sysroot_consistency() {
188183
return;
189184
}
190185

191-
let rustc_sysroot = get_sysroot(Command::new("rustc"));
192-
let miri_sysroot = get_sysroot(Command::new(find_miri()));
186+
let rustc_sysroot = get_sysroot(rustc());
187+
let miri_sysroot = get_sysroot(miri());
193188

194189
if rustc_sysroot != miri_sysroot {
195190
show_error(format!(
@@ -274,7 +269,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) {
274269
/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has
275270
/// done all this already.
276271
fn setup(subcommand: MiriCommand) {
277-
if std::env::var("MIRI_SYSROOT").is_ok() {
272+
if std::env::var_os("MIRI_SYSROOT").is_some() {
278273
if subcommand == MiriCommand::Setup {
279274
println!("WARNING: MIRI_SYSROOT already set, not doing anything.")
280275
}
@@ -287,7 +282,7 @@ fn setup(subcommand: MiriCommand) {
287282

288283
// First, we need xargo.
289284
if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) {
290-
if std::env::var("XARGO_CHECK").is_ok() {
285+
if std::env::var_os("XARGO_CHECK").is_some() {
291286
// The user manually gave us a xargo binary; don't do anything automatically.
292287
show_error(format!("Your xargo is too old; please upgrade to the latest version"))
293288
}
@@ -297,11 +292,11 @@ fn setup(subcommand: MiriCommand) {
297292
}
298293

299294
// Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything.
300-
let rust_src = match std::env::var("XARGO_RUST_SRC") {
301-
Ok(val) => PathBuf::from(val),
302-
Err(_) => {
295+
let rust_src = match std::env::var_os("XARGO_RUST_SRC") {
296+
Some(val) => PathBuf::from(val),
297+
None => {
303298
// Check for `rust-src` rustup component.
304-
let sysroot = Command::new("rustc")
299+
let sysroot = rustc()
305300
.args(&["--print", "sysroot"])
306301
.output()
307302
.expect("failed to get rustc sysroot")
@@ -462,6 +457,14 @@ fn in_cargo_miri() {
462457
}
463458
cmd.arg(arg);
464459
}
460+
// We want to always run `cargo` with `--target`. This later helps us detect
461+
// which crates are proc-macro/build-script (host crates) and which crates are
462+
// needed for the program itself.
463+
if get_arg_flag_value("--target").is_none() {
464+
// When no `--target` is given, default to the host.
465+
cmd.arg("--target");
466+
cmd.arg(rustc_version::version_meta().unwrap().host);
467+
}
465468

466469
// Serialize the remaining args into a special environemt variable.
467470
// This will be read by `inside_cargo_rustc` when we go to invoke
@@ -491,24 +494,22 @@ fn in_cargo_miri() {
491494
}
492495

493496
fn inside_cargo_rustc() {
494-
/// Determines if we are being invoked (as rustc) to build a runnable
495-
/// executable. We run "cargo check", so this should only happen when
496-
/// we are trying to compile a build script or build script dependency,
497-
/// which actually needs to be executed on the host platform.
497+
/// Determines if we are being invoked (as rustc) to build a crate for
498+
/// the "target" architecture, in contrast to the "host" architecture.
499+
/// Host crates are for build scripts and proc macros and still need to
500+
/// be built like normal; target crates need to be built for or interpreted
501+
/// by Miri.
498502
///
499-
/// Currently, we detect this by checking for "--emit=link",
500-
/// which indicates that Cargo instruced rustc to output
501-
/// a native object.
503+
/// Currently, we detect this by checking for "--target=", which is
504+
/// never set for host crates. This matches what rustc bootstrap does,
505+
/// which hopefully makes it "reliable enough". This relies on us always
506+
/// invoking cargo itself with `--target`, which `in_cargo_miri` ensures.
502507
fn is_target_crate() -> bool {
503-
// `--emit` is sometimes missing, e.g. cargo calls rustc for "--print".
504-
// That is definitely not a target crate.
505-
// If `--emit` is present, then host crates are built ("--emit=link,...),
506-
// while the rest is only checked.
507-
get_arg_flag_value("--emit").map_or(false, |emit| !emit.contains("link"))
508+
get_arg_flag_value("--target").is_some()
508509
}
509510

510511
/// Returns whether or not Cargo invoked the wrapper (this binary) to compile
511-
/// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run')
512+
/// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run')
512513
/// Cargo does not give us this information directly, so we need to check
513514
/// various command-line flags.
514515
fn is_runnable_crate() -> bool {
@@ -521,7 +522,7 @@ fn inside_cargo_rustc() {
521522
is_bin || is_test
522523
}
523524

524-
let verbose = std::env::var("MIRI_VERBOSE").is_ok();
525+
let verbose = std::env::var_os("MIRI_VERBOSE").is_some();
525526
let target_crate = is_target_crate();
526527

527528
// Figure out which arguments we need to pass.
@@ -530,6 +531,7 @@ fn inside_cargo_rustc() {
530531
// other args for target crates - that is, crates which are ultimately
531532
// going to get interpreted by Miri.
532533
if target_crate {
534+
// FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead).
533535
let sysroot =
534536
std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT");
535537
args.push("--sysroot".to_owned());
@@ -544,14 +546,16 @@ fn inside_cargo_rustc() {
544546
// we want to interpret under Miri. We deserialize the user-provided arguments
545547
// from the special environment variable "MIRI_ARGS", and feed them
546548
// to the 'miri' binary.
549+
//
550+
// `env::var` is okay here, well-formed JSON is always UTF-8.
547551
let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS");
548552
let mut user_args: Vec<String> =
549553
serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS");
550554
args.append(&mut user_args);
551555
// Run this in Miri.
552-
Command::new(find_miri())
556+
miri()
553557
} else {
554-
Command::new("rustc")
558+
rustc()
555559
};
556560

557561
// Run it.

src/bin/miri.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,17 @@ fn init_early_loggers() {
6161
// If it is not set, we avoid initializing now so that we can initialize
6262
// later with our custom settings, and *not* log anything for what happens before
6363
// `miri` gets started.
64-
if env::var("RUSTC_LOG").is_ok() {
64+
if env::var_os("RUSTC_LOG").is_some() {
6565
rustc_driver::init_rustc_env_logger();
6666
}
6767
}
6868

6969
fn init_late_loggers(tcx: TyCtxt<'_>) {
7070
// We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
7171
// env var if it is not set, control it based on `MIRI_LOG`.
72+
// (FIXE: use `var_os`, but then we need to manually concatenate instead of `format!`.)
7273
if let Ok(var) = env::var("MIRI_LOG") {
73-
if env::var("RUSTC_LOG").is_err() {
74+
if env::var_os("RUSTC_LOG").is_none() {
7475
// We try to be a bit clever here: if `MIRI_LOG` is just a single level
7576
// used for everything, we only apply it to the parts of rustc that are
7677
// CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
@@ -90,8 +91,8 @@ fn init_late_loggers(tcx: TyCtxt<'_>) {
9091

9192
// If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
9293
// Do this late, so we ideally only apply this to Miri's errors.
93-
if let Ok(val) = env::var("MIRI_BACKTRACE") {
94-
let ctfe_backtrace = match &*val {
94+
if let Some(val) = env::var_os("MIRI_BACKTRACE") {
95+
let ctfe_backtrace = match &*val.to_string_lossy() {
9596
"immediate" => CtfeBacktrace::Immediate,
9697
"0" => CtfeBacktrace::Disabled,
9798
_ => CtfeBacktrace::Capture,

0 commit comments

Comments
 (0)