Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit dd01870

Browse files
committed
cargo-miri: use '--config target.runner' rather than the TARGET_RUNNER env vars
1 parent b2418e8 commit dd01870

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

cargo-miri/bin.rs

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::ffi::{OsStr, OsString};
99
use std::fmt::Write as _;
1010
use std::fs::{self, File};
1111
use std::io::{self, BufRead, BufReader, BufWriter, Read, Write};
12-
use std::iter::TakeWhile;
12+
use std::iter::{self, TakeWhile};
1313
use std::ops::Not;
1414
use std::path::{Path, PathBuf};
1515
use std::process::{self, Command};
@@ -206,6 +206,14 @@ fn forward_miri_sysroot(cmd: &mut Command) {
206206
cmd.arg(sysroot);
207207
}
208208

209+
/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
210+
fn escape_for_toml(s: &str) -> String {
211+
// We want to surround this string in quotes `"`. So we first escape all quotes,
212+
// and also all backslashes (that are used to escape quotes).
213+
let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#);
214+
format!("\"{}\"", s)
215+
}
216+
209217
/// Returns the path to the `miri` binary
210218
fn find_miri() -> PathBuf {
211219
if let Some(path) = env::var_os("MIRI") {
@@ -669,7 +677,11 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
669677
// <https://github.com/rust-lang/miri/pull/1540#issuecomment-693553191> describes an alternative
670678
// approach that uses `cargo check`, making that part easier but target and binary handling
671679
// harder.
672-
let cargo_miri_path = std::env::current_exe().expect("current executable path invalid");
680+
let cargo_miri_path = std::env::current_exe()
681+
.expect("current executable path invalid")
682+
.into_os_string()
683+
.into_string()
684+
.expect("current executable path is not valid UTF-8");
673685
let cargo_cmd = match subcommand {
674686
MiriCommand::Forward(s) => s,
675687
MiriCommand::Setup => return, // `cargo miri setup` stops here.
@@ -699,8 +711,8 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
699711
target_dir.push("miri");
700712
cmd.arg("--target-dir").arg(target_dir);
701713

702-
// Make sure we know the build target, and cargo does, too.
703-
// This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something,
714+
// Make sure the build target is explicitly set.
715+
// This is needed to make the `target.runner` settings do something,
704716
// and it later helps us detect which crates are proc-macro/build-script
705717
// (host crates) and which crates are needed for the program itself.
706718
let host = version_info().host;
@@ -714,6 +726,18 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
714726
&host
715727
};
716728

729+
let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path);
730+
cmd.arg("--config")
731+
.arg(format!("target.{target}.runner=[{cargo_miri_path_for_toml}, 'runner']",));
732+
if &host != target {
733+
// Set ourselves as runner for host and target. (Unit tests of `proc-macro` crates are run on
734+
// the host, so we set the host runner to us in order to skip them.)
735+
// But only do that if host and target are different; setting this command twice otherwise
736+
// makes cargo concatenate the two arrays.
737+
cmd.arg("--config")
738+
.arg(format!("target.{host}.runner=[{cargo_miri_path_for_toml}, 'runner']",));
739+
}
740+
717741
// Forward all further arguments after `--` to cargo.
718742
cmd.arg("--").args(args);
719743

@@ -743,16 +767,6 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
743767
// bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds.
744768
cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap());
745769

746-
let runner_env_name =
747-
|triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_"));
748-
let host_runner_env_name = runner_env_name(&host);
749-
let target_runner_env_name = runner_env_name(target);
750-
// Set the target runner to us, so we can interpret the binaries.
751-
cmd.env(&target_runner_env_name, &cargo_miri_path);
752-
// Unit tests of `proc-macro` crates are run on the host, so we set the host runner to
753-
// us in order to skip them.
754-
cmd.env(&host_runner_env_name, &cargo_miri_path);
755-
756770
// Set rustdoc to us as well, so we can run doctests.
757771
cmd.env("RUSTDOC", &cargo_miri_path);
758772

@@ -1194,38 +1208,25 @@ fn main() {
11941208
return;
11951209
}
11961210

1197-
let mut args = args.peekable();
1198-
if args.next_if(|a| a == "miri").is_some() {
1199-
phase_cargo_miri(args);
1200-
} else if let Some(arg) = args.peek().cloned() {
1201-
// Cargo calls us for everything it does. We could be invoked as rustc, rustdoc, or the runner.
1202-
1203-
// If the first arg is equal to the RUSTC variable (which should be set at this point),
1204-
// then we need to behave as rustc. This is the somewhat counter-intuitive behavior of
1205-
// having both RUSTC and RUSTC_WRAPPER set (see
1206-
// https://github.com/rust-lang/cargo/issues/10886).
1207-
if arg == env::var("RUSTC").unwrap() {
1208-
args.next().unwrap(); // consume wrapped RUSTC command.
1209-
return phase_rustc(args, RustcPhase::Build);
1210-
}
1211-
// We have to distinguish the "runner" and "rustdoc" cases.
1212-
// As runner, the first argument is the binary (a file that should exist, with an absolute path);
1213-
// as rustdoc, the first argument is a flag (`--something`).
1214-
let binary = Path::new(&arg);
1215-
if binary.exists() {
1216-
assert!(!arg.starts_with("--")); // not a flag
1217-
phase_runner(args, RunnerPhase::Cargo);
1218-
} else if arg.starts_with("--") {
1219-
phase_rustdoc(args);
1220-
} else {
1221-
show_error(format!(
1222-
"`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`",
1223-
arg
1224-
));
1225-
}
1226-
} else {
1211+
let Some(first) = args.next() else {
12271212
show_error(format!(
12281213
"`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`"
1229-
));
1214+
))
1215+
};
1216+
match first.as_str() {
1217+
"miri" => phase_cargo_miri(args),
1218+
"runner" => phase_runner(args, RunnerPhase::Cargo),
1219+
arg if arg == env::var("RUSTC").unwrap() => {
1220+
// If the first arg is equal to the RUSTC env ariable (which should be set at this
1221+
// point), then we need to behave as rustc. This is the somewhat counter-intuitive
1222+
// behavior of having both RUSTC and RUSTC_WRAPPER set
1223+
// (see https://github.com/rust-lang/cargo/issues/10886).
1224+
phase_rustc(args, RustcPhase::Build)
1225+
}
1226+
_ => {
1227+
// Everything else must be rustdoc. But we need to get `first` "back onto the iterator",
1228+
// it is some part of the rustdoc invocation.
1229+
phase_rustdoc(iter::once(first).chain(args));
1230+
}
12301231
}
12311232
}

0 commit comments

Comments
 (0)