@@ -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,15 +450,27 @@ 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+ is_direct_dependency : bool ,
454+ ) -> Vec < ( RawDylibName , Vec < DllImport > , bool ) > {
441455 // Use index maps to preserve original order of imports and libraries.
442- let mut dylib_table = FxIndexMap :: < String , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
456+ let mut dylib_table =
457+ FxIndexMap :: < ( RawDylibName , bool ) , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
443458
444459 for lib in used_libraries {
445460 if lib. kind == NativeLibKind :: RawDylib {
446- let ext = if lib. verbatim { "" } else { ".dll" } ;
447- let name = format ! ( "{}{}" , lib. name, ext) ;
448- let imports = dylib_table. entry ( name. clone ( ) ) . or_default ( ) ;
461+ let ext = if lib. verbatim { "" } else { sess. target . dll_suffix . as_ref ( ) } ;
462+
463+ let filename = if sess. target . is_like_windows {
464+ let name_suffix =
465+ if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
466+ format ! ( "{}{ext}{name_suffix}.lib" , lib. name)
467+ } else {
468+ let prefix = if lib. verbatim { "" } else { sess. target . dll_prefix . as_ref ( ) } ;
469+ format ! ( "{prefix}{}{ext}" , lib. name)
470+ } ;
471+
472+ let name = RawDylibName { filename, library_name : lib. name } ;
473+ let imports = dylib_table. entry ( ( name. clone ( ) , lib. verbatim ) ) . or_default ( ) ;
449474 for import in & lib. dll_imports {
450475 if let Some ( old_import) = imports. insert ( import. name , import) {
451476 // FIXME: when we add support for ordinals, figure out if we need to do anything
@@ -454,7 +479,7 @@ fn collate_raw_dylibs<'a>(
454479 sess. dcx ( ) . emit_err ( errors:: MultipleExternalFuncDecl {
455480 span : import. span ,
456481 function : import. name ,
457- library_name : & name,
482+ library_name : & name. filename ,
458483 } ) ;
459484 }
460485 }
@@ -464,24 +489,23 @@ fn collate_raw_dylibs<'a>(
464489 sess. dcx ( ) . abort_if_errors ( ) ;
465490 dylib_table
466491 . into_iter ( )
467- . map ( |( name, imports) | {
468- ( name, imports. into_iter ( ) . map ( |( _, import) | import. clone ( ) ) . collect ( ) )
492+ . map ( |( ( name, verbatim ) , imports) | {
493+ ( name, imports. into_iter ( ) . map ( |( _, import) | import. clone ( ) ) . collect ( ) , verbatim )
469494 } )
470495 . collect ( )
471496}
472497
473- fn create_dll_import_libs < ' a > (
498+ fn create_raw_dylib_dll_import_libs < ' a > (
474499 sess : & Session ,
475500 archive_builder_builder : & dyn ArchiveBuilderBuilder ,
476501 used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
477502 tmpdir : & Path ,
478503 is_direct_dependency : bool ,
479504) -> Vec < PathBuf > {
480- collate_raw_dylibs ( sess, used_libraries)
505+ collate_raw_dylibs ( sess, used_libraries, is_direct_dependency )
481506 . into_iter ( )
482- . map ( |( raw_dylib_name, raw_dylib_imports) | {
483- let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
484- let output_path = tmpdir. join ( format ! ( "{raw_dylib_name}{name_suffix}.lib" ) ) ;
507+ . map ( |( raw_dylib_name, raw_dylib_imports, _) | {
508+ let output_path = tmpdir. join ( & raw_dylib_name. filename ) ;
485509
486510 let mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( & sess. target ) ;
487511
@@ -520,7 +544,7 @@ fn create_dll_import_libs<'a>(
520544
521545 archive_builder_builder. create_dll_import_lib (
522546 sess,
523- & raw_dylib_name,
547+ & raw_dylib_name. filename ,
524548 items,
525549 & output_path,
526550 ) ;
@@ -530,6 +554,38 @@ fn create_dll_import_libs<'a>(
530554 . collect ( )
531555}
532556
557+ fn create_raw_dylib_elf_stub_shared_objects < ' a > (
558+ sess : & Session ,
559+ used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
560+ raw_dylib_so_dir : & Path ,
561+ ) -> Vec < ( Symbol , bool ) > {
562+ collate_raw_dylibs ( sess, used_libraries, false )
563+ . into_iter ( )
564+ . map ( |( raw_dylib_name, raw_dylib_imports, verbatim) | {
565+ let filename = raw_dylib_name. filename ;
566+
567+ let shared_object = create_elf_raw_dylib_stub ( & raw_dylib_imports, sess) ;
568+
569+ let so_path = raw_dylib_so_dir. join ( & filename) ;
570+ let file = match fs:: File :: create_new ( & so_path) {
571+ Ok ( file) => file,
572+ Err ( error) => sess. dcx ( ) . emit_fatal ( ErrorCreatingImportLibrary {
573+ lib_name : & filename,
574+ error : error. to_string ( ) ,
575+ } ) ,
576+ } ;
577+ if let Err ( error) = BufWriter :: new ( file) . write_all ( & shared_object) {
578+ sess. dcx ( ) . emit_fatal ( ErrorCreatingImportLibrary {
579+ lib_name : & filename,
580+ error : error. to_string ( ) ,
581+ } ) ;
582+ } ;
583+
584+ ( raw_dylib_name. library_name , verbatim)
585+ } )
586+ . collect ( )
587+ }
588+
533589/// Create a static archive.
534590///
535591/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2319,15 +2375,32 @@ fn linker_with_args(
23192375 link_output_kind,
23202376 ) ;
23212377
2378+ let raw_dylib_dir = tmpdir. join ( "raw-dylibs" ) ;
2379+ if let Err ( error) = fs:: create_dir ( & raw_dylib_dir) {
2380+ sess. dcx ( ) . emit_fatal ( errors:: CreateTempDir { error } )
2381+ }
2382+ // Only used on ELF for raw-dylibs.
2383+ cmd. include_path ( & raw_dylib_dir) ;
2384+
23222385 // 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) ;
2386+ if sess. target . is_like_windows {
2387+ for output_path in create_raw_dylib_dll_import_libs (
2388+ sess,
2389+ archive_builder_builder,
2390+ codegen_results. crate_info . used_libraries . iter ( ) ,
2391+ tmpdir,
2392+ true ,
2393+ ) {
2394+ cmd. add_object ( & output_path) ;
2395+ }
2396+ } else {
2397+ for ( library_name, verbatim) in create_raw_dylib_elf_stub_shared_objects (
2398+ sess,
2399+ codegen_results. crate_info . used_libraries . iter ( ) ,
2400+ & raw_dylib_dir,
2401+ ) {
2402+ cmd. link_dylib_by_name ( library_name. as_str ( ) , verbatim, false ) ;
2403+ }
23312404 }
23322405 // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
23332406 // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2346,19 +2419,34 @@ fn linker_with_args(
23462419 . native_libraries
23472420 . iter ( )
23482421 . filter_map ( |( & cnum, libraries) | {
2349- ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2422+ if sess. target . is_like_windows {
2423+ ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2424+ } else {
2425+ Some ( libraries)
2426+ }
23502427 } )
23512428 . flatten ( )
23522429 . collect :: < Vec < _ > > ( ) ;
23532430 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) ;
2431+
2432+ if sess. target . is_like_windows {
2433+ for output_path in create_raw_dylib_dll_import_libs (
2434+ sess,
2435+ archive_builder_builder,
2436+ native_libraries_from_nonstatics,
2437+ tmpdir,
2438+ false ,
2439+ ) {
2440+ cmd. add_object ( & output_path) ;
2441+ }
2442+ } else {
2443+ for ( library_name, verbatim) in create_raw_dylib_elf_stub_shared_objects (
2444+ sess,
2445+ native_libraries_from_nonstatics,
2446+ & raw_dylib_dir,
2447+ ) {
2448+ cmd. link_dylib_by_name ( library_name. as_str ( ) , verbatim, false ) ;
2449+ }
23622450 }
23632451
23642452 // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -3356,3 +3444,138 @@ fn add_lld_args(
33563444 }
33573445 }
33583446}
3447+
3448+ /// Create an ELF .so stub file for raw-dylib.
3449+ /// It exports all the provided symbols, but is otherwise empty.
3450+ fn create_elf_raw_dylib_stub ( symbols : & [ DllImport ] , sess : & Session ) -> Vec < u8 > {
3451+ use object:: write:: elf as write;
3452+ use object:: { Architecture , elf} ;
3453+
3454+ let mut stub_buf = Vec :: new ( ) ;
3455+
3456+ // When using the low-level object::write::elf, the order of the reservations
3457+ // needs to match the order of the writing.
3458+
3459+ let mut stub = write:: Writer :: new ( object:: Endianness :: Little , true , & mut stub_buf) ;
3460+
3461+ // These initial reservations don't reserve any space yet.
3462+ stub. reserve_null_dynamic_symbol_index ( ) ;
3463+
3464+ let dynstrs = symbols
3465+ . iter ( )
3466+ . map ( |sym| {
3467+ stub. reserve_dynamic_symbol_index ( ) ;
3468+ ( sym, stub. add_dynamic_string ( sym. name . as_str ( ) . as_bytes ( ) ) )
3469+ } )
3470+ . collect :: < Vec < _ > > ( ) ;
3471+
3472+ stub. reserve_shstrtab_section_index ( ) ;
3473+ let text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ;
3474+ let text_section = stub. reserve_section_index ( ) ;
3475+ stub. reserve_dynstr_section_index ( ) ;
3476+ stub. reserve_dynsym_section_index ( ) ;
3477+
3478+ // These reservations determine the actual layout order of the object file.
3479+ stub. reserve_file_header ( ) ;
3480+ stub. reserve_shstrtab ( ) ;
3481+ stub. reserve_section_headers ( ) ;
3482+ stub. reserve_dynstr ( ) ;
3483+ stub. reserve_dynsym ( ) ;
3484+
3485+ // File header
3486+ let Some ( ( arch, sub_arch) ) = sess. target . object_architecture ( & sess. unstable_target_features )
3487+ else {
3488+ sess. dcx ( ) . fatal ( format ! (
3489+ "raw-dylib is not supported for the architecture `{}`" ,
3490+ sess. target. arch
3491+ ) ) ;
3492+ } ;
3493+ let e_machine = match ( arch, sub_arch) {
3494+ ( Architecture :: Aarch64 , None ) => elf:: EM_AARCH64 ,
3495+ ( Architecture :: Aarch64_Ilp32 , None ) => elf:: EM_AARCH64 ,
3496+ ( Architecture :: Arm , None ) => elf:: EM_ARM ,
3497+ ( Architecture :: Avr , None ) => elf:: EM_AVR ,
3498+ ( Architecture :: Bpf , None ) => elf:: EM_BPF ,
3499+ ( Architecture :: Csky , None ) => elf:: EM_CSKY ,
3500+ ( Architecture :: E2K32 , None ) => elf:: EM_MCST_ELBRUS ,
3501+ ( Architecture :: E2K64 , None ) => elf:: EM_MCST_ELBRUS ,
3502+ ( Architecture :: I386 , None ) => elf:: EM_386 ,
3503+ ( Architecture :: X86_64 , None ) => elf:: EM_X86_64 ,
3504+ ( Architecture :: X86_64_X32 , None ) => elf:: EM_X86_64 ,
3505+ ( Architecture :: Hexagon , None ) => elf:: EM_HEXAGON ,
3506+ ( Architecture :: LoongArch64 , None ) => elf:: EM_LOONGARCH ,
3507+ ( Architecture :: M68k , None ) => elf:: EM_68K ,
3508+ ( Architecture :: Mips , None ) => elf:: EM_MIPS ,
3509+ ( Architecture :: Mips64 , None ) => elf:: EM_MIPS ,
3510+ ( Architecture :: Mips64_N32 , None ) => elf:: EM_MIPS ,
3511+ ( Architecture :: Msp430 , None ) => elf:: EM_MSP430 ,
3512+ ( Architecture :: PowerPc , None ) => elf:: EM_PPC ,
3513+ ( Architecture :: PowerPc64 , None ) => elf:: EM_PPC64 ,
3514+ ( Architecture :: Riscv32 , None ) => elf:: EM_RISCV ,
3515+ ( Architecture :: Riscv64 , None ) => elf:: EM_RISCV ,
3516+ ( Architecture :: S390x , None ) => elf:: EM_S390 ,
3517+ ( Architecture :: Sbf , None ) => elf:: EM_SBF ,
3518+ ( Architecture :: Sharc , None ) => elf:: EM_SHARC ,
3519+ ( Architecture :: Sparc , None ) => elf:: EM_SPARC ,
3520+ ( Architecture :: Sparc32Plus , None ) => elf:: EM_SPARC32PLUS ,
3521+ ( Architecture :: Sparc64 , None ) => elf:: EM_SPARCV9 ,
3522+ ( Architecture :: Xtensa , None ) => elf:: EM_XTENSA ,
3523+ _ => {
3524+ sess. dcx ( ) . fatal ( format ! (
3525+ "raw-dylib is not supported for the architecture `{}`" ,
3526+ sess. target. arch
3527+ ) ) ;
3528+ }
3529+ } ;
3530+
3531+ stub. write_file_header ( & write:: FileHeader {
3532+ os_abi : super :: metadata:: elf_os_abi ( sess) ,
3533+ abi_version : 0 ,
3534+ e_type : object:: elf:: ET_DYN ,
3535+ e_machine,
3536+ e_entry : 0 ,
3537+ e_flags : super :: metadata:: elf_e_flags ( arch, sess) ,
3538+ } )
3539+ . unwrap ( ) ;
3540+
3541+ // .shstrtab
3542+ stub. write_shstrtab ( ) ;
3543+
3544+ // Section headers
3545+ stub. write_null_section_header ( ) ;
3546+ stub. write_shstrtab_section_header ( ) ;
3547+ // Create a dummy .text section for our dummy symbols.
3548+ stub. write_section_header ( & write:: SectionHeader {
3549+ name : Some ( text_section_name) ,
3550+ sh_type : elf:: SHT_PROGBITS ,
3551+ sh_flags : 0 ,
3552+ sh_addr : 0 ,
3553+ sh_offset : 0 ,
3554+ sh_size : 0 ,
3555+ sh_link : 0 ,
3556+ sh_info : 0 ,
3557+ sh_addralign : 1 ,
3558+ sh_entsize : 0 ,
3559+ } ) ;
3560+ stub. write_dynstr_section_header ( 0 ) ;
3561+ stub. write_dynsym_section_header ( 0 , 1 ) ;
3562+
3563+ // .dynstr
3564+ stub. write_dynstr ( ) ;
3565+
3566+ // .dynsym
3567+ stub. write_null_dynamic_symbol ( ) ;
3568+ for ( _, name) in dynstrs {
3569+ stub. write_dynamic_symbol ( & write:: Sym {
3570+ name : Some ( name) ,
3571+ st_info : ( elf:: STB_GLOBAL << 4 ) | elf:: STT_NOTYPE ,
3572+ st_other : elf:: STV_DEFAULT ,
3573+ section : Some ( text_section) ,
3574+ st_shndx : 0 , // ignored by object in favor of the `section` field
3575+ st_value : 0 ,
3576+ st_size : 0 ,
3577+ } ) ;
3578+ }
3579+
3580+ stub_buf
3581+ }
0 commit comments