@@ -6,6 +6,7 @@ use std::io::{self, BufRead, Write};
66use std:: ops:: Not ;
77use std:: path:: { Path , PathBuf } ;
88use std:: process:: Command ;
9+ use std:: ffi:: OsString ;
910
1011const 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
9596fn 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
104100fn 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
113108fn 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.
276271fn 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
493496fn 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.
0 commit comments