@@ -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