@@ -9,7 +9,7 @@ use std::ffi::{OsStr, OsString};
9
9
use std:: fmt:: Write as _;
10
10
use std:: fs:: { self , File } ;
11
11
use std:: io:: { self , BufRead , BufReader , BufWriter , Read , Write } ;
12
- use std:: iter:: TakeWhile ;
12
+ use std:: iter:: { self , TakeWhile } ;
13
13
use std:: ops:: Not ;
14
14
use std:: path:: { Path , PathBuf } ;
15
15
use std:: process:: { self , Command } ;
@@ -206,6 +206,14 @@ fn forward_miri_sysroot(cmd: &mut Command) {
206
206
cmd. arg ( sysroot) ;
207
207
}
208
208
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
+
209
217
/// Returns the path to the `miri` binary
210
218
fn find_miri ( ) -> PathBuf {
211
219
if let Some ( path) = env:: var_os ( "MIRI" ) {
@@ -669,7 +677,11 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
669
677
// <https://github.com/rust-lang/miri/pull/1540#issuecomment-693553191> describes an alternative
670
678
// approach that uses `cargo check`, making that part easier but target and binary handling
671
679
// 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" ) ;
673
685
let cargo_cmd = match subcommand {
674
686
MiriCommand :: Forward ( s) => s,
675
687
MiriCommand :: Setup => return , // `cargo miri setup` stops here.
@@ -699,8 +711,8 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
699
711
target_dir. push ( "miri" ) ;
700
712
cmd. arg ( "--target-dir" ) . arg ( target_dir) ;
701
713
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,
704
716
// and it later helps us detect which crates are proc-macro/build-script
705
717
// (host crates) and which crates are needed for the program itself.
706
718
let host = version_info ( ) . host ;
@@ -714,6 +726,18 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
714
726
& host
715
727
} ;
716
728
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
+
717
741
// Forward all further arguments after `--` to cargo.
718
742
cmd. arg ( "--" ) . args ( args) ;
719
743
@@ -743,16 +767,6 @@ fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
743
767
// bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds.
744
768
cmd. env ( "RUSTC" , & fs:: canonicalize ( find_miri ( ) ) . unwrap ( ) ) ;
745
769
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
-
756
770
// Set rustdoc to us as well, so we can run doctests.
757
771
cmd. env ( "RUSTDOC" , & cargo_miri_path) ;
758
772
@@ -1194,38 +1208,25 @@ fn main() {
1194
1208
return ;
1195
1209
}
1196
1210
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 {
1227
1212
show_error ( format ! (
1228
1213
"`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
+ }
1230
1231
}
1231
1232
}
0 commit comments