Skip to content

Commit 38ce67b

Browse files
committed
change rlib format to discern native dependencies
1 parent f03ce30 commit 38ce67b

File tree

21 files changed

+311
-49
lines changed

21 files changed

+311
-49
lines changed

compiler/rustc_codegen_ssa/src/back/archive.rs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,16 @@
1+
use rustc_data_structures::fx::FxHashSet;
2+
use rustc_data_structures::memmap::Mmap;
13
use rustc_session::cstore::DllImport;
24
use rustc_session::Session;
5+
use rustc_span::symbol::Symbol;
36

7+
use object::read::archive::ArchiveFile;
8+
9+
use std::fmt::Display;
10+
use std::fs::File;
411
use std::io;
512
use std::path::{Path, PathBuf};
613

7-
pub(super) fn find_library(
8-
name: &str,
9-
verbatim: bool,
10-
search_paths: &[PathBuf],
11-
sess: &Session,
12-
) -> PathBuf {
13-
// On Windows, static libraries sometimes show up as libfoo.a and other
14-
// times show up as foo.lib
15-
let oslibname = if verbatim {
16-
name.to_string()
17-
} else {
18-
format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
19-
};
20-
let unixlibname = format!("lib{}.a", name);
21-
22-
for path in search_paths {
23-
debug!("looking for {} inside {:?}", name, path);
24-
let test = path.join(&oslibname);
25-
if test.exists() {
26-
return test;
27-
}
28-
if oslibname != unixlibname {
29-
let test = path.join(&unixlibname);
30-
if test.exists() {
31-
return test;
32-
}
33-
}
34-
}
35-
sess.fatal(&format!(
36-
"could not find native static library `{}`, \
37-
perhaps an -L flag is missing?",
38-
name
39-
));
40-
}
41-
4214
pub trait ArchiveBuilderBuilder {
4315
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a>;
4416

@@ -54,6 +26,36 @@ pub trait ArchiveBuilderBuilder {
5426
dll_imports: &[DllImport],
5527
tmpdir: &Path,
5628
) -> PathBuf;
29+
30+
fn extract_bundled_libs(
31+
&self,
32+
rlib: &Path,
33+
outdir: &Path,
34+
bundled_lib_file_names: &FxHashSet<Symbol>,
35+
) -> Result<(), String> {
36+
let message = |msg: &str, e: &dyn Display| format!("{} '{}': {}", msg, &rlib.display(), e);
37+
let archive_map = unsafe {
38+
Mmap::map(File::open(rlib).map_err(|e| message("failed to open file", &e))?)
39+
.map_err(|e| message("failed to mmap file", &e))?
40+
};
41+
let archive = ArchiveFile::parse(&*archive_map)
42+
.map_err(|e| message("failed to parse archive", &e))?;
43+
44+
for entry in archive.members() {
45+
let entry = entry.map_err(|e| message("failed to read entry", &e))?;
46+
let data = entry
47+
.data(&*archive_map)
48+
.map_err(|e| message("failed to get data from archive member", &e))?;
49+
let name = std::str::from_utf8(entry.name())
50+
.map_err(|e| message("failed to convert name", &e))?;
51+
if !bundled_lib_file_names.contains(&Symbol::intern(name)) {
52+
continue; // We need to extract only native libraries.
53+
}
54+
std::fs::write(&outdir.join(&name), data)
55+
.map_err(|e| message("failed to write file", &e))?;
56+
}
57+
Ok(())
58+
}
5759
}
5860

5961
pub trait ArchiveBuilder<'a> {

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
66
use rustc_errors::{ErrorGuaranteed, Handler};
77
use rustc_fs_util::fix_windows_verbatim_for_gcc;
88
use rustc_hir::def_id::CrateNum;
9+
use rustc_metadata::find_native_static_library;
910
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
1011
use rustc_middle::middle::dependency_format::Linkage;
1112
use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -24,7 +25,7 @@ use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
2425
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
2526
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
2627

27-
use super::archive::{find_library, ArchiveBuilder, ArchiveBuilderBuilder};
28+
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
2829
use super::command::Command;
2930
use super::linker::{self, Linker};
3031
use super::metadata::{create_rmeta_file, MetadataPosition};
@@ -307,6 +308,9 @@ fn link_rlib<'a>(
307308
}
308309
}
309310

