rustc_codegen_ssa/back/
rmeta_link.rs1use std::fs::File;
6use std::path::{Path, PathBuf};
7
8use object::read::archive::ArchiveFile;
9use rustc_data_structures::fx::FxHashMap;
10use rustc_data_structures::memmap::Mmap;
11use rustc_hir::attrs::NativeLibKind;
12use rustc_serialize::opaque::mem_encoder::MemEncoder;
13use rustc_serialize::opaque::{MAGIC_END_BYTES, MemDecoder};
14use rustc_serialize::{Decodable, Encodable};
15use rustc_span::Symbol;
16use rustc_target::spec::Target;
17use tracing::debug;
18
19use super::metadata::{get_metadata_xcoff, search_for_section};
20use crate::NativeLib;
21
22pub(crate) const FILENAME: &str = "lib.rmeta-link";
23pub(crate) const SECTION: &str = ".rmeta-link";
24
25pub struct RmetaLink {
26 pub rust_object_files: Vec<String>,
27 pub native_lib_filenames: Vec<Option<String>>,
30}
31
32impl RmetaLink {
33 pub(crate) fn encode(&self) -> Vec<u8> {
34 let mut encoder = MemEncoder::new();
35 self.rust_object_files.encode(&mut encoder);
36 self.native_lib_filenames.encode(&mut encoder);
37 let mut data = encoder.finish();
38 data.extend_from_slice(MAGIC_END_BYTES);
39 data
40 }
41
42 pub(crate) fn decode(data: &[u8]) -> Option<RmetaLink> {
43 let mut decoder = MemDecoder::new(data, 0).ok()?;
44 let rust_object_files = Vec::<String>::decode(&mut decoder);
45 let native_lib_filenames = Vec::<Option<String>>::decode(&mut decoder);
46 Some(RmetaLink { rust_object_files, native_lib_filenames })
47 }
48}
49
50pub fn read(archive: &ArchiveFile<'_>, archive_data: &[u8], rlib_path: &Path) -> Option<RmetaLink> {
52 for entry in archive.members() {
53 let entry = entry.ok()?;
54 if entry.name() == FILENAME.as_bytes() {
55 let data = entry.data(archive_data).ok()?;
56 let section_data = search_for_section(rlib_path, data, SECTION).ok()?;
57 return RmetaLink::decode(section_data);
58 }
59 }
60 None
61}
62
63pub fn read_from_data(archive_data: &[u8], rlib_path: &Path) -> Option<RmetaLink> {
67 let archive = ArchiveFile::parse(archive_data).ok()?;
68 read(&archive, archive_data, rlib_path)
69}
70
71#[derive(#[automatically_derived]
impl ::core::default::Default for RmetaLinkCache {
#[inline]
fn default() -> RmetaLinkCache {
RmetaLinkCache { cache: ::core::default::Default::default() }
}
}Default)]
72pub struct RmetaLinkCache {
73 cache: FxHashMap<PathBuf, Option<RmetaLink>>,
74}
75
76impl RmetaLinkCache {
77 pub fn get_or_insert_with(
78 &mut self,
79 rlib_path: &Path,
80 load: impl FnOnce() -> Option<RmetaLink>,
81 ) -> Option<&RmetaLink> {
82 self.cache.entry(rlib_path.to_path_buf()).or_insert_with(load).as_ref()
83 }
84
85 pub fn native_lib_filenames(
86 &mut self,
87 target: &Target,
88 rlib_path: &Path,
89 native_libs: &[NativeLib],
90 ) -> Vec<Option<Symbol>> {
91 if !crate_may_have_bundled_libs(native_libs) {
92 return Vec::new();
93 }
94 self.get_or_insert_with(rlib_path, || read_from_path(target, rlib_path))
95 .map(|rl| {
96 rl.native_lib_filenames.iter().map(|f| f.as_deref().map(Symbol::intern)).collect()
97 })
98 .unwrap_or_default()
99 }
100}
101
102fn crate_may_have_bundled_libs(libs: &[NativeLib]) -> bool {
103 libs.iter()
104 .any(|lib| #[allow(non_exhaustive_omitted_patterns)] match lib.kind {
NativeLibKind::Static { bundle: Some(true) | None, .. } => true,
_ => false,
}matches!(lib.kind, NativeLibKind::Static { bundle: Some(true) | None, .. }))
105}
106
107fn read_from_path(target: &Target, path: &Path) -> Option<RmetaLink> {
109 let Ok(file) = File::open(path) else {
110 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rmeta_link.rs:110",
"rustc_codegen_ssa::back::rmeta_link",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rmeta_link.rs"),
::tracing_core::__macro_support::Option::Some(110u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rmeta_link"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("failed to open rlib for rmeta-link: {0}",
path.display()) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("failed to open rlib for rmeta-link: {}", path.display());
111 return None;
112 };
113 let Ok(mmap) = (unsafe { Mmap::map(file) }) else {
114 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/rmeta_link.rs:114",
"rustc_codegen_ssa::back::rmeta_link",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/rmeta_link.rs"),
::tracing_core::__macro_support::Option::Some(114u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::rmeta_link"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("failed to mmap rlib for rmeta-link: {0}",
path.display()) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("failed to mmap rlib for rmeta-link: {}", path.display());
115 return None;
116 };
117
118 if target.is_like_aix {
119 let archive = ArchiveFile::parse(&*mmap).ok()?;
120 for entry in archive.members() {
121 let entry = entry.ok()?;
122 if entry.name() == FILENAME.as_bytes() {
123 let member_data = entry.data(&*mmap).ok()?;
124 let section_data = get_metadata_xcoff(path, member_data).ok()?;
125 return RmetaLink::decode(section_data);
126 }
127 }
128 return None;
129 }
130
131 read_from_data(&mmap, path)
132}