33extern crate cargo_metadata;
44
55use std:: path:: { PathBuf , Path } ;
6- use std:: io:: { self , Write } ;
6+ use std:: io:: { self , Write , BufRead } ;
77use std:: process:: Command ;
88use std:: fs:: { self , File } ;
99
@@ -114,6 +114,42 @@ fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
114114 package. targets . into_iter ( )
115115}
116116
117+ fn xargo_version ( ) -> Option < ( u32 , u32 , u32 ) > {
118+ let out = Command :: new ( "xargo" ) . arg ( "--version" ) . output ( ) . ok ( ) ?;
119+ if !out. status . success ( ) {
120+ return None ;
121+ }
122+ // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)".
123+ let line = out. stderr . lines ( ) . nth ( 0 )
124+ . expect ( "malformed `xargo --version` output: not at least one line" )
125+ . expect ( "malformed `xargo --version` output: error reading first line" ) ;
126+ let ( name, version) = {
127+ let mut split = line. split ( ' ' ) ;
128+ ( split. next ( ) . expect ( "malformed `xargo --version` output: empty" ) ,
129+ split. next ( ) . expect ( "malformed `xargo --version` output: not at least two words" ) )
130+ } ;
131+ if name != "xargo" {
132+ panic ! ( "malformed `xargo --version` output: application name is not `xargo`" ) ;
133+ }
134+ let mut version_pieces = version. split ( '.' ) ;
135+ let major = version_pieces. next ( )
136+ . expect ( "malformed `xargo --version` output: not a major version piece" )
137+ . parse ( )
138+ . expect ( "malformed `xargo --version` output: major version is not an integer" ) ;
139+ let minor = version_pieces. next ( )
140+ . expect ( "malformed `xargo --version` output: not a minor version piece" )
141+ . parse ( )
142+ . expect ( "malformed `xargo --version` output: minor version is not an integer" ) ;
143+ let patch = version_pieces. next ( )
144+ . expect ( "malformed `xargo --version` output: not a patch version piece" )
145+ . parse ( )
146+ . expect ( "malformed `xargo --version` output: patch version is not an integer" ) ;
147+ if !version_pieces. next ( ) . is_none ( ) {
148+ panic ! ( "malformed `xargo --version` output: more than three pieces in version" ) ;
149+ }
150+ Some ( ( major, minor, patch) )
151+ }
152+
117153fn ask ( question : & str ) {
118154 let mut buf = String :: new ( ) ;
119155 print ! ( "{} [Y/n] " , question) ;
@@ -134,14 +170,14 @@ fn setup(ask_user: bool) {
134170 }
135171
136172 // First, we need xargo
137- if Command :: new ( " xargo" ) . arg ( "--version" ) . output ( ) . is_err ( )
138- {
173+ let xargo = xargo_version ( ) ;
174+ if xargo . map_or ( true , |v| v < ( 0 , 3 , 13 ) ) {
139175 if ask_user {
140- ask ( "It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?" ) ;
176+ ask ( "It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f `. Proceed?" ) ;
141177 } else {
142- println ! ( "Installing xargo: `cargo install xargo`" ) ;
178+ println ! ( "Installing xargo: `cargo install xargo -f `" ) ;
143179 }
144- if !Command :: new ( "cargo" ) . args ( & [ "install" , "xargo" ] ) . status ( ) . unwrap ( ) . success ( ) {
180+ if !Command :: new ( "cargo" ) . args ( & [ "install" , "xargo" , "-f" ] ) . status ( ) . unwrap ( ) . success ( ) {
145181 show_error ( format ! ( "Failed to install xargo" ) ) ;
146182 }
147183 }
@@ -279,9 +315,8 @@ fn main() {
279315 ( MiriCommand :: Test , "lib" ) => {
280316 // For libraries we call `cargo rustc -- --test <rustc args>`
281317 // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
282- // rustc to build a test harness which calls all #[test] functions. We don't
283- // use the harness since we execute each #[test] function's MIR ourselves before
284- // compilation even completes, but this option is necessary to build the library.
318+ // rustc to build a test harness which calls all #[test] functions.
319+ // We then execute that harness just like any other binary.
285320 if let Err ( code) = process (
286321 vec ! [ "--" . to_string( ) , "--test" . to_string( ) ] . into_iter ( ) . chain (
287322 args,
@@ -305,8 +340,8 @@ fn main() {
305340 _ => { }
306341 }
307342 }
308- } else {
309- // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC ` env var set to itself:
343+ } else if let Some ( "rustc" ) = std :: env :: args ( ) . nth ( 1 ) . as_ref ( ) . map ( AsRef :: as_ref ) {
344+ // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER ` env var set to itself:
310345 // Dependencies get dispatched to rustc, the final test/binary to miri.
311346
312347 let home = option_env ! ( "RUSTUP_HOME" ) . or ( option_env ! ( "MULTIRUST_HOME" ) ) ;
@@ -332,11 +367,11 @@ fn main() {
332367
333368 // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
334369 // without having to pass --sysroot or anything
370+ let rustc_args = std:: env:: args ( ) . skip ( 2 ) ;
335371 let mut args: Vec < String > = if std:: env:: args ( ) . any ( |s| s == "--sysroot" ) {
336- std :: env :: args ( ) . skip ( 1 ) . collect ( )
372+ rustc_args . collect ( )
337373 } else {
338- std:: env:: args ( )
339- . skip ( 1 )
374+ rustc_args
340375 . chain ( Some ( "--sysroot" . to_owned ( ) ) )
341376 . chain ( Some ( sys_root) )
342377 . collect ( )
@@ -365,6 +400,8 @@ fn main() {
365400 Err ( ref e) if miri_enabled => panic ! ( "error during miri run: {:?}" , e) ,
366401 Err ( ref e) => panic ! ( "error during rustc call: {:?}" , e) ,
367402 }
403+ } else {
404+ show_error ( format ! ( "Must be called with either `miri` or `rustc` as first argument." ) )
368405 }
369406}
370407
@@ -383,13 +420,11 @@ where
383420 args. push ( "--" . to_owned ( ) ) ;
384421 }
385422 args. push ( "--emit=dep-info,metadata" . to_owned ( ) ) ;
386- args. push ( "--cfg" . to_owned ( ) ) ;
387- args. push ( r#"feature="cargo-miri""# . to_owned ( ) ) ;
388423
389424 let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
390425 let exit_status = Command :: new ( "cargo" )
391426 . args ( & args)
392- . env ( "RUSTC " , path)
427+ . env ( "RUSTC_WRAPPER " , path)
393428 . spawn ( )
394429 . expect ( "could not run cargo" )
395430 . wait ( )
0 commit comments