311+
// Used if packed_bundled_libs flag enabled.
312+
let mut packed_bundled_libs = Vec::new();
313+
310314
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
311315
// we may not be configured to actually include a static library if we're
312316
// adding it here. That's because later when we consume this rlib we'll
@@ -325,6 +329,8 @@ fn link_rlib<'a>(
325329
// metadata of the rlib we're generating somehow.
326330
for lib in codegen_results.crate_info.used_libraries.iter() {
327331
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 => {}
328334
NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
329335
if flavor == RlibFlavor::Normal =>
330336
{
@@ -348,7 +354,16 @@ fn link_rlib<'a>(
348354
}
349355
if let Some(name) = lib.name {
350356
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+
}
352367
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
353368
sess.fatal(&format!(
354369
"failed to add native library {}: {}",
@@ -403,6 +418,12 @@ fn link_rlib<'a>(
403418
ab.add_file(&trailing_metadata);
404419
}
405420

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+
406427
return Ok(ab);
407428
}
408429

@@ -2384,7 +2405,15 @@ fn add_upstream_rust_crates<'a>(
23842405
let src = &codegen_results.crate_info.used_crate_source[&cnum];
23852406
match data[cnum.as_usize() - 1] {
23862407
_ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
2387-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2408+
add_static_crate(
2409+
cmd,
2410+
sess,
2411+
archive_builder_builder,
2412+
codegen_results,
2413+
tmpdir,
2414+
cnum,
2415+
&Default::default(),
2416+
);
23882417
}
23892418
// compiler-builtins are always placed last to ensure that they're
23902419
// linked correctly.
@@ -2394,7 +2423,23 @@ fn add_upstream_rust_crates<'a>(
23942423
}
23952424
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
23962425
Linkage::Static => {
2397-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2426+
let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs {
2427+
codegen_results.crate_info.native_libraries[&cnum]
2428+
.iter()
2429+
.filter_map(|lib| lib.filename)
2430+
.collect::<FxHashSet<_>>()
2431+
} else {
2432+
Default::default()
2433+
};
2434+
add_static_crate(
2435+
cmd,
2436+
sess,
2437+
archive_builder_builder,
2438+
codegen_results,
2439+
tmpdir,
2440+
cnum,
2441+
&bundled_libs,
2442+
);
23982443

23992444
// Link static native libs with "-bundle" modifier only if the crate they originate from
24002445
// is being linked statically to the current crate. If it's linked dynamically
@@ -2405,6 +2450,14 @@ fn add_upstream_rust_crates<'a>(
24052450
// external build system already has the native dependencies defined, and it
24062451
// will provide them to the linker itself.
24072452
if sess.opts.unstable_opts.link_native_libraries {
2453+
if sess.opts.unstable_opts.packed_bundled_libs {
2454+
// If rlib contains native libs as archives, unpack them to tmpdir.
2455+
let rlib = &src.rlib.as_ref().unwrap().0;
2456+
archive_builder_builder
2457+
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
2458+
.unwrap_or_else(|e| sess.fatal(e));
2459+
}
2460+
24082461
let mut last = (None, NativeLibKind::Unspecified, None);
24092462
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
24102463
let Some(name) = lib.name else {
@@ -2446,10 +2499,17 @@ fn add_upstream_rust_crates<'a>(
24462499
| NativeLibKind::Framework { .. }
24472500
| NativeLibKind::Unspecified
24482501
| NativeLibKind::RawDylib => {}
2449-
NativeLibKind::Static {
2450-
bundle: Some(true) | None,
2451-
whole_archive: _,
2452-
} => {}
2502+
NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
2503+
if sess.opts.unstable_opts.packed_bundled_libs {
2504+
// If rlib contains native libs as archives, they are unpacked to tmpdir.
2505+
let path = tmpdir.join(lib.filename.unwrap().as_str());
2506+
if whole_archive == Some(true) {
2507+
cmd.link_whole_rlib(&path);
2508+
} else {
2509+
cmd.link_rlib(&path);
2510+
}
2511+
}
2512+
}
24532513
}
24542514
}
24552515
}
@@ -2468,7 +2528,15 @@ fn add_upstream_rust_crates<'a>(
24682528
// was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
24692529
// is used)
24702530
if let Some(cnum) = compiler_builtins {
2471-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2531+
add_static_crate(
2532+
cmd,
2533+
sess,
2534+
archive_builder_builder,
2535+
codegen_results,
2536+
tmpdir,
2537+
cnum,
2538+
&Default::default(),
2539+
);
24722540
}
24732541

