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 ;
@@ -48,15 +49,14 @@ use rustc_target::spec::{
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 ) {
@@ -381,16 +381,22 @@ fn link_rlib<'a>(
381381 }
382382 }
383383
384- for output_path in create_dll_import_libs (
385- sess,
386- archive_builder_builder,
387- codegen_results. crate_info . used_libraries . iter ( ) ,
388- tmpdir. as_ref ( ) ,
389- true ,
390- ) {
391- ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
392- sess. dcx ( ) . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
393- } ) ;
384+ // On Windows, we add the raw-dylib import libraries to the rlibs already.
385+ // But on ELF, this is not possible, as a shared object cannot be a member of a static library.
386+ // Instead, we add all raw-dylibs to the final link on ELF.
387+ if sess. target . is_like_windows {
388+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
389+ sess,
390+ archive_builder_builder,
391+ codegen_results. crate_info . used_libraries . iter ( ) ,
392+ tmpdir. as_ref ( ) ,
393+ true ,
394+ ) {
395+ ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
396+ sess. dcx ( )
397+ . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
398+ } ) ;
399+ }
394400 }
395401
396402 if let Some ( trailing_metadata) = trailing_metadata {
@@ -431,108 +437,6 @@ fn link_rlib<'a>(
431437 ab
432438}
433439
434- /// Extract all symbols defined in raw-dylib libraries, collated by library name.
435- ///
436- /// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
437- /// then the CodegenResults value contains one NativeLib instance for each block. However, the
438- /// linker appears to expect only a single import library for each library used, so we need to
439- /// collate the symbols together by library name before generating the import libraries.
440- fn collate_raw_dylibs < ' a > (
441- sess : & Session ,
442- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
443- ) -> Vec < ( String , Vec < DllImport > ) > {
444- // Use index maps to preserve original order of imports and libraries.
445- let mut dylib_table = FxIndexMap :: < String , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
446-
447- for lib in used_libraries {
448- if lib. kind == NativeLibKind :: RawDylib {
449- let ext = if lib. verbatim { "" } else { ".dll" } ;
450- let name = format ! ( "{}{}" , lib. name, ext) ;
451- let imports = dylib_table. entry ( name. clone ( ) ) . or_default ( ) ;
452- for import in & lib. dll_imports {
453- if let Some ( old_import) = imports. insert ( import. name , import) {
454- // FIXME: when we add support for ordinals, figure out if we need to do anything
455- // if we have two DllImport values with the same name but different ordinals.
456- if import. calling_convention != old_import. calling_convention {
457- sess. dcx ( ) . emit_err ( errors:: MultipleExternalFuncDecl {
458- span : import. span ,
459- function : import. name ,
460- library_name : & name,
461- } ) ;
462- }
463- }
464- }
465- }
466- }
467- sess. dcx ( ) . abort_if_errors ( ) ;
468- dylib_table
469- . into_iter ( )
470- . map ( |( name, imports) | {
471- ( name, imports. into_iter ( ) . map ( |( _, import) | import. clone ( ) ) . collect ( ) )
472- } )
473- . collect ( )
474- }
475-
476- fn create_dll_import_libs < ' a > (
477- sess : & Session ,
478- archive_builder_builder : & dyn ArchiveBuilderBuilder ,
479- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
480- tmpdir : & Path ,
481- is_direct_dependency : bool ,
482- ) -> Vec < PathBuf > {
483- collate_raw_dylibs ( sess, used_libraries)
484- . into_iter ( )
485- . map ( |( raw_dylib_name, raw_dylib_imports) | {
486- let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
487- let output_path = tmpdir. join ( format ! ( "{raw_dylib_name}{name_suffix}.lib" ) ) ;
488-
489- let mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( & sess. target ) ;
490-
491- let items: Vec < ImportLibraryItem > = raw_dylib_imports
492- . iter ( )
493- . map ( |import : & DllImport | {
494- if sess. target . arch == "x86" {
495- ImportLibraryItem {
496- name : common:: i686_decorated_name (
497- import,
498- mingw_gnu_toolchain,
499- false ,
500- false ,
501- ) ,
502- ordinal : import. ordinal ( ) ,
503- symbol_name : import. is_missing_decorations ( ) . then ( || {
504- common:: i686_decorated_name (
505- import,
506- mingw_gnu_toolchain,
507- false ,
508- true ,
509- )
510- } ) ,
511- is_data : !import. is_fn ,
512- }
513- } else {
514- ImportLibraryItem {
515- name : import. name . to_string ( ) ,
516- ordinal : import. ordinal ( ) ,
517- symbol_name : None ,
518- is_data : !import. is_fn ,
519- }
520- }
521- } )
522- . collect ( ) ;
523-
524- archive_builder_builder. create_dll_import_lib (
525- sess,
526- & raw_dylib_name,
527- items,
528- & output_path,
529- ) ;
530-
531- output_path
532- } )
533- . collect ( )
534- }
535-
536440/// Create a static archive.
537441///
538442/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2370,15 +2274,39 @@ fn linker_with_args(
23702274 link_output_kind,
23712275 ) ;
23722276
2277+ // Raw-dylibs from all crates.
2278+ let raw_dylib_dir = tmpdir. join ( "raw-dylibs" ) ;
2279+ if sess. target . binary_format ( ) == object:: BinaryFormat :: Elf {
2280+ // On ELF we can't pass the raw-dylibs stubs to the linker as a path,
2281+ // instead we need to pass them via -l. To find the stub, we need to add
2282+ // the directory of the stub to the linker search path.
2283+ // We make an extra directory for this to avoid polluting the search path.
2284+ if let Err ( error) = fs:: create_dir ( & raw_dylib_dir) {
2285+ sess. dcx ( ) . emit_fatal ( errors:: CreateTempDir { error } )
2286+ }
2287+ cmd. include_path ( & raw_dylib_dir) ;
2288+ }
2289+
23732290 // Link with the import library generated for any raw-dylib functions.
2374- for output_path in create_dll_import_libs (
2375- sess,
2376- archive_builder_builder,
2377- codegen_results. crate_info . used_libraries . iter ( ) ,
2378- tmpdir,
2379- true ,
2380- ) {
2381- cmd. add_object ( & output_path) ;
2291+ if sess. target . is_like_windows {
2292+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2293+ sess,
2294+ archive_builder_builder,
2295+ codegen_results. crate_info . used_libraries . iter ( ) ,
2296+ tmpdir,
2297+ true ,
2298+ ) {
2299+ cmd. add_object ( & output_path) ;
2300+ }
2301+ } else {
2302+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2303+ sess,
2304+ codegen_results. crate_info . used_libraries . iter ( ) ,
2305+ & raw_dylib_dir,
2306+ ) {
2307+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2308+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2309+ }
23822310 }
23832311 // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
23842312 // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2397,19 +2325,35 @@ fn linker_with_args(
23972325 . native_libraries
23982326 . iter ( )
23992327 . filter_map ( |( & cnum, libraries) | {
2400- ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2328+ if sess. target . is_like_windows {
2329+ ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2330+ } else {
2331+ Some ( libraries)
2332+ }
24012333 } )
24022334 . flatten ( )
24032335 . collect :: < Vec < _ > > ( ) ;
24042336 native_libraries_from_nonstatics. sort_unstable_by ( |a, b| a. name . as_str ( ) . cmp ( b. name . as_str ( ) ) ) ;
2405- for output_path in create_dll_import_libs (
2406- sess,
2407- archive_builder_builder,
2408- native_libraries_from_nonstatics,
2409- tmpdir,
2410- false ,
2411- ) {
2412- cmd. add_object ( & output_path) ;
2337+
2338+ if sess. target . is_like_windows {
2339+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2340+ sess,
2341+ archive_builder_builder,
2342+ native_libraries_from_nonstatics,
2343+ tmpdir,
2344+ false ,
2345+ ) {
2346+ cmd. add_object ( & output_path) ;
2347+ }
2348+ } else {
2349+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2350+ sess,
2351+ native_libraries_from_nonstatics,
2352+ & raw_dylib_dir,
2353+ ) {
2354+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2355+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2356+ }
24132357 }
24142358
24152359 // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
0 commit comments