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 ;
@@ -41,22 +42,21 @@ use rustc_session::{Session, filesearch};
41
42
use rustc_span:: Symbol ;
42
43
use rustc_target:: spec:: crt_objects:: CrtObjects ;
43
44
use rustc_target:: spec:: {
44
- Cc , LinkOutputKind , LinkSelfContainedComponents , LinkSelfContainedDefault , LinkerFeatures ,
45
- LinkerFlavor , LinkerFlavorCli , Lld , PanicStrategy , RelocModel , RelroLevel , SanitizerSet ,
46
- SplitDebuginfo ,
45
+ BinaryFormat , Cc , LinkOutputKind , LinkSelfContainedComponents , LinkSelfContainedDefault ,
46
+ LinkerFeatures , LinkerFlavor , LinkerFlavorCli , Lld , PanicStrategy , RelocModel , RelroLevel ,
47
+ SanitizerSet , SplitDebuginfo ,
47
48
} ;
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 ) {
@@ -376,16 +376,22 @@ fn link_rlib<'a>(
376
376
}
377
377
}
378
378
379
- for output_path in create_dll_import_libs (
380
- sess,
381
- archive_builder_builder,
382
- codegen_results. crate_info . used_libraries . iter ( ) ,
383
- tmpdir. as_ref ( ) ,
384
- true ,
385
- ) {
386
- ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
387
- sess. dcx ( ) . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
388
- } ) ;
379
+ // On Windows, we add the raw-dylib import libraries to the rlibs already.
380
+ // But on ELF, this is not possible, as a shared object cannot be a member of a static library.
381
+ // Instead, we add all raw-dylibs to the final link on ELF.
382
+ if sess. target . is_like_windows {
383
+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
384
+ sess,
385
+ archive_builder_builder,
386
+ codegen_results. crate_info . used_libraries . iter ( ) ,
387
+ tmpdir. as_ref ( ) ,
388
+ true ,
389
+ ) {
390
+ ab. add_archive ( & output_path, Box :: new ( |_| false ) ) . unwrap_or_else ( |error| {
391
+ sess. dcx ( )
392
+ . emit_fatal ( errors:: AddNativeLibrary { library_path : output_path, error } ) ;
393
+ } ) ;
394
+ }
389
395
}
390
396
391
397
if let Some ( trailing_metadata) = trailing_metadata {
@@ -426,108 +432,6 @@ fn link_rlib<'a>(
426
432
ab
427
433
}
428
434
429
- /// Extract all symbols defined in raw-dylib libraries, collated by library name.
430
- ///
431
- /// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
432
- /// then the CodegenResults value contains one NativeLib instance for each block. However, the
433
- /// linker appears to expect only a single import library for each library used, so we need to
434
- /// collate the symbols together by library name before generating the import libraries.
435
- fn collate_raw_dylibs < ' a > (
436
- sess : & Session ,
437
- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
438
- ) -> Vec < ( String , Vec < DllImport > ) > {
439
- // Use index maps to preserve original order of imports and libraries.
440
- let mut dylib_table = FxIndexMap :: < String , FxIndexMap < Symbol , & DllImport > > :: default ( ) ;
441
-
442
- for lib in used_libraries {
443
- if lib. kind == NativeLibKind :: RawDylib {
444
- let ext = if lib. verbatim { "" } else { ".dll" } ;
445
- let name = format ! ( "{}{}" , lib. name, ext) ;
446
- let imports = dylib_table. entry ( name. clone ( ) ) . or_default ( ) ;
447
- for import in & lib. dll_imports {
448
- if let Some ( old_import) = imports. insert ( import. name , import) {
449
- // FIXME: when we add support for ordinals, figure out if we need to do anything
450
- // if we have two DllImport values with the same name but different ordinals.
451
- if import. calling_convention != old_import. calling_convention {
452
- sess. dcx ( ) . emit_err ( errors:: MultipleExternalFuncDecl {
453
- span : import. span ,
454
- function : import. name ,
455
- library_name : & name,
456
- } ) ;
457
- }
458
- }
459
- }
460
- }
461
- }
462
- sess. dcx ( ) . abort_if_errors ( ) ;
463
- dylib_table
464
- . into_iter ( )
465
- . map ( |( name, imports) | {
466
- ( name, imports. into_iter ( ) . map ( |( _, import) | import. clone ( ) ) . collect ( ) )
467
- } )
468
- . collect ( )
469
- }
470
-
471
- fn create_dll_import_libs < ' a > (
472
- sess : & Session ,
473
- archive_builder_builder : & dyn ArchiveBuilderBuilder ,
474
- used_libraries : impl IntoIterator < Item = & ' a NativeLib > ,
475
- tmpdir : & Path ,
476
- is_direct_dependency : bool ,
477
- ) -> Vec < PathBuf > {
478
- collate_raw_dylibs ( sess, used_libraries)
479
- . into_iter ( )
480
- . map ( |( raw_dylib_name, raw_dylib_imports) | {
481
- let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" } ;
482
- let output_path = tmpdir. join ( format ! ( "{raw_dylib_name}{name_suffix}.lib" ) ) ;
483
-
484
- let mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( & sess. target ) ;
485
-
486
- let items: Vec < ImportLibraryItem > = raw_dylib_imports
487
- . iter ( )
488
- . map ( |import : & DllImport | {
489
- if sess. target . arch == "x86" {
490
- ImportLibraryItem {
491
- name : common:: i686_decorated_name (
492
- import,
493
- mingw_gnu_toolchain,
494
- false ,
495
- false ,
496
- ) ,
497
- ordinal : import. ordinal ( ) ,
498
- symbol_name : import. is_missing_decorations ( ) . then ( || {
499
- common:: i686_decorated_name (
500
- import,
501
- mingw_gnu_toolchain,
502
- false ,
503
- true ,
504
- )
505
- } ) ,
506
- is_data : !import. is_fn ,
507
- }
508
- } else {
509
- ImportLibraryItem {
510
- name : import. name . to_string ( ) ,
511
- ordinal : import. ordinal ( ) ,
512
- symbol_name : None ,
513
- is_data : !import. is_fn ,
514
- }
515
- }
516
- } )
517
- . collect ( ) ;
518
-
519
- archive_builder_builder. create_dll_import_lib (
520
- sess,
521
- & raw_dylib_name,
522
- items,
523
- & output_path,
524
- ) ;
525
-
526
- output_path
527
- } )
528
- . collect ( )
529
- }
530
-
531
435
/// Create a static archive.
532
436
///
533
437
/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2422,15 +2326,39 @@ fn linker_with_args(
2422
2326
link_output_kind,
2423
2327
) ;
2424
2328
2329
+ // Raw-dylibs from all crates.
2330
+ let raw_dylib_dir = tmpdir. join ( "raw-dylibs" ) ;
2331
+ if sess. target . binary_format == BinaryFormat :: Elf {
2332
+ // On ELF we can't pass the raw-dylibs stubs to the linker as a path,
2333
+ // instead we need to pass them via -l. To find the stub, we need to add
2334
+ // the directory of the stub to the linker search path.
2335
+ // We make an extra directory for this to avoid polluting the search path.
2336
+ if let Err ( error) = fs:: create_dir ( & raw_dylib_dir) {
2337
+ sess. dcx ( ) . emit_fatal ( errors:: CreateTempDir { error } )
2338
+ }
2339
+ cmd. include_path ( & raw_dylib_dir) ;
2340
+ }
2341
+
2425
2342
// Link with the import library generated for any raw-dylib functions.
2426
- for output_path in create_dll_import_libs (
2427
- sess,
2428
- archive_builder_builder,
2429
- codegen_results. crate_info . used_libraries . iter ( ) ,
2430
- tmpdir,
2431
- true ,
2432
- ) {
2433
- cmd. add_object ( & output_path) ;
2343
+ if sess. target . is_like_windows {
2344
+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2345
+ sess,
2346
+ archive_builder_builder,
2347
+ codegen_results. crate_info . used_libraries . iter ( ) ,
2348
+ tmpdir,
2349
+ true ,
2350
+ ) {
2351
+ cmd. add_object ( & output_path) ;
2352
+ }
2353
+ } else {
2354
+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2355
+ sess,
2356
+ codegen_results. crate_info . used_libraries . iter ( ) ,
2357
+ & raw_dylib_dir,
2358
+ ) {
2359
+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2360
+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2361
+ }
2434
2362
}
2435
2363
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
2436
2364
// they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2449,19 +2377,35 @@ fn linker_with_args(
2449
2377
. native_libraries
2450
2378
. iter ( )
2451
2379
. filter_map ( |( & cnum, libraries) | {
2452
- ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2380
+ if sess. target . is_like_windows {
2381
+ ( dependency_linkage[ cnum] != Linkage :: Static ) . then_some ( libraries)
2382
+ } else {
2383
+ Some ( libraries)
2384
+ }
2453
2385
} )
2454
2386
. flatten ( )
2455
2387
. collect :: < Vec < _ > > ( ) ;
2456
2388
native_libraries_from_nonstatics. sort_unstable_by ( |a, b| a. name . as_str ( ) . cmp ( b. name . as_str ( ) ) ) ;
2457
- for output_path in create_dll_import_libs (
2458
- sess,
2459
- archive_builder_builder,
2460
- native_libraries_from_nonstatics,
2461
- tmpdir,
2462
- false ,
2463
- ) {
2464
- cmd. add_object ( & output_path) ;
2389
+
2390
+ if sess. target . is_like_windows {
2391
+ for output_path in raw_dylib:: create_raw_dylib_dll_import_libs (
2392
+ sess,
2393
+ archive_builder_builder,
2394
+ native_libraries_from_nonstatics,
2395
+ tmpdir,
2396
+ false ,
2397
+ ) {
2398
+ cmd. add_object ( & output_path) ;
2399
+ }
2400
+ } else {
2401
+ for link_path in raw_dylib:: create_raw_dylib_elf_stub_shared_objects (
2402
+ sess,
2403
+ native_libraries_from_nonstatics,
2404
+ & raw_dylib_dir,
2405
+ ) {
2406
+ // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
2407
+ cmd. link_dylib_by_name ( & link_path, true , false ) ;
2408
+ }
2465
2409
}
2466
2410
2467
2411
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
0 commit comments