rustc_metadata/
native_libs.rs1use rustc_abi::ExternAbi;
2use rustc_attr_ir::{PeImportNameType, find_attr};
3use rustc_attr_parsing::eval_config_entry;
4use rustc_crate_store::{
5 DllCallingConvention, DllImport, DllImportSymbolType, ForeignModule, NativeLib,
6};
7use rustc_data_structures::fx::FxHashSet;
8use rustc_hir::def::DefKind;
9use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
10use rustc_middle::query::LocalCrate;
11use rustc_middle::ty::{self, List, Ty, TyCtxt};
12use rustc_session::Session;
13use rustc_span::def_id::{DefId, LOCAL_CRATE};
14use rustc_span::{Symbol, bug};
15use rustc_structures::NativeLibKind;
16use rustc_target::spec::{Arch, BinaryFormat, CfgAbi};
17
18use crate::diagnostics;
19
20pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
21 let mut collector = Collector { tcx, libs: Vec::new() };
22 if tcx.sess.opts.unstable_opts.link_directives {
23 for module in tcx.foreign_modules(LOCAL_CRATE).values() {
24 collector.process_module(module);
25 }
26 }
27 collector.process_command_line();
28 for lib in &mut collector.libs {
29 if tcx.sess.target.cfg_abi == CfgAbi::Pauthtest {
33 if let NativeLibKind::Static { .. } = lib.kind {
34 if !tcx.sess.opts.unstable_opts.ui_testing {
35 let diag = if lib.foreign_module.is_none() {
36 diagnostics::StaticLinkingNotSupported::UserRequested {
37 lib_name: lib.name,
38 target: tcx.sess.target.llvm_target.as_ref(),
39 }
40 } else {
41 diagnostics::StaticLinkingNotSupported::FromDependency {
42 lib_name: lib.name,
43 target: tcx.sess.target.llvm_target.as_ref(),
44 }
45 };
46 tcx.dcx().emit_warn(diag);
47 }
48
49 lib.kind = NativeLibKind::Dylib { as_needed: None };
50 }
51 }
52 }
53 collector.libs
54}
55
56pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
57 match lib.cfg {
58 Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(),
59 None => true,
60 }
61}
62
63struct Collector<'tcx> {
64 tcx: TyCtxt<'tcx>,
65 libs: Vec<NativeLib>,
66}
67
68impl<'tcx> Collector<'tcx> {
69 fn process_module(&mut self, module: &ForeignModule) {
70 let ForeignModule { def_id, abi, ref foreign_items } = *module;
71 let def_id = def_id.expect_local();
72
73 let sess = self.tcx.sess;
74
75 if #[allow(non_exhaustive_omitted_patterns)] match abi {
ExternAbi::Rust => true,
_ => false,
}matches!(abi, ExternAbi::Rust) {
76 return;
77 }
78
79 for attr in {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(Link(links, _)) => {
break 'done Some(links);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(self.tcx, def_id, Link(links, _) => links).into_flat_iter() {
80 let dll_imports = match attr.kind {
81 NativeLibKind::RawDylib { .. } => foreign_items
82 .iter()
83 .filter_map(|&child_item| {
84 self.build_dll_import(
85 abi,
86 attr.import_name_type.map(|(import_name_type, _)| import_name_type),
87 child_item,
88 )
89 })
90 .collect(),
91 _ => {
92 for &child_item in foreign_items {
93 if let Some(span) =
94 {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(child_item, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(LinkOrdinal { span, .. })
=> {
break 'done Some(*span);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(self.tcx, child_item, LinkOrdinal {span, ..} => *span)
95 {
96 sess.dcx().emit_err(diagnostics::LinkOrdinalRawDylib { span });
97 }
98 }
99
100 Vec::new()
101 }
102 };
103
104 self.libs.push(NativeLib {
105 name: attr.name,
106 kind: attr.kind,
107 cfg: attr.cfg.clone(),
108 foreign_module: Some(def_id.to_def_id()),
109 verbatim: attr.verbatim,
110 dll_imports,
111 });
112 }
113 }
114
115 fn process_command_line(&mut self) {
117 let mut renames = FxHashSet::default();
119 for lib in &self.tcx.sess.opts.libs {
120 if let NativeLibKind::Framework { .. } = lib.kind
121 && !self.tcx.sess.target.is_like_darwin
122 {
123 self.tcx.dcx().emit_err(diagnostics::LibFrameworkApple);
125 }
126 if let Some(ref new_name) = lib.new_name {
127 let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
128 if new_name.is_empty() {
129 self.tcx
130 .dcx()
131 .emit_err(diagnostics::EmptyRenamingTarget { lib_name: &lib.name });
132 } else if !any_duplicate {
133 self.tcx.dcx().emit_err(diagnostics::RenamingNoLink { lib_name: &lib.name });
134 } else if !renames.insert(&lib.name) {
135 self.tcx.dcx().emit_err(diagnostics::MultipleRenamings { lib_name: &lib.name });
136 }
137 }
138 }
139
140 for passed_lib in &self.tcx.sess.opts.libs {
148 let mut existing = self
152 .libs
153 .extract_if(.., |lib| {
154 if lib.name.as_str() == passed_lib.name {
155 if lib.has_modifiers() || passed_lib.has_modifiers() {
159 match lib.foreign_module {
160 Some(def_id) => {
161 self.tcx.dcx().emit_err(diagnostics::NoLinkModOverride {
162 span: Some(self.tcx.def_span(def_id)),
163 })
164 }
165 None => self
166 .tcx
167 .dcx()
168 .emit_err(diagnostics::NoLinkModOverride { span: None }),
169 };
170 }
171 if passed_lib.kind != NativeLibKind::Unspecified {
172 lib.kind = passed_lib.kind;
173 }
174 if let Some(new_name) = &passed_lib.new_name {
175 lib.name = Symbol::intern(new_name);
176 }
177 lib.verbatim = passed_lib.verbatim;
178 return true;
179 }
180 false
181 })
182 .collect::<Vec<_>>();
183 if existing.is_empty() {
184 let new_name: Option<&str> = passed_lib.new_name.as_deref();
186 let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
187 self.libs.push(NativeLib {
188 name,
189 kind: passed_lib.kind,
190 cfg: None,
191 foreign_module: None,
192 verbatim: passed_lib.verbatim,
193 dll_imports: Vec::new(),
194 });
195 } else {
196 self.libs.append(&mut existing);
199 }
200 }
201 }
202
203 fn i686_arg_list_size(&self, item: DefId) -> usize {
204 let argument_types: &List<Ty<'_>> = self.tcx.instantiate_bound_regions_with_erased(
205 self.tcx
206 .type_of(item)
207 .instantiate_identity()
208 .skip_norm_wip()
209 .fn_sig(self.tcx)
210 .inputs()
211 .map_bound(|slice| self.tcx.mk_type_list(slice)),
212 );
213
214 argument_types
215 .iter()
216 .map(|ty| {
217 let layout = self
218 .tcx
219 .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
220 .expect("layout")
221 .layout;
222 (layout.size().bytes_usize() + 3) & !3
225 })
226 .sum()
227 }
228
229 fn build_dll_import(
230 &self,
231 abi: ExternAbi,
232 import_name_type: Option<PeImportNameType>,
233 item: DefId,
234 ) -> Option<DllImport> {
235 let span = self.tcx.def_span(item);
236
237 if !self.tcx.sess.target.is_abi_supported(abi) {
::core::panicking::panic("assertion failed: self.tcx.sess.target.is_abi_supported(abi)")
};assert!(self.tcx.sess.target.is_abi_supported(abi));
240
241 let calling_convention = if self.tcx.sess.target.arch == Arch::X86 {
245 match abi {
246 ExternAbi::C { .. } | ExternAbi::Cdecl { .. } => DllCallingConvention::C,
247 ExternAbi::Stdcall { .. } => {
248 DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
249 }
250 ExternAbi::System { .. } => {
254 let c_variadic = self
255 .tcx
256 .type_of(item)
257 .instantiate_identity()
258 .skip_norm_wip()
259 .fn_sig(self.tcx)
260 .c_variadic();
261
262 if c_variadic {
263 DllCallingConvention::C
264 } else {
265 DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
266 }
267 }
268 ExternAbi::Fastcall { .. } => {
269 DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
270 }
271 ExternAbi::Vectorcall { .. } => {
272 DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
273 }
274 _ => {
275 self.tcx.dcx().emit_err(diagnostics::RawDylibUnsupportedAbi { span });
276 return None;
277 }
278 }
279 } else {
280 match abi {
281 ExternAbi::C { .. } | ExternAbi::Win64 { .. } | ExternAbi::System { .. } => {
282 DllCallingConvention::C
283 }
284 _ => {
285 self.tcx.dcx().emit_err(diagnostics::RawDylibUnsupportedAbi { span });
286 return None;
287 }
288 }
289 };
290
291 let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
292 let import_name_type = codegen_fn_attrs
293 .link_ordinal
294 .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
295
296 let name = codegen_fn_attrs.symbol_name.unwrap_or_else(|| self.tcx.item_name(item));
297
298 if self.tcx.sess.target.binary_format == BinaryFormat::Elf {
299 let name = name.as_str();
300 if name.contains('\0') {
301 self.tcx.dcx().emit_err(diagnostics::RawDylibMalformed { span });
302 } else if let Some((left, right)) = name.split_once('@')
303 && (left.is_empty() || right.is_empty() || right.contains('@'))
304 {
305 self.tcx.dcx().emit_err(diagnostics::RawDylibMalformed { span });
306 }
307 }
308
309 let def_kind = self.tcx.def_kind(item);
310 let symbol_type = if def_kind.is_fn_like() {
311 DllImportSymbolType::Function
312 } else if #[allow(non_exhaustive_omitted_patterns)] match def_kind {
DefKind::Static { .. } => true,
_ => false,
}matches!(def_kind, DefKind::Static { .. }) {
313 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
314 DllImportSymbolType::ThreadLocal
315 } else {
316 DllImportSymbolType::Static
317 }
318 } else if def_kind == DefKind::ForeignTy {
319 return None;
320 } else {
321 ::rustc_span::macros::bug_impl(None,
format_args!("Unexpected type for raw-dylib: {0}", def_kind.descr(item)),
Location::caller());bug!("Unexpected type for raw-dylib: {}", def_kind.descr(item));
322 };
323
324 let size = match symbol_type {
325 DllImportSymbolType::Function => rustc_abi::Size::ZERO,
327 DllImportSymbolType::Static | DllImportSymbolType::ThreadLocal => {
328 let ty = self.tcx.type_of(item).instantiate_identity().skip_norm_wip();
329 self.tcx
330 .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
331 .ok()
332 .map(|layout| layout.size)
333 .unwrap_or_else(|| ::rustc_span::macros::bug_impl(None,
format_args!("Non-function symbols must have a size"), Location::caller())bug!("Non-function symbols must have a size"))
334 }
335 };
336
337 Some(DllImport { name, import_name_type, calling_convention, span, symbol_type, size })
338 }
339}