@@ -24,7 +24,7 @@ use std::{
2424 env,
2525 ffi:: { OsStr , OsString } ,
2626 path:: { Path , PathBuf } ,
27- process:: { self , Command , ExitStatus } ,
27+ process:: { self , Command , ExitStatus } , iter ,
2828} ;
2929
3030use rustc_ast:: ast:: { Item , ItemKind , Visibility , VisibilityKind } ;
@@ -119,7 +119,7 @@ fn resolve_sysroot() -> anyhow::Result<PathBuf> {
119119 Ok ( path)
120120}
121121
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.
123123///
124124/// We can't insert them at the end because they could come after a `--` and thus be ignored.
125125/// And we can't insert them at the beginning before the `cargo` subcommand argument,
@@ -129,13 +129,12 @@ fn resolve_sysroot() -> anyhow::Result<PathBuf> {
129129/// * it would panic on splicing/insertion
130130/// * we don't want to add the feature flags anyways, as `cargo` without arguments is already an error
131131/// * 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 ] ) {
133133 let insertion_point = 1 ;
134134 if cargo_args. len ( ) >= insertion_point {
135135 cargo_args. splice (
136136 insertion_point..insertion_point,
137- [ "--features" , "c2rust-analysis-rt" ]
138- . iter ( )
137+ iter:: once ( & "--features" ) . chain ( features)
139138 . map ( |s| s. into ( ) ) ,
140139 ) ;
141140 }
@@ -181,16 +180,24 @@ const RUSTC_WRAPPER_VAR: &str = "RUSTC_WRAPPER";
181180const RUST_SYSROOT_VAR : & str = "RUST_SYSROOT" ;
182181const METADATA_VAR : & str = "C2RUST_INSTRUMENT_METADATA_PATH" ;
183182
183+ /// Read a [`PathBuf`] from the [`mod@env`]ironment that should've been set by the [`cargo_wrapper`].
184184fn env_path_from_wrapper ( var : & str ) -> anyhow:: Result < PathBuf > {
185185 let path = env:: var_os ( var)
186186 . ok_or_else ( || anyhow ! ( "the `cargo` wrapper should've `${var}` for the `rustc` wrapper" ) ) ?;
187187 Ok ( path. into ( ) )
188188}
189189
190+ /// Check if the current [`rustc_wrapper`] invocation is for the primary `cargo` package,
191+ /// as determined by `$CARGO_PRIMARY_PACKAGE`.
190192fn is_primary_package ( ) -> bool {
191193 env:: var ( "CARGO_PRIMARY_PACKAGE" ) . is_ok ( )
192194}
193195
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.
194201fn is_bin_crate ( at_args : & [ String ] ) -> anyhow:: Result < bool > {
195202 let args = rustc_driver:: args:: arg_expand_all ( at_args) ;
196203 let matches = rustc_driver:: handle_options ( & args)
@@ -200,11 +207,16 @@ fn is_bin_crate(at_args: &[String]) -> anyhow::Result<bool> {
200207 Ok ( is_bin)
201208}
202209
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.
203215fn bin_crate_name ( ) -> Option < PathBuf > {
204216 env:: var_os ( "CARGO_BIN_NAME" ) . map ( PathBuf :: from)
205217}
206218
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.
208220///
209221/// `c2rust-analysis-rt` is not yet built for the build script,
210222/// so trying to compile it will fail.
@@ -240,6 +252,7 @@ fn is_build_script(at_args: &[String]) -> anyhow::Result<bool> {
240252 Ok ( bin_crate_name ( ) . is_none ( ) && is_bin_crate ( at_args) ?)
241253}
242254
255+ /// Run as a `rustc` wrapper (a la `$RUSTC_WRAPPER`/[`RUSTC_WRAPPER_VAR`]).
243256fn rustc_wrapper ( ) -> anyhow:: Result < ( ) > {
244257 let mut at_args = env:: args ( ) . skip ( 1 ) . collect :: < Vec < _ > > ( ) ;
245258 // We also want to avoid proc-macro crates,
@@ -268,14 +281,18 @@ fn rustc_wrapper() -> anyhow::Result<()> {
268281 Ok ( ( ) )
269282}
270283
284+ /// Run as a `cargo` wrapper/plugin, the default invocation.
271285fn cargo_wrapper ( rustc_wrapper : & Path ) -> anyhow:: Result < ( ) > {
272286 let Args {
273287 metadata,
274288 mut cargo_args,
275289 } = Args :: parse ( ) ;
276290
291+ // Ensure we use a toolchain compatible with the `rustc` private crates we linked to.
277292 env:: set_var ( "RUSTUP_TOOLCHAIN" , include_str ! ( "../rust-toolchain" ) . trim ( ) ) ;
278293
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.
279296 let sysroot = resolve_sysroot ( ) ?;
280297
281298 let cargo = Cargo :: new ( ) ;
@@ -286,11 +303,18 @@ fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> {
286303 . ok_or_else ( || anyhow ! ( "no root package found by `cargo`" ) ) ?;
287304
288305 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.
289312 cmd. args ( & [ "clean" , "--package" , root_package. name . as_str ( ) ] ) ;
290313 } ) ?;
291314
292315 cargo. run ( |cmd| {
293- add_runtime_feature ( & mut cargo_args) ;
316+ // Enable the runtime dependency.
317+ add_feature ( & mut cargo_args, & [ "c2rust-analysis-rt" ] ) ;
294318 cmd. args ( cargo_args)
295319 . env ( RUSTC_WRAPPER_VAR , rustc_wrapper)
296320 . env ( RUST_SYSROOT_VAR , & sysroot)
0 commit comments