@@ -51,6 +51,7 @@ use super::linker::{self, Linker};
5151use super :: metadata:: { MetadataPosition , create_wrapper_file} ;
5252use super :: rpath:: { self , RPathConfig } ;
5353use super :: { apple, versioned_llvm_target} ;
54+ use crate :: errors:: ErrorCreatingImportLibrary ;
5455use crate :: {
5556 CodegenResults , CompiledModule , CrateInfo , NativeLib , common, errors,
5657 looks_like_rust_object_file,
@@ -378,16 +379,22 @@ fn link_rlib<'a>(
378379 }
379380 }
380381
381- for output_path in create_dll_import_libs (
382- sess,
383- archive_builder_builder,
384- codegen_results. crate_info . used_libraries . iter ( ) ,
385- tmpdir. as_ref ( ) ,
386- true ,
387- ) {
388- ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
389- sess. dcx ( ) . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
390- } ) ;
382+ // On Windows, we add the raw-dylib import libraries to the rlibs already.
383+ // But on ELF, this is not possible, as a shared object cannot be a member of a static library.
384+ // Instead, we add all raw-dylibs to the final link on ELF.
385+ if sess. target . is_like_windows {
386+ for output_path in create_raw_dylib_dll_import_libs (
387+ sess,
388+ archive_builder_builder,
389+ codegen_results. crate_info . used_libraries . iter ( ) ,
390+ tmpdir. as_ref ( ) ,
391+ true ,
392+ ) {
393+ ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
394+ sess. dcx ( )
395+ . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
396+ } ) ;
397+ }
391398 }
392399
393400 if let Some ( trailing_metadata) = trailing_metadata {
@@ -428,6 +435,12 @@ fn link_rlib<'a>(
428435 ab
429436}
430437
438+ #[ derive( Debug , PartialEq , Eq , Hash , Clone ) ]
439+ struct RawDylibName {
440+ filename : String ,
441+ library_name : Symbol ,
442+ }
443+
431444/// Extract all symbols defined in raw-dylib libraries, collated by library name.
432445///
433446/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
@@ -437,14 +450,19 @@ fn link_rlib<'a>(
437450fn collate_raw_dylibs < ' a > (
438451 sess : & Session ,
439452 used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
440- ) -> Vec < ( String , Vec < DllImport > ) > {
453+ ) -> Vec < ( RawDylibName , Vec < DllImport > ) > {
441454 // Use index maps to preserve original order of imports and libraries.
442- let mut dylib_table = FxIndexMap :: < String , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
455+ let mut dylib_table = FxIndexMap :: < RawDylibName , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
443456
444457 for lib in used_libraries {
445458 if lib. kind == NativeLibKind :: RawDylib {
446- let ext = if lib. verbatim { "" } else { ".dll" } ;
447- let name = format ! ( "{}{}" , lib. name, ext) ;
459+ let ext = if sess. target . is_like_windows {
460+ if lib. verbatim { "" } else { ".dll" }
461+ } else {
462+ ".so"
463+ } ;
464+ let filename = format ! ( "{}{}" , lib. name, ext) ;
465+ let name = RawDylibName { filename, library_name : lib. name } ;
448466 let imports = dylib_table. entry ( name. clone ( ) ) . or_default ( ) ;
449467 for import in & lib. dll_imports {
450468 if let Some ( old_import) = imports. insert ( import. name , import) {
@@ -454,7 +472,7 @@ fn collate_raw_dylibs<'a>(
454472 sess. dcx ( ) . emit_err ( errors:: MultipleExternalFuncDecl {
455473 span : import. span ,
456474 function : import. name ,
457- library_name : & name,
475+ library_name : & name. filename ,
458476 } ) ;
459477 }
460478 }
@@ -470,7 +488,7 @@ fn collate_raw_dylibs<'a>(
470488 . collect ( )
471489}
472490
473- fn create_dll_import_libs < ' a > (
491+ fn create_raw_dylib_dll_import_libs < ' a > (
474492 sess : & Session ,
475493 archive_builder_builder : & dyn ArchiveBuilderBuilder ,
476494 used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
@@ -481,7 +499,7 @@ fn create_dll_import_libs<'a>(
481499 . into_iter ( )
482500 . map ( |( raw_dylib_name, raw_dylib_imports) | {
483501 let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
484- let output_path = tmpdir. join ( format ! ( "{raw_dylib_name }{name_suffix}.lib" ) ) ;
502+ let output_path = tmpdir. join ( format ! ( "{}{name_suffix}.lib" , raw_dylib_name . filename ) ) ;
485503
486504 let mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( & sess. target ) ;
487505
@@ -520,7 +538,7 @@ fn create_dll_import_libs<'a>(
520538
521539 archive_builder_builder. create_dll_import_lib (
522540 sess,
523- & raw_dylib_name,
541+ & raw_dylib_name. filename ,
524542 items,
525543 & output_path,
526544 ) ;
@@ -530,6 +548,38 @@ fn create_dll_import_libs<'a>(
530548 . collect ( )
531549}
532550
551+ fn create_raw_dylib_elf_stub_shared_objects < ' a > (
552+ sess : & Session ,
553+ used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
554+ raw_dylib_so_dir : & Path ,
555+ ) -> Vec < Symbol > {
556+ collate_raw_dylibs ( sess, used_libraries)
557+ . into_iter ( )
558+ . map ( |( raw_dylib_name, raw_dylib_imports) | {
559+ let filename = format ! ( "lib{}" , raw_dylib_name. filename) ;
560+
561+ let shared_object = create_elf_raw_dylib_stub ( & raw_dylib_imports, sess) ;
562+
563+ let so_path = raw_dylib_so_dir. join ( & filename) ;
564+ let file = match fs:: File :: create_new ( & so_path) {
565+ Ok ( file) => file,
566+ Err ( error) => sess. dcx ( ) . emit_fatal ( ErrorCreatingImportLibrary {
567+ lib_name : & filename,
568+ error : error. to_string ( ) ,
569+ } ) ,
570+ } ;
571+ if let Err ( error) = BufWriter :: new ( file) . write_all ( & shared_object) {
572+ sess. dcx ( ) . emit_fatal ( ErrorCreatingImportLibrary {
573+ lib_name : & filename,
574+ error : error. to_string ( ) ,
575+ } ) ;
576+ } ;
577+
578+ raw_dylib_name. library_name
579+ } )
580+ . collect ( )
581+ }
582+
533583/// Create a static archive.
534584///
535585/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2319,15 +2369,32 @@ fn linker_with_args(
23192369 link_output_kind,
23202370 ) ;
23212371
2372+ let raw_dylib_dir = tmpdir. join ( "raw-dylibs" ) ;
2373+ if let Err ( error) = fs:: create_dir ( & raw_dylib_dir) {
2374+ sess. dcx ( ) . emit_fatal ( errors:: CreateTempDir { error } )
2375+ }
2376+ // Only used on ELF for raw-dylibs.
2377+ cmd. include_path ( & raw_dylib_dir) ;
2378+
23222379 // Link with the import library generated for any raw-dylib functions.
2323- for output_path in create_dll_import_libs (
2324- sess,
2325- archive_builder_builder,
2326- codegen_results. crate_info . used_libraries . iter ( ) ,
2327- tmpdir,
2328- true ,
2329- ) {
2330- cmd. add_object ( & output_path) ;
2380+ if sess. target . is_like_windows {
2381+ for output_path in create_raw_dylib_dll_import_libs (
2382+ sess,
2383+ archive_builder_builder,
2384+ codegen_results. crate_info . used_libraries . iter ( ) ,
2385+ tmpdir,
2386+ true ,
2387+ ) {
2388+ cmd. add_object ( & output_path) ;
2389+ }
2390+ } else {
2391+ for library_name in create_raw_dylib_elf_stub_shared_objects (
2392+ sess,
2393+ codegen_results. crate_info . used_libraries . iter ( ) ,
2394+ & raw_dylib_dir,
2395+ ) {
2396+ cmd. link_dylib_by_name ( library_name. as_str ( ) , false , false ) ;
2397+ }
23312398 }
23322399 // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
23332400 // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2346,19 +2413,34 @@ fn linker_with_args(
23462413 . native_libraries
23472414 . iter ( )
23482415 . filter_map ( |( & cnum, libraries) | {
2349- ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2416+ if sess. target . is_like_windows {
2417+ ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2418+ } else {
2419+ Some ( libraries)
2420+ }
23502421 } )
23512422 . flatten ( )
23522423 . collect :: < Vec < _ > > ( ) ;
23532424 native_libraries_from_nonstatics. sort_unstable_by ( |a, b| a. name . as_str ( ) . cmp ( b. name . as_str ( ) ) ) ;
2354- for output_path in create_dll_import_libs (
2355- sess,
2356- archive_builder_builder,
2357- native_libraries_from_nonstatics,
2358- tmpdir,
2359- false ,
2360- ) {
2361- cmd. add_object ( & output_path) ;
2425+
2426+ if sess. target . is_like_windows {
2427+ for output_path in create_raw_dylib_dll_import_libs (
2428+ sess,
2429+ archive_builder_builder,
2430+ native_libraries_from_nonstatics,
2431+ tmpdir,
2432+ false ,
2433+ ) {
2434+ cmd. add_object ( & output_path) ;
2435+ }
2436+ } else {
2437+ for library_name in create_raw_dylib_elf_stub_shared_objects (
2438+ sess,
2439+ native_libraries_from_nonstatics,
2440+ & raw_dylib_dir,
2441+ ) {
2442+ cmd. link_dylib_by_name ( library_name. as_str ( ) , false , false ) ;
2443+ }
23622444 }
23632445
23642446 // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -3356,3 +3438,132 @@ fn add_lld_args(
33563438 }
33573439 }
33583440}
3441+
3442+ /// Create an ELF .so stub file for raw-dylib.
3443+ /// It exports all the provided symbols, but is otherwise empty.
3444+ fn create_elf_raw_dylib_stub ( symbols : & [ DllImport ] , sess : & Session ) -> Vec < u8 > {
3445+ use object:: write:: elf as write;
3446+ use object:: { Architecture , elf} ;
3447+
3448+ let mut stub_buf = Vec :: new ( ) ;
3449+
3450+ // When using the low-level object::write::elf, the order of the reservations
3451+ // needs to match the order of the writing.
3452+
3453+ let mut stub = write:: Writer :: new ( object:: Endianness :: Little , true , & mut stub_buf) ;
3454+
3455+ // These initial reservations don't reserve any space yet.
3456+ stub. reserve_null_dynamic_symbol_index ( ) ;
3457+
3458+ let dynstrs = symbols
3459+ . iter ( )
3460+ . map ( |sym| {
3461+ stub. reserve_dynamic_symbol_index ( ) ;
3462+ ( sym, stub. add_dynamic_string ( sym. name . as_str ( ) . as_bytes ( ) ) )
3463+ } )
3464+ . collect :: < Vec < _ > > ( ) ;
3465+
3466+ stub. reserve_shstrtab_section_index ( ) ;
3467+ let text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ;
3468+ let text_section = stub. reserve_section_index ( ) ;
3469+ stub. reserve_dynstr_section_index ( ) ;
3470+ stub. reserve_dynsym_section_index ( ) ;
3471+
3472+ // These reservations determine the actual layout order of the object file.
3473+ stub. reserve_file_header ( ) ;
3474+ stub. reserve_shstrtab ( ) ;
3475+ stub. reserve_section_headers ( ) ;
3476+ stub. reserve_dynstr ( ) ;
3477+ stub. reserve_dynsym ( ) ;
3478+
3479+ // File header
3480+ let ( arch, sub_arch) = sess. target . object_architecture ( & sess. unstable_target_features ) ;
3481+ let e_machine = match ( arch, sub_arch) {
3482+ ( Architecture :: Aarch64 , None ) => elf:: EM_AARCH64 ,
3483+ ( Architecture :: Aarch64_Ilp32 , None ) => elf:: EM_AARCH64 ,
3484+ ( Architecture :: Arm , None ) => elf:: EM_ARM ,
3485+ ( Architecture :: Avr , None ) => elf:: EM_AVR ,
3486+ ( Architecture :: Bpf , None ) => elf:: EM_BPF ,
3487+ ( Architecture :: Csky , None ) => elf:: EM_CSKY ,
3488+ ( Architecture :: E2K32 , None ) => elf:: EM_MCST_ELBRUS ,
3489+ ( Architecture :: E2K64 , None ) => elf:: EM_MCST_ELBRUS ,
3490+ ( Architecture :: I386 , None ) => elf:: EM_386 ,
3491+ ( Architecture :: X86_64 , None ) => elf:: EM_X86_64 ,
3492+ ( Architecture :: X86_64_X32 , None ) => elf:: EM_X86_64 ,
3493+ ( Architecture :: Hexagon , None ) => elf:: EM_HEXAGON ,
3494+ ( Architecture :: LoongArch64 , None ) => elf:: EM_LOONGARCH ,
3495+ ( Architecture :: M68k , None ) => elf:: EM_68K ,
3496+ ( Architecture :: Mips , None ) => elf:: EM_MIPS ,
3497+ ( Architecture :: Mips64 , None ) => elf:: EM_MIPS ,
3498+ ( Architecture :: Mips64_N32 , None ) => elf:: EM_MIPS ,
3499+ ( Architecture :: Msp430 , None ) => elf:: EM_MSP430 ,
3500+ ( Architecture :: PowerPc , None ) => elf:: EM_PPC ,
3501+ ( Architecture :: PowerPc64 , None ) => elf:: EM_PPC64 ,
3502+ ( Architecture :: Riscv32 , None ) => elf:: EM_RISCV ,
3503+ ( Architecture :: Riscv64 , None ) => elf:: EM_RISCV ,
3504+ ( Architecture :: S390x , None ) => elf:: EM_S390 ,
3505+ ( Architecture :: Sbf , None ) => elf:: EM_SBF ,
3506+ ( Architecture :: Sharc , None ) => elf:: EM_SHARC ,
3507+ ( Architecture :: Sparc , None ) => elf:: EM_SPARC ,
3508+ ( Architecture :: Sparc32Plus , None ) => elf:: EM_SPARC32PLUS ,
3509+ ( Architecture :: Sparc64 , None ) => elf:: EM_SPARCV9 ,
3510+ ( Architecture :: Xtensa , None ) => elf:: EM_XTENSA ,
3511+ _ => {
3512+ sess. dcx ( ) . fatal ( format ! (
3513+ "raw-dylib is not supported for the architecture {}" ,
3514+ sess. target. arch
3515+ ) ) ;
3516+ }
3517+ } ;
3518+
3519+ stub. write_file_header ( & write:: FileHeader {
3520+ os_abi : super :: metadata:: elf_os_abi ( sess) ,
3521+ abi_version : 0 ,
3522+ e_type : object:: elf:: ET_DYN ,
3523+ e_machine,
3524+ e_entry : 0 ,
3525+ e_flags : super :: metadata:: elf_e_flags ( arch, sess) ,
3526+ } )
3527+ . unwrap ( ) ;
3528+
3529+ // .shstrtab
3530+ stub. write_shstrtab ( ) ;
3531+
3532+ // Section headers
3533+ stub. write_null_section_header ( ) ;
3534+ stub. write_shstrtab_section_header ( ) ;
3535+ // Create a dummy .text section for our dummy symbols.
3536+ stub. write_section_header ( & write:: SectionHeader {
3537+ name : Some ( text_section_name) ,
3538+ sh_type : elf:: SHT_PROGBITS ,
3539+ sh_flags : 0 ,
3540+ sh_addr : 0 ,
3541+ sh_offset : 0 ,
3542+ sh_size : 0 ,
3543+ sh_link : 0 ,
3544+ sh_info : 0 ,
3545+ sh_addralign : 1 ,
3546+ sh_entsize : 0 ,
3547+ } ) ;
3548+ stub. write_dynstr_section_header ( 0 ) ;
3549+ stub. write_dynsym_section_header ( 0 , 1 ) ;
3550+
3551+ // .dynstr
3552+ stub. write_dynstr ( ) ;
3553+
3554+ // .dynsym
3555+ stub. write_null_dynamic_symbol ( ) ;
3556+ for ( _, name) in dynstrs {
3557+ stub. write_dynamic_symbol ( & write:: Sym {
3558+ name : Some ( name) ,
3559+ st_info : ( elf:: STB_GLOBAL << 4 ) | elf:: STT_NOTYPE ,
3560+ st_other : elf:: STV_DEFAULT ,
3561+ section : Some ( text_section) ,
3562+ st_shndx : 0 , // ignored by object in favor of the `section` field
3563+ st_value : 0 ,
3564+ st_size : 0 ,
3565+ } ) ;
3566+ }
3567+
3568+ stub_buf
3569+ }
0 commit comments