1
1
use std:: ffi:: { OsStr , OsString } ;
2
+ use std:: fmt:: Write ;
2
3
use std:: ops:: Range ;
3
4
use std:: path:: { Path , PathBuf } ;
4
5
use std:: sync:: atomic:: { AtomicBool , AtomicU32 , Ordering } ;
@@ -7,7 +8,7 @@ use std::thread;
7
8
use anyhow:: { anyhow, Context , Result } ;
8
9
use dunce:: canonicalize;
9
10
use path_macro:: path;
10
- use xshell:: { cmd, Shell } ;
11
+ use xshell:: { cmd, Cmd , Shell } ;
11
12
12
13
pub fn miri_dir ( ) -> std:: io:: Result < PathBuf > {
13
14
const MIRI_SCRIPT_ROOT_DIR : & str = env ! ( "CARGO_MANIFEST_DIR" ) ;
@@ -28,13 +29,14 @@ pub fn flagsplit(flags: &str) -> Vec<String> {
28
29
}
29
30
30
31
/// Some extra state we track for building Miri, such as the right RUSTFLAGS.
32
+ #[ derive( Clone ) ]
31
33
pub struct MiriEnv {
32
34
/// miri_dir is the root of the miri repository checkout we are working in.
33
35
pub miri_dir : PathBuf ,
34
36
/// active_toolchain is passed as `+toolchain` argument to cargo/rustc invocations.
35
37
pub toolchain : String ,
36
38
/// Extra flags to pass to cargo.
37
- pub cargo_extra_flags : Vec < String > ,
39
+ cargo_extra_flags : Vec < String > ,
38
40
/// The rustc sysroot
39
41
pub sysroot : PathBuf ,
40
42
/// The shell we use.
@@ -54,15 +56,11 @@ impl MiriEnv {
54
56
55
57
// Determine some toolchain properties
56
58
if !libdir. exists ( ) {
57
- println ! ( "Something went wrong determining the library dir." ) ;
58
- println ! ( "I got {} but that does not exist." , libdir. display( ) ) ;
59
- println ! ( "Please report a bug at https://github.com/rust-lang/miri/issues." ) ;
59
+ eprintln ! ( "Something went wrong determining the library dir." ) ;
60
+ eprintln ! ( "I got {} but that does not exist." , libdir. display( ) ) ;
61
+ eprintln ! ( "Please report a bug at https://github.com/rust-lang/miri/issues." ) ;
60
62
std:: process:: exit ( 2 ) ;
61
63
}
62
- // Share target dir between `miri` and `cargo-miri`.
63
- let target_dir = std:: env:: var_os ( "CARGO_TARGET_DIR" )
64
- . unwrap_or_else ( || path ! ( miri_dir / "target" ) . into ( ) ) ;
65
- sh. set_var ( "CARGO_TARGET_DIR" , target_dir) ;
66
64
67
65
// We configure dev builds to not be unusably slow.
68
66
let devel_opt_level =
@@ -91,17 +89,48 @@ impl MiriEnv {
91
89
// Get extra flags for cargo.
92
90
let cargo_extra_flags = std:: env:: var ( "CARGO_EXTRA_FLAGS" ) . unwrap_or_default ( ) ;
93
91
let cargo_extra_flags = flagsplit ( & cargo_extra_flags) ;
92
+ if cargo_extra_flags. iter ( ) . any ( |a| a == "--release" || a. starts_with ( "--profile" ) ) {
93
+ // This makes binaries end up in different paths, let's not do that.
94
+ eprintln ! (
95
+ "Passing `--release` or `--profile` in `CARGO_EXTRA_FLAGS` will totally confuse miri-script, please don't do that."
96
+ ) ;
97
+ std:: process:: exit ( 1 ) ;
98
+ }
94
99
95
100
Ok ( MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags } )
96
101
}
97
102
103
+ pub fn cargo_cmd ( & self , manifest_path : impl AsRef < OsStr > , cmd : & str ) -> Cmd < ' _ > {
104
+ let MiriEnv { toolchain, cargo_extra_flags, .. } = self ;
105
+ let manifest_path = Path :: new ( manifest_path. as_ref ( ) ) ;
106
+ let cmd = cmd ! (
107
+ self . sh,
108
+ "cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path}"
109
+ ) ;
110
+ // Hard-code the target dir, since we rely on knowing where the binaries end up.
111
+ let manifest_dir = manifest_path. parent ( ) . unwrap ( ) ;
112
+ let cmd = cmd. env ( "CARGO_TARGET_DIR" , path ! ( manifest_dir / "target" ) ) ;
113
+ // Apply path remapping to have errors printed relative to `miri_dir`.
114
+ let cmd = if let Ok ( relative_to_miri) = manifest_dir. strip_prefix ( & self . miri_dir ) {
115
+ // Add `--remap-path-prefix` to RUSTFLAGS.
116
+ let mut rustflags = self . sh . var ( "RUSTFLAGS" ) . unwrap ( ) ;
117
+ write ! ( rustflags, " --remap-path-prefix ={}" , relative_to_miri. display( ) ) . unwrap ( ) ;
118
+ cmd. env ( "RUSTFLAGS" , rustflags)
119
+ } else {
120
+ cmd
121
+ } ;
122
+ // All set up!
123
+ cmd
124
+ }
125
+
98
126
pub fn install_to_sysroot (
99
127
& self ,
100
128
path : impl AsRef < OsStr > ,
101
129
args : impl IntoIterator < Item = impl AsRef < OsStr > > ,
102
130
) -> Result < ( ) > {
103
131
let MiriEnv { sysroot, toolchain, cargo_extra_flags, .. } = self ;
104
132
// Install binaries to the miri toolchain's `sysroot` so they do not interact with other toolchains.
133
+ // (Not using `cargo_cmd` as `install` is special and doesn't use `--manifest-path`.)
105
134
cmd ! ( self . sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {args...}" ) . run ( ) ?;
106
135
Ok ( ( ) )
107
136
}
@@ -112,40 +141,34 @@ impl MiriEnv {
112
141
args : & [ String ] ,
113
142
quiet : bool ,
114
143
) -> Result < ( ) > {
115
- let MiriEnv { toolchain, cargo_extra_flags, .. } = self ;
116
144
let quiet_flag = if quiet { Some ( "--quiet" ) } else { None } ;
117
145
// We build the tests as well, (a) to avoid having rebuilds when building the tests later
118
146
// and (b) to have more parallelism during the build of Miri and its tests.
119
- let mut cmd = cmd ! (
120
- self . sh,
121
- "cargo +{toolchain} build --bins --tests {cargo_extra_flags...} --manifest-path {manifest_path} {quiet_flag...} {args...}"
122
- ) ;
147
+ // This means `./miri run` without `--dep` will build Miri twice (for the sysroot with
148
+ // dev-dependencies, and then for running without dev-dependencies), but the way more common
149
+ // `./miri test` will avoid building Miri twice.
150
+ let mut cmd = self
151
+ . cargo_cmd ( manifest_path, "build" )
152
+ . args ( & [ "--bins" , "--tests" ] )
153
+ . args ( quiet_flag)
154
+ . args ( args) ;
123
155
cmd. set_quiet ( quiet) ;
124
156
cmd. run ( ) ?;
125
157
Ok ( ( ) )
126
158
}
127
159
128
160
pub fn check ( & self , manifest_path : impl AsRef < OsStr > , args : & [ String ] ) -> Result < ( ) > {
129
- let MiriEnv { toolchain, cargo_extra_flags, .. } = self ;
130
- cmd ! ( self . sh, "cargo +{toolchain} check {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}" )
131
- . run ( ) ?;
161
+ self . cargo_cmd ( manifest_path, "check" ) . arg ( "--all-targets" ) . args ( args) . run ( ) ?;
132
162
Ok ( ( ) )
133
163
}
134
164
135
165
pub fn clippy ( & self , manifest_path : impl AsRef < OsStr > , args : & [ String ] ) -> Result < ( ) > {
136
- let MiriEnv { toolchain, cargo_extra_flags, .. } = self ;
137
- cmd ! ( self . sh, "cargo +{toolchain} clippy {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}" )
138
- . run ( ) ?;
166
+ self . cargo_cmd ( manifest_path, "clippy" ) . arg ( "--all-targets" ) . args ( args) . run ( ) ?;
139
167
Ok ( ( ) )
140
168
}
141
169
142
170
pub fn test ( & self , manifest_path : impl AsRef < OsStr > , args : & [ String ] ) -> Result < ( ) > {
143
- let MiriEnv { toolchain, cargo_extra_flags, .. } = self ;
144
- cmd ! (
145
- self . sh,
146
- "cargo +{toolchain} test {cargo_extra_flags...} --manifest-path {manifest_path} {args...}"
147
- )
148
- . run ( ) ?;
171
+ self . cargo_cmd ( manifest_path, "test" ) . args ( args) . run ( ) ?;
149
172
Ok ( ( ) )
150
173
}
151
174
@@ -155,7 +178,6 @@ impl MiriEnv {
155
178
pub fn format_files (
156
179
& self ,
157
180
files : impl Iterator < Item = Result < PathBuf , walkdir:: Error > > ,
158
- toolchain : & str ,
159
181
config_path : & Path ,
160
182
flags : & [ String ] ,
161
183
) -> anyhow:: Result < ( ) > {
@@ -166,6 +188,7 @@ impl MiriEnv {
166
188
// Format in batches as not all our files fit into Windows' command argument limit.
167
189
for batch in & files. chunks ( 256 ) {
168
190
// Build base command.
191
+ let toolchain = & self . toolchain ;
169
192
let mut cmd = cmd ! (
170
193
self . sh,
171
194
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
@@ -197,7 +220,7 @@ impl MiriEnv {
197
220
pub fn run_many_times (
198
221
& self ,
199
222
range : Range < u32 > ,
200
- run : impl Fn ( & Shell , u32 ) -> Result < ( ) > + Sync ,
223
+ run : impl Fn ( & Self , u32 ) -> Result < ( ) > + Sync ,
201
224
) -> Result < ( ) > {
202
225
// `next` is atomic so threads can concurrently fetch their next value to run.
203
226
let next = AtomicU32 :: new ( range. start ) ;
@@ -207,10 +230,10 @@ impl MiriEnv {
207
230
let mut handles = Vec :: new ( ) ;
208
231
// Spawn one worker per core.
209
232
for _ in 0 ..thread:: available_parallelism ( ) ?. get ( ) {
210
- // Create a copy of the shell for this thread.
211
- let local_shell = self . sh . clone ( ) ;
233
+ // Create a copy of the environment for this thread.
234
+ let local_miri = self . clone ( ) ;
212
235
let handle = s. spawn ( || -> Result < ( ) > {
213
- let local_shell = local_shell ; // move the copy into this thread.
236
+ let local_miri = local_miri ; // move the copy into this thread.
214
237
// Each worker thread keeps asking for numbers until we're all done.
215
238
loop {
216
239
let cur = next. fetch_add ( 1 , Ordering :: Relaxed ) ;
@@ -219,7 +242,7 @@ impl MiriEnv {
219
242
break ;
220
243
}
221
244
// Run the command with this seed.
222
- run ( & local_shell , cur) . inspect_err ( |_| {
245
+ run ( & local_miri , cur) . inspect_err ( |_| {
223
246
// If we failed, tell everyone about this.
224
247
failed. store ( true , Ordering :: Relaxed ) ;
225
248
} ) ?;
0 commit comments