@@ -58,12 +58,9 @@ use super::command::Command;
5858use super :: linker:: { self , Linker } ;
5959use super :: metadata:: { MetadataPosition , create_wrapper_file} ;
6060use super :: rpath:: { self , RPathConfig } ;
61- use super :: { apple, versioned_llvm_target} ;
61+ use super :: { apple, rmeta_link , versioned_llvm_target} ;
6262use crate :: base:: needs_allocator_shim_for_linking;
63- use crate :: {
64- CodegenLintLevels , CompiledModule , CompiledModules , CrateInfo , NativeLib , errors,
65- looks_like_rust_object_file,
66- } ;
63+ use crate :: { CodegenLintLevels , CompiledModule , CompiledModules , CrateInfo , NativeLib , errors} ;
6764
6865pub fn ensure_removed ( dcx : DiagCtxtHandle < ' _ > , path : & Path ) {
6966 if let Err ( e) = fs:: remove_file ( path) {
@@ -307,6 +304,26 @@ fn link_rlib<'a>(
307304) -> Box < dyn ArchiveBuilder + ' a > {
308305 let mut ab = archive_builder_builder. new_archive_builder ( sess) ;
309306
307+ // Pre-compute the list of Rust object filenames and materialize the rlib
308+ // digest wrapper file before any `add_file` calls. This lets the digest be
309+ // placed immediately after metadata in the archive, so consumers can find
310+ // it without iterating every archive member.
311+ let rust_object_files: Vec < String > = compiled_modules
312+ . modules
313+ . iter ( )
314+ . filter_map ( |m| m. object . as_ref ( ) )
315+ . map ( |obj| obj. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) )
316+ . collect ( ) ;
317+
318+ let digest_file = if matches ! ( flavor, RlibFlavor :: Normal ) {
319+ let digest = rmeta_link:: RmetaLink { rust_object_files } ;
320+ let digest_data = digest. encode ( ) ;
321+ let ( wrapper, _) = create_wrapper_file ( sess, rmeta_link:: SECTION . to_string ( ) , & digest_data) ;
322+ Some ( emit_wrapper_file ( sess, & wrapper, tmpdir. as_ref ( ) , rmeta_link:: FILENAME ) )
323+ } else {
324+ None
325+ } ;
326+
310327 let trailing_metadata = match flavor {
311328 RlibFlavor :: Normal => {
312329 let ( metadata, metadata_position) =
@@ -320,6 +337,11 @@ fn link_rlib<'a>(
320337 // If it is possible however, placing the metadata object first improves
321338 // performance of getting metadata from rlibs.
322339 ab. add_file ( & metadata) ;
340+ // Place the rlib digest immediately after metadata so consumers
341+ // can find it without iterating the whole archive.
342+ if let Some ( df) = & digest_file {
343+ ab. add_file ( df) ;
344+ }
323345 None
324346 }
325347 MetadataPosition :: Last => Some ( metadata) ,
@@ -383,7 +405,7 @@ fn link_rlib<'a>(
383405 packed_bundled_libs. push ( wrapper_file) ;
384406 } else {
385407 let path = find_native_static_library ( lib. name . as_str ( ) , lib. verbatim , sess) ;
386- ab. add_archive ( & path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
408+ ab. add_archive ( & path, None ) . unwrap_or_else ( |error| {
387409 sess. dcx ( ) . emit_fatal ( errors:: AddNativeLibrary { library_path : path, error } )
388410 } ) ;
389411 }
@@ -400,7 +422,7 @@ fn link_rlib<'a>(
400422 tmpdir. as_ref ( ) ,
401423 true ,
402424 ) {
403- ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
425+ ab. add_archive ( & output_path, None ) . unwrap_or_else ( |error| {
404426 sess. dcx ( )
405427 . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
406428 } ) ;
@@ -434,6 +456,11 @@ fn link_rlib<'a>(
434456 // Basically, all this means is that this code should not move above the
435457 // code above.
436458 ab. add_file ( & trailing_metadata) ;
459+ // Place the rlib digest immediately after metadata so consumers can find
460+ // it without iterating the whole archive.
461+ if let Some ( df) = & digest_file {
462+ ab. add_file ( df) ;
463+ }
437464 }
438465
439466 // Add all bundled static native library dependencies.
@@ -488,14 +515,14 @@ fn link_staticlib(
488515 let bundled_libs: FxIndexSet < _ > = native_libs. filter_map ( |lib| lib. filename ) . collect ( ) ;
489516 ab. add_archive (
490517 path,
491- Box :: new ( move |fname : & str | {
492- // Ignore metadata files, no matter the name .
493- if fname == METADATA_FILENAME {
518+ Some ( Box :: new ( move |fname : & str , digest | {
519+ // Ignore metadata and rlib digest files .
520+ if fname == METADATA_FILENAME || fname == rmeta_link :: FILENAME {
494521 return true ;
495522 }
496523
497- // Don't include Rust objects if LTO is enabled
498- if lto && looks_like_rust_object_file ( fname) {
524+ // Don't include Rust objects if LTO is enabled.
525+ if lto && digest . is_some_and ( |d| d . rust_object_files . iter ( ) . any ( |f| f == fname) ) {
499526 return true ;
500527 }
501528
@@ -505,7 +532,7 @@ fn link_staticlib(
505532 }
506533
507534 false
508- } ) ,
535+ } ) ) ,
509536 )
510537 . unwrap ( ) ;
511538
@@ -516,7 +543,7 @@ fn link_staticlib(
516543 for filename in relevant_libs. iter ( ) {
517544 let joined = tempdir. as_ref ( ) . join ( filename. as_str ( ) ) ;
518545 let path = joined. as_path ( ) ;
519- ab. add_archive ( path, Box :: new ( |_| false ) ) . unwrap ( ) ;
546+ ab. add_archive ( path, None ) . unwrap ( ) ;
520547 }
521548
522549 all_native_libs. extend ( crate_info. native_libraries [ & cnum] . iter ( ) . cloned ( ) ) ;
@@ -3167,23 +3194,20 @@ fn add_static_crate(
31673194 let bundled_lib_file_names = bundled_lib_file_names. clone ( ) ;
31683195
31693196 sess. prof . generic_activity_with_arg ( "link_altering_rlib" , name) . run ( || {
3170- let canonical_name = name. replace ( '-' , "_" ) ;
31713197 let upstream_rust_objects_already_included =
31723198 are_upstream_rust_objects_already_included ( sess) ;
31733199 let is_builtins = sess. target . no_builtins || !crate_info. is_no_builtins . contains ( & cnum) ;
31743200
31753201 let mut archive = archive_builder_builder. new_archive_builder ( sess) ;
31763202 if let Err ( error) = archive. add_archive (
31773203 cratepath,
3178- Box :: new ( move |f| {
3179- if f == METADATA_FILENAME {
3204+ Some ( Box :: new ( move |f, digest | {
3205+ if f == METADATA_FILENAME || f == rmeta_link :: FILENAME {
31803206 return true ;
31813207 }
31823208
3183- let canonical = f. replace ( '-' , "_" ) ;
3184-
31853209 let is_rust_object =
3186- canonical . starts_with ( & canonical_name ) && looks_like_rust_object_file ( f ) ;
3210+ digest . is_some_and ( |d| d . rust_object_files . iter ( ) . any ( |rf| rf == f ) ) ;
31873211
31883212 // If we're performing LTO and this is a rust-generated object
31893213 // file, then we don't need the object file as it's part of the
@@ -3203,7 +3227,7 @@ fn add_static_crate(
32033227 }
32043228
32053229 false
3206- } ) ,
3230+ } ) ) ,
32073231 ) {
32083232 sess. dcx ( )
32093233 . emit_fatal ( errors:: RlibArchiveBuildFailure { path : cratepath. clone ( ) , error } ) ;
0 commit comments