24742542
// Converts a library file-stem into a cc -l argument
@@ -2501,6 +2569,7 @@ fn add_upstream_rust_crates<'a>(
25012569
codegen_results: &CodegenResults,
25022570
tmpdir: &Path,
25032571
cnum: CrateNum,
2572+
bundled_lib_file_names: &FxHashSet<Symbol>,
25042573
) {
25052574
let src = &codegen_results.crate_info.used_crate_source[&cnum];
25062575
let cratepath = &src.rlib.as_ref().unwrap().0;
@@ -2529,6 +2598,7 @@ fn add_upstream_rust_crates<'a>(
25292598
let dst = tmpdir.join(cratepath.file_name().unwrap());
25302599
let name = cratepath.file_name().unwrap().to_str().unwrap();
25312600
let name = &name[3..name.len() - 5]; // chop off lib/.rlib
2601+
let bundled_lib_file_names = bundled_lib_file_names.clone();
25322602

25332603
sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
25342604
let canonical_name = name.replace('-', "_");
@@ -2562,6 +2632,15 @@ fn add_upstream_rust_crates<'a>(
25622632
let skip_because_lto =
25632633
upstream_rust_objects_already_included && is_rust_object && is_builtins;
25642634

2635+
// We skip native libraries because:
2636+
// 1. This native libraries won't be used from the generated rlib,
2637+
// so we can throw them away to avoid the copying work.
2638+
// 2. We can't allow it to be a single remaining entry in archive
2639+
// as some linkers may complain on that.
2640+
if bundled_lib_file_names.contains(&Symbol::intern(f)) {
2641+
return true;
2642+
}
2643+
25652644
if skip_because_cfg_say_so || skip_because_lto {
25662645
return true;
25672646
}

compiler/rustc_codegen_ssa/src/back/linker.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::archive;
21
use super::command::Command;
32
use super::symbol_export;
43
use rustc_span::symbol::sym;
@@ -11,6 +10,7 @@ use std::path::{Path, PathBuf};
1110
use std::{env, mem, str};
1211

1312
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
13+
use rustc_metadata::find_native_static_library;
1414
use rustc_middle::middle::dependency_format::Linkage;
1515
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
1616
use rustc_middle::ty::TyCtxt;
@@ -519,7 +519,7 @@ impl<'a> Linker for GccLinker<'a> {
519519
// -force_load is the macOS equivalent of --whole-archive, but it
520520
// involves passing the full path to the library to link.
521521
self.linker_arg("-force_load");
522-
let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
522+
let lib = find_native_static_library(lib, Some(verbatim), search_path, &self.sess);
523523
self.linker_arg(&lib);
524524
}
525525
}

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ bitflags::bitflags! {
113113
pub struct NativeLib {
114114
pub kind: NativeLibKind,
115115
pub name: Option<Symbol>,
116+
pub filename: Option<Symbol>,
116117
pub cfg: Option<ast::MetaItem>,
117118
pub verbatim: Option<bool>,
118119
pub dll_imports: Vec<cstore::DllImport>,
@@ -122,6 +123,7 @@ impl From<&cstore::NativeLib> for NativeLib {
122123
fn from(lib: &cstore::NativeLib) -> Self {
123124
NativeLib {
124125
kind: lib.kind,
126+
filename: lib.filename,
125127
name: lib.name,
126128
cfg: lib.cfg.clone(),
127129
verbatim: lib.verbatim,

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ fn test_unstable_options_tracking_hash() {
767767
tracked!(no_profiler_runtime, true);
768768
tracked!(oom, OomStrategy::Panic);
769769
tracked!(osx_rpath_install_name, true);
770+
tracked!(packed_bundled_libs, true);
770771
tracked!(panic_abort_tests, true);
771772
tracked!(panic_in_drop, PanicStrategy::Abort);
772773
tracked!(pick_stable_methods_before_any_unstable, false);

compiler/rustc_metadata/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ pub mod fs;
3838
pub mod locator;
3939

4040
pub use fs::{emit_metadata, METADATA_FILENAME};
41+
pub use native_libs::find_native_static_library;
4142
pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};

0 commit comments

Comments
 (0)