Skip to content

Commit ffa8359

Browse files
committed
change rlib format to discern native dependencies
1 parent 56e7678 commit ffa8359

File tree

23 files changed

+328
-54
lines changed

23 files changed

+328
-54
lines changed

compiler/rustc_codegen_ssa/src/back/archive.rs

+37-35
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

+89-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use rustc_arena::TypedArena;
22
use rustc_ast::CRATE_NODE_ID;
3+
use rustc_data_structures::fx::FxHashSet;
34
use rustc_data_structures::fx::FxIndexMap;
45
use rustc_data_structures::memmap::Mmap;
56
use rustc_data_structures::temp_dir::MaybeTempDir;
67
use rustc_errors::{ErrorGuaranteed, Handler};
78
use rustc_fs_util::fix_windows_verbatim_for_gcc;
89
use rustc_hir::def_id::CrateNum;
10+
use rustc_metadata::find_native_static_library;
911
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
1012
use rustc_middle::middle::dependency_format::Linkage;
1113
use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -24,7 +26,7 @@ use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
2426
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
2527
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
2628

27-
use super::archive::{find_library, ArchiveBuilder, ArchiveBuilderBuilder};
29+
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
2830
use super::command::Command;
2931
use super::linker::{self, Linker};
3032
use super::metadata::{create_rmeta_file, MetadataPosition};
@@ -307,6 +309,9 @@ fn link_rlib<'a>(
307309
}
308310
}
309311

312+
// Used if packed_bundled_libs flag enabled.
313+
let mut packed_bundled_libs = Vec::new();
314+
310315
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
311316
// we may not be configured to actually include a static library if we're
312317
// adding it here. That's because later when we consume this rlib we'll
@@ -325,6 +330,8 @@ fn link_rlib<'a>(
325330
// metadata of the rlib we're generating somehow.
326331
for lib in codegen_results.crate_info.used_libraries.iter() {
327332
match lib.kind {
333+
NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
334+
if flavor == RlibFlavor::Normal && sess.opts.unstable_opts.packed_bundled_libs => {}
328335
NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
329336
if flavor == RlibFlavor::Normal =>
330337
{
@@ -348,7 +355,16 @@ fn link_rlib<'a>(
348355
}
349356
if let Some(name) = lib.name {
350357
let location =
351-
find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess);
358+
find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess);
359+
if sess.opts.unstable_opts.packed_bundled_libs && flavor == RlibFlavor::Normal {
360+
packed_bundled_libs.push(find_native_static_library(
361+
lib.filename.unwrap().as_str(),
362+
Some(true),
363+
&lib_search_paths,
364+
sess,
365+
));
366+
continue;
367+
}
352368
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
353369
sess.fatal(&format!(
354370
"failed to add native library {}: {}",
@@ -403,6 +419,12 @@ fn link_rlib<'a>(
403419
ab.add_file(&trailing_metadata);
404420
}
405421

422+
// Add all bundled static native library dependencies.
423+
// Archives added to the end of .rlib archive, see comment above for the reason.
424+
for lib in packed_bundled_libs {
425+
ab.add_file(&lib)
426+
}
427+
406428
return Ok(ab);
407429
}
408430

@@ -2350,7 +2372,15 @@ fn add_upstream_rust_crates<'a>(
23502372
let src = &codegen_results.crate_info.used_crate_source[&cnum];
23512373
match data[cnum.as_usize() - 1] {
23522374
_ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
2353-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2375+
add_static_crate(
2376+
cmd,
2377+
sess,
2378+
archive_builder_builder,
2379+
codegen_results,
2380+
tmpdir,
2381+
cnum,
2382+
&Default::default(),
2383+
);
23542384
}
23552385
// compiler-builtins are always placed last to ensure that they're
23562386
// linked correctly.
@@ -2360,7 +2390,23 @@ fn add_upstream_rust_crates<'a>(
23602390
}
23612391
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
23622392
Linkage::Static => {
2363-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2393+
let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs {
2394+
codegen_results.crate_info.native_libraries[&cnum]
2395+
.iter()
2396+
.filter_map(|lib| lib.filename)
2397+
.collect::<FxHashSet<_>>()
2398+
} else {
2399+
Default::default()
2400+
};
2401+
add_static_crate(
2402+
cmd,
2403+
sess,
2404+
archive_builder_builder,
2405+
codegen_results,
2406+
tmpdir,
2407+
cnum,
2408+
&bundled_libs,
2409+
);
23642410

23652411
// Link static native libs with "-bundle" modifier only if the crate they originate from
23662412
// is being linked statically to the current crate. If it's linked dynamically
@@ -2371,6 +2417,14 @@ fn add_upstream_rust_crates<'a>(
23712417
// external build system already has the native dependencies defined, and it
23722418
// will provide them to the linker itself.
23732419
if sess.opts.unstable_opts.link_native_libraries {
2420+
if sess.opts.unstable_opts.packed_bundled_libs {
2421+
// If rlib contains native libs as archives, unpack them to tmpdir.
2422+
let rlib = &src.rlib.as_ref().unwrap().0;
2423+
archive_builder_builder
2424+
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
2425+
.unwrap_or_else(|e| sess.fatal(e));
2426+
}
2427+
23742428
let mut last = (None, NativeLibKind::Unspecified, None);
23752429
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
23762430
let Some(name) = lib.name else {
@@ -2420,10 +2474,17 @@ fn add_upstream_rust_crates<'a>(
24202474
| NativeLibKind::Framework { .. }
24212475
| NativeLibKind::Unspecified
24222476
| NativeLibKind::RawDylib => {}
2423-
NativeLibKind::Static {
2424-
bundle: Some(true) | None,
2425-
whole_archive: _,
2426-
} => {}
2477+
NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
2478+
if sess.opts.unstable_opts.packed_bundled_libs {
2479+
// If rlib contains native libs as archives, they are unpacked to tmpdir.
2480+
let path = tmpdir.join(lib.filename.unwrap().as_str());
2481+
if whole_archive == Some(true) {
2482+
cmd.link_whole_rlib(&path);
2483+
} else {
2484+
cmd.link_rlib(&path);
2485+
}
2486+
}
2487+
}
24272488
}
24282489
}
24292490
}
@@ -2438,7 +2499,15 @@ fn add_upstream_rust_crates<'a>(
24382499
// was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
24392500
// is used)
24402501
if let Some(cnum) = compiler_builtins {
2441-
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
2502+
add_static_crate(
2503+
cmd,
2504+
sess,
2505+
archive_builder_builder,
2506+
codegen_results,
2507+
tmpdir,
2508+
cnum,
2509+
&Default::default(),
2510+
);
24422511
}
24432512

