3
3
extern crate cargo_metadata;
4
4
5
5
use std:: path:: { PathBuf , Path } ;
6
- use std:: io:: { self , Write } ;
6
+ use std:: io:: { self , Write , BufRead } ;
7
7
use std:: process:: Command ;
8
8
use std:: fs:: { self , File } ;
9
9
@@ -114,6 +114,42 @@ fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
114
114
package. targets . into_iter ( )
115
115
}
116
116
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
+
117
153
fn ask ( question : & str ) {
118
154
let mut buf = String :: new ( ) ;
119
155
print ! ( "{} [Y/n] " , question) ;
@@ -134,14 +170,14 @@ fn setup(ask_user: bool) {
134
170
}
135
171
136
172
// 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 ) ) {
139
175
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?" ) ;
141
177
} else {
142
- println ! ( "Installing xargo: `cargo install xargo`" ) ;
178
+ println ! ( "Installing xargo: `cargo install xargo -f `" ) ;
143
179
}
144
- if !Command :: new ( "cargo" ) . args ( & [ "install" , "xargo" ] ) . status ( ) . unwrap ( ) . success ( ) {
180
+ if !Command :: new ( "cargo" ) . args ( & [ "install" , "xargo" , "-f" ] ) . status ( ) . unwrap ( ) . success ( ) {
145
181
show_error ( format ! ( "Failed to install xargo" ) ) ;
146
182
}
147
183
}
@@ -279,9 +315,8 @@ fn main() {
279
315
( MiriCommand :: Test , "lib" ) => {
280
316
// For libraries we call `cargo rustc -- --test <rustc args>`
281
317
// 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.
285
320
if let Err ( code) = process (
286
321
vec ! [ "--" . to_string( ) , "--test" . to_string( ) ] . into_iter ( ) . chain (
287
322
args,
@@ -305,8 +340,8 @@ fn main() {
305
340
_ => { }
306
341
}
307
342
}
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:
310
345
// Dependencies get dispatched to rustc, the final test/binary to miri.
311
346
312
347
let home = option_env ! ( "RUSTUP_HOME" ) . or ( option_env ! ( "MULTIRUST_HOME" ) ) ;
@@ -332,11 +367,11 @@ fn main() {
332
367
333
368
// this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
334
369
// without having to pass --sysroot or anything
370
+ let rustc_args = std:: env:: args ( ) . skip ( 2 ) ;
335
371
let mut args: Vec < String > = if std:: env:: args ( ) . any ( |s| s == "--sysroot" ) {
336
- std :: env :: args ( ) . skip ( 1 ) . collect ( )
372
+ rustc_args . collect ( )
337
373
} else {
338
- std:: env:: args ( )
339
- . skip ( 1 )
374
+ rustc_args
340
375
. chain ( Some ( "--sysroot" . to_owned ( ) ) )
341
376
. chain ( Some ( sys_root) )
342
377
. collect ( )
@@ -365,6 +400,8 @@ fn main() {
365
400
Err ( ref e) if miri_enabled => panic ! ( "error during miri run: {:?}" , e) ,
366
401
Err ( ref e) => panic ! ( "error during rustc call: {:?}" , e) ,
367
402
}
403
+ } else {
404
+ show_error ( format ! ( "Must be called with either `miri` or `rustc` as first argument." ) )
368
405
}
369
406
}
370
407
@@ -383,13 +420,11 @@ where
383
420
args. push ( "--" . to_owned ( ) ) ;
384
421
}
385
422
args. push ( "--emit=dep-info,metadata" . to_owned ( ) ) ;
386
- args. push ( "--cfg" . to_owned ( ) ) ;
387
- args. push ( r#"feature="cargo-miri""# . to_owned ( ) ) ;
388
423
389
424
let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
390
425
let exit_status = Command :: new ( "cargo" )
391
426
. args ( & args)
392
- . env ( "RUSTC " , path)
427
+ . env ( "RUSTC_WRAPPER " , path)
393
428
. spawn ( )
394
429
. expect ( "could not run cargo" )
395
430
. wait ( )
0 commit comments