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