1+ mod raw_dylib;
2+
13use std:: collections:: BTreeSet ;
24use std:: ffi:: OsString ;
35use std:: fs:: { File , OpenOptions , read} ;
@@ -12,7 +14,7 @@ use itertools::Itertools;
1214use regex:: Regex ;
1315use rustc_arena:: TypedArena ;
1416use rustc_ast:: CRATE_NODE_ID ;
15- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
17+ use rustc_data_structures:: fx:: FxIndexSet ;
1618use rustc_data_structures:: memmap:: Mmap ;
1719use rustc_data_structures:: temp_dir:: MaybeTempDir ;
1820use rustc_errors:: { DiagCtxtHandle , LintDiagnostic } ;
@@ -30,7 +32,6 @@ use rustc_session::config::{
3032 self , CFGuard , CrateType , DebugInfo , LinkerFeaturesCli , OutFileName , OutputFilenames ,
3133 OutputType , PrintKind , SplitDwarfKind , Strip ,
3234} ;
33- use rustc_session:: cstore:: DllImport ;
3435use rustc_session:: lint:: builtin:: LINKER_MESSAGES ;
3536use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
3637use rustc_session:: search_paths:: PathKind ;
@@ -41,22 +42,21 @@ use rustc_session::{Session, filesearch};
4142use rustc_span:: Symbol ;
4243use rustc_target:: spec:: crt_objects:: CrtObjects ;
4344use rustc_target:: spec:: {
44- Cc , LinkOutputKind , LinkSelfContainedComponents , LinkSelfContainedDefault , LinkerFeatures ,
45- LinkerFlavor , LinkerFlavorCli , Lld , PanicStrategy , RelocModel , RelroLevel , SanitizerSet ,
46- SplitDebuginfo ,
45+ BinaryFormat , Cc , LinkOutputKind , LinkSelfContainedComponents , LinkSelfContainedDefault ,
46+ LinkerFeatures , LinkerFlavor , LinkerFlavorCli , Lld , PanicStrategy , RelocModel , RelroLevel ,
47+ SanitizerSet , SplitDebuginfo ,
4748} ;
4849use tempfile:: Builder as TempFileBuilder ;
4950use tracing:: { debug, info, warn} ;
5051
51- use super :: archive:: { ArchiveBuilder , ArchiveBuilderBuilder , ImportLibraryItem } ;
52+ use super :: archive:: { ArchiveBuilder , ArchiveBuilderBuilder } ;
5253use super :: command:: Command ;
5354use super :: linker:: { self , Linker } ;
5455use super :: metadata:: { MetadataPosition , create_wrapper_file} ;
5556use super :: rpath:: { self , RPathConfig } ;
5657use super :: { apple, versioned_llvm_target} ;
5758use crate :: {
58- CodegenResults , CompiledModule , CrateInfo , NativeLib , common, errors,
59- looks_like_rust_object_file,
59+ CodegenResults , CompiledModule , CrateInfo , NativeLib , errors, looks_like_rust_object_file,
6060} ;
6161
6262pub fn ensure_removed ( dcx : DiagCtxtHandle < ' _ > , path : & Path ) {
@@ -376,16 +376,22 @@ fn link_rlib<'a>(
376376 }
377377 }
378378
379- for output_path in create_dll_import_libs (
380- sess,
381- archive_builder_builder,
382- codegen_results. crate_info . used_libraries . iter ( ) ,
383- tmpdir. as_ref ( ) ,
384- true ,
385- ) {
386- ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
387- sess. dcx ( ) . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
388- } ) ;
379+ // On Windows, we add the raw-dylib import libraries to the rlibs already.
380+ // But on ELF, this is not possible, as a shared object cannot be a member of a static library.
381+ // Instead, we add all raw-dylibs to the final link on ELF.
382+ if sess. target . is_like_windows {
383+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
384+ sess,
385+ archive_builder_builder,
386+ codegen_results. crate_info . used_libraries . iter ( ) ,
387+ tmpdir. as_ref ( ) ,
388+ true ,
389+ ) {
390+ ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
391+ sess. dcx ( )
392+ . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
393+ } ) ;
394+ }
389395 }
390396
391397 if let Some ( trailing_metadata) = trailing_metadata {
@@ -426,108 +432,6 @@ fn link_rlib<'a>(
426432 ab
427433}
428434
429- /// Extract all symbols defined in raw-dylib libraries, collated by library name.
430- ///
431- /// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
432- /// then the CodegenResults value contains one NativeLib instance for each block. However, the
433- /// linker appears to expect only a single import library for each library used, so we need to
434- /// collate the symbols together by library name before generating the import libraries.
435- fn collate_raw_dylibs < ' a > (
436- sess : & Session ,
437- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
438- ) -> Vec < ( String , Vec < DllImport > ) > {
439- // Use index maps to preserve original order of imports and libraries.
440- let mut dylib_table = FxIndexMap :: < String , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
441-
442- for lib in used_libraries {
443- if lib. kind == NativeLibKind :: RawDylib {
444- let ext = if lib. verbatim { "" } else { ".dll" } ;
445- let name = format ! ( "{}{}" , lib. name, ext) ;
446- let imports = dylib_table. entry ( name. clone ( ) ) . or_default ( ) ;
447- for import in & lib. dll_imports {
448- if let Some ( old_import) = imports. insert ( import. name , import) {
449- // FIXME: when we add support for ordinals, figure out if we need to do anything
450- // if we have two DllImport values with the same name but different ordinals.
451- if import. calling_convention != old_import. calling_convention {
452- sess. dcx ( ) . emit_err ( errors:: MultipleExternalFuncDecl {
453- span : import. span ,
454- function : import. name ,
455- library_name : & name,
456- } ) ;
457- }
458- }
459- }
460- }
461- }
462- sess. dcx ( ) . abort_if_errors ( ) ;
463- dylib_table
464- . into_iter ( )
465- . map ( |( name, imports) | {
466- ( name, imports. into_iter ( ) . map ( |( _, import) | import. clone ( ) ) . collect ( ) )
467- } )
468- . collect ( )
469- }
470-
471- fn create_dll_import_libs < ' a > (
472- sess : & Session ,
473- archive_builder_builder : & dyn ArchiveBuilderBuilder ,
474- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
475- tmpdir : & Path ,
476- is_direct_dependency : bool ,
477- ) -> Vec < PathBuf > {
478- collate_raw_dylibs ( sess, used_libraries)
479- . into_iter ( )
480- . map ( |( raw_dylib_name, raw_dylib_imports) | {
481- let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
482- let output_path = tmpdir. join ( format ! ( "{raw_dylib_name}{name_suffix}.lib" ) ) ;
483-
484- let mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( & sess. target ) ;
485-
486- let items: Vec < ImportLibraryItem > = raw_dylib_imports
487- . iter ( )
488- . map ( |import : & DllImport | {
489- if sess. target . arch == "x86" {
490- ImportLibraryItem {
491- name : common:: i686_decorated_name (
492- import,
493- mingw_gnu_toolchain,
494- false ,
495- false ,
496- ) ,
497- ordinal : import. ordinal ( ) ,
498- symbol_name : import. is_missing_decorations ( ) . then ( || {
499- common:: i686_decorated_name (
500- import,
501- mingw_gnu_toolchain,
502- false ,
503- true ,
504- )
505- } ) ,
506- is_data : !import. is_fn ,
507- }
508- } else {
509- ImportLibraryItem {
510- name : import. name . to_string ( ) ,
511- ordinal : import. ordinal ( ) ,
512- symbol_name : None ,
513- is_data : !import. is_fn ,
514- }
515- }
516- } )
517- . collect ( ) ;
518-
519- archive_builder_builder. create_dll_import_lib (
520- sess,
521- & raw_dylib_name,
522- items,
523- & output_path,
524- ) ;
525-
526- output_path
527- } )
528- . collect ( )
529- }
530-
531435/// Create a static archive.
532436///
533437/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2422,15 +2326,39 @@ fn linker_with_args(
24222326 link_output_kind,
24232327 ) ;
24242328
2329+ // Raw-dylibs from all crates.
2330+ let raw_dylib_dir = tmpdir. join ( "raw-dylibs" ) ;
2331+ if sess. target . binary_format == BinaryFormat :: Elf {
2332+ // On ELF we can't pass the raw-dylibs stubs to the linker as a path,
2333+ // instead we need to pass them via -l. To find the stub, we need to add
2334+ // the directory of the stub to the linker search path.
2335+ // We make an extra directory for this to avoid polluting the search path.
2336+ if let Err ( error) = fs:: create_dir ( & raw_dylib_dir) {
2337+ sess. dcx ( ) . emit_fatal ( errors:: CreateTempDir { error } )
2338+ }
2339+ cmd. include_path ( & raw_dylib_dir) ;
2340+ }
2341+
24252342 // Link with the import library generated for any raw-dylib functions.
2426- for output_path in create_dll_import_libs (
2427- sess,
2428- archive_builder_builder,
2429- codegen_results. crate_info . used_libraries . iter ( ) ,
2430- tmpdir,
2431- true ,
2432- ) {
2433- cmd. add_object ( & output_path) ;
2343+ if sess. target . is_like_windows {
2344+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2345+ sess,
2346+ archive_builder_builder,
2347+ codegen_results. crate_info . used_libraries . iter ( ) ,
2348+ tmpdir,
2349+ true ,
2350+ ) {
2351+ cmd. add_object ( & output_path) ;
2352+ }
2353+ } else {
2354+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2355+ sess,
2356+ codegen_results. crate_info . used_libraries . iter ( ) ,
2357+ & raw_dylib_dir,
2358+ ) {
2359+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2360+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2361+ }
24342362 }
24352363 // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
24362364 // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2449,19 +2377,35 @@ fn linker_with_args(
24492377 . native_libraries
24502378 . iter ( )
24512379 . filter_map ( |( & cnum, libraries) | {
2452- ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2380+ if sess. target . is_like_windows {
2381+ ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2382+ } else {
2383+ Some ( libraries)
2384+ }
24532385 } )
24542386 . flatten ( )
24552387 . collect :: < Vec < _ > > ( ) ;
24562388 native_libraries_from_nonstatics. sort_unstable_by ( |a, b| a. name . as_str ( ) . cmp ( b. name . as_str ( ) ) ) ;
2457- for output_path in create_dll_import_libs (
2458- sess,
2459- archive_builder_builder,
2460- native_libraries_from_nonstatics,
2461- tmpdir,
2462- false ,
2463- ) {
2464- cmd. add_object ( & output_path) ;
2389+
2390+ if sess. target . is_like_windows {
2391+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2392+ sess,
2393+ archive_builder_builder,
2394+ native_libraries_from_nonstatics,
2395+ tmpdir,
2396+ false ,
2397+ ) {
2398+ cmd. add_object ( & output_path) ;
2399+ }
2400+ } else {
2401+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2402+ sess,
2403+ native_libraries_from_nonstatics,
2404+ & raw_dylib_dir,
2405+ ) {
2406+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2407+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2408+ }
24652409 }
24662410
24672411 // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
0 commit comments