@@ -6,6 +6,7 @@ use std::io::{self, BufRead, Write};
6
6
use std:: ops:: Not ;
7
7
use std:: path:: { Path , PathBuf } ;
8
8
use std:: process:: Command ;
9
+ use std:: ffi:: OsString ;
9
10
10
11
const XARGO_MIN_VERSION : ( u32 , u32 , u32 ) = ( 0 , 3 , 20 ) ;
11
12
@@ -85,29 +86,23 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
85
86
}
86
87
}
87
88
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 {
90
91
let mut path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
91
92
path. set_file_name ( "miri" ) ;
92
- path
93
+ Command :: new ( path)
93
94
}
94
95
95
96
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" ) ) )
102
98
}
103
99
104
100
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" ) ) )
111
106
}
112
107
113
108
fn list_targets ( ) -> impl Iterator < Item = cargo_metadata:: Target > {
@@ -188,8 +183,8 @@ fn test_sysroot_consistency() {
188
183
return ;
189
184
}
190
185
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 ( ) ) ;
193
188
194
189
if rustc_sysroot != miri_sysroot {
195
190
show_error ( format ! (
@@ -274,7 +269,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) {
274
269
/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has
275
270
/// done all this already.
276
271
fn setup ( subcommand : MiriCommand ) {
277
- if std:: env:: var ( "MIRI_SYSROOT" ) . is_ok ( ) {
272
+ if std:: env:: var_os ( "MIRI_SYSROOT" ) . is_some ( ) {
278
273
if subcommand == MiriCommand :: Setup {
279
274
println ! ( "WARNING: MIRI_SYSROOT already set, not doing anything." )
280
275
}
@@ -287,7 +282,7 @@ fn setup(subcommand: MiriCommand) {
287
282
288
283
// First, we need xargo.
289
284
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 ( ) {
291
286
// The user manually gave us a xargo binary; don't do anything automatically.
292
287
show_error ( format ! ( "Your xargo is too old; please upgrade to the latest version" ) )
293
288
}
@@ -297,11 +292,11 @@ fn setup(subcommand: MiriCommand) {
297
292
}
298
293
299
294
// 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 => {
303
298
// Check for `rust-src` rustup component.
304
- let sysroot = Command :: new ( " rustc" )
299
+ let sysroot = rustc ( )
305
300
. args ( & [ "--print" , "sysroot" ] )
306
301
. output ( )
307
302
. expect ( "failed to get rustc sysroot" )
@@ -462,6 +457,14 @@ fn in_cargo_miri() {
462
457
}
463
458
cmd. arg ( arg) ;
464
459
}
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
+ }
465
468
466
469
// Serialize the remaining args into a special environemt variable.
467
470
// This will be read by `inside_cargo_rustc` when we go to invoke
@@ -491,24 +494,22 @@ fn in_cargo_miri() {
491
494
}
492
495
493
496
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.
498
502
///
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.
502
507
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 ( )
508
509
}
509
510
510
511
/// 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')
512
513
/// Cargo does not give us this information directly, so we need to check
513
514
/// various command-line flags.
514
515
fn is_runnable_crate ( ) -> bool {
@@ -521,7 +522,7 @@ fn inside_cargo_rustc() {
521
522
is_bin || is_test
522
523
}
523
524
524
- let verbose = std:: env:: var ( "MIRI_VERBOSE" ) . is_ok ( ) ;
525
+ let verbose = std:: env:: var_os ( "MIRI_VERBOSE" ) . is_some ( ) ;
525
526
let target_crate = is_target_crate ( ) ;
526
527
527
528
// Figure out which arguments we need to pass.
@@ -530,6 +531,7 @@ fn inside_cargo_rustc() {
530
531
// other args for target crates - that is, crates which are ultimately
531
532
// going to get interpreted by Miri.
532
533
if target_crate {
534
+ // FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead).
533
535
let sysroot =
534
536
std:: env:: var ( "MIRI_SYSROOT" ) . expect ( "The wrapper should have set MIRI_SYSROOT" ) ;
535
537
args. push ( "--sysroot" . to_owned ( ) ) ;
@@ -544,14 +546,16 @@ fn inside_cargo_rustc() {
544
546
// we want to interpret under Miri. We deserialize the user-provided arguments
545
547
// from the special environment variable "MIRI_ARGS", and feed them
546
548
// to the 'miri' binary.
549
+ //
550
+ // `env::var` is okay here, well-formed JSON is always UTF-8.
547
551
let magic = std:: env:: var ( "MIRI_ARGS" ) . expect ( "missing MIRI_ARGS" ) ;
548
552
let mut user_args: Vec < String > =
549
553
serde_json:: from_str ( & magic) . expect ( "failed to deserialize MIRI_ARGS" ) ;
550
554
args. append ( & mut user_args) ;
551
555
// Run this in Miri.
552
- Command :: new ( find_miri ( ) )
556
+ miri ( )
553
557
} else {
554
- Command :: new ( " rustc" )
558
+ rustc ( )
555
559
} ;
556
560
557
561
// Run it.
0 commit comments