@@ -6,6 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
6
6
use rustc_errors:: { ErrorGuaranteed , Handler } ;
7
7
use rustc_fs_util:: fix_windows_verbatim_for_gcc;
8
8
use rustc_hir:: def_id:: CrateNum ;
9
+ use rustc_metadata:: find_native_static_library;
9
10
use rustc_metadata:: fs:: { emit_metadata, METADATA_FILENAME } ;
10
11
use rustc_middle:: middle:: dependency_format:: Linkage ;
11
12
use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
@@ -24,7 +25,7 @@ use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
24
25
use rustc_target:: spec:: { LinkOutputKind , LinkerFlavor , LldFlavor , SplitDebuginfo } ;
25
26
use rustc_target:: spec:: { PanicStrategy , RelocModel , RelroLevel , SanitizerSet , Target } ;
26
27
27
- use super :: archive:: { find_library , ArchiveBuilder , ArchiveBuilderBuilder } ;
28
+ use super :: archive:: { ArchiveBuilder , ArchiveBuilderBuilder } ;
28
29
use super :: command:: Command ;
29
30
use super :: linker:: { self , Linker } ;
30
31
use super :: metadata:: { create_rmeta_file, MetadataPosition } ;
@@ -307,6 +308,9 @@ fn link_rlib<'a>(
307
308
}
308
309
}
309
310
311
+ // Used if packed_bundled_libs flag enabled.
312
+ let mut packed_bundled_libs = Vec :: new ( ) ;
313
+
310
314
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
311
315
// we may not be configured to actually include a static library if we're
312
316
// adding it here. That's because later when we consume this rlib we'll
@@ -325,6 +329,8 @@ fn link_rlib<'a>(
325
329
// metadata of the rlib we're generating somehow.
326
330
for lib in codegen_results. crate_info . used_libraries . iter ( ) {
327
331
match lib. kind {
332
+ NativeLibKind :: Static { bundle : None | Some ( true ) , whole_archive : Some ( true ) }
333
+ if flavor == RlibFlavor :: Normal && sess. opts . unstable_opts . packed_bundled_libs => { }
328
334
NativeLibKind :: Static { bundle : None | Some ( true ) , whole_archive : Some ( true ) }
329
335
if flavor == RlibFlavor :: Normal =>
330
336
{
@@ -348,7 +354,16 @@ fn link_rlib<'a>(
348
354
}
349
355
if let Some ( name) = lib. name {
350
356
let location =
351
- find_library ( name. as_str ( ) , lib. verbatim . unwrap_or ( false ) , & lib_search_paths, sess) ;
357
+ find_native_static_library ( name. as_str ( ) , lib. verbatim , & lib_search_paths, sess) ;
358
+ if sess. opts . unstable_opts . packed_bundled_libs && flavor == RlibFlavor :: Normal {
359
+ packed_bundled_libs. push ( find_native_static_library (
360
+ lib. filename . unwrap ( ) . as_str ( ) ,
361
+ Some ( true ) ,
362
+ & lib_search_paths,
363
+ sess,
364
+ ) ) ;
365
+ continue ;
366
+ }
352
367
ab. add_archive ( & location, Box :: new ( |_| false ) ) . unwrap_or_else ( |e| {
353
368
sess. fatal ( & format ! (
354
369
"failed to add native library {}: {}" ,
@@ -403,6 +418,12 @@ fn link_rlib<'a>(
403
418
ab. add_file ( & trailing_metadata) ;
404
419
}
405
420
421
+ // Add all bundled static native library dependencies.
422
+ // Archives added to the end of .rlib archive, see comment above for the reason.
423
+ for lib in packed_bundled_libs {
424
+ ab. add_file ( & lib)
425
+ }
426
+
406
427
return Ok ( ab) ;
407
428
}
408
429
@@ -2398,7 +2419,15 @@ fn add_upstream_rust_crates<'a>(
2398
2419
let src = & codegen_results. crate_info . used_crate_source [ & cnum] ;
2399
2420
match data[ cnum. as_usize ( ) - 1 ] {
2400
2421
_ if codegen_results. crate_info . profiler_runtime == Some ( cnum) => {
2401
- add_static_crate ( cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum) ;
2422
+ add_static_crate (
2423
+ cmd,
2424
+ sess,
2425
+ archive_builder_builder,
2426
+ codegen_results,
2427
+ tmpdir,
2428
+ cnum,
2429
+ & Default :: default ( ) ,
2430
+ ) ;
2402
2431
}
2403
2432
// compiler-builtins are always placed last to ensure that they're
2404
2433
// linked correctly.
@@ -2408,7 +2437,23 @@ fn add_upstream_rust_crates<'a>(
2408
2437
}
2409
2438
Linkage :: NotLinked | Linkage :: IncludedFromDylib => { }
2410
2439
Linkage :: Static => {
2411
- add_static_crate ( cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum) ;
2440
+ let bundled_libs = if sess. opts . unstable_opts . packed_bundled_libs {
2441
+ codegen_results. crate_info . native_libraries [ & cnum]
2442
+ . iter ( )
2443
+ . filter_map ( |lib| lib. filename )
2444
+ . collect :: < FxHashSet < _ > > ( )
2445
+ } else {
2446
+ Default :: default ( )
2447
+ } ;
2448
+ add_static_crate (
2449
+ cmd,
2450
+ sess,
2451
+ archive_builder_builder,
2452
+ codegen_results,
2453
+ tmpdir,
2454
+ cnum,
2455
+ & bundled_libs,
2456
+ ) ;
2412
2457
2413
2458
// Link static native libs with "-bundle" modifier only if the crate they originate from
2414
2459
// is being linked statically to the current crate. If it's linked dynamically
@@ -2419,6 +2464,14 @@ fn add_upstream_rust_crates<'a>(
2419
2464
// external build system already has the native dependencies defined, and it
2420
2465
// will provide them to the linker itself.
2421
2466
if sess. opts . unstable_opts . link_native_libraries {
2467
+ if sess. opts . unstable_opts . packed_bundled_libs {
2468
+ // If rlib contains native libs as archives, unpack them to tmpdir.
2469
+ let rlib = & src. rlib . as_ref ( ) . unwrap ( ) . 0 ;
2470
+ archive_builder_builder
2471
+ . extract_bundled_libs ( rlib, tmpdir, & bundled_libs)
2472
+ . unwrap_or_else ( |e| sess. fatal ( e) ) ;
2473
+ }
2474
+
2422
2475
let mut last = ( None , NativeLibKind :: Unspecified , None ) ;
2423
2476
for lib in & codegen_results. crate_info . native_libraries [ & cnum] {
2424
2477
let Some ( name) = lib. name else {
@@ -2460,10 +2513,17 @@ fn add_upstream_rust_crates<'a>(
2460
2513
| NativeLibKind :: Framework { .. }
2461
2514
| NativeLibKind :: Unspecified
2462
2515
| NativeLibKind :: RawDylib => { }
2463
- NativeLibKind :: Static {
2464
- bundle : Some ( true ) | None ,
2465
- whole_archive : _,
2466
- } => { }
2516
+ NativeLibKind :: Static { bundle : Some ( true ) | None , whole_archive } => {
2517
+ if sess. opts . unstable_opts . packed_bundled_libs {
2518
+ // If rlib contains native libs as archives, they are unpacked to tmpdir.
2519
+ let path = tmpdir. join ( lib. filename . unwrap ( ) . as_str ( ) ) ;
2520
+ if whole_archive == Some ( true ) {
2521
+ cmd. link_whole_rlib ( & path) ;
2522
+ } else {
2523
+ cmd. link_rlib ( & path) ;
2524
+ }
2525
+ }
2526
+ }
2467
2527
}
2468
2528
}
2469
2529
}
@@ -2482,7 +2542,15 @@ fn add_upstream_rust_crates<'a>(
2482
2542
// was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
2483
2543
// is used)
2484
2544
if let Some ( cnum) = compiler_builtins {
2485
- add_static_crate ( cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum) ;
2545
+ add_static_crate (
2546
+ cmd,
2547
+ sess,
2548
+ archive_builder_builder,
2549
+ codegen_results,
2550
+ tmpdir,
2551
+ cnum,
2552
+ & Default :: default ( ) ,
2553
+ ) ;
2486
2554
}
2487
2555
2488
2556
// Converts a library file-stem into a cc -l argument
@@ -2515,6 +2583,7 @@ fn add_upstream_rust_crates<'a>(
2515
2583
codegen_results : & CodegenResults ,
2516
2584
tmpdir : & Path ,
2517
2585
cnum : CrateNum ,
2586
+ bundled_lib_file_names : & FxHashSet < Symbol > ,
2518
2587
) {
2519
2588
let src = & codegen_results. crate_info . used_crate_source [ & cnum] ;
2520
2589
let cratepath = & src. rlib . as_ref ( ) . unwrap ( ) . 0 ;
@@ -2543,6 +2612,7 @@ fn add_upstream_rust_crates<'a>(
2543
2612
let dst = tmpdir. join ( cratepath. file_name ( ) . unwrap ( ) ) ;
2544
2613
let name = cratepath. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
2545
2614
let name = & name[ 3 ..name. len ( ) - 5 ] ; // chop off lib/.rlib
2615
+ let bundled_lib_file_names = bundled_lib_file_names. clone ( ) ;
2546
2616
2547
2617
sess. prof . generic_activity_with_arg ( "link_altering_rlib" , name) . run ( || {
2548
2618
let canonical_name = name. replace ( '-' , "_" ) ;
@@ -2576,6 +2646,15 @@ fn add_upstream_rust_crates<'a>(
2576
2646
let skip_because_lto =
2577
2647
upstream_rust_objects_already_included && is_rust_object && is_builtins;
2578
2648
2649
+ // We skip native libraries because:
2650
+ // 1. This native libraries won't be used from the generated rlib,
2651
+ // so we can throw them away to avoid the copying work.
2652
+ // 2. We can't allow it to be a single remaining entry in archive
2653
+ // as some linkers may complain on that.
2654
+ if bundled_lib_file_names. contains ( & Symbol :: intern ( f) ) {
2655
+ return true ;
2656
+ }
2657
+
2579
2658
if skip_because_cfg_say_so || skip_because_lto {
2580
2659
return true ;
2581
2660
}
0 commit comments