@@ -6,7 +6,7 @@ use std::ops::Not;
6
6
use std:: path:: { Path , PathBuf } ;
7
7
use std:: process:: Command ;
8
8
9
- const XARGO_MIN_VERSION : ( u32 , u32 , u32 ) = ( 0 , 3 , 17 ) ;
9
+ const XARGO_MIN_VERSION : ( u32 , u32 , u32 ) = ( 0 , 3 , 19 ) ;
10
10
11
11
const CARGO_MIRI_HELP : & str = r#"Interprets bin crates and tests in Miri
12
12
@@ -84,6 +84,34 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
84
84
}
85
85
}
86
86
87
+
88
+ /// Determines if we are being invoked (as rustc) to build a runnable
89
+ /// executable. We run "cargo check", so this should only happen when
90
+ /// we are trying to compile a build script or build script dependency,
91
+ /// which actually needs to be executed on the host platform.
92
+ ///
93
+ /// Currently, we detect this by checking for "--emit=link",
94
+ /// which indicates that Cargo instruced rustc to output
95
+ /// a native object.
96
+ fn is_build_dep ( ) -> bool {
97
+ std:: env:: args ( ) . any ( |arg| arg. starts_with ( "--emit=" ) && arg. contains ( "link" ) )
98
+ }
99
+
100
+ /// Returns whether or not Cargo invoked the wrapper (this binary) to compile
101
+ /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run')
102
+ /// Cargo does not give us this information directly, so we need to check
103
+ /// various command-line flags.
104
+ fn is_target_crate ( is_build_script : bool ) -> bool {
105
+ let is_bin = get_arg_flag_value ( "--crate-type" ) . as_deref ( ) == Some ( "bin" ) ;
106
+ let is_test = std:: env:: args ( ) . find ( |arg| arg == "--test" ) . is_some ( ) ;
107
+
108
+ // The final runnable (under Miri) crate will either be a binary crate
109
+ // or a test crate. We make sure to exclude build scripts here, since
110
+ // they are also build with "--crate-type bin"
111
+ ( is_bin || is_test) && !is_build_script
112
+ }
113
+
114
+
87
115
fn list_targets ( ) -> impl Iterator < Item = cargo_metadata:: Target > {
88
116
// We need to get the manifest, and then the metadata, to enumerate targets.
89
117
let manifest_path =
@@ -197,7 +225,7 @@ fn xargo() -> Command {
197
225
// Bootstrap tells us where to find xargo
198
226
Command :: new ( val)
199
227
} else {
200
- Command :: new ( "xargo" )
228
+ Command :: new ( "xargo-check " )
201
229
}
202
230
}
203
231
@@ -467,7 +495,7 @@ fn in_cargo_miri() {
467
495
// change to add additional arguments. `FLAGS` is set to identify
468
496
// this target. The user gets to control what gets actually passed to Miri.
469
497
let mut cmd = cargo ( ) ;
470
- cmd. arg ( "rustc " ) ;
498
+ cmd. arg ( "check " ) ;
471
499
match ( subcommand, kind. as_str ( ) ) {
472
500
( MiriCommand :: Run , "bin" ) => {
473
501
// FIXME: we just run all the binaries here.
@@ -494,10 +522,15 @@ fn in_cargo_miri() {
494
522
}
495
523
cmd. arg ( arg) ;
496
524
}
497
- // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the
498
- // user flags to be able to identify them later. "cargo rustc" adds more stuff after this,
499
- // so we have to mark both the beginning and the end.
500
- cmd. arg ( "--" ) . arg ( "cargo-miri-marker-begin" ) . args ( args) . arg ( "cargo-miri-marker-end" ) ;
525
+
526
+ // Serialize our actual args into a special environemt variable.
527
+ // This will be read by `inside_cargo_rustc` when we go to invoke
528
+ // our actual target crate (the binary or the test we are running).
529
+ // Since we're using "cargo check", we have no other way of passing
530
+ // these arguments.
531
+ let args_vec: Vec < String > = args. collect ( ) ;
532
+ cmd. env ( "MIRI_MAGIC_ARGS" , serde_json:: to_string ( & args_vec) . expect ( "failed to serialize args" ) ) ;
533
+
501
534
let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
502
535
cmd. env ( "RUSTC_WRAPPER" , path) ;
503
536
if verbose {
@@ -517,25 +550,32 @@ fn inside_cargo_rustc() {
517
550
let sysroot = std:: env:: var ( "MIRI_SYSROOT" ) . expect ( "The wrapper should have set MIRI_SYSROOT" ) ;
518
551
519
552
let rustc_args = std:: env:: args ( ) . skip ( 2 ) ; // skip `cargo rustc`
520
- let mut args: Vec < String > =
521
- rustc_args. chain ( Some ( "--sysroot" . to_owned ( ) ) ) . chain ( Some ( sysroot) ) . collect ( ) ;
522
- args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
523
553
524
- // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to
525
- // run. They also serve to mark the user-defined arguments, which we have to move all the way
526
- // to the end (they get added somewhere in the middle).
554
+ let in_build_script = is_build_dep ( ) ;
555
+
556
+ // Build scripts need to be compiled to actual runnable executables,
557
+ // and therefore completely bypass Miri. We make sure to only specify
558
+ // our custom Xargo sysroot for non-build-script crate - that is,
559
+ // crates which are ultimately going to get interpreted by Miri.
560
+ let mut args = if in_build_script {
561
+ rustc_args. collect ( )
562
+ } else {
563
+ let mut args: Vec < String > = rustc_args
564
+ . chain ( Some ( "--sysroot" . to_owned ( ) ) )
565
+ . chain ( Some ( sysroot) )
566
+ . collect ( ) ;
567
+ args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
568
+ args
569
+ } ;
570
+
527
571
let needs_miri =
528
- if let Some ( begin) = args. iter ( ) . position ( |arg| arg == "cargo-miri-marker-begin" ) {
529
- let end = args
530
- . iter ( )
531
- . position ( |arg| arg == "cargo-miri-marker-end" )
532
- . expect ( "cannot find end marker" ) ;
533
- // These mark the user arguments. We remove the first and last as they are the markers.
534
- let mut user_args = args. drain ( begin..=end) ;
535
- assert_eq ! ( user_args. next( ) . unwrap( ) , "cargo-miri-marker-begin" ) ;
536
- assert_eq ! ( user_args. next_back( ) . unwrap( ) , "cargo-miri-marker-end" ) ;
537
- // Collect the rest and add it back at the end.
538
- let mut user_args = user_args. collect :: < Vec < String > > ( ) ;
572
+ if is_target_crate ( in_build_script) {
573
+ // This is the 'target crate '- the binary or test crate that
574
+ // we want to interpret under Miri. We deserialize the user-provided arguments
575
+ // from the special environment variable "MIRI_MAGIC_ARGS", and feed them
576
+ // to the 'miri' binary.
577
+ let magic = std:: env:: var ( "MIRI_MAGIC_ARGS" ) . expect ( "missing MIRI_MAGIC_ARGS" ) ;
578
+ let mut user_args: Vec < String > = serde_json:: from_str ( & magic) . expect ( "failed to deserialize args" ) ;
539
579
args. append ( & mut user_args) ;
540
580
// Run this in Miri.
541
581
true
0 commit comments