@@ -23,7 +23,7 @@ Common options:
2323 --features Features to compile for the package
2424 -V, --version Print version info and exit
2525
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
2727passed verbatim to Miri, which will pass everything after the second "--" verbatim
2828to the interpreted program.
2929"# ;
@@ -84,33 +84,30 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
8484 }
8585}
8686
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
9892}
9993
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+ }
112101}
113102
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+ }
114111
115112fn list_targets ( ) -> impl Iterator < Item = cargo_metadata:: Target > {
116113 // 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> {
155152 package. targets . into_iter ( )
156153}
157154
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-
165155/// Make sure that the `miri` and `rustc` binary are from the same sysroot.
166156/// This can be violated e.g. when miri is locally built and installed with a different
167157/// toolchain than what is used when `cargo miri` is run.
@@ -211,24 +201,6 @@ fn test_sysroot_consistency() {
211201 }
212202}
213203
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-
232204fn xargo_version ( ) -> Option < ( u32 , u32 , u32 ) > {
233205 let out = xargo ( ) . arg ( "--version" ) . output ( ) . ok ( ) ?;
234206 if !out. status . success ( ) {
@@ -385,6 +357,7 @@ features = ["panic_unwind"]
385357 )
386358 . unwrap ( ) ;
387359 // The boring bits: a dummy project for xargo.
360+ // FIXME: With xargo-check, can we avoid doing this?
388361 File :: create ( dir. join ( "Cargo.toml" ) )
389362 . unwrap ( )
390363 . write_all (
@@ -447,12 +420,12 @@ fn main() {
447420 }
448421
449422 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,
451424 // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch,
452425 // and dispatch the invocations to `rustc` and `miri`, respectively.
453426 in_cargo_miri ( ) ;
454427 } 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:
456429 // dependencies get dispatched to `rustc`, the final test/binary to `miri`.
457430 inside_cargo_rustc ( ) ;
458431 } else {
@@ -491,7 +464,7 @@ fn in_cargo_miri() {
491464 . kind
492465 . get ( 0 )
493466 . 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
495468 // change to add additional arguments. `FLAGS` is set to identify
496469 // this target. The user gets to control what gets actually passed to Miri.
497470 let mut cmd = cargo ( ) ;
@@ -515,25 +488,29 @@ fn in_cargo_miri() {
515488 // The remaining targets we do not even want to build.
516489 _ => continue ,
517490 }
518- // Add user-defined args until first `--`.
491+ // Forward user-defined `cargo` args until first `--`.
519492 while let Some ( arg) = args. next ( ) {
520493 if arg == "--" {
521494 break ;
522495 }
523496 cmd. arg ( arg) ;
524497 }
525498
526- // Serialize our actual args into a special environemt variable.
499+ // Serialize the remaining args into a special environemt variable.
527500 // This will be read by `inside_cargo_rustc` when we go to invoke
528501 // our actual target crate (the binary or the test we are running).
529502 // Since we're using "cargo check", we have no other way of passing
530503 // these arguments.
531504 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" ) ) ;
533506
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.
534510 let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
535511 cmd. env ( "RUSTC_WRAPPER" , path) ;
536512 if verbose {
513+ cmd. env ( "MIRI_VERBOSE" , "" ) ; // this makes `inside_cargo_rustc` verbose.
537514 eprintln ! ( "+ {:?}" , cmd) ;
538515 }
539516
@@ -547,45 +524,71 @@ fn in_cargo_miri() {
547524}
548525
549526fn 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+ }
553542
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+ }
555556
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) ;
567569 args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
568- args
569- } ;
570+ }
570571
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
574577 // 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
576579 // 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 " ) ;
579582 args. append ( & mut user_args) ;
580583 // Run this in Miri.
581- true
584+ Command :: new ( find_miri ( ) )
582585 } else {
583- false
586+ Command :: new ( "rustc" )
584587 } ;
585588
586- let mut command = if needs_miri { Command :: new ( find_miri ( ) ) } else { Command :: new ( "rustc" ) } ;
589+ // Run it.
587590 command. args ( & args) ;
588- if has_arg_flag ( "-v" ) {
591+ if verbose {
589592 eprintln ! ( "+ {:?}" , command) ;
590593 }
591594
@@ -594,7 +597,6 @@ fn inside_cargo_rustc() {
594597 if !exit. success ( ) {
595598 std:: process:: exit ( exit. code ( ) . unwrap_or ( 42 ) ) ;
596599 } ,
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) ,
599601 }
600602}
0 commit comments