24442513
// Converts a library file-stem into a cc -l argument
@@ -2471,6 +2540,7 @@ fn add_upstream_rust_crates<'a>(
24712540
codegen_results: &CodegenResults,
24722541
tmpdir: &Path,
24732542
cnum: CrateNum,
2543+
bundled_lib_file_names: &FxHashSet<Symbol>,
24742544
) {
24752545
let src = &codegen_results.crate_info.used_crate_source[&cnum];
24762546
let cratepath = &src.rlib.as_ref().unwrap().0;
@@ -2499,6 +2569,7 @@ fn add_upstream_rust_crates<'a>(
24992569
let dst = tmpdir.join(cratepath.file_name().unwrap());
25002570
let name = cratepath.file_name().unwrap().to_str().unwrap();
25012571
let name = &name[3..name.len() - 5]; // chop off lib/.rlib
2572+
let bundled_lib_file_names = bundled_lib_file_names.clone();
25022573

25032574
sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
25042575
let canonical_name = name.replace('-', "_");
@@ -2532,6 +2603,15 @@ fn add_upstream_rust_crates<'a>(
25322603
let skip_because_lto =
25332604
upstream_rust_objects_already_included && is_rust_object && is_builtins;
25342605

2606+
// We skip native libraries because:
2607+
// 1. This native libraries won't be used from the generated rlib,
2608+
// so we can throw them away to avoid the copying work.
2609+
// 2. We can't allow it to be a single remaining entry in archive
2610+
// as some linkers may complain on that.
2611+
if bundled_lib_file_names.contains(&Symbol::intern(f)) {
2612+
return true;
2613+
}
2614+
25352615
if skip_because_cfg_say_so || skip_because_lto {
25362616
return true;
25372617
}

compiler/rustc_codegen_ssa/src/back/linker.rs

+2-2
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;
@@ -514,7 +514,7 @@ impl<'a> Linker for GccLinker<'a> {
514514
// -force_load is the macOS equivalent of --whole-archive, but it
515515
// involves passing the full path to the library to link.
516516
self.linker_arg("-force_load");
517-
let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
517+
let lib = find_native_static_library(lib, Some(verbatim), search_path, &self.sess);
518518
self.linker_arg(&lib);
519519
}
520520
}

compiler/rustc_codegen_ssa/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ bitflags::bitflags! {
112112
pub struct NativeLib {
113113
pub kind: NativeLibKind,
114114
pub name: Option<Symbol>,
115+
pub filename: Option<Symbol>,
115116
pub cfg: Option<ast::MetaItem>,
116117
pub verbatim: Option<bool>,
117118
pub dll_imports: Vec<cstore::DllImport>,
@@ -121,6 +122,7 @@ impl From<&cstore::NativeLib> for NativeLib {
121122
fn from(lib: &cstore::NativeLib) -> Self {
122123
NativeLib {
123124
kind: lib.kind,
125+
filename: lib.filename,
124126
name: lib.name,
125127
cfg: lib.cfg.clone(),
126128
verbatim: lib.verbatim,

compiler/rustc_error_messages/locales/en-US/metadata.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ metadata_no_transitive_needs_dep =
162162
metadata_failed_write_error =
163163
failed to write {$filename}: {$err}
164164
165+
metadata_missing_native_library =
166+
could not find native static library `{$libname}`, perhaps an -L flag is missing?
167+
165168
metadata_failed_create_tempdir =
166169
couldn't create a temp dir: {$err}
167170

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ fn test_unstable_options_tracking_hash() {
765765
tracked!(no_profiler_runtime, true);
766766
tracked!(oom, OomStrategy::Panic);
767767
tracked!(osx_rpath_install_name, true);
768+
tracked!(packed_bundled_libs, true);
768769
tracked!(panic_abort_tests, true);
769770
tracked!(panic_in_drop, PanicStrategy::Abort);
770771
tracked!(pick_stable_methods_before_any_unstable, false);

compiler/rustc_metadata/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,12 @@ pub struct FailedWriteError {
369369
pub err: Error,
370370
}
371371

372+
#[derive(SessionDiagnostic)]
373+
#[diag(metadata::missing_native_library)]
374+
pub struct MissingNativeLibrary<'a> {
375+
pub libname: &'a str,
376+
}
377+
372378
#[derive(SessionDiagnostic)]
373379
#[diag(metadata::failed_create_tempdir)]
374380
pub struct FailedCreateTempdir {

compiler/rustc_metadata/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ pub mod fs;
4444
pub mod locator;
4545

4646
pub use fs::{emit_metadata, METADATA_FILENAME};
47+
pub use native_libs::find_native_static_library;
4748
pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};

0 commit comments

Comments
 (0)