linker: Move some inner functions to the outside
Inline `fn unlib`
This commit is contained in:
parent
e792de28c8
commit
fe7aab13b1
@ -24,7 +24,7 @@ use rustc_span::symbol::Symbol;
|
||||
use rustc_span::DebuggerVisualizerFile;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, Target};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
||||
|
||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
||||
use super::command::Command;
|
||||
@ -2512,138 +2512,6 @@ fn add_upstream_rust_crates<'a>(
|
||||
link_dynamic,
|
||||
);
|
||||
}
|
||||
|
||||
// Converts a library file-stem into a cc -l argument
|
||||
fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
|
||||
if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem }
|
||||
}
|
||||
|
||||
// Adds the static "rlib" versions of all crates to the command line.
|
||||
// There's a bit of magic which happens here specifically related to LTO,
|
||||
// namely that we remove upstream object files.
|
||||
//
|
||||
// When performing LTO, almost(*) all of the bytecode from the upstream
|
||||
// libraries has already been included in our object file output. As a
|
||||
// result we need to remove the object files in the upstream libraries so
|
||||
// the linker doesn't try to include them twice (or whine about duplicate
|
||||
// symbols). We must continue to include the rest of the rlib, however, as
|
||||
// it may contain static native libraries which must be linked in.
|
||||
//
|
||||
// (*) Crates marked with `#![no_builtins]` don't participate in LTO and
|
||||
// their bytecode wasn't included. The object files in those libraries must
|
||||
// still be passed to the linker.
|
||||
//
|
||||
// Note, however, that if we're not doing LTO we can just pass the rlib
|
||||
// blindly to the linker (fast) because it's fine if it's not actually
|
||||
// included as we're at the end of the dependency chain.
|
||||
fn add_static_crate<'a>(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &'a Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
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;
|
||||
|
||||
let mut link_upstream = |path: &Path| {
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
|
||||
};
|
||||
|
||||
// See the comment above in `link_staticlib` and `link_rlib` for why if
|
||||
// there's a static library that's not relevant we skip all object
|
||||
// files.
|
||||
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
|
||||
let skip_native = native_libs.iter().any(|lib| {
|
||||
matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
|
||||
&& !relevant_lib(sess, lib)
|
||||
});
|
||||
|
||||
if (!are_upstream_rust_objects_already_included(sess)
|
||||
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
|
||||
&& !skip_native
|
||||
{
|
||||
link_upstream(cratepath);
|
||||
return;
|
||||
}
|
||||
|
||||
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('-', "_");
|
||||
let upstream_rust_objects_already_included =
|
||||
are_upstream_rust_objects_already_included(sess);
|
||||
let is_builtins = sess.target.no_builtins
|
||||
|| !codegen_results.crate_info.is_no_builtins.contains(&cnum);
|
||||
|
||||
let mut archive = archive_builder_builder.new_archive_builder(sess);
|
||||
if let Err(error) = archive.add_archive(
|
||||
cratepath,
|
||||
Box::new(move |f| {
|
||||
if f == METADATA_FILENAME {
|
||||
return true;
|
||||
}
|
||||
|
||||
let canonical = f.replace('-', "_");
|
||||
|
||||
let is_rust_object =
|
||||
canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
|
||||
|
||||
// If we've been requested to skip all native object files
|
||||
// (those not generated by the rust compiler) then we can skip
|
||||
// this file. See above for why we may want to do this.
|
||||
let skip_because_cfg_say_so = skip_native && !is_rust_object;
|
||||
|
||||
// If we're performing LTO and this is a rust-generated object
|
||||
// file, then we don't need the object file as it's part of the
|
||||
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
|
||||
// though, so we let that object file slide.
|
||||
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;
|
||||
}
|
||||
|
||||
false
|
||||
}),
|
||||
) {
|
||||
sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
|
||||
}
|
||||
if archive.build(&dst) {
|
||||
link_upstream(&dst);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Same thing as above, but for dynamic crates instead of static crates.
|
||||
fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
|
||||
// Just need to tell the linker about where the library lives and
|
||||
// what its name is
|
||||
let parent = cratepath.parent();
|
||||
if let Some(dir) = parent {
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
|
||||
}
|
||||
let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
|
||||
cmd.link_rust_dylib(
|
||||
&unlib(&sess.target, filestem),
|
||||
parent.unwrap_or_else(|| Path::new("")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_upstream_native_libraries(
|
||||
@ -2684,6 +2552,132 @@ fn add_upstream_native_libraries(
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the static "rlib" versions of all crates to the command line.
|
||||
// There's a bit of magic which happens here specifically related to LTO,
|
||||
// namely that we remove upstream object files.
|
||||
//
|
||||
// When performing LTO, almost(*) all of the bytecode from the upstream
|
||||
// libraries has already been included in our object file output. As a
|
||||
// result we need to remove the object files in the upstream libraries so
|
||||
// the linker doesn't try to include them twice (or whine about duplicate
|
||||
// symbols). We must continue to include the rest of the rlib, however, as
|
||||
// it may contain static native libraries which must be linked in.
|
||||
//
|
||||
// (*) Crates marked with `#![no_builtins]` don't participate in LTO and
|
||||
// their bytecode wasn't included. The object files in those libraries must
|
||||
// still be passed to the linker.
|
||||
//
|
||||
// Note, however, that if we're not doing LTO we can just pass the rlib
|
||||
// blindly to the linker (fast) because it's fine if it's not actually
|
||||
// included as we're at the end of the dependency chain.
|
||||
fn add_static_crate<'a>(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &'a Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
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;
|
||||
|
||||
let mut link_upstream = |path: &Path| {
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
|
||||
};
|
||||
|
||||
// See the comment above in `link_staticlib` and `link_rlib` for why if
|
||||
// there's a static library that's not relevant we skip all object
|
||||
// files.
|
||||
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
|
||||
let skip_native = native_libs.iter().any(|lib| {
|
||||
matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
|
||||
&& !relevant_lib(sess, lib)
|
||||
});
|
||||
|
||||
if (!are_upstream_rust_objects_already_included(sess)
|
||||
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
|
||||
&& !skip_native
|
||||
{
|
||||
link_upstream(cratepath);
|
||||
return;
|
||||
}
|
||||
|
||||
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('-', "_");
|
||||
let upstream_rust_objects_already_included =
|
||||
are_upstream_rust_objects_already_included(sess);
|
||||
let is_builtins =
|
||||
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
|
||||
|
||||
let mut archive = archive_builder_builder.new_archive_builder(sess);
|
||||
if let Err(e) = archive.add_archive(
|
||||
cratepath,
|
||||
Box::new(move |f| {
|
||||
if f == METADATA_FILENAME {
|
||||
return true;
|
||||
}
|
||||
|
||||
let canonical = f.replace('-', "_");
|
||||
|
||||
let is_rust_object =
|
||||
canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
|
||||
|
||||
// If we've been requested to skip all native object files
|
||||
// (those not generated by the rust compiler) then we can skip
|
||||
// this file. See above for why we may want to do this.
|
||||
let skip_because_cfg_say_so = skip_native && !is_rust_object;
|
||||
|
||||
// If we're performing LTO and this is a rust-generated object
|
||||
// file, then we don't need the object file as it's part of the
|
||||
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
|
||||
// though, so we let that object file slide.
|
||||
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;
|
||||
}
|
||||
|
||||
false
|
||||
}),
|
||||
) {
|
||||
sess.fatal(&format!("failed to build archive from rlib: {}", e));
|
||||
}
|
||||
if archive.build(&dst) {
|
||||
link_upstream(&dst);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Same thing as above, but for dynamic crates instead of static crates.
|
||||
fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
|
||||
// Just need to tell the linker about where the library lives and
|
||||
// what its name is
|
||||
let parent = cratepath.parent();
|
||||
if let Some(dir) = parent {
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
|
||||
}
|
||||
let stem = cratepath.file_stem().unwrap().to_str().unwrap();
|
||||
// Convert library file-stem into a cc -l argument.
|
||||
let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
|
||||
cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new("")));
|
||||
}
|
||||
|
||||
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
|
||||
match lib.cfg {
|
||||
Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
|
||||
|
Loading…
x
Reference in New Issue
Block a user