@@ -6,7 +6,7 @@ use std::path::{PathBuf, Path};
6
6
use std:: process:: Command ;
7
7
use std:: ops:: Not ;
8
8
9
- const XARGO_MIN_VERSION : ( u32 , u32 , u32 ) = ( 0 , 3 , 17 ) ;
9
+ const XARGO_MIN_VERSION : ( u32 , u32 , u32 ) = ( 0 , 3 , 18 ) ;
10
10
11
11
const CARGO_MIRI_HELP : & str = r#"Interprets bin crates and tests in Miri
12
12
@@ -80,7 +80,36 @@ fn get_arg_flag_value(name: &str) -> Option<String> {
80
80
}
81
81
}
82
82
83
- fn list_targets ( ) -> impl Iterator < Item =cargo_metadata:: Target > {
83
+ fn is_build_dep ( mut args : impl Iterator < Item = String > ) -> bool {
84
+ args. any ( |arg| arg. starts_with ( "--emit=" ) && arg. contains ( "link" ) )
85
+ }
86
+
87
+ // Returns whether or not Cargo invoked the wrapper (this binary) to compile
88
+ // the final, target crate (either a test for 'cargo test', or a binary for 'cargo run')
89
+ // Right now, this is an awful hack that checks several different pieces of information
90
+ // to try to figure out if the crate being compiled is the right one.
91
+ // Ideally, Cargo would set en environment variable indicating whether or
92
+ // not the wrapper is being invoked on the target crate.
93
+ // For now, this is the best we can do
94
+ fn is_target_crate ( is_build_script : bool ) -> bool {
95
+ // Cargo sets this to the directory containing the manifest of the crate
96
+ // the wrapper is being invoekd to compile. This should be unique
97
+ // across the entire build (except for build scripts, which we handle below).
98
+ // We cannot check the crate name, since this may not be unique
99
+ // (e.g. if the build contains multiple versions of the same crate,
100
+ // or the same crate from multiple sources)
101
+ let manifest_dir = std:: env:: var ( "CARGO_MANIFEST_DIR" ) . ok ( ) ;
102
+
103
+ // The manifest directory for our target crate. This is set by `cargo-miri`
104
+ // (the original invoation by the user) by using `cargo_metadata` to locate
105
+ // the manifest.
106
+ let expected_dir = std:: env:: var ( "MIRI_MAGIC_DIR" ) . expect ( "MIRI_MAGIC_DIR not set!" ) ;
107
+
108
+ manifest_dir == Some ( expected_dir) && !is_build_script
109
+
110
+ }
111
+
112
+ fn read_cargo_metadata ( ) -> ( impl Iterator < Item =cargo_metadata:: Target > , String ) {
84
113
// We need to get the manifest, and then the metadata, to enumerate targets.
85
114
let manifest_path = get_arg_flag_value ( "--manifest-path" ) . map ( |m|
86
115
Path :: new ( & m) . canonicalize ( ) . unwrap ( )
@@ -119,7 +148,7 @@ fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
119
148
let package = metadata. packages . remove ( package_index) ;
120
149
121
150
// Finally we got the list of targets to build
122
- package. targets . into_iter ( )
151
+ ( package. targets . into_iter ( ) , metadata . workspace_root . to_string_lossy ( ) . to_string ( ) )
123
152
}
124
153
125
154
/// Returns the path to the `miri` binary
@@ -266,7 +295,7 @@ fn setup(ask_user: bool) {
266
295
show_error ( format ! ( "Your xargo is too old; please upgrade to the latest version" ) )
267
296
}
268
297
let mut cmd = cargo ( ) ;
269
- cmd. args ( & [ "install" , "xargo" , "-f " ] ) ;
298
+ cmd. args ( & [ "install" , "-f" , "--git" , "https://github.com./Aaron1011/ xargo", "--branch" , "feature/cargo-mode "] ) ;
270
299
ask_to_run ( cmd, ask_user, "install a recent enough xargo" ) ;
271
300
}
272
301
@@ -294,6 +323,7 @@ fn setup(ask_user: bool) {
294
323
// The interesting bit: Xargo.toml
295
324
File :: create ( dir. join ( "Xargo.toml" ) ) . unwrap ( )
296
325
. write_all ( br#"
326
+ cargo_mode = "check"
297
327
[dependencies.std]
298
328
default_features = false
299
329
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
@@ -318,7 +348,12 @@ path = "lib.rs"
318
348
let target = get_arg_flag_value ( "--target" ) ;
319
349
let print_sysroot = !ask_user && has_arg_flag ( "--print-sysroot" ) ; // whether we just print the sysroot path
320
350
let mut command = xargo ( ) ;
321
- command. arg ( "build" ) . arg ( "-q" ) ;
351
+ // This may seen somewhat suprising - we are 'building' libstd
352
+ // by running (the equivalent of) `cargo check`. It turns out
353
+ // that `cargo check` has exactly the behavior that we want:
354
+ // it emits crate metadata (including MIR) without running any
355
+ // codegen.
356
+ command. arg ( "check" ) . arg ( "-q" ) ;
322
357
command. current_dir ( & dir) ;
323
358
command. env ( "RUSTFLAGS" , miri:: miri_default_args ( ) . join ( " " ) ) ;
324
359
command. env ( "XARGO_HOME" , dir. to_str ( ) . unwrap ( ) ) ;
@@ -336,6 +371,7 @@ path = "lib.rs"
336
371
show_error ( format ! ( "Failed to run xargo" ) ) ;
337
372
}
338
373
374
+
339
375
// That should be it! But we need to figure out where xargo built stuff.
340
376
// Unfortunately, it puts things into a different directory when the
341
377
// architecture matches the host.
@@ -404,8 +440,10 @@ fn in_cargo_miri() {
404
440
return ;
405
441
}
406
442
443
+ let ( targets, root_dir) = read_cargo_metadata ( ) ;
444
+
407
445
// Now run the command.
408
- for target in list_targets ( ) {
446
+ for target in targets {
409
447
let mut args = std:: env:: args ( ) . skip ( skip) ;
410
448
let kind = target. kind . get ( 0 ) . expect (
411
449
"badly formatted cargo metadata: target::kind is an empty array" ,
@@ -414,7 +452,7 @@ fn in_cargo_miri() {
414
452
// change to add additional arguments. `FLAGS` is set to identify
415
453
// this target. The user gets to control what gets actually passed to Miri.
416
454
let mut cmd = cargo ( ) ;
417
- cmd. arg ( "rustc " ) ;
455
+ cmd. arg ( "check " ) ;
418
456
match ( subcommand, kind. as_str ( ) ) {
419
457
( MiriCommand :: Run , "bin" ) => {
420
458
// FIXME: we just run all the binaries here.
@@ -441,14 +479,17 @@ fn in_cargo_miri() {
441
479
}
442
480
cmd. arg ( arg) ;
443
481
}
444
- // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the
445
- // user flags to be able to identify them later. "cargo rustc" adds more stuff after this,
446
- // so we have to mark both the beginning and the end.
447
- cmd
448
- . arg ( "--" )
449
- . arg ( "cargo-miri-marker-begin" )
450
- . args ( args)
451
- . arg ( "cargo-miri-marker-end" ) ;
482
+
483
+ let mut prefixed_args = String :: new ( ) ;
484
+ for arg in args {
485
+ prefixed_args += & arg. len ( ) . to_string ( ) ;
486
+ prefixed_args. push ( ';' ) ;
487
+ prefixed_args += & arg;
488
+ }
489
+
490
+ cmd. env ( "MIRI_MAGIC_ARGS" , prefixed_args) ;
491
+ cmd. env ( "MIRI_MAGIC_DIR" , root_dir. clone ( ) ) ;
492
+
452
493
let path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
453
494
cmd. env ( "RUSTC_WRAPPER" , path) ;
454
495
if verbose {
@@ -470,27 +511,45 @@ fn in_cargo_miri() {
470
511
fn inside_cargo_rustc ( ) {
471
512
let sysroot = std:: env:: var ( "MIRI_SYSROOT" ) . expect ( "The wrapper should have set MIRI_SYSROOT" ) ;
472
513
514
+
473
515
let rustc_args = std:: env:: args ( ) . skip ( 2 ) ; // skip `cargo rustc`
474
- let mut args: Vec < String > = rustc_args
475
- . chain ( Some ( "--sysroot" . to_owned ( ) ) )
476
- . chain ( Some ( sysroot) )
477
- . collect ( ) ;
478
- args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
516
+
517
+
518
+ eprintln ! ( "cargo rustc env: {:?}" , std:: env:: vars( ) . collect:: <Vec <_>>( ) ) ;
519
+
520
+ let in_build_script = is_build_dep ( std:: env:: args ( ) . skip ( 2 ) ) ;
521
+
522
+
523
+ let mut args = if in_build_script {
524
+ rustc_args. collect ( )
525
+ } else {
526
+ let mut args: Vec < String > = rustc_args
527
+ . chain ( Some ( "--sysroot" . to_owned ( ) ) )
528
+ . chain ( Some ( sysroot) )
529
+ . collect ( ) ;
530
+ args. splice ( 0 ..0 , miri:: miri_default_args ( ) . iter ( ) . map ( ToString :: to_string) ) ;
531
+ args
532
+ } ;
479
533
480
534
// See if we can find the `cargo-miri` markers. Those only get added to the binary we want to
481
535
// run. They also serve to mark the user-defined arguments, which we have to move all the way
482
536
// to the end (they get added somewhere in the middle).
483
- let needs_miri = if let Some ( begin) = args. iter ( ) . position ( |arg| arg == "cargo-miri-marker-begin" ) {
484
- let end = args
485
- . iter ( )
486
- . position ( |arg| arg == "cargo-miri-marker-end" )
487
- . expect ( "cannot find end marker" ) ;
488
- // These mark the user arguments. We remove the first and last as they are the markers.
489
- let mut user_args = args. drain ( begin..=end) ;
490
- assert_eq ! ( user_args. next( ) . unwrap( ) , "cargo-miri-marker-begin" ) ;
491
- assert_eq ! ( user_args. next_back( ) . unwrap( ) , "cargo-miri-marker-end" ) ;
492
- // Collect the rest and add it back at the end.
493
- let mut user_args = user_args. collect :: < Vec < String > > ( ) ;
537
+ let needs_miri = if is_target_crate ( in_build_script) {
538
+ let raw_args = std:: env:: var ( "MIRI_MAGIC_ARGS" ) . expect ( "Missing magic!" ) ;
539
+ let mut user_args = vec ! [ ] ;
540
+ let mut slice = raw_args. as_str ( ) ;
541
+ loop {
542
+ match slice. find ( ';' ) {
543
+ Some ( pos) => {
544
+ let len: usize = slice[ ..( pos) ] . parse ( ) . unwrap ( ) ;
545
+ let arg = slice[ ( pos+1 ) ..=( pos+len) ] . to_string ( ) ;
546
+ user_args. push ( arg) ;
547
+ slice = & slice[ ( pos+len+1 ) ..] ;
548
+ } ,
549
+ None => break
550
+ }
551
+ }
552
+
494
553
args. append ( & mut user_args) ;
495
554
// Run this in Miri.
496
555
true
0 commit comments