1
+ mod raw_dylib;
2
+
1
3
use std:: collections:: BTreeSet ;
2
4
use std:: ffi:: OsString ;
3
5
use std:: fs:: { File , OpenOptions , read} ;
@@ -12,7 +14,7 @@ use itertools::Itertools;
12
14
use regex:: Regex ;
13
15
use rustc_arena:: TypedArena ;
14
16
use rustc_ast:: CRATE_NODE_ID ;
15
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
17
+ use rustc_data_structures:: fx:: FxIndexSet ;
16
18
use rustc_data_structures:: memmap:: Mmap ;
17
19
use rustc_data_structures:: temp_dir:: MaybeTempDir ;
18
20
use rustc_errors:: { DiagCtxtHandle , LintDiagnostic } ;
@@ -30,7 +32,6 @@ use rustc_session::config::{
30
32
self , CFGuard , CrateType , DebugInfo , LinkerFeaturesCli , OutFileName , OutputFilenames ,
31
33
OutputType , PrintKind , SplitDwarfKind , Strip ,
32
34
} ;
33
- use rustc_session:: cstore:: DllImport ;
34
35
use rustc_session:: lint:: builtin:: LINKER_MESSAGES ;
35
36
use rustc_session:: output:: { check_file_is_writeable, invalid_output_for_target, out_filename} ;
36
37
use rustc_session:: search_paths:: PathKind ;
@@ -48,15 +49,14 @@ use rustc_target::spec::{
48
49
use tempfile:: Builder as TempFileBuilder ;
49
50
use tracing:: { debug, info, warn} ;
50
51
51
- use super :: archive:: { ArchiveBuilder , ArchiveBuilderBuilder , ImportLibraryItem } ;
52
+ use super :: archive:: { ArchiveBuilder , ArchiveBuilderBuilder } ;
52
53
use super :: command:: Command ;
53
54
use super :: linker:: { self , Linker } ;
54
55
use super :: metadata:: { MetadataPosition , create_wrapper_file} ;
55
56
use super :: rpath:: { self , RPathConfig } ;
56
57
use super :: { apple, versioned_llvm_target} ;
57
58
use 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,
60
60
} ;
61
61
62
62
pub fn ensure_removed ( dcx : DiagCtxtHandle < ' _ > , path : & Path ) {
@@ -381,16 +381,22 @@ fn link_rlib<'a>(
381
381
}
382
382
}
383
383
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
+ }
394
400
}
395
401
396
402
if let Some ( trailing_metadata) = trailing_metadata {
@@ -431,108 +437,6 @@ fn link_rlib<'a>(
431
437
ab
432
438
}
433
439
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
-
536
440
/// Create a static archive.
537
441
///
538
442
/// 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(
2370
2274
link_output_kind,
2371
2275
) ;
2372
2276
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
+
2373
2290
// 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
+ }
2382
2310
}
2383
2311
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
2384
2312
// they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2397,19 +2325,35 @@ fn linker_with_args(
2397
2325
. native_libraries
2398
2326
. iter ( )
2399
2327
. 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
+ }
2401
2333
} )
2402
2334
. flatten ( )
2403
2335
. collect :: < Vec < _ > > ( ) ;
2404
2336
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
+ }
2413
2357
}
2414
2358
2415
2359
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
0 commit comments