@@ -225,13 +225,134 @@ impl BindingGenerationContext {
225225 Ok ( Self { pkg_to_artifact, root, ordered, dirs, resolve : resolve. clone ( ) } )
226226 }
227227
228+ fn get_sysroot ( ) -> Result < Utf8PathBuf > {
229+ // The user requested finding this from cargo_metadata, but since it's not actually
230+ // present in `cargo metadata` output, we fall back to invoking `rustc --print sysroot`.
231+ let output = std:: process:: Command :: new ( "rustc" ) . arg ( "--print" ) . arg ( "sysroot" ) . output ( ) ?;
232+ if !output. status . success ( ) {
233+ bail ! ( "Failed to get sysroot from rustc" ) ;
234+ }
235+ let path = std:: str:: from_utf8 ( & output. stdout ) ?. trim ( ) ;
236+ Ok ( Utf8PathBuf :: from ( path) )
237+ }
238+
239+ fn find_stdlib_rmetas ( sysroot : & Utf8PathBuf ) -> Result < Vec < ( String , Utf8PathBuf ) > > {
240+ let mut rmetas = Vec :: new ( ) ;
241+ let libs = [ "core" , "alloc" , "std" , "proc_macro" ] ;
242+ // Walk the lib directory to find the matching rmeta files.
243+ // Usually sysroot/lib/rustlib/<target>/lib/
244+ let rustlib = sysroot. join ( "lib" ) . join ( "rustlib" ) ;
245+ let mut target_lib_dir = None ;
246+ if rustlib. exists ( ) {
247+ for entry in std:: fs:: read_dir ( rustlib) ? {
248+ let entry = entry?;
249+ let path = entry. path ( ) ;
250+ if path. is_dir ( ) {
251+ let lib_sub = path. join ( "lib" ) ;
252+ if lib_sub. exists ( ) {
253+ // Make sure it's the target directory by checking if any rlib/rmeta is there.
254+ for sub_entry in std:: fs:: read_dir ( & lib_sub) ? {
255+ let sub_entry = sub_entry?;
256+ if sub_entry
257+ . path ( )
258+ . extension ( )
259+ . is_some_and ( |ext| ext == "rmeta" || ext == "rlib" )
260+ {
261+ target_lib_dir = Some ( Utf8PathBuf :: from_path_buf ( lib_sub) . unwrap ( ) ) ;
262+ break ;
263+ }
264+ }
265+ if target_lib_dir. is_some ( ) {
266+ break ;
267+ }
268+ }
269+ }
270+ }
271+ }
272+ let lib_dir =
273+ target_lib_dir. ok_or_else ( || anyhow ! ( "Could not find target lib dir in sysroot" ) ) ?;
274+
275+ for lib in libs {
276+ let mut found = None ;
277+ for entry in std:: fs:: read_dir ( & lib_dir) ? {
278+ let entry = entry?;
279+ let path = entry. path ( ) ;
280+ if let Some ( ext) = path. extension ( ) {
281+ if ext == "rmeta"
282+ && let Some ( file_name) = path. file_name ( ) . and_then ( |s| s. to_str ( ) )
283+ && file_name. starts_with ( & format ! ( "lib{}-" , lib) )
284+ {
285+ found = Some ( Utf8PathBuf :: from_path_buf ( path) . unwrap ( ) ) ;
286+ break ;
287+ }
288+ }
289+ }
290+ let path = found. ok_or_else ( || anyhow ! ( "Failed to find rmeta for {}" , lib) ) ?;
291+ rmetas. push ( ( lib. to_string ( ) , path) ) ;
292+ }
293+ Ok ( rmetas)
294+ }
295+
228296 fn generate_bindings ( & self ) -> Result < String > {
229297 let mut pkg_to_header = HashMap :: new ( ) ;
230298 let mut lib_rs_content = String :: new ( ) ;
231299 let deps_dir = & self . dirs . deps_dir ;
232300 let headers_dir = & self . dirs . headers_dir ;
233301
234302 fs:: create_dir_all ( headers_dir) ?;
303+
304+ // 1. Locate standard library crates and generate bindings for them first.
305+ let sysroot = Self :: get_sysroot ( ) ?;
306+ let stdlib_crates = Self :: find_stdlib_rmetas ( & sysroot) ?;
307+ let mut stdlib_externs = Vec :: new ( ) ;
308+ for ( crate_name, rmeta_path) in & stdlib_crates {
309+ let intermediate_h = deps_dir. join ( format ! ( "{}.h" , crate_name) ) ;
310+ let final_h = headers_dir. join ( format ! ( "{}.h" , crate_name) ) ;
311+ let intermediate_rs = deps_dir. join ( format ! ( "lib{}.rs" , crate_name) ) ;
312+
313+ if intermediate_h. exists ( ) && intermediate_rs. exists ( ) {
314+ pkg_to_header. insert ( crate_name. to_string ( ) , format ! ( "{}.h" , crate_name) ) ;
315+ stdlib_externs. push ( ( crate_name. clone ( ) , rmeta_path. clone ( ) ) ) ;
316+ if !final_h. exists ( ) {
317+ fs:: copy ( & intermediate_h, & final_h) ?;
318+ }
319+ continue ;
320+ }
321+
322+ let mut current_args = vec ! [
323+ "cpp_api_from_rust" . to_string( ) ,
324+ "--crubit-support-path-format=<support/{header}>" . to_string( ) ,
325+ "--enable-rmeta-interface" . to_string( ) ,
326+ format!( "--source-crate-name={}" , crate_name) ,
327+ format!( "--h-out={}" , intermediate_h) ,
328+ format!( "--rs-out={}" , intermediate_rs) ,
329+ format!( "--extern={}={}" , crate_name, rmeta_path) ,
330+ format!( "-Ldependency={}" , deps_dir. as_str( ) ) ,
331+ ] ;
332+ // Explicitly pass preceding standard library crates to succeeding ones.
333+ for ( prev_name, prev_path) in & stdlib_externs {
334+ current_args. push ( format ! ( "--extern={}={}" , prev_name, prev_path) ) ;
335+ if let Some ( prev_header) = pkg_to_header. get ( prev_name) {
336+ current_args. push ( format ! ( "--crate-header={}={}" , prev_name, prev_header) ) ;
337+ }
338+ }
339+
340+ let cmdline = Cmdline :: new ( & current_args) . map_err ( |err| {
341+ match err. downcast_ref :: < clap:: Error > ( ) {
342+ Some ( clap_err) => {
343+ let _: std:: convert:: Infallible = clap_err. exit ( ) ;
344+ }
345+ None => err,
346+ }
347+ } ) ?;
348+ cpp_api_from_rust_lib:: run_with_cmdline_args ( & cmdline) ?;
349+ pkg_to_header. insert ( crate_name. to_string ( ) , format ! ( "{}.h" , crate_name) ) ;
350+ stdlib_externs. push ( ( crate_name. clone ( ) , rmeta_path. clone ( ) ) ) ;
351+
352+ fs:: copy ( & intermediate_h, & final_h) ?;
353+ }
354+
355+ // 2. Generate bindings for user packages in topological order.
235356 for pkg_id in self . ordered . iter ( ) {
236357 let Some ( artifact_info) = self . pkg_to_artifact . get ( & pkg_id. repr ) else {
237358 continue ;
@@ -265,6 +386,15 @@ impl BindingGenerationContext {
265386 format!( "--extern={}={}" , crate_name, artifact_info. path) ,
266387 format!( "-Ldependency={}" , deps_dir. as_str( ) ) ,
267388 ] ;
389+
390+ // Pass stdlib dependencies to user crates
391+ for ( std_name, std_path) in & stdlib_externs {
392+ current_args. push ( format ! ( "--extern={}={}" , std_name, std_path) ) ;
393+ if let Some ( std_header) = pkg_to_header. get ( std_name. as_str ( ) ) {
394+ current_args. push ( format ! ( "--crate-header={}={}" , std_name, std_header) ) ;
395+ }
396+ }
397+
268398 let resolve_node = self
269399 . resolve
270400 . nodes
@@ -381,8 +511,17 @@ bridge_rust = {{ package = "crubit_bridge_rust", version = "0.0.1" }}
381511 let message =
382512 message. map_err ( |err| anyhow ! ( "Failed to parse cargo message: {}" , err) ) ?;
383513 // TODO: Extract an iterator wrapper that prints out lines out output and returns artifacts.
384- let Message :: CompilerArtifact ( artifact) = message else {
385- continue ;
514+ let artifact = match message {
515+ Message :: CompilerArtifact ( artifact) => artifact,
516+ Message :: CompilerMessage ( msg) => {
517+ eprintln ! ( "{}" , msg) ;
518+ continue ;
519+ }
520+ Message :: TextLine ( line) => {
521+ println ! ( "{}" , line) ;
522+ continue ;
523+ }
524+ _ => continue ,
386525 } ;
387526 if artifact. target . kind . contains ( & cargo_metadata:: TargetKind :: StaticLib ) {
388527 cargo_static_lib_path = artifact. filenames . first ( ) . cloned ( ) ;
0 commit comments