1
1
use std:: ffi:: { OsStr , OsString } ;
2
+ use std:: io:: BufRead ;
2
3
use std:: ops:: Range ;
3
4
use std:: path:: { Path , PathBuf } ;
4
5
use std:: sync:: atomic:: { AtomicBool , AtomicU32 , Ordering } ;
5
6
use std:: thread;
6
7
7
- use anyhow:: { anyhow, Context , Result } ;
8
+ use anyhow:: { anyhow, bail , Context , Result } ;
8
9
use dunce:: canonicalize;
9
10
use path_macro:: path;
10
11
use xshell:: { cmd, Cmd , Shell } ;
@@ -111,6 +112,12 @@ impl MiriEnv {
111
112
)
112
113
}
113
114
115
+ /// Prepares a command to be run in the toolchain (via `rustup run`).
116
+ pub fn toolchain_cmd ( & self , cmd : impl AsRef < OsStr > ) -> Cmd < ' _ > {
117
+ let MiriEnv { toolchain, .. } = self ;
118
+ cmd ! ( self . sh, "rustup run {toolchain} {cmd}" )
119
+ }
120
+
114
121
pub fn install_to_sysroot (
115
122
& self ,
116
123
path : impl AsRef < OsStr > ,
@@ -126,21 +133,40 @@ impl MiriEnv {
126
133
127
134
pub fn build ( & self , crate_dir : impl AsRef < OsStr > , args : & [ String ] , quiet : bool ) -> Result < ( ) > {
128
135
let quiet_flag = if quiet { Some ( "--quiet" ) } else { None } ;
129
- // We build the tests as well, (a) to avoid having rebuilds when building the tests later
130
- // and (b) to have more parallelism during the build of Miri and its tests.
131
- // This means `./miri run` without `--dep` will build Miri twice (for the sysroot with
132
- // dev-dependencies, and then for running without dev-dependencies), but the way more common
133
- // `./miri test` will avoid building Miri twice.
134
- let mut cmd = self
135
- . cargo_cmd ( crate_dir, "build" )
136
- . args ( & [ "--bins" , "--tests" ] )
137
- . args ( quiet_flag)
138
- . args ( args) ;
136
+ // We build all targets, since building *just* the bin target doesnot include
137
+ // `dev-dependencies` and that changes feature resolution. This also gets us more
138
+ // parallelism in `./miri test` as we build Miri and its tests together.
139
+ let mut cmd =
140
+ self . cargo_cmd ( crate_dir, "build" ) . args ( & [ "--all-targets" ] ) . args ( quiet_flag) . args ( args) ;
139
141
cmd. set_quiet ( quiet) ;
140
142
cmd. run ( ) ?;
141
143
Ok ( ( ) )
142
144
}
143
145
146
+ /// Returns the path to the main crate binary. Assumes that `build` has been called before.
147
+ pub fn build_get_binary ( & self , crate_dir : impl AsRef < OsStr > ) -> Result < PathBuf > {
148
+ let cmd =
149
+ self . cargo_cmd ( crate_dir, "build" ) . args ( & [ "--all-targets" , "--message-format=json" ] ) ;
150
+ let output = cmd. output ( ) ?;
151
+ let mut bin = None ;
152
+ for line in output. stdout . lines ( ) {
153
+ let line = line?;
154
+ if line. starts_with ( "{" ) {
155
+ let json: serde_json:: Value = serde_json:: from_str ( & line) ?;
156
+ if json[ "reason" ] == "compiler-artifact"
157
+ && !json[ "profile" ] [ "test" ] . as_bool ( ) . unwrap ( )
158
+ && !json[ "executable" ] . is_null ( )
159
+ {
160
+ if bin. is_some ( ) {
161
+ bail ! ( "found two binaries in cargo output" ) ;
162
+ }
163
+ bin = Some ( PathBuf :: from ( json[ "executable" ] . as_str ( ) . unwrap ( ) ) )
164
+ }
165
+ }
166
+ }
167
+ bin. ok_or_else ( || anyhow ! ( "found no binary in cargo output" ) )
168
+ }
169
+
144
170
pub fn check ( & self , crate_dir : impl AsRef < OsStr > , args : & [ String ] ) -> Result < ( ) > {
145
171
self . cargo_cmd ( crate_dir, "check" ) . arg ( "--all-targets" ) . args ( args) . run ( ) ?;
146
172
Ok ( ( ) )
0 commit comments