rustc_metadata/
native_libs.rs

1use std::ops::ControlFlow;
2use std::path::{Path, PathBuf};
3
4use rustc_abi::ExternAbi;
5use rustc_ast::CRATE_NODE_ID;
6use rustc_attr_parsing as attr;
7use rustc_data_structures::fx::FxHashSet;
8use rustc_middle::query::LocalCrate;
9use rustc_middle::ty::{self, List, Ty, TyCtxt};
10use rustc_session::Session;
11use rustc_session::config::CrateType;
12use rustc_session::cstore::{
13    DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
14};
15use rustc_session::parse::feature_err;
16use rustc_session::search_paths::PathKind;
17use rustc_session::utils::NativeLibKind;
18use rustc_span::def_id::{DefId, LOCAL_CRATE};
19use rustc_span::{Symbol, sym};
20use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents};
21
22use crate::{errors, fluent_generated};
23
24/// The fallback directories are passed to linker, but not used when rustc does the search,
25/// because in the latter case the set of fallback directories cannot always be determined
26/// consistently at the moment.
27pub struct NativeLibSearchFallback<'a> {
28    pub self_contained_components: LinkSelfContainedComponents,
29    pub apple_sdk_root: Option<&'a Path>,
30}
31
32pub fn walk_native_lib_search_dirs<R>(
33    sess: &Session,
34    fallback: Option<NativeLibSearchFallback<'_>>,
35    mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
36) -> ControlFlow<R> {
37    // Library search paths explicitly supplied by user (`-L` on the command line).
38    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Native) {
39        f(&search_path.dir, false)?;
40    }
41    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Framework) {
42        // Frameworks are looked up strictly in framework-specific paths.
43        if search_path.kind != PathKind::All {
44            f(&search_path.dir, true)?;
45        }
46    }
47
48    let Some(NativeLibSearchFallback { self_contained_components, apple_sdk_root }) = fallback
49    else {
50        return ControlFlow::Continue(());
51    };
52
53    // The toolchain ships some native library components and self-contained linking was enabled.
54    // Add the self-contained library directory to search paths.
55    if self_contained_components.intersects(
56        LinkSelfContainedComponents::LIBC
57            | LinkSelfContainedComponents::UNWIND
58            | LinkSelfContainedComponents::MINGW,
59    ) {
60        f(&sess.target_tlib_path.dir.join("self-contained"), false)?;
61    }
62
63    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
64    // library directory instead of the self-contained directories.
65    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
66    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
67    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
68    // and sanitizers to self-contained directory, and stop adding this search path.
69    // FIXME: On AIX this also has the side-effect of making the list of library search paths
70    // non-empty, which is needed or the linker may decide to record the LIBPATH env, if
71    // defined, as the search path instead of appending the default search paths.
72    if sess.target.vendor == "fortanix"
73        || sess.target.os == "linux"
74        || sess.target.os == "fuchsia"
75        || sess.target.is_like_aix
76        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
77    {
78        f(&sess.target_tlib_path.dir, false)?;
79    }
80
81    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
82    // we must have the support library stubs in the library search path (#121430).
83    if let Some(sdk_root) = apple_sdk_root
84        && sess.target.llvm_target.contains("macabi")
85    {
86        f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
87        f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
88    }
89
90    ControlFlow::Continue(())
91}
92
93pub fn try_find_native_static_library(
94    sess: &Session,
95    name: &str,
96    verbatim: bool,
97) -> Option<PathBuf> {
98    let default = sess.staticlib_components(verbatim);
99    let formats = if verbatim {
100        vec![default]
101    } else {
102        // On Windows, static libraries sometimes show up as libfoo.a and other
103        // times show up as foo.lib
104        let unix = ("lib", ".a");
105        if default == unix { vec![default] } else { vec![default, unix] }
106    };
107
108    walk_native_lib_search_dirs(sess, None, |dir, is_framework| {
109        if !is_framework {
110            for (prefix, suffix) in &formats {
111                let test = dir.join(format!("{prefix}{name}{suffix}"));
112                if test.exists() {
113                    return ControlFlow::Break(test);
114                }
115            }
116        }
117        ControlFlow::Continue(())
118    })
119    .break_value()
120}
121
122pub fn try_find_native_dynamic_library(
123    sess: &Session,
124    name: &str,
125    verbatim: bool,
126) -> Option<PathBuf> {
127    let default = sess.staticlib_components(verbatim);
128    let formats = if verbatim {
129        vec![default]
130    } else {
131        // While the official naming convention for MSVC import libraries
132        // is foo.lib, Meson follows the libfoo.dll.a convention to
133        // disambiguate .a for static libraries
134        let meson = ("lib", ".dll.a");
135        // and MinGW uses .a altogether
136        let mingw = ("lib", ".a");
137        vec![default, meson, mingw]
138    };
139
140    walk_native_lib_search_dirs(sess, None, |dir, is_framework| {
141        if !is_framework {
142            for (prefix, suffix) in &formats {
143                let test = dir.join(format!("{prefix}{name}{suffix}"));
144                if test.exists() {
145                    return ControlFlow::Break(test);
146                }
147            }
148        }
149        ControlFlow::Continue(())
150    })
151    .break_value()
152}
153
154pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
155    try_find_native_static_library(sess, name, verbatim)
156        .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
157}
158
159fn find_bundled_library(
160    name: Symbol,
161    verbatim: Option<bool>,
162    kind: NativeLibKind,
163    has_cfg: bool,
164    tcx: TyCtxt<'_>,
165) -> Option<Symbol> {
166    let sess = tcx.sess;
167    if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
168        && tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
169        && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
170    {
171        let verbatim = verbatim.unwrap_or(false);
172        return find_native_static_library(name.as_str(), verbatim, sess)
173            .file_name()
174            .and_then(|s| s.to_str())
175            .map(Symbol::intern);
176    }
177    None
178}
179
180pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
181    let mut collector = Collector { tcx, libs: Vec::new() };
182    if tcx.sess.opts.unstable_opts.link_directives {
183        for module in tcx.foreign_modules(LOCAL_CRATE).values() {
184            collector.process_module(module);
185        }
186    }
187    collector.process_command_line();
188    collector.libs
189}
190
191pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
192    match lib.cfg {
193        Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
194        None => true,
195    }
196}
197
198struct Collector<'tcx> {
199    tcx: TyCtxt<'tcx>,
200    libs: Vec<NativeLib>,
201}
202
203impl<'tcx> Collector<'tcx> {
204    fn process_module(&mut self, module: &ForeignModule) {
205        let ForeignModule { def_id, abi, ref foreign_items } = *module;
206        let def_id = def_id.expect_local();
207
208        let sess = self.tcx.sess;
209
210        if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) {
211            return;
212        }
213
214        // Process all of the #[link(..)]-style arguments
215        let features = self.tcx.features();
216
217        for m in self.tcx.get_attrs(def_id, sym::link) {
218            let Some(items) = m.meta_item_list() else {
219                continue;
220            };
221
222            let mut name = None;
223            let mut kind = None;
224            let mut modifiers = None;
225            let mut cfg = None;
226            let mut wasm_import_module = None;
227            let mut import_name_type = None;
228            for item in items.iter() {
229                match item.name_or_empty() {
230                    sym::name => {
231                        if name.is_some() {
232                            sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
233                            continue;
234                        }
235                        let Some(link_name) = item.value_str() else {
236                            sess.dcx().emit_err(errors::LinkNameForm { span: item.span() });
237                            continue;
238                        };
239                        let span = item.name_value_literal_span().unwrap();
240                        if link_name.is_empty() {
241                            sess.dcx().emit_err(errors::EmptyLinkName { span });
242                        }
243                        name = Some((link_name, span));
244                    }
245                    sym::kind => {
246                        if kind.is_some() {
247                            sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
248                            continue;
249                        }
250                        let Some(link_kind) = item.value_str() else {
251                            sess.dcx().emit_err(errors::LinkKindForm { span: item.span() });
252                            continue;
253                        };
254
255                        let span = item.name_value_literal_span().unwrap();
256                        let link_kind = match link_kind.as_str() {
257                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
258                            "dylib" => NativeLibKind::Dylib { as_needed: None },
259                            "framework" => {
260                                if !sess.target.is_like_osx {
261                                    sess.dcx().emit_err(errors::LinkFrameworkApple { span });
262                                }
263                                NativeLibKind::Framework { as_needed: None }
264                            }
265                            "raw-dylib" => {
266                                if sess.target.is_like_windows {
267                                    // raw-dylib is stable and working on Windows
268                                } else if sess.target.binary_format == BinaryFormat::Elf
269                                    && features.raw_dylib_elf()
270                                {
271                                    // raw-dylib is unstable on ELF, but the user opted in
272                                } else if sess.target.binary_format == BinaryFormat::Elf
273                                    && sess.is_nightly_build()
274                                {
275                                    feature_err(
276                                        sess,
277                                        sym::raw_dylib_elf,
278                                        span,
279                                        fluent_generated::metadata_raw_dylib_elf_unstable,
280                                    )
281                                    .emit();
282                                } else {
283                                    sess.dcx().emit_err(errors::RawDylibOnlyWindows { span });
284                                }
285
286                                NativeLibKind::RawDylib
287                            }
288                            "link-arg" => {
289                                if !features.link_arg_attribute() {
290                                    feature_err(
291                                        sess,
292                                        sym::link_arg_attribute,
293                                        span,
294                                        fluent_generated::metadata_link_arg_unstable,
295                                    )
296                                    .emit();
297                                }
298                                NativeLibKind::LinkArg
299                            }
300                            kind => {
301                                sess.dcx().emit_err(errors::UnknownLinkKind { span, kind });
302                                continue;
303                            }
304                        };
305                        kind = Some(link_kind);
306                    }
307                    sym::modifiers => {
308                        if modifiers.is_some() {
309                            sess.dcx()
310                                .emit_err(errors::MultipleLinkModifiers { span: item.span() });
311                            continue;
312                        }
313                        let Some(link_modifiers) = item.value_str() else {
314                            sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() });
315                            continue;
316                        };
317                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
318                    }
319                    sym::cfg => {
320                        if cfg.is_some() {
321                            sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
322                            continue;
323                        }
324                        let Some(link_cfg) = item.meta_item_list() else {
325                            sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
326                            continue;
327                        };
328                        let [link_cfg] = link_cfg else {
329                            sess.dcx()
330                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
331                            continue;
332                        };
333                        let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
334                            sess.dcx()
335                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
336                            continue;
337                        };
338                        if !features.link_cfg() {
339                            feature_err(
340                                sess,
341                                sym::link_cfg,
342                                item.span(),
343                                fluent_generated::metadata_link_cfg_unstable,
344                            )
345                            .emit();
346                        }
347                        cfg = Some(link_cfg.clone());
348                    }
349                    sym::wasm_import_module => {
350                        if wasm_import_module.is_some() {
351                            sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
352                            continue;
353                        }
354                        let Some(link_wasm_import_module) = item.value_str() else {
355                            sess.dcx().emit_err(errors::WasmImportForm { span: item.span() });
356                            continue;
357                        };
358                        wasm_import_module = Some((link_wasm_import_module, item.span()));
359                    }
360                    sym::import_name_type => {
361                        if import_name_type.is_some() {
362                            sess.dcx()
363                                .emit_err(errors::MultipleImportNameType { span: item.span() });
364                            continue;
365                        }
366                        let Some(link_import_name_type) = item.value_str() else {
367                            sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() });
368                            continue;
369                        };
370                        if self.tcx.sess.target.arch != "x86" {
371                            sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() });
372                            continue;
373                        }
374
375                        let link_import_name_type = match link_import_name_type.as_str() {
376                            "decorated" => PeImportNameType::Decorated,
377                            "noprefix" => PeImportNameType::NoPrefix,
378                            "undecorated" => PeImportNameType::Undecorated,
379                            import_name_type => {
380                                sess.dcx().emit_err(errors::UnknownImportNameType {
381                                    span: item.span(),
382                                    import_name_type,
383                                });
384                                continue;
385                            }
386                        };
387                        import_name_type = Some((link_import_name_type, item.span()));
388                    }
389                    _ => {
390                        sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() });
391                    }
392                }
393            }
394
395            // Do this outside the above loop so we don't depend on modifiers coming after kinds
396            let mut verbatim = None;
397            if let Some((modifiers, span)) = modifiers {
398                for modifier in modifiers.as_str().split(',') {
399                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
400                        Some(m) => (m, modifier.starts_with('+')),
401                        None => {
402                            sess.dcx().emit_err(errors::InvalidLinkModifier { span });
403                            continue;
404                        }
405                    };
406
407                    macro report_unstable_modifier($feature: ident) {
408                        if !features.$feature() {
409                            // FIXME: make this translatable
410                            #[expect(rustc::untranslatable_diagnostic)]
411                            feature_err(
412                                sess,
413                                sym::$feature,
414                                span,
415                                format!("linking modifier `{modifier}` is unstable"),
416                            )
417                            .emit();
418                        }
419                    }
420                    let assign_modifier = |dst: &mut Option<bool>| {
421                        if dst.is_some() {
422                            sess.dcx().emit_err(errors::MultipleModifiers { span, modifier });
423                        } else {
424                            *dst = Some(value);
425                        }
426                    };
427                    match (modifier, &mut kind) {
428                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
429                            assign_modifier(bundle)
430                        }
431                        ("bundle", _) => {
432                            sess.dcx().emit_err(errors::BundleNeedsStatic { span });
433                        }
434
435                        ("verbatim", _) => assign_modifier(&mut verbatim),
436
437                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
438                            assign_modifier(whole_archive)
439                        }
440                        ("whole-archive", _) => {
441                            sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span });
442                        }
443
444                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
445                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
446                            report_unstable_modifier!(native_link_modifiers_as_needed);
447                            assign_modifier(as_needed)
448                        }
449                        ("as-needed", _) => {
450                            sess.dcx().emit_err(errors::AsNeededCompatibility { span });
451                        }
452
453                        _ => {
454                            sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier });
455                        }
456                    }
457                }
458            }
459
460            if let Some((_, span)) = wasm_import_module {
461                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
462                    sess.dcx().emit_err(errors::IncompatibleWasmLink { span });
463                }
464            }
465
466            if wasm_import_module.is_some() {
467                (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
468            }
469            let Some((name, name_span)) = name else {
470                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() });
471                continue;
472            };
473
474            // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
475            if let Some((_, span)) = import_name_type {
476                if kind != Some(NativeLibKind::RawDylib) {
477                    sess.dcx().emit_err(errors::ImportNameTypeRaw { span });
478                }
479            }
480
481            let dll_imports = match kind {
482                Some(NativeLibKind::RawDylib) => {
483                    if name.as_str().contains('\0') {
484                        sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span });
485                    }
486                    foreign_items
487                        .iter()
488                        .map(|&child_item| {
489                            self.build_dll_import(
490                                abi,
491                                import_name_type.map(|(import_name_type, _)| import_name_type),
492                                child_item,
493                            )
494                        })
495                        .collect()
496                }
497                _ => {
498                    for &child_item in foreign_items {
499                        if self.tcx.def_kind(child_item).has_codegen_attrs()
500                            && self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
501                        {
502                            let link_ordinal_attr =
503                                self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
504                            sess.dcx().emit_err(errors::LinkOrdinalRawDylib {
505                                span: link_ordinal_attr.span(),
506                            });
507                        }
508                    }
509
510                    Vec::new()
511                }
512            };
513
514            let kind = kind.unwrap_or(NativeLibKind::Unspecified);
515            let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx);
516            self.libs.push(NativeLib {
517                name,
518                filename,
519                kind,
520                cfg,
521                foreign_module: Some(def_id.to_def_id()),
522                verbatim,
523                dll_imports,
524            });
525        }
526    }
527
528    // Process libs passed on the command line
529    fn process_command_line(&mut self) {
530        // First, check for errors
531        let mut renames = FxHashSet::default();
532        for lib in &self.tcx.sess.opts.libs {
533            if let NativeLibKind::Framework { .. } = lib.kind
534                && !self.tcx.sess.target.is_like_osx
535            {
536                // Cannot check this when parsing options because the target is not yet available.
537                self.tcx.dcx().emit_err(errors::LibFrameworkApple);
538            }
539            if let Some(ref new_name) = lib.new_name {
540                let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
541                if new_name.is_empty() {
542                    self.tcx.dcx().emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
543                } else if !any_duplicate {
544                    self.tcx.dcx().emit_err(errors::RenamingNoLink { lib_name: &lib.name });
545                } else if !renames.insert(&lib.name) {
546                    self.tcx.dcx().emit_err(errors::MultipleRenamings { lib_name: &lib.name });
547                }
548            }
549        }
550
551        // Update kind and, optionally, the name of all native libraries
552        // (there may be more than one) with the specified name. If any
553        // library is mentioned more than once, keep the latest mention
554        // of it, so that any possible dependent libraries appear before
555        // it. (This ensures that the linker is able to see symbols from
556        // all possible dependent libraries before linking in the library
557        // in question.)
558        for passed_lib in &self.tcx.sess.opts.libs {
559            // If we've already added any native libraries with the same
560            // name, they will be pulled out into `existing`, so that we
561            // can move them to the end of the list below.
562            let mut existing = self
563                .libs
564                .extract_if(.., |lib| {
565                    if lib.name.as_str() == passed_lib.name {
566                        // FIXME: This whole logic is questionable, whether modifiers are
567                        // involved or not, library reordering and kind overriding without
568                        // explicit `:rename` in particular.
569                        if lib.has_modifiers() || passed_lib.has_modifiers() {
570                            match lib.foreign_module {
571                                Some(def_id) => {
572                                    self.tcx.dcx().emit_err(errors::NoLinkModOverride {
573                                        span: Some(self.tcx.def_span(def_id)),
574                                    })
575                                }
576                                None => self
577                                    .tcx
578                                    .dcx()
579                                    .emit_err(errors::NoLinkModOverride { span: None }),
580                            };
581                        }
582                        if passed_lib.kind != NativeLibKind::Unspecified {
583                            lib.kind = passed_lib.kind;
584                        }
585                        if let Some(new_name) = &passed_lib.new_name {
586                            lib.name = Symbol::intern(new_name);
587                        }
588                        lib.verbatim = passed_lib.verbatim;
589                        return true;
590                    }
591                    false
592                })
593                .collect::<Vec<_>>();
594            if existing.is_empty() {
595                // Add if not found
596                let new_name: Option<&str> = passed_lib.new_name.as_deref();
597                let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
598                let filename = find_bundled_library(
599                    name,
600                    passed_lib.verbatim,
601                    passed_lib.kind,
602                    false,
603                    self.tcx,
604                );
605                self.libs.push(NativeLib {
606                    name,
607                    filename,
608                    kind: passed_lib.kind,
609                    cfg: None,
610                    foreign_module: None,
611                    verbatim: passed_lib.verbatim,
612                    dll_imports: Vec::new(),
613                });
614            } else {
615                // Move all existing libraries with the same name to the
616                // end of the command line.
617                self.libs.append(&mut existing);
618            }
619        }
620    }
621
622    fn i686_arg_list_size(&self, item: DefId) -> usize {
623        let argument_types: &List<Ty<'_>> = self.tcx.instantiate_bound_regions_with_erased(
624            self.tcx
625                .type_of(item)
626                .instantiate_identity()
627                .fn_sig(self.tcx)
628                .inputs()
629                .map_bound(|slice| self.tcx.mk_type_list(slice)),
630        );
631
632        argument_types
633            .iter()
634            .map(|ty| {
635                let layout = self
636                    .tcx
637                    .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
638                    .expect("layout")
639                    .layout;
640                // In both stdcall and fastcall, we always round up the argument size to the
641                // nearest multiple of 4 bytes.
642                (layout.size().bytes_usize() + 3) & !3
643            })
644            .sum()
645    }
646
647    fn build_dll_import(
648        &self,
649        abi: ExternAbi,
650        import_name_type: Option<PeImportNameType>,
651        item: DefId,
652    ) -> DllImport {
653        let span = self.tcx.def_span(item);
654
655        // this logic is similar to `Target::adjust_abi` (in rustc_target/src/spec/mod.rs) but errors on unsupported inputs
656        let calling_convention = if self.tcx.sess.target.arch == "x86" {
657            match abi {
658                ExternAbi::C { .. } | ExternAbi::Cdecl { .. } => DllCallingConvention::C,
659                ExternAbi::Stdcall { .. } => {
660                    DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
661                }
662                // On Windows, `extern "system"` behaves like msvc's `__stdcall`.
663                // `__stdcall` only applies on x86 and on non-variadic functions:
664                // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
665                ExternAbi::System { .. } => {
666                    let c_variadic =
667                        self.tcx.type_of(item).instantiate_identity().fn_sig(self.tcx).c_variadic();
668
669                    if c_variadic {
670                        DllCallingConvention::C
671                    } else {
672                        DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
673                    }
674                }
675                ExternAbi::Fastcall { .. } => {
676                    DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
677                }
678                ExternAbi::Vectorcall { .. } => {
679                    DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
680                }
681                _ => {
682                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbiI686 { span });
683                }
684            }
685        } else {
686            match abi {
687                ExternAbi::C { .. } | ExternAbi::Win64 { .. } | ExternAbi::System { .. } => {
688                    DllCallingConvention::C
689                }
690                _ => {
691                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbi { span });
692                }
693            }
694        };
695
696        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
697        let import_name_type = codegen_fn_attrs
698            .link_ordinal
699            .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
700
701        DllImport {
702            name: codegen_fn_attrs.link_name.unwrap_or(self.tcx.item_name(item)),
703            import_name_type,
704            calling_convention,
705            span,
706            is_fn: self.tcx.def_kind(item).is_fn_like(),
707        }
708    }
709}