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