1use std::error::Error;
4use std::ops::Fn;
5use std::path::Path;
6use std::str::FromStr;
7use std::time::Duration;
8use std::{cmp, env, iter};
9
10use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name};
11use rustc_ast::{self as ast, *};
12use rustc_data_structures::fx::FxHashSet;
13use rustc_data_structures::owned_slice::OwnedSlice;
14use rustc_data_structures::svh::Svh;
15use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
16use rustc_errors::DiagCtxtHandle;
17use rustc_expand::base::SyntaxExtension;
18use rustc_fs_util::try_canonicalize;
19use rustc_hir as hir;
20use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId};
21use rustc_hir::definitions::Definitions;
22use rustc_index::IndexVec;
23use rustc_middle::bug;
24use rustc_middle::ty::data_structures::IndexSet;
25use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
26use rustc_proc_macro::bridge::client::ProcMacro;
27use rustc_session::config::{
28 self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
29 TargetModifier,
30};
31use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
32use rustc_session::lint::{self, BuiltinLintDiag};
33use rustc_session::output::validate_crate_name;
34use rustc_session::search_paths::PathKind;
35use rustc_span::edition::Edition;
36use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
37use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
38use tracing::{debug, info, trace};
39
40use crate::errors;
41use crate::locator::{CrateError, CrateLocator, CratePaths};
42use crate::rmeta::{
43 CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
44};
45
46pub trait MetadataLoader {
51 fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
52 fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
53}
54
55pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
56
57pub struct CStore {
58 metadata_loader: Box<MetadataLoaderDyn>,
59
60 metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>,
61 injected_panic_runtime: Option<CrateNum>,
62 allocator_kind: Option<AllocatorKind>,
65 alloc_error_handler_kind: Option<AllocatorKind>,
68 has_global_allocator: bool,
70 has_alloc_error_handler: bool,
72
73 unused_externs: Vec<Symbol>,
75}
76
77impl std::fmt::Debug for CStore {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_struct("CStore").finish_non_exhaustive()
80 }
81}
82
83pub struct CrateLoader<'a, 'tcx: 'a> {
84 tcx: TyCtxt<'tcx>,
86 cstore: &'a mut CStore,
88 used_extern_options: &'a mut FxHashSet<Symbol>,
89}
90
91impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
92 type Target = TyCtxt<'tcx>;
93
94 fn deref(&self) -> &Self::Target {
95 &self.tcx
96 }
97}
98
99impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
100 fn dcx(&self) -> DiagCtxtHandle<'tcx> {
101 self.tcx.dcx()
102 }
103}
104
105pub enum LoadedMacro {
106 MacroDef {
107 def: MacroDef,
108 ident: Ident,
109 attrs: Vec<hir::Attribute>,
110 span: Span,
111 edition: Edition,
112 },
113 ProcMacro(SyntaxExtension),
114}
115
116pub(crate) struct Library {
117 pub source: CrateSource,
118 pub metadata: MetadataBlob,
119}
120
121enum LoadResult {
122 Previous(CrateNum),
123 Loaded(Library),
124}
125
126#[derive(Clone, Copy)]
128pub(crate) struct CrateMetadataRef<'a> {
129 pub cdata: &'a CrateMetadata,
130 pub cstore: &'a CStore,
131}
132
133impl std::ops::Deref for CrateMetadataRef<'_> {
134 type Target = CrateMetadata;
135
136 fn deref(&self) -> &Self::Target {
137 self.cdata
138 }
139}
140
141struct CrateDump<'a>(&'a CStore);
142
143impl<'a> std::fmt::Debug for CrateDump<'a> {
144 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 writeln!(fmt, "resolved crates:")?;
146 for (cnum, data) in self.0.iter_crate_data() {
147 writeln!(fmt, " name: {}", data.name())?;
148 writeln!(fmt, " cnum: {cnum}")?;
149 writeln!(fmt, " hash: {}", data.hash())?;
150 writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
151 writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
152 let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
153 if let Some(dylib) = dylib {
154 writeln!(fmt, " dylib: {}", dylib.0.display())?;
155 }
156 if let Some(rlib) = rlib {
157 writeln!(fmt, " rlib: {}", rlib.0.display())?;
158 }
159 if let Some(rmeta) = rmeta {
160 writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
161 }
162 if let Some(sdylib_interface) = sdylib_interface {
163 writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;
164 }
165 }
166 Ok(())
167 }
168}
169
170#[derive(Clone, Copy)]
172enum CrateOrigin<'a> {
173 IndirectDependency {
175 dep_root: &'a CratePaths,
177 parent_private: bool,
179 dep: &'a CrateDep,
181 },
182 Injected,
184 Extern,
186}
187
188impl<'a> CrateOrigin<'a> {
189 fn dep_root(&self) -> Option<&'a CratePaths> {
191 match self {
192 CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
193 _ => None,
194 }
195 }
196
197 fn dep(&self) -> Option<&'a CrateDep> {
199 match self {
200 CrateOrigin::IndirectDependency { dep, .. } => Some(dep),
201 _ => None,
202 }
203 }
204
205 fn private_dep(&self) -> Option<bool> {
208 match self {
209 CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
210 Some(dep.is_private || *parent_private)
211 }
212 _ => None,
213 }
214 }
215}
216
217impl CStore {
218 pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
219 FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
220 cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
221 })
222 }
223
224 pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {
225 FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
226 cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
227 })
228 }
229
230 fn intern_stable_crate_id<'tcx>(
231 &mut self,
232 root: &CrateRoot,
233 tcx: TyCtxt<'tcx>,
234 ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
235 assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
236 let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
237 if existing == LOCAL_CRATE {
239 CrateError::SymbolConflictsCurrent(root.name())
240 } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
241 {
242 let crate_name0 = root.name();
243 CrateError::StableCrateIdCollision(crate_name0, crate_name1)
244 } else {
245 CrateError::NotFound(root.name())
246 }
247 })?;
248
249 self.metas.push(None);
250 Ok(num)
251 }
252
253 pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
254 self.metas[cnum].is_some()
255 }
256
257 pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
258 let cdata = self.metas[cnum]
259 .as_ref()
260 .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
261 CrateMetadataRef { cdata, cstore: self }
262 }
263
264 pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {
265 self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
266 }
267
268 fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
269 assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
270 self.metas[cnum] = Some(Box::new(data));
271 }
272
273 pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
274 self.metas
275 .iter_enumerated()
276 .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
277 }
278
279 fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> {
280 self.metas
281 .iter_enumerated_mut()
282 .filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data)))
283 }
284
285 fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
286 if !deps.contains(&cnum) {
287 let data = self.get_crate_data(cnum);
288 for dep in data.dependencies() {
289 if dep != cnum {
290 self.push_dependencies_in_postorder(deps, dep);
291 }
292 }
293
294 deps.insert(cnum);
295 }
296 }
297
298 pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> IndexSet<CrateNum> {
299 let mut deps = IndexSet::default();
300 if cnum == LOCAL_CRATE {
301 for (cnum, _) in self.iter_crate_data() {
302 self.push_dependencies_in_postorder(&mut deps, cnum);
303 }
304 } else {
305 self.push_dependencies_in_postorder(&mut deps, cnum);
306 }
307 deps
308 }
309
310 fn crate_dependencies_in_reverse_postorder(
311 &self,
312 cnum: CrateNum,
313 ) -> impl Iterator<Item = CrateNum> {
314 self.crate_dependencies_in_postorder(cnum).into_iter().rev()
315 }
316
317 pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
318 self.injected_panic_runtime
319 }
320
321 pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {
322 self.allocator_kind
323 }
324
325 pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
326 self.alloc_error_handler_kind
327 }
328
329 pub(crate) fn has_global_allocator(&self) -> bool {
330 self.has_global_allocator
331 }
332
333 pub(crate) fn has_alloc_error_handler(&self) -> bool {
334 self.has_alloc_error_handler
335 }
336
337 pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
338 let json_unused_externs = tcx.sess.opts.json_unused_externs;
339
340 if !json_unused_externs.is_enabled() {
344 return;
345 }
346 let level = tcx
347 .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
348 .level;
349 if level != lint::Level::Allow {
350 let unused_externs =
351 self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
352 let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
353 tcx.dcx().emit_unused_externs(level, json_unused_externs.is_loud(), &unused_externs);
354 }
355 }
356
357 fn report_target_modifiers_extended(
358 tcx: TyCtxt<'_>,
359 krate: &Crate,
360 mods: &TargetModifiers,
361 dep_mods: &TargetModifiers,
362 data: &CrateMetadata,
363 ) {
364 let span = krate.spans.inner_span.shrink_to_lo();
365 let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
366 let local_crate = tcx.crate_name(LOCAL_CRATE);
367 let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
368 let report_diff = |prefix: &String,
369 opt_name: &String,
370 flag_local_value: Option<&String>,
371 flag_extern_value: Option<&String>| {
372 if allowed_flag_mismatches.contains(&opt_name) {
373 return;
374 }
375 let extern_crate = data.name();
376 let flag_name = opt_name.clone();
377 let flag_name_prefixed = format!("-{}{}", prefix, opt_name);
378
379 match (flag_local_value, flag_extern_value) {
380 (Some(local_value), Some(extern_value)) => {
381 tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
382 span,
383 extern_crate,
384 local_crate,
385 flag_name,
386 flag_name_prefixed,
387 local_value: local_value.to_string(),
388 extern_value: extern_value.to_string(),
389 })
390 }
391 (None, Some(extern_value)) => {
392 tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed {
393 span,
394 extern_crate,
395 local_crate,
396 flag_name,
397 flag_name_prefixed,
398 extern_value: extern_value.to_string(),
399 })
400 }
401 (Some(local_value), None) => {
402 tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed {
403 span,
404 extern_crate,
405 local_crate,
406 flag_name,
407 flag_name_prefixed,
408 local_value: local_value.to_string(),
409 })
410 }
411 (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),
412 };
413 };
414 let mut it1 = mods.iter().map(tmod_extender);
415 let mut it2 = dep_mods.iter().map(tmod_extender);
416 let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
417 let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
418 loop {
419 left_name_val = left_name_val.or_else(|| it1.next());
420 right_name_val = right_name_val.or_else(|| it2.next());
421 match (&left_name_val, &right_name_val) {
422 (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
423 cmp::Ordering::Equal => {
424 if l.0.tech_value != r.0.tech_value {
425 report_diff(
426 &l.0.prefix,
427 &l.0.name,
428 Some(&l.1.value_name),
429 Some(&r.1.value_name),
430 );
431 }
432 left_name_val = None;
433 right_name_val = None;
434 }
435 cmp::Ordering::Greater => {
436 report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
437 right_name_val = None;
438 }
439 cmp::Ordering::Less => {
440 report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
441 left_name_val = None;
442 }
443 },
444 (Some(l), None) => {
445 report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
446 left_name_val = None;
447 }
448 (None, Some(r)) => {
449 report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
450 right_name_val = None;
451 }
452 (None, None) => break,
453 }
454 }
455 }
456
457 pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
458 for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
459 if !OptionsTargetModifiers::is_target_modifier(flag_name) {
460 tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
461 span: krate.spans.inner_span.shrink_to_lo(),
462 flag_name: flag_name.clone(),
463 });
464 }
465 }
466 let mods = tcx.sess.opts.gather_target_modifiers();
467 for (_cnum, data) in self.iter_crate_data() {
468 if data.is_proc_macro_crate() {
469 continue;
470 }
471 let dep_mods = data.target_modifiers();
472 if mods != dep_mods {
473 Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
474 }
475 }
476 }
477
478 pub fn report_incompatible_async_drop_feature(&self, tcx: TyCtxt<'_>, krate: &Crate) {
480 if tcx.features().async_drop() {
481 return;
482 }
483 for (_cnum, data) in self.iter_crate_data() {
484 if data.is_proc_macro_crate() {
485 continue;
486 }
487 if data.has_async_drops() {
488 let extern_crate = data.name();
489 let local_crate = tcx.crate_name(LOCAL_CRATE);
490 tcx.dcx().emit_warn(errors::AsyncDropTypesInDependency {
491 span: krate.spans.inner_span.shrink_to_lo(),
492 extern_crate,
493 local_crate,
494 });
495 }
496 }
497 }
498
499 pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
500 CStore {
501 metadata_loader,
502 metas: IndexVec::from_iter(iter::once(None)),
507 injected_panic_runtime: None,
508 allocator_kind: None,
509 alloc_error_handler_kind: None,
510 has_global_allocator: false,
511 has_alloc_error_handler: false,
512 unused_externs: Vec::new(),
513 }
514 }
515}
516
517impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
518 pub fn new(
519 tcx: TyCtxt<'tcx>,
520 cstore: &'a mut CStore,
521 used_extern_options: &'a mut FxHashSet<Symbol>,
522 ) -> Self {
523 CrateLoader { tcx, cstore, used_extern_options }
524 }
525
526 fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
527 for (cnum, data) in self.cstore.iter_crate_data() {
528 if data.name() != name {
529 trace!("{} did not match {}", data.name(), name);
530 continue;
531 }
532
533 match hash {
534 Some(hash) if hash == data.hash() => return Some(cnum),
535 Some(hash) => {
536 debug!("actual hash {} did not match expected {}", hash, data.hash());
537 continue;
538 }
539 None => {}
540 }
541
542 let source = self.cstore.get_crate_data(cnum).cdata.source();
552 if let Some(entry) = self.sess.opts.externs.get(name.as_str()) {
553 if let Some(mut files) = entry.files() {
555 if files.any(|l| {
556 let l = l.canonicalized();
557 source.dylib.as_ref().map(|(p, _)| p) == Some(l)
558 || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
559 || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
560 }) {
561 return Some(cnum);
562 }
563 }
564 continue;
565 }
566
567 let prev_kind = source
574 .dylib
575 .as_ref()
576 .or(source.rlib.as_ref())
577 .or(source.rmeta.as_ref())
578 .expect("No sources for crate")
579 .1;
580 if kind.matches(prev_kind) {
581 return Some(cnum);
582 } else {
583 debug!(
584 "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
585 name, kind, prev_kind
586 );
587 }
588 }
589
590 None
591 }
592
593 fn is_private_dep(
604 &self,
605 name: Symbol,
606 private_dep: Option<bool>,
607 origin: CrateOrigin<'_>,
608 ) -> bool {
609 if matches!(origin, CrateOrigin::Injected) {
610 return true;
611 }
612
613 let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
614 match (extern_private, private_dep) {
615 (Some(false), _) | (_, Some(false)) | (None, None) => false,
618 (Some(true) | None, Some(true) | None) => true,
620 }
621 }
622
623 fn register_crate(
624 &mut self,
625 host_lib: Option<Library>,
626 origin: CrateOrigin<'_>,
627 lib: Library,
628 dep_kind: CrateDepKind,
629 name: Symbol,
630 private_dep: Option<bool>,
631 ) -> Result<CrateNum, CrateError> {
632 let _prof_timer =
633 self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
634
635 let Library { source, metadata } = lib;
636 let crate_root = metadata.get_root();
637 let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
638 let private_dep = self.is_private_dep(name, private_dep, origin);
639
640 let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
642 let cnum = feed.key();
643
644 info!(
645 "register crate `{}` (cnum = {}. private_dep = {})",
646 crate_root.name(),
647 cnum,
648 private_dep
649 );
650
651 let crate_paths;
654 let dep_root = if let Some(dep_root) = origin.dep_root() {
655 dep_root
656 } else {
657 crate_paths = CratePaths::new(crate_root.name(), source.clone());
658 &crate_paths
659 };
660
661 let cnum_map =
662 self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
663
664 let raw_proc_macros = if crate_root.is_proc_macro_crate() {
665 let temp_root;
666 let (dlsym_source, dlsym_root) = match &host_lib {
667 Some(host_lib) => (&host_lib.source, {
668 temp_root = host_lib.metadata.get_root();
669 &temp_root
670 }),
671 None => (&source, &crate_root),
672 };
673 let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
674 Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
675 } else {
676 None
677 };
678
679 let crate_metadata = CrateMetadata::new(
680 self.sess,
681 self.cstore,
682 metadata,
683 crate_root,
684 raw_proc_macros,
685 cnum,
686 cnum_map,
687 dep_kind,
688 source,
689 private_dep,
690 host_hash,
691 );
692
693 self.cstore.set_crate_data(cnum, crate_metadata);
694
695 Ok(cnum)
696 }
697
698 fn load_proc_macro<'b>(
699 &self,
700 locator: &mut CrateLocator<'b>,
701 path_kind: PathKind,
702 host_hash: Option<Svh>,
703 ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
704 where
705 'a: 'b,
706 {
707 let mut proc_macro_locator = locator.clone();
710
711 proc_macro_locator.is_proc_macro = true;
713
714 let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros {
716 proc_macro_locator.reset();
717 let result = match self.load(&mut proc_macro_locator)? {
718 Some(LoadResult::Previous(cnum)) => {
719 return Ok(Some((LoadResult::Previous(cnum), None)));
720 }
721 Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
722 None => return Ok(None),
723 };
724 locator.hash = host_hash;
725 (locator, result)
728 } else {
729 (&mut proc_macro_locator, None)
730 };
731
732 locator.reset();
735 locator.is_proc_macro = true;
736 locator.target = &self.sess.host;
737 locator.tuple = TargetTuple::from_tuple(config::host_tuple());
738 locator.filesearch = self.sess.host_filesearch();
739 locator.path_kind = path_kind;
740
741 let Some(host_result) = self.load(locator)? else {
742 return Ok(None);
743 };
744
745 Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros {
746 let host_result = match host_result {
747 LoadResult::Previous(..) => {
748 panic!("host and target proc macros must be loaded in lock-step")
749 }
750 LoadResult::Loaded(library) => library,
751 };
752 (target_result.unwrap(), Some(host_result))
753 } else {
754 (host_result, None)
755 }))
756 }
757
758 fn resolve_crate(
759 &mut self,
760 name: Symbol,
761 span: Span,
762 dep_kind: CrateDepKind,
763 origin: CrateOrigin<'_>,
764 ) -> Option<CrateNum> {
765 self.used_extern_options.insert(name);
766 match self.maybe_resolve_crate(name, dep_kind, origin) {
767 Ok(cnum) => {
768 self.cstore.set_used_recursively(cnum);
769 Some(cnum)
770 }
771 Err(err) => {
772 debug!("failed to resolve crate {} {:?}", name, dep_kind);
773 let missing_core = self
774 .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
775 .is_err();
776 err.report(self.sess, span, missing_core);
777 None
778 }
779 }
780 }
781
782 fn maybe_resolve_crate<'b>(
783 &'b mut self,
784 name: Symbol,
785 mut dep_kind: CrateDepKind,
786 origin: CrateOrigin<'b>,
787 ) -> Result<CrateNum, CrateError> {
788 info!("resolving crate `{}`", name);
789 if !name.as_str().is_ascii() {
790 return Err(CrateError::NonAsciiName(name));
791 }
792
793 let dep_root = origin.dep_root();
794 let dep = origin.dep();
795 let hash = dep.map(|d| d.hash);
796 let host_hash = dep.map(|d| d.host_hash).flatten();
797 let extra_filename = dep.map(|d| &d.extra_filename[..]);
798 let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
799 let private_dep = origin.private_dep();
800
801 let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
802 (LoadResult::Previous(cnum), None)
803 } else {
804 info!("falling back to a load");
805 let mut locator = CrateLocator::new(
806 self.sess,
807 &*self.cstore.metadata_loader,
808 name,
809 self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
812 hash,
813 extra_filename,
814 path_kind,
815 );
816
817 match self.load(&mut locator)? {
818 Some(res) => (res, None),
819 None => {
820 info!("falling back to loading proc_macro");
821 dep_kind = CrateDepKind::MacrosOnly;
822 match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
823 Some(res) => res,
824 None => return Err(locator.into_error(dep_root.cloned())),
825 }
826 }
827 }
828 };
829
830 match result {
831 (LoadResult::Previous(cnum), None) => {
832 info!("library for `{}` was loaded previously, cnum {cnum}", name);
833 let private_dep = self.is_private_dep(name, private_dep, origin);
838 let data = self.cstore.get_crate_data_mut(cnum);
839 if data.is_proc_macro_crate() {
840 dep_kind = CrateDepKind::MacrosOnly;
841 }
842 data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
843 data.update_and_private_dep(private_dep);
844 Ok(cnum)
845 }
846 (LoadResult::Loaded(library), host_library) => {
847 info!("register newly loaded library for `{}`", name);
848 self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
849 }
850 _ => panic!(),
851 }
852 }
853
854 fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
855 let Some(library) = locator.maybe_load_library_crate()? else {
856 return Ok(None);
857 };
858
859 let root = library.metadata.get_root();
864 let mut result = LoadResult::Loaded(library);
865 for (cnum, data) in self.cstore.iter_crate_data() {
866 if data.name() == root.name() && root.hash() == data.hash() {
867 assert!(locator.hash.is_none());
868 info!("load success, going to previous cnum: {}", cnum);
869 result = LoadResult::Previous(cnum);
870 break;
871 }
872 }
873 Ok(Some(result))
874 }
875
876 fn resolve_crate_deps(
878 &mut self,
879 dep_root: &CratePaths,
880 crate_root: &CrateRoot,
881 metadata: &MetadataBlob,
882 krate: CrateNum,
883 dep_kind: CrateDepKind,
884 parent_is_private: bool,
885 ) -> Result<CrateNumMap, CrateError> {
886 debug!(
887 "resolving deps of external crate `{}` with dep root `{}`",
888 crate_root.name(),
889 dep_root.name
890 );
891 if crate_root.is_proc_macro_crate() {
892 return Ok(CrateNumMap::new());
893 }
894
895 let deps = crate_root.decode_crate_deps(metadata);
899 let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
900 crate_num_map.push(krate);
901 for dep in deps {
902 info!(
903 "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",
904 crate_root.name(),
905 dep.name,
906 dep.hash,
907 dep.extra_filename,
908 dep.is_private,
909 );
910 let dep_kind = match dep_kind {
911 CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
912 _ => dep.kind,
913 };
914 let cnum = self.maybe_resolve_crate(
915 dep.name,
916 dep_kind,
917 CrateOrigin::IndirectDependency {
918 dep_root,
919 parent_private: parent_is_private,
920 dep: &dep,
921 },
922 )?;
923 crate_num_map.push(cnum);
924 }
925
926 debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);
927 Ok(crate_num_map)
928 }
929
930 fn dlsym_proc_macros(
931 &self,
932 path: &Path,
933 stable_crate_id: StableCrateId,
934 ) -> Result<&'static [ProcMacro], CrateError> {
935 let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
936 debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
937
938 unsafe {
939 let result = load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name);
940 match result {
941 Ok(result) => {
942 debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
943 Ok(*result)
944 }
945 Err(err) => {
946 debug!(
947 "failed to dlsym proc_macros {} for symbol `{}`",
948 path.display(),
949 sym_name
950 );
951 Err(err.into())
952 }
953 }
954 }
955 }
956
957 fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
958 let only_rlib = self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
961 if only_rlib {
962 info!("panic runtime injection skipped, only generating rlib");
963 return;
964 }
965
966 let desired_strategy = self.sess.panic_strategy();
974 let mut runtime_found = false;
975 let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
976
977 let mut panic_runtimes = Vec::new();
978 for (cnum, data) in self.cstore.iter_crate_data() {
979 needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
980 if data.is_panic_runtime() {
981 panic_runtimes.push(cnum);
984 runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
985 }
986 }
987 for cnum in panic_runtimes {
988 self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
989 }
990
991 if !needs_panic_runtime || runtime_found {
995 return;
996 }
997
998 let name = match desired_strategy {
1011 PanicStrategy::Unwind => sym::panic_unwind,
1012 PanicStrategy::Abort => sym::panic_abort,
1013 };
1014 info!("panic runtime not found -- loading {}", name);
1015
1016 let Some(cnum) =
1017 self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
1018 else {
1019 return;
1020 };
1021 let data = self.cstore.get_crate_data(cnum);
1022
1023 if !data.is_panic_runtime() {
1026 self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
1027 }
1028 if data.required_panic_strategy() != Some(desired_strategy) {
1029 self.dcx()
1030 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
1031 }
1032
1033 self.cstore.injected_panic_runtime = Some(cnum);
1034 self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
1035 }
1036
1037 fn inject_profiler_runtime(&mut self) {
1038 let needs_profiler_runtime =
1039 self.sess.instrument_coverage() || self.sess.opts.cg.profile_generate.enabled();
1040 if !needs_profiler_runtime || self.sess.opts.unstable_opts.no_profiler_runtime {
1041 return;
1042 }
1043
1044 info!("loading profiler");
1045
1046 let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
1047 let Some(cnum) =
1048 self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
1049 else {
1050 return;
1051 };
1052 let data = self.cstore.get_crate_data(cnum);
1053
1054 if !data.is_profiler_runtime() {
1056 self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
1057 }
1058 }
1059
1060 fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
1061 self.cstore.has_global_allocator =
1062 match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {
1063 [span1, span2, ..] => {
1064 self.dcx()
1065 .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
1066 true
1067 }
1068 spans => !spans.is_empty(),
1069 };
1070 self.cstore.has_alloc_error_handler = match &*fn_spans(
1071 krate,
1072 Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
1073 ) {
1074 [span1, span2, ..] => {
1075 self.dcx()
1076 .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
1077 true
1078 }
1079 spans => !spans.is_empty(),
1080 };
1081
1082 if !attr::contains_name(&krate.attrs, sym::needs_allocator)
1086 && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
1087 {
1088 return;
1089 }
1090
1091 let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
1095 if all_rlib {
1096 return;
1097 }
1098
1099 #[allow(rustc::symbol_intern_string_literal)]
1107 let this_crate = Symbol::intern("this crate");
1108
1109 let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate);
1110 for (_, data) in self.cstore.iter_crate_data() {
1111 if data.has_global_allocator() {
1112 match global_allocator {
1113 Some(other_crate) => {
1114 self.dcx().emit_err(errors::ConflictingGlobalAlloc {
1115 crate_name: data.name(),
1116 other_crate_name: other_crate,
1117 });
1118 }
1119 None => global_allocator = Some(data.name()),
1120 }
1121 }
1122 }
1123 let mut alloc_error_handler = self.cstore.has_alloc_error_handler.then_some(this_crate);
1124 for (_, data) in self.cstore.iter_crate_data() {
1125 if data.has_alloc_error_handler() {
1126 match alloc_error_handler {
1127 Some(other_crate) => {
1128 self.dcx().emit_err(errors::ConflictingAllocErrorHandler {
1129 crate_name: data.name(),
1130 other_crate_name: other_crate,
1131 });
1132 }
1133 None => alloc_error_handler = Some(data.name()),
1134 }
1135 }
1136 }
1137
1138 if global_allocator.is_some() {
1139 self.cstore.allocator_kind = Some(AllocatorKind::Global);
1140 } else {
1141 if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
1146 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
1147 {
1148 self.dcx().emit_err(errors::GlobalAllocRequired);
1149 }
1150 self.cstore.allocator_kind = Some(AllocatorKind::Default);
1151 }
1152
1153 if alloc_error_handler.is_some() {
1154 self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
1155 } else {
1156 self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
1159 }
1160 }
1161
1162 fn inject_forced_externs(&mut self) {
1163 for (name, entry) in self.sess.opts.externs.iter() {
1164 if entry.force {
1165 let name_interned = Symbol::intern(name);
1166 if !self.used_extern_options.contains(&name_interned) {
1167 self.resolve_crate(
1168 name_interned,
1169 DUMMY_SP,
1170 CrateDepKind::Explicit,
1171 CrateOrigin::Extern,
1172 );
1173 }
1174 }
1175 }
1176 }
1177
1178 fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
1180 if attr::contains_name(&krate.attrs, sym::compiler_builtins)
1182 || attr::contains_name(&krate.attrs, sym::no_core)
1183 {
1184 info!("`compiler_builtins` unneeded");
1185 return;
1186 }
1187
1188 for (cnum, cmeta) in self.cstore.iter_crate_data() {
1191 if cmeta.is_compiler_builtins() {
1192 info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
1193 return;
1194 }
1195 }
1196
1197 let Some(cnum) = self.resolve_crate(
1199 sym::compiler_builtins,
1200 krate.spans.inner_span.shrink_to_lo(),
1201 CrateDepKind::Explicit,
1202 CrateOrigin::Injected,
1203 ) else {
1204 info!("`compiler_builtins` not resolved");
1205 return;
1206 };
1207
1208 let cmeta = self.cstore.get_crate_data(cnum);
1210 if !cmeta.is_compiler_builtins() {
1211 self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
1212 }
1213 }
1214
1215 fn inject_dependency_if(
1216 &mut self,
1217 krate: CrateNum,
1218 what: &str,
1219 needs_dep: &dyn Fn(&CrateMetadata) -> bool,
1220 ) {
1221 if self.dcx().has_errors().is_some() {
1225 return;
1226 }
1227
1228 for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
1232 let data = self.cstore.get_crate_data(dep);
1233 if needs_dep(&data) {
1234 self.dcx().emit_err(errors::NoTransitiveNeedsDep {
1235 crate_name: self.cstore.get_crate_data(krate).name(),
1236 needs_crate_name: what,
1237 deps_crate_name: data.name(),
1238 });
1239 }
1240 }
1241
1242 for (cnum, data) in self.cstore.iter_crate_data_mut() {
1247 if needs_dep(data) {
1248 info!("injecting a dep from {} to {}", cnum, krate);
1249 data.add_dependency(krate);
1250 }
1251 }
1252 }
1253
1254 fn report_unused_deps(&mut self, krate: &ast::Crate) {
1255 let span = krate.spans.inner_span.shrink_to_lo();
1257 for (name, entry) in self.sess.opts.externs.iter() {
1259 if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
1260 continue;
1262 }
1263 if entry.nounused_dep || entry.force {
1264 continue;
1266 }
1267 let name_interned = Symbol::intern(name);
1268 if self.used_extern_options.contains(&name_interned) {
1269 continue;
1270 }
1271
1272 if self.sess.opts.json_unused_externs.is_enabled() {
1274 self.cstore.unused_externs.push(name_interned);
1275 continue;
1276 }
1277
1278 self.sess.psess.buffer_lint(
1279 lint::builtin::UNUSED_CRATE_DEPENDENCIES,
1280 span,
1281 ast::CRATE_NODE_ID,
1282 BuiltinLintDiag::UnusedCrateDependency {
1283 extern_crate: name_interned,
1284 local_crate: self.tcx.crate_name(LOCAL_CRATE),
1285 },
1286 );
1287 }
1288 }
1289
1290 fn report_future_incompatible_deps(&self, krate: &ast::Crate) {
1291 let name = self.tcx.crate_name(LOCAL_CRATE);
1292
1293 if name.as_str() == "wasm_bindgen" {
1294 let major = env::var("CARGO_PKG_VERSION_MAJOR")
1295 .ok()
1296 .and_then(|major| u64::from_str(&major).ok());
1297 let minor = env::var("CARGO_PKG_VERSION_MINOR")
1298 .ok()
1299 .and_then(|minor| u64::from_str(&minor).ok());
1300 let patch = env::var("CARGO_PKG_VERSION_PATCH")
1301 .ok()
1302 .and_then(|patch| u64::from_str(&patch).ok());
1303
1304 match (major, minor, patch) {
1305 (Some(1..), _, _) => return,
1307 (Some(0), Some(3..), _) => return,
1309 (Some(0), Some(2), Some(88..)) => return,
1311 (None, None, None) => return,
1313 _ => (),
1314 }
1315
1316 let span = krate.spans.inner_span.shrink_to_lo();
1318
1319 self.sess.dcx().emit_err(errors::WasmCAbi { span });
1320 }
1321 }
1322
1323 pub fn postprocess(&mut self, krate: &ast::Crate) {
1324 self.inject_compiler_builtins(krate);
1325 self.inject_forced_externs();
1326 self.inject_profiler_runtime();
1327 self.inject_allocator_crate(krate);
1328 self.inject_panic_runtime(krate);
1329
1330 self.report_unused_deps(krate);
1331 self.report_future_incompatible_deps(krate);
1332
1333 info!("{:?}", CrateDump(self.cstore));
1334 }
1335
1336 pub fn process_extern_crate(
1338 &mut self,
1339 item: &ast::Item,
1340 def_id: LocalDefId,
1341 definitions: &Definitions,
1342 ) -> Option<CrateNum> {
1343 match item.kind {
1344 ast::ItemKind::ExternCrate(orig_name, ident) => {
1345 debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);
1346 let name = match orig_name {
1347 Some(orig_name) => {
1348 validate_crate_name(self.sess, orig_name, Some(item.span));
1349 orig_name
1350 }
1351 None => ident.name,
1352 };
1353 let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
1354 CrateDepKind::MacrosOnly
1355 } else {
1356 CrateDepKind::Explicit
1357 };
1358
1359 let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
1360
1361 let path_len = definitions.def_path(def_id).data.len();
1362 self.cstore.update_extern_crate(
1363 cnum,
1364 ExternCrate {
1365 src: ExternCrateSource::Extern(def_id.to_def_id()),
1366 span: item.span,
1367 path_len,
1368 dependency_of: LOCAL_CRATE,
1369 },
1370 );
1371 Some(cnum)
1372 }
1373 _ => bug!(),
1374 }
1375 }
1376
1377 pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
1378 let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
1379
1380 self.cstore.update_extern_crate(
1381 cnum,
1382 ExternCrate {
1383 src: ExternCrateSource::Path,
1384 span,
1385 path_len: usize::MAX,
1387 dependency_of: LOCAL_CRATE,
1388 },
1389 );
1390
1391 Some(cnum)
1392 }
1393
1394 pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
1395 self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
1396 }
1397}
1398
1399fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec<Span> {
1400 struct Finder {
1401 name: Symbol,
1402 spans: Vec<Span>,
1403 }
1404 impl<'ast> visit::Visitor<'ast> for Finder {
1405 fn visit_item(&mut self, item: &'ast ast::Item) {
1406 if let Some(ident) = item.kind.ident()
1407 && ident.name == self.name
1408 && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1409 {
1410 self.spans.push(item.span);
1411 }
1412 visit::walk_item(self, item)
1413 }
1414 }
1415
1416 let mut f = Finder { name, spans: Vec::new() };
1417 visit::walk_crate(&mut f, krate);
1418 f.spans
1419}
1420
1421fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
1422 e.sources().map(|e| format!(": {e}")).collect()
1423}
1424
1425fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
1426 #[cfg(target_os = "aix")]
1427 if let Some(ext) = path.extension()
1428 && ext.eq("a")
1429 {
1430 let library_name = path.file_stem().expect("expect a library name");
1434 let mut archive_member = std::ffi::OsString::from("a(");
1435 archive_member.push(library_name);
1436 archive_member.push(".so)");
1437 let new_path = path.with_extension(archive_member);
1438
1439 let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
1441 return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
1442 .map(|lib| lib.into());
1443 }
1444
1445 unsafe { libloading::Library::new(&path) }
1446}
1447
1448fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
1453 assert!(max_attempts > 0);
1454
1455 let mut last_error = None;
1456
1457 for attempt in 0..max_attempts {
1458 debug!("Attempt to load proc-macro `{}`.", path.display());
1459 match attempt_load_dylib(path) {
1460 Ok(lib) => {
1461 if attempt > 0 {
1462 debug!(
1463 "Loaded proc-macro `{}` after {} attempts.",
1464 path.display(),
1465 attempt + 1
1466 );
1467 }
1468 return Ok(lib);
1469 }
1470 Err(err) => {
1471 if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
1473 debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
1474 let err = format_dlopen_err(&err);
1475 if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) {
1478 return Err(err.to_string());
1479 }
1480 return Err(err);
1481 }
1482
1483 last_error = Some(err);
1484 std::thread::sleep(Duration::from_millis(100));
1485 debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
1486 }
1487 }
1488 }
1489
1490 debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
1491
1492 let last_error = last_error.unwrap();
1493 let message = if let Some(src) = last_error.source() {
1494 format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
1495 } else {
1496 format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
1497 };
1498 Err(message)
1499}
1500
1501pub enum DylibError {
1502 DlOpen(String, String),
1503 DlSym(String, String),
1504}
1505
1506impl From<DylibError> for CrateError {
1507 fn from(err: DylibError) -> CrateError {
1508 match err {
1509 DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
1510 DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
1511 }
1512 }
1513}
1514
1515pub unsafe fn load_symbol_from_dylib<T: Copy>(
1516 path: &Path,
1517 sym_name: &str,
1518) -> Result<T, DylibError> {
1519 let path = try_canonicalize(path).unwrap();
1521 let lib =
1522 load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
1523
1524 let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
1525 .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
1526
1527 let sym = unsafe { sym.into_raw() };
1530 std::mem::forget(lib);
1531
1532 Ok(*sym)
1533}