@@ -23,7 +23,7 @@ Common options:
23
23
--features Features to compile for the package
24
24
-V, --version Print version info and exit
25
25
26
- Other [options] are the same as `cargo rustc `. Everything after the first "--" is
26
+ Other [options] are the same as `cargo check `. Everything after the first "--" is
27
27
passed verbatim to Miri, which will pass everything after the second "--" verbatim
28
28
to the interpreted program.
29
29
"# ;
@@ -84,33 +84,30 @@ 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" ) )
87
+ /// Returns the path to the `miri` binary
88
+ fn find_miri ( ) -> PathBuf {
89
+ let mut path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
90
+ path. set_file_name ( "miri" ) ;
91
+ path
98
92
}
99
93
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
94
+ fn cargo ( ) -> Command {
95
+ if let Ok ( val) = std:: env:: var ( "CARGO" ) {
96
+ // Bootstrap tells us where to find cargo
97
+ Command :: new ( val)
98
+ } else {
99
+ Command :: new ( "cargo" )
100
+ }
112
101
}
113
102
103
+ fn xargo ( ) -> Command {
104
+ if let Ok ( val) = std:: env:: var ( "XARGO" ) {
105
+ // Bootstrap tells us where to find xargo
106
+ Command :: new ( val)
107
+ } else {
108
+ Command :: new ( "xargo-check" )
109
+ }
110
+ }
114
111
115
112
fn list_targets ( ) -> impl Iterator < Item = cargo_metadata:: Target > {
116
113
// We need to get the manifest, and then the metadata, to enumerate targets.
@@ -155,13 +152,6 @@ fn list_targets() -> impl Iterator<Item = cargo_metadata::Target> {
155
152
package. targets . into_iter ( )
156
153
}
157
154
158
- /// Returns the path to the `miri` binary
159
- fn find_miri ( ) -> PathBuf {
160
- let mut path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
161
- path. set_file_name ( "miri" ) ;
162
- path
163
- }
164
-
165
155
/// Make sure that the `miri` and `rustc` binary are from the same sysroot.
166
156
/// This can be violated e.g. when miri is locally built and installed with a different
167
157
/// toolchain than what is used when `cargo miri` is run.
@@ -211,24 +201,6 @@ fn test_sysroot_consistency() {
211
201
}
212
202
}
213
203
214
- fn cargo ( ) -> Command {
215
- if let Ok ( val) = std:: env:: var ( "CARGO" ) {
216
- // Bootstrap tells us where to find cargo
217
- Command :: new ( val)
218
- } else {
219
- Command :: new ( "cargo" )
220
- }
221
- }
222
-
223
- fn xargo ( ) -> Command {
224
- if let Ok ( val) = std:: env:: var ( "XARGO" ) {
225
- // Bootstrap tells us where to find xargo
226
- Command :: new ( val)
227
- } else {
228
- Command :: new ( "xargo-check" )
229
- }
230
- }
231
-
232
204
fn xargo_version ( ) -> Option < ( u32 , u32 , u32 ) > {
233
205
let out = xargo ( ) . arg ( "--version" ) . output ( ) . ok ( ) ?;
234
206
if !out. status . success ( ) {
@@ -385,6 +357,7 @@ features = ["panic_unwind"]
385
357
)
386
358
. unwrap ( ) ;
387
359
// The boring bits: a dummy project for xargo.
360
+ // FIXME: With xargo-check, can we avoid doing this?
388
361
File :: create ( dir. join ( "Cargo.toml" ) )
389
362
. unwrap ( )
390
363
. write_all (
@@ -447,12 +420,12 @@ fn main() {
447
420
}
448
421
449
422
if let Some ( "miri" ) = std:: env:: args ( ) . nth ( 1 ) . as_ref ( ) . map ( AsRef :: as_ref) {
450
- // This arm is for when `cargo miri` is called. We call `cargo rustc ` for each applicable target,
423
+ // This arm is for when `cargo miri` is called. We call `cargo check ` for each applicable target,
451
424
// but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch,
452
425
// and dispatch the invocations to `rustc` and `miri`, respectively.
453
426
in_cargo_miri ( ) ;
454
427
} else if let Some ( "rustc" ) = std:: env:: args ( ) . nth ( 1 ) . as_ref ( ) . map ( AsRef :: as_ref) {
455
- // This arm is executed when `cargo-miri` runs `cargo rustc ` with the `RUSTC_WRAPPER` env var set to itself:
428
+ // This arm is executed when `cargo-miri` runs `cargo check ` with the `RUSTC_WRAPPER` env var set to itself:
456
429
// dependencies get dispatched to `rustc`, the final test/binary to `miri`.
457
430
inside_cargo_rustc ( ) ;
458
431
} else {
@@ -491,7 +464,7 @@ fn in_cargo_miri() {
491
464
. kind
492
465
. get ( 0 )
493
466
. expect ( "badly formatted cargo metadata: target::kind is an empty array" ) ;
494
- // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the
467
+ // Now we run `cargo check $FLAGS $ARGS`, giving the user the
495
468
// change to add additional arguments. `FLAGS` is set to identify
496
469
// this target. The user gets to control what gets actually passed to Miri.
497
470
let mut cmd = cargo ( ) ;
@@ -515,25 +488,29 @@ fn in_cargo_miri() {
515
488
// The remaining targets we do not even want to build.
516
489
_ => continue ,
517
490
}
518
- // Add user-defined args until first `--`.
491
+ // Forward user-defined `cargo` args until first `--`.
519
492
while let Some ( arg) = args. next ( ) {
520
493
if arg == "--" {
521
494
break ;
522
495
}
523
496
cmd. arg ( arg) ;
524
497
}
525
498
526
- // Serialize our actual args into a special environemt variable.
499
+ // Serialize the remaining args into a special environemt variable.
527
500
// This will be read by `inside_cargo_rustc` when we go to invoke
528
501
// our actual target crate (the binary or the test we are running).
529
502
// Since we're using "cargo check", we have no other way of passing
530
503
// these arguments.
531
504
let args_vec: Vec < String > = args. collect ( ) ;
532
- cmd. env ( "MIRI_MAGIC_ARGS " , serde_json:: to_string ( & args_vec) . expect ( "failed to serialize args" ) ) ;
505
+ cmd. env ( "MIRI_ARGS " , serde_json:: to_string ( & args_vec) . expect ( "failed to serialize args" ) ) ;
533
506
507
+ // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation,
508
+ // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish
509
+ // the two codepaths.
534
510
let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
535
511
cmd. env ( "RUSTC_WRAPPER" , path) ;
536
512
if verbose {
513
+ cmd. env ( "MIRI_VERBOSE" , "" ) ; // this makes `inside_cargo_rustc` verbose.
537
514
eprintln ! ( "+ {:?}" , cmd) ;
538
515
}
539
516
@@ -547,45 +524,71 @@ fn in_cargo_miri() {
547
524
}
548
525
549
526
fn inside_cargo_rustc ( ) {
550
- let sysroot = std:: env:: var ( "MIRI_SYSROOT" ) . expect ( "The wrapper should have set MIRI_SYSROOT" ) ;
551
-
552
- let rustc_args = std:: env:: args ( ) . skip ( 2 ) ; // skip `cargo rustc`
527
+ /// Determines if we are being invoked (as rustc) to build a runnable
528
+ /// executable. We run "cargo check", so this should only happen when
529
+ /// we are trying to compile a build script or build script dependency,
530
+ /// which actually needs to be executed on the host platform.
531
+ ///
532
+ /// Currently, we detect this by checking for "--emit=link",
533
+ /// which indicates that Cargo instruced rustc to output
534
+ /// a native object.
535
+ fn is_target_crate ( ) -> bool {
536
+ // `--emit` is sometimes missing, e.g. cargo calls rustc for "--print".
537
+ // That is definitely not a target crate.
538
+ // If `--emit` is present, then host crates are built ("--emit=link,...),
539
+ // while the rest is only checked.
540
+ get_arg_flag_value ( "--emit" ) . map_or ( false , |emit| !emit. contains ( "link" ) )
541
+ }
553
542
554
- let in_build_script = is_build_dep ( ) ;
543
+ /// Returns whether or not Cargo invoked the wrapper (this binary) to compile
544
+ /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run')
545
+ /// Cargo does not give us this information directly, so we need to check
546
+ /// various command-line flags.
547
+ fn is_runnable_crate ( ) -> bool {
548
+ let is_bin = get_arg_flag_value ( "--crate-type" ) . as_deref ( ) == Some ( "bin" ) ;
549
+ let is_test = has_arg_flag ( "--test" ) ;
550
+
551
+ // The final runnable (under Miri) crate will either be a binary crate
552
+ // or a test crate. We make sure to exclude build scripts here, since
553
+ // they are also build with "--crate-type bin"
554
+ is_bin || is_test
555
+ }
555
556
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 ( ) ;
557
+ let verbose = std:: env:: var ( "MIRI_VERBOSE" ) . is_ok ( ) ;
558
+ let target_crate = is_target_crate ( ) ;
559
+
560
+ // Figure out which arguments we need to pass.
561
+ let mut args: Vec < String > = std:: env:: args ( ) . skip ( 2 ) . collect ( ) ; // skip `cargo-miri rustc`
562
+ // We make sure to only specify our custom Xargo sysroot and
563
+ // other args for target crates - that is, crates which are ultimately
564
+ // going to get interpreted by Miri.
565
+ if target_crate {
566
+ let sysroot = std:: env:: var ( "MIRI_SYSROOT" ) . expect ( "The wrapper should have set MIRI_SYSROOT" ) ;
567
+ args. push ( "--sysroot" . to_owned ( ) ) ;
568
+ args. push ( sysroot) ;
567
569
args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
568
- args
569
- } ;
570
+ }
570
571
571
- let needs_miri =
572
- if is_target_crate ( in_build_script) {
573
- // This is the 'target crate '- the binary or test crate that
572
+ // Figure out the binary we need to call. If this is a runnable target crate, we want to call
573
+ // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual.
574
+ let mut command =
575
+ if target_crate && is_runnable_crate ( ) {
576
+ // This is the 'target crate' - the binary or test crate that
574
577
// we want to interpret under Miri. We deserialize the user-provided arguments
575
- // from the special environment variable "MIRI_MAGIC_ARGS ", and feed them
578
+ // from the special environment variable "MIRI_ARGS ", and feed them
576
579
// 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 " ) ;
580
+ let magic = std:: env:: var ( "MIRI_ARGS " ) . expect ( "missing MIRI_ARGS " ) ;
581
+ let mut user_args: Vec < String > = serde_json:: from_str ( & magic) . expect ( "failed to deserialize MIRI_ARGS " ) ;
579
582
args. append ( & mut user_args) ;
580
583
// Run this in Miri.
581
- true
584
+ Command :: new ( find_miri ( ) )
582
585
} else {
583
- false
586
+ Command :: new ( "rustc" )
584
587
} ;
585
588
586
- let mut command = if needs_miri { Command :: new ( find_miri ( ) ) } else { Command :: new ( "rustc" ) } ;
589
+ // Run it.
587
590
command. args ( & args) ;
588
- if has_arg_flag ( "-v" ) {
591
+ if verbose {
589
592
eprintln ! ( "+ {:?}" , command) ;
590
593
}
591
594
@@ -594,7 +597,6 @@ fn inside_cargo_rustc() {
594
597
if !exit. success ( ) {
595
598
std:: process:: exit ( exit. code ( ) . unwrap_or ( 42 ) ) ;
596
599
} ,
597
- Err ( ref e) if needs_miri => panic ! ( "error during miri run: {:?}" , e) ,
598
- Err ( ref e) => panic ! ( "error during rustc call: {:?}" , e) ,
600
+ Err ( ref e) => panic ! ( "error running {:?}:\n {:?}" , command, e) ,
599
601
}
600
602
}
0 commit comments