From b8f22847b05177c42eccab018db05bc83bbd975e Mon Sep 17 00:00:00 2001 From: mehdiakiki Date: Mon, 18 May 2026 21:23:01 -0400 Subject: [PATCH] Move NativeLib::filename to the rmeta-link archive member --- compiler/rustc_codegen_ssa/src/back/link.rs | 121 +++++++++++++++--- .../rustc_codegen_ssa/src/back/rmeta_link.rs | 40 +++++- compiler/rustc_codegen_ssa/src/lib.rs | 2 - compiler/rustc_metadata/src/lib.rs | 4 +- compiler/rustc_metadata/src/native_libs.rs | 24 +--- compiler/rustc_session/src/cstore.rs | 2 - 6 files changed, 148 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c527dd95e2db4..a42225aee9e97 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -26,7 +26,7 @@ use rustc_lint_defs::builtin::LINKER_INFO; use rustc_macros::Diagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; use rustc_metadata::{ - EncodedMetadata, NativeLibSearchFallback, find_native_static_library, + EncodedMetadata, NativeLibSearchFallback, find_bundled_library, find_native_static_library, walk_native_lib_search_dirs, }; use rustc_middle::bug; @@ -310,8 +310,25 @@ fn link_rlib<'a>( .map(|obj| obj.file_name().unwrap().to_str().unwrap().to_string()) .collect(); + let native_lib_filenames: Vec> = crate_info + .used_libraries + .iter() + .map(|lib| { + find_bundled_library( + lib.name, + Some(lib.verbatim), + lib.kind, + lib.cfg.is_some(), + sess, + &crate_info.crate_types, + ) + }) + .collect(); + let metadata_link_file = if matches!(flavor, RlibFlavor::Normal) { - let metadata_link = rmeta_link::RmetaLink { rust_object_files }; + let native_lib_filenames: Vec> = + native_lib_filenames.iter().map(|f| f.map(|s| s.to_string())).collect(); + let metadata_link = rmeta_link::RmetaLink { rust_object_files, native_lib_filenames }; let metadata_link_data = metadata_link.encode(); let (wrapper, _) = create_wrapper_file(sess, rmeta_link::SECTION.to_string(), &metadata_link_data); @@ -386,12 +403,12 @@ fn link_rlib<'a>( // feature then we'll need to figure out how to record what objects were // loaded from the libraries found here and then encode that into the // metadata of the rlib we're generating somehow. - for lib in crate_info.used_libraries.iter() { + for (i, lib) in crate_info.used_libraries.iter().enumerate() { let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else { continue; }; if flavor == RlibFlavor::Normal - && let Some(filename) = lib.filename + && let Some(filename) = native_lib_filenames[i] { let path = find_native_static_library(filename.as_str(), true, sess); let src = read(path) @@ -504,11 +521,31 @@ fn link_staticlib( let lto = are_upstream_rust_objects_already_included(sess) && !ignored_for_lto(sess, crate_info, cnum); - let native_libs = crate_info.native_libraries[&cnum].iter(); - let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); - let relevant_libs: FxIndexSet<_> = relevant.filter_map(|lib| lib.filename).collect(); + let native_libs = &crate_info.native_libraries[&cnum]; + let filenames: Vec> = if crate_may_have_bundled_libs(native_libs) { + rmeta_link::read_from_path(&sess.target, path) + .map(|rl| { + rl.native_lib_filenames + .iter() + .map(|f| f.as_deref().map(Symbol::intern)) + .collect() + }) + .unwrap_or_default() + } else { + Vec::new() + }; + let relevant_libs: FxIndexSet<_> = native_libs + .iter() + .enumerate() + .filter(|(_, lib)| relevant_lib(sess, lib)) + .filter_map(|(i, _)| filenames.get(i).copied().flatten()) + .collect(); - let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); + let bundled_libs: FxIndexSet<_> = native_libs + .iter() + .enumerate() + .filter_map(|(i, _)| filenames.get(i).copied().flatten()) + .collect(); ab.add_archive( path, Some(Box::new(move |fname: &str, metadata_link| { @@ -2866,6 +2903,11 @@ fn collect_natvis_visualizers( visualizer_paths } +fn crate_may_have_bundled_libs(libs: &[NativeLib]) -> bool { + libs.iter() + .any(|lib| matches!(lib.kind, NativeLibKind::Static { bundle: Some(true) | None, .. })) +} + fn add_native_libs_from_crate( cmd: &mut dyn Linker, sess: &Session, @@ -2893,13 +2935,47 @@ fn add_native_libs_from_crate( .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); } - let native_libs = match cnum { - LOCAL_CRATE => &crate_info.used_libraries, - _ => &crate_info.native_libraries[&cnum], + let (native_libs, filenames): (&Vec, Vec>) = match cnum { + LOCAL_CRATE => { + let libs = &crate_info.used_libraries; + let filenames = libs + .iter() + .map(|lib| { + find_bundled_library( + lib.name, + Some(lib.verbatim), + lib.kind, + lib.cfg.is_some(), + sess, + &crate_info.crate_types, + ) + }) + .collect(); + (libs, filenames) + } + _ => { + let native_libs = &crate_info.native_libraries[&cnum]; + let filenames: Vec> = if crate_may_have_bundled_libs(native_libs) { + crate_info.used_crate_source[&cnum] + .rlib + .as_ref() + .and_then(|rlib_path| rmeta_link::read_from_path(&sess.target, rlib_path)) + .map(|rl| { + rl.native_lib_filenames + .iter() + .map(|f| f.as_deref().map(Symbol::intern)) + .collect() + }) + .unwrap_or_default() + } else { + Vec::new() + }; + (native_libs, filenames) + } }; let mut last = (None, NativeLibKind::Unspecified, false); - for lib in native_libs { + for (i, lib) in native_libs.iter().enumerate() { if !relevant_lib(sess, lib) { continue; } @@ -2919,7 +2995,7 @@ fn add_native_libs_from_crate( let bundle = bundle.unwrap_or(true); let whole_archive = whole_archive == Some(true); if bundle && cnum != LOCAL_CRATE { - if let Some(filename) = lib.filename { + if let Some(filename) = filenames.get(i).copied().flatten() { // If rlib contains native libs as archives, they are unpacked to tmpdir. let path = tmpdir.join(filename.as_str()); cmd.link_staticlib_by_path(&path, whole_archive); @@ -3040,10 +3116,21 @@ fn add_upstream_rust_crates( match linkage { Linkage::Static | Linkage::IncludedFromDylib | Linkage::NotLinked => { if link_static_crate { - bundled_libs = crate_info.native_libraries[&cnum] - .iter() - .filter_map(|lib| lib.filename) - .collect(); + if crate_may_have_bundled_libs(&crate_info.native_libraries[&cnum]) { + bundled_libs = crate_info.used_crate_source[&cnum] + .rlib + .as_ref() + .and_then(|rlib_path| { + rmeta_link::read_from_path(&sess.target, rlib_path) + }) + .map(|rl| { + rl.native_lib_filenames + .iter() + .filter_map(|f| f.as_deref().map(Symbol::intern)) + .collect() + }) + .unwrap_or_default(); + } add_static_crate( cmd, sess, diff --git a/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs b/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs index 68b23ca9ac5cb..44bbbb7cf81f4 100644 --- a/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs +++ b/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs @@ -2,26 +2,34 @@ //! and potentially other data collected and used when building or linking a rlib. //! See . +use std::fs::File; use std::path::Path; use object::read::archive::ArchiveFile; +use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::mem_encoder::MemEncoder; use rustc_serialize::opaque::{MAGIC_END_BYTES, MemDecoder}; use rustc_serialize::{Decodable, Encodable}; +use rustc_target::spec::Target; +use tracing::debug; -use super::metadata::search_for_section; +use super::metadata::{get_metadata_xcoff, search_for_section}; pub(crate) const FILENAME: &str = "lib.rmeta-link"; pub(crate) const SECTION: &str = ".rmeta-link"; pub struct RmetaLink { pub rust_object_files: Vec, + /// Positionally aligned with `native_libraries` in regular metadata: index `i` is the + /// bundled filename for native library `i`, or `None` if that library needs no bundling. + pub native_lib_filenames: Vec>, } impl RmetaLink { pub(crate) fn encode(&self) -> Vec { let mut encoder = MemEncoder::new(); self.rust_object_files.encode(&mut encoder); + self.native_lib_filenames.encode(&mut encoder); let mut data = encoder.finish(); data.extend_from_slice(MAGIC_END_BYTES); data @@ -30,7 +38,8 @@ impl RmetaLink { pub(crate) fn decode(data: &[u8]) -> Option { let mut decoder = MemDecoder::new(data, 0).ok()?; let rust_object_files = Vec::::decode(&mut decoder); - Some(RmetaLink { rust_object_files }) + let native_lib_filenames = Vec::>::decode(&mut decoder); + Some(RmetaLink { rust_object_files, native_lib_filenames }) } } @@ -54,3 +63,30 @@ pub fn read_from_data(archive_data: &[u8], rlib_path: &Path) -> Option Option { + let Ok(file) = File::open(path) else { + debug!("failed to open rlib for rmeta-link: {}", path.display()); + return None; + }; + let Ok(mmap) = (unsafe { Mmap::map(file) }) else { + debug!("failed to mmap rlib for rmeta-link: {}", path.display()); + return None; + }; + + if target.is_like_aix { + let archive = ArchiveFile::parse(&*mmap).ok()?; + for entry in archive.members() { + let entry = entry.ok()?; + if entry.name() == FILENAME.as_bytes() { + let member_data = entry.data(&*mmap).ok()?; + let section_data = get_metadata_xcoff(path, member_data).ok()?; + return RmetaLink::decode(section_data); + } + } + return None; + } + + read_from_data(&mmap, path) +} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index c7446bd784b40..006271c95dc9b 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -208,7 +208,6 @@ bitflags::bitflags! { pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, - pub filename: Option, pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, @@ -218,7 +217,6 @@ impl From<&cstore::NativeLib> for NativeLib { fn from(lib: &cstore::NativeLib) -> Self { NativeLib { kind: lib.kind, - filename: lib.filename, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim.unwrap_or(false), diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 1dff5740ab3bc..0dc43ec89a1c2 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -28,7 +28,7 @@ pub mod locator; pub use creader::{DylibError, load_symbol_from_dylib}; pub use fs::{METADATA_FILENAME, emit_wrapper_file}; pub use native_libs::{ - NativeLibSearchFallback, find_native_static_library, try_find_native_dynamic_library, - try_find_native_static_library, walk_native_lib_search_dirs, + NativeLibSearchFallback, find_bundled_library, find_native_static_library, + try_find_native_dynamic_library, try_find_native_static_library, walk_native_lib_search_dirs, }; pub use rmeta::{EncodedMetadata, METADATA_HEADER, encode_metadata, rendered_const}; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index b64cb8843ed71..3dd429c2d3790 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -163,16 +163,16 @@ pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim))) } -fn find_bundled_library( +pub fn find_bundled_library( name: Symbol, verbatim: Option, kind: NativeLibKind, has_cfg: bool, - tcx: TyCtxt<'_>, + sess: &Session, + crate_types: &[CrateType], ) -> Option { - let sess = tcx.sess; if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive, .. } = kind - && tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib)) + && crate_types.iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib)) && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true)) { let verbatim = verbatim.unwrap_or(false); @@ -245,16 +245,8 @@ impl<'tcx> Collector<'tcx> { } }; - let filename = find_bundled_library( - attr.name, - attr.verbatim, - attr.kind, - attr.cfg.is_some(), - self.tcx, - ); self.libs.push(NativeLib { name: attr.name, - filename, kind: attr.kind, cfg: attr.cfg.clone(), foreign_module: Some(def_id.to_def_id()), @@ -334,16 +326,8 @@ impl<'tcx> Collector<'tcx> { // Add if not found let new_name: Option<&str> = passed_lib.new_name.as_deref(); let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name)); - let filename = find_bundled_library( - name, - passed_lib.verbatim, - passed_lib.kind, - false, - self.tcx, - ); self.libs.push(NativeLib { name, - filename, kind: passed_lib.kind, cfg: None, foreign_module: None, diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 39fe9c80923ec..0c5150ac3efcc 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -68,8 +68,6 @@ pub enum LinkagePreference { pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, - /// If packed_bundled_libs enabled, actual filename of library is stored. - pub filename: Option, pub cfg: Option, pub foreign_module: Option, pub verbatim: Option,