Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change rlib format to distinguish native dependencies #100101

Merged
merged 1 commit into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 37 additions & 35 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::memmap::Mmap;
use rustc_session::cstore::DllImport;
use rustc_session::Session;
use rustc_span::symbol::Symbol;

use object::read::archive::ArchiveFile;

use std::fmt::Display;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

pub(super) fn find_library(
name: &str,
verbatim: bool,
search_paths: &[PathBuf],
sess: &Session,
) -> PathBuf {
// On Windows, static libraries sometimes show up as libfoo.a and other
// times show up as foo.lib
let oslibname = if verbatim {
name.to_string()
} else {
format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
};
let unixlibname = format!("lib{}.a", name);

for path in search_paths {
debug!("looking for {} inside {:?}", name, path);
let test = path.join(&oslibname);
if test.exists() {
return test;
}
if oslibname != unixlibname {
let test = path.join(&unixlibname);
if test.exists() {
return test;
}
}
}
sess.fatal(&format!(
"could not find native static library `{}`, \
perhaps an -L flag is missing?",
name
));
}

pub trait ArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a>;

Expand All @@ -54,6 +26,36 @@ pub trait ArchiveBuilderBuilder {
dll_imports: &[DllImport],
tmpdir: &Path,
) -> PathBuf;

fn extract_bundled_libs(
&self,
rlib: &Path,
outdir: &Path,
bundled_lib_file_names: &FxHashSet<Symbol>,
) -> Result<(), String> {
let message = |msg: &str, e: &dyn Display| format!("{} '{}': {}", msg, &rlib.display(), e);
let archive_map = unsafe {
Mmap::map(File::open(rlib).map_err(|e| message("failed to open file", &e))?)
.map_err(|e| message("failed to mmap file", &e))?
};
let archive = ArchiveFile::parse(&*archive_map)
.map_err(|e| message("failed to parse archive", &e))?;

for entry in archive.members() {
let entry = entry.map_err(|e| message("failed to read entry", &e))?;
let data = entry
.data(&*archive_map)
.map_err(|e| message("failed to get data from archive member", &e))?;
let name = std::str::from_utf8(entry.name())
.map_err(|e| message("failed to convert name", &e))?;
if !bundled_lib_file_names.contains(&Symbol::intern(name)) {
continue; // We need to extract only native libraries.
}
std::fs::write(&outdir.join(&name), data)
.map_err(|e| message("failed to write file", &e))?;
}
Ok(())
}
}

pub trait ArchiveBuilder<'a> {
Expand Down
98 changes: 89 additions & 9 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use rustc_arena::TypedArena;
use rustc_ast::CRATE_NODE_ID;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
Expand All @@ -24,7 +26,7 @@ use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};

use super::archive::{find_library, ArchiveBuilder, ArchiveBuilderBuilder};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use super::command::Command;
use super::linker::{self, Linker};
use super::metadata::{create_rmeta_file, MetadataPosition};
Expand Down Expand Up @@ -307,6 +309,9 @@ fn link_rlib<'a>(
}
}

// Used if packed_bundled_libs flag enabled.
let mut packed_bundled_libs = Vec::new();

// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
// we may not be configured to actually include a static library if we're
// adding it here. That's because later when we consume this rlib we'll
Expand All @@ -325,6 +330,8 @@ fn link_rlib<'a>(
// metadata of the rlib we're generating somehow.
for lib in codegen_results.crate_info.used_libraries.iter() {
match lib.kind {
NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
if flavor == RlibFlavor::Normal && sess.opts.unstable_opts.packed_bundled_libs => {}
NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
if flavor == RlibFlavor::Normal =>
{
Expand All @@ -348,7 +355,16 @@ fn link_rlib<'a>(
}
if let Some(name) = lib.name {
let location =
find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess);
find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess);
if sess.opts.unstable_opts.packed_bundled_libs && flavor == RlibFlavor::Normal {
packed_bundled_libs.push(find_native_static_library(
lib.filename.unwrap().as_str(),
Some(true),
&lib_search_paths,
sess,
));
continue;
}
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
sess.fatal(&format!(
"failed to add native library {}: {}",
Expand Down Expand Up @@ -403,6 +419,12 @@ fn link_rlib<'a>(
ab.add_file(&trailing_metadata);
}

// Add all bundled static native library dependencies.
// Archives added to the end of .rlib archive, see comment above for the reason.
for lib in packed_bundled_libs {
ab.add_file(&lib)
}

return Ok(ab);
}

Expand Down Expand Up @@ -2350,7 +2372,15 @@ fn add_upstream_rust_crates<'a>(
let src = &codegen_results.crate_info.used_crate_source[&cnum];
match data[cnum.as_usize() - 1] {
_ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
add_static_crate(
cmd,
sess,
archive_builder_builder,
codegen_results,
tmpdir,
cnum,
&Default::default(),
);
}
// compiler-builtins are always placed last to ensure that they're
// linked correctly.
Expand All @@ -2360,7 +2390,23 @@ fn add_upstream_rust_crates<'a>(
}
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
Linkage::Static => {
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs {
codegen_results.crate_info.native_libraries[&cnum]
.iter()
.filter_map(|lib| lib.filename)
.collect::<FxHashSet<_>>()
} else {
Default::default()
};
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
add_static_crate(
cmd,
sess,
archive_builder_builder,
codegen_results,
tmpdir,
cnum,
&bundled_libs,
);

// Link static native libs with "-bundle" modifier only if the crate they originate from
// is being linked statically to the current crate. If it's linked dynamically
Expand All @@ -2371,6 +2417,14 @@ fn add_upstream_rust_crates<'a>(
// external build system already has the native dependencies defined, and it
// will provide them to the linker itself.
if sess.opts.unstable_opts.link_native_libraries {
if sess.opts.unstable_opts.packed_bundled_libs {
// If rlib contains native libs as archives, unpack them to tmpdir.
let rlib = &src.rlib.as_ref().unwrap().0;
archive_builder_builder
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
.unwrap_or_else(|e| sess.fatal(e));
}

let mut last = (None, NativeLibKind::Unspecified, None);
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
let Some(name) = lib.name else {
Expand Down Expand Up @@ -2420,10 +2474,17 @@ fn add_upstream_rust_crates<'a>(
| NativeLibKind::Framework { .. }
| NativeLibKind::Unspecified
| NativeLibKind::RawDylib => {}
NativeLibKind::Static {
bundle: Some(true) | None,
whole_archive: _,
} => {}
NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
if sess.opts.unstable_opts.packed_bundled_libs {
// If rlib contains native libs as archives, they are unpacked to tmpdir.
let path = tmpdir.join(lib.filename.unwrap().as_str());
if whole_archive == Some(true) {
cmd.link_whole_rlib(&path);
} else {
cmd.link_rlib(&path);
}
}
}
}
}
}
Expand All @@ -2438,7 +2499,15 @@ fn add_upstream_rust_crates<'a>(
// was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
// is used)
if let Some(cnum) = compiler_builtins {
add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum);
add_static_crate(
cmd,
sess,
archive_builder_builder,
codegen_results,
tmpdir,
cnum,
&Default::default(),
);
}

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

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

// We skip native libraries because:
// 1. This native libraries won't be used from the generated rlib,
// so we can throw them away to avoid the copying work.
// 2. We can't allow it to be a single remaining entry in archive
// as some linkers may complain on that.
if bundled_lib_file_names.contains(&Symbol::intern(f)) {
return true;
}

if skip_because_cfg_say_so || skip_because_lto {
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::archive;
use super::command::Command;
use super::symbol_export;
use rustc_span::symbol::sym;
Expand All @@ -11,6 +10,7 @@ use std::path::{Path, PathBuf};
use std::{env, mem, str};

use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_metadata::find_native_static_library;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
use rustc_middle::ty::TyCtxt;
Expand Down Expand Up @@ -514,7 +514,7 @@ impl<'a> Linker for GccLinker<'a> {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
self.linker_arg("-force_load");
let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
let lib = find_native_static_library(lib, Some(verbatim), search_path, &self.sess);
self.linker_arg(&lib);
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ bitflags::bitflags! {
pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Option<Symbol>,
pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub verbatim: Option<bool>,
pub dll_imports: Vec<cstore::DllImport>,
Expand All @@ -121,6 +122,7 @@ impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
NativeLib {
kind: lib.kind,
filename: lib.filename,
name: lib.name,
cfg: lib.cfg.clone(),
verbatim: lib.verbatim,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/metadata.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ metadata_no_transitive_needs_dep =
metadata_failed_write_error =
failed to write {$filename}: {$err}

metadata_missing_native_library =
could not find native static library `{$libname}`, perhaps an -L flag is missing?

metadata_failed_create_tempdir =
couldn't create a temp dir: {$err}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(no_profiler_runtime, true);
tracked!(oom, OomStrategy::Panic);
tracked!(osx_rpath_install_name, true);
tracked!(packed_bundled_libs, true);
tracked!(panic_abort_tests, true);
tracked!(panic_in_drop, PanicStrategy::Abort);
tracked!(pick_stable_methods_before_any_unstable, false);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_metadata/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,12 @@ pub struct FailedWriteError {
pub err: Error,
}

#[derive(SessionDiagnostic)]
#[diag(metadata::missing_native_library)]
pub struct MissingNativeLibrary<'a> {
pub libname: &'a str,
}

#[derive(SessionDiagnostic)]
#[diag(metadata::failed_create_tempdir)]
pub struct FailedCreateTempdir {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ pub mod fs;
pub mod locator;

pub use fs::{emit_metadata, METADATA_FILENAME};
pub use native_libs::find_native_static_library;
pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};
Loading