@@ -24,7 +24,7 @@ use std::{
24
24
env,
25
25
ffi:: { OsStr , OsString } ,
26
26
path:: { Path , PathBuf } ,
27
- process:: { self , Command , ExitStatus } ,
27
+ process:: { self , Command , ExitStatus } , iter ,
28
28
} ;
29
29
30
30
use rustc_ast:: ast:: { Item , ItemKind , Visibility , VisibilityKind } ;
@@ -119,7 +119,7 @@ fn resolve_sysroot() -> anyhow::Result<PathBuf> {
119
119
Ok ( path)
120
120
}
121
121
122
- /// Insert the feature flags as the first arguments following the `cargo` subcommand.
122
+ /// Insert feature flags as the first arguments following the `cargo` subcommand.
123
123
///
124
124
/// We can't insert them at the end because they could come after a `--` and thus be ignored.
125
125
/// And we can't insert them at the beginning before the `cargo` subcommand argument,
@@ -129,13 +129,12 @@ fn resolve_sysroot() -> anyhow::Result<PathBuf> {
129
129
/// * it would panic on splicing/insertion
130
130
/// * we don't want to add the feature flags anyways, as `cargo` without arguments is already an error
131
131
/// * we don't want to obfuscate that error with an error about unexpected feature flags
132
- fn add_runtime_feature ( cargo_args : & mut Vec < OsString > ) {
132
+ fn add_feature ( cargo_args : & mut Vec < OsString > , features : & [ & str ] ) {
133
133
let insertion_point = 1 ;
134
134
if cargo_args. len ( ) >= insertion_point {
135
135
cargo_args. splice (
136
136
insertion_point..insertion_point,
137
- [ "--features" , "c2rust-analysis-rt" ]
138
- . iter ( )
137
+ iter:: once ( & "--features" ) . chain ( features)
139
138
. map ( |s| s. into ( ) ) ,
140
139
) ;
141
140
}
@@ -181,16 +180,24 @@ const RUSTC_WRAPPER_VAR: &str = "RUSTC_WRAPPER";
181
180
const RUST_SYSROOT_VAR : & str = "RUST_SYSROOT" ;
182
181
const METADATA_VAR : & str = "C2RUST_INSTRUMENT_METADATA_PATH" ;
183
182
183
+ /// Read a [`PathBuf`] from the [`mod@env`]ironment that should've been set by the [`cargo_wrapper`].
184
184
fn env_path_from_wrapper ( var : & str ) -> anyhow:: Result < PathBuf > {
185
185
let path = env:: var_os ( var)
186
186
. ok_or_else ( || anyhow ! ( "the `cargo` wrapper should've `${var}` for the `rustc` wrapper" ) ) ?;
187
187
Ok ( path. into ( ) )
188
188
}
189
189
190
+ /// Check if the current [`rustc_wrapper`] invocation is for the primary `cargo` package,
191
+ /// as determined by `$CARGO_PRIMARY_PACKAGE`.
190
192
fn is_primary_package ( ) -> bool {
191
193
env:: var ( "CARGO_PRIMARY_PACKAGE" ) . is_ok ( )
192
194
}
193
195
196
+ /// Check if the current [`rustc_wrapper`] invocation is a binary crate,
197
+ /// i.e., if `--crate-type bin` was specified.
198
+ ///
199
+ /// This uses the [`rustc_driver`] and [`rustc_session`] APIs
200
+ /// to check this exactly as `rustc` would.
194
201
fn is_bin_crate ( at_args : & [ String ] ) -> anyhow:: Result < bool > {
195
202
let args = rustc_driver:: args:: arg_expand_all ( at_args) ;
196
203
let matches = rustc_driver:: handle_options ( & args)
@@ -200,11 +207,16 @@ fn is_bin_crate(at_args: &[String]) -> anyhow::Result<bool> {
200
207
Ok ( is_bin)
201
208
}
202
209
210
+ /// Read the name of the current binary crate being compiled, if it is a binary crate ([`is_bin_crate`]).
211
+ ///
212
+ /// Note that despite setting `--crate-type bin` and [`is_bin_crate`] being true,
213
+ /// there is no name set for build scripts.
214
+ /// That's how we can detect them.
203
215
fn bin_crate_name ( ) -> Option < PathBuf > {
204
216
env:: var_os ( "CARGO_BIN_NAME" ) . map ( PathBuf :: from)
205
217
}
206
218
207
- /// Detect if the `rustc` invocation is for compiling a build script.
219
+ /// Detect if the current [`rustc_wrapper`] is for compiling a build script.
208
220
///
209
221
/// `c2rust-analysis-rt` is not yet built for the build script,
210
222
/// so trying to compile it will fail.
@@ -240,6 +252,7 @@ fn is_build_script(at_args: &[String]) -> anyhow::Result<bool> {
240
252
Ok ( bin_crate_name ( ) . is_none ( ) && is_bin_crate ( at_args) ?)
241
253
}
242
254
255
+ /// Run as a `rustc` wrapper (a la `$RUSTC_WRAPPER`/[`RUSTC_WRAPPER_VAR`]).
243
256
fn rustc_wrapper ( ) -> anyhow:: Result < ( ) > {
244
257
let mut at_args = env:: args ( ) . skip ( 1 ) . collect :: < Vec < _ > > ( ) ;
245
258
// We also want to avoid proc-macro crates,
@@ -268,14 +281,18 @@ fn rustc_wrapper() -> anyhow::Result<()> {
268
281
Ok ( ( ) )
269
282
}
270
283
284
+ /// Run as a `cargo` wrapper/plugin, the default invocation.
271
285
fn cargo_wrapper ( rustc_wrapper : & Path ) -> anyhow:: Result < ( ) > {
272
286
let Args {
273
287
metadata,
274
288
mut cargo_args,
275
289
} = Args :: parse ( ) ;
276
290
291
+ // Ensure we use a toolchain compatible with the `rustc` private crates we linked to.
277
292
env:: set_var ( "RUSTUP_TOOLCHAIN" , include_str ! ( "../rust-toolchain" ) . trim ( ) ) ;
278
293
294
+ // Resolve the sysroot once in the [`cargo_wrapper`]
295
+ // so that we don't need all of the [`rustc_wrapper`]s to have to do it.
279
296
let sysroot = resolve_sysroot ( ) ?;
280
297
281
298
let cargo = Cargo :: new ( ) ;
@@ -286,11 +303,18 @@ fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> {
286
303
. ok_or_else ( || anyhow ! ( "no root package found by `cargo`" ) ) ?;
287
304
288
305
cargo. run ( |cmd| {
306
+ // Clean the primary package so that we always rebuild it
307
+ // and get up-to-date, complete instrumentation [`Metadata`].
308
+ // Incremental instrumentation is very tricky,
309
+ // so don't try that yet,
310
+ // and if we only need to rebuild the primary package,
311
+ // it usually isn't that slow.
289
312
cmd. args ( & [ "clean" , "--package" , root_package. name . as_str ( ) ] ) ;
290
313
} ) ?;
291
314
292
315
cargo. run ( |cmd| {
293
- add_runtime_feature ( & mut cargo_args) ;
316
+ // Enable the runtime dependency.
317
+ add_feature ( & mut cargo_args, & [ "c2rust-analysis-rt" ] ) ;
294
318
cmd. args ( cargo_args)
295
319
. env ( RUSTC_WRAPPER_VAR , rustc_wrapper)
296
320
. env ( RUST_SYSROOT_VAR , & sysroot)
0 commit comments