summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_ssa/src/back/link.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back/link.rs')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs206
1 files changed, 120 insertions, 86 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index fe2e4b36c..34e042376 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -208,16 +208,16 @@ pub fn link_binary<'a>(
Ok(())
}
+// Crate type is not passed when calculating the dylibs to include for LTO. In that case all
+// crate types must use the same dependency formats.
pub fn each_linked_rlib(
- sess: &Session,
info: &CrateInfo,
+ crate_type: Option<CrateType>,
f: &mut dyn FnMut(CrateNum, &Path),
) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
- let mut fmts = None;
- let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
- if lto_active {
+ let fmts = if crate_type.is_none() {
for combination in info.dependency_formats.iter().combinations(2) {
let (ty1, list1) = &combination[0];
let (ty2, list2) = &combination[1];
@@ -230,27 +230,23 @@ pub fn each_linked_rlib(
});
}
}
- }
-
- for (ty, list) in info.dependency_formats.iter() {
- match ty {
- CrateType::Executable
- | CrateType::Staticlib
- | CrateType::Cdylib
- | CrateType::ProcMacro => {
- fmts = Some(list);
- break;
- }
- CrateType::Dylib if lto_active => {
- fmts = Some(list);
- break;
- }
- _ => {}
+ if info.dependency_formats.is_empty() {
+ return Err(errors::LinkRlibError::MissingFormat);
}
- }
- let Some(fmts) = fmts else {
- return Err(errors::LinkRlibError::MissingFormat);
+ &info.dependency_formats[0].1
+ } else {
+ let fmts = info
+ .dependency_formats
+ .iter()
+ .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
+
+ let Some(fmts) = fmts else {
+ return Err(errors::LinkRlibError::MissingFormat);
+ };
+
+ fmts
};
+
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
@@ -449,7 +445,7 @@ fn link_rlib<'a>(
/// Extract all symbols defined in raw-dylib libraries, collated by library name.
///
/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
-/// then the CodegenResults value contains one NativeLib instance for each block. However, the
+/// then the CodegenResults value contains one NativeLib instance for each block. However, the
/// linker appears to expect only a single import library for each library used, so we need to
/// collate the symbols together by library name before generating the import libraries.
fn collate_raw_dylibs<'a, 'b>(
@@ -516,64 +512,71 @@ fn link_staticlib<'a>(
)?;
let mut all_native_libs = vec![];
- let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
- let name = codegen_results.crate_info.crate_name[&cnum];
- let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-
- // Here when we include the rlib into our staticlib we need to make a
- // decision whether to include the extra object files along the way.
- // These extra object files come from statically included native
- // libraries, but they may be cfg'd away with #[link(cfg(..))].
- //
- // This unstable feature, though, only needs liblibc to work. The only
- // use case there is where musl is statically included in liblibc.rlib,
- // so if we don't want the included version we just need to skip it. As
- // a result the logic here is that if *any* linked library is cfg'd away
- // we just skip all object files.
- //
- // Clearly this is not sufficient for a general purpose feature, and
- // we'd want to read from the library's metadata to determine which
- // object files come from where and selectively skip them.
- let skip_object_files = native_libs.iter().any(|lib| {
- matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
- && !relevant_lib(sess, lib)
- });
+ let res = each_linked_rlib(
+ &codegen_results.crate_info,
+ Some(CrateType::Staticlib),
+ &mut |cnum, path| {
+ let name = codegen_results.crate_info.crate_name[&cnum];
+ let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
+
+ // Here when we include the rlib into our staticlib we need to make a
+ // decision whether to include the extra object files along the way.
+ // These extra object files come from statically included native
+ // libraries, but they may be cfg'd away with #[link(cfg(..))].
+ //
+ // This unstable feature, though, only needs liblibc to work. The only
+ // use case there is where musl is statically included in liblibc.rlib,
+ // so if we don't want the included version we just need to skip it. As
+ // a result the logic here is that if *any* linked library is cfg'd away
+ // we just skip all object files.
+ //
+ // Clearly this is not sufficient for a general purpose feature, and
+ // we'd want to read from the library's metadata to determine which
+ // object files come from where and selectively skip them.
+ let skip_object_files = native_libs.iter().any(|lib| {
+ matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+ && !relevant_lib(sess, lib)
+ });
- let lto = are_upstream_rust_objects_already_included(sess)
- && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
+ let lto = are_upstream_rust_objects_already_included(sess)
+ && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
- // Ignoring obj file starting with the crate name
- // as simple comparison is not enough - there
- // might be also an extra name suffix
- let obj_start = name.as_str().to_owned();
+ // Ignoring obj file starting with the crate name
+ // as simple comparison is not enough - there
+ // might be also an extra name suffix
+ let obj_start = name.as_str().to_owned();
- ab.add_archive(
- path,
- Box::new(move |fname: &str| {
- // Ignore metadata files, no matter the name.
- if fname == METADATA_FILENAME {
- return true;
- }
+ ab.add_archive(
+ path,
+ Box::new(move |fname: &str| {
+ // Ignore metadata files, no matter the name.
+ if fname == METADATA_FILENAME {
+ return true;
+ }
- // Don't include Rust objects if LTO is enabled
- if lto && looks_like_rust_object_file(fname) {
- return true;
- }
+ // Don't include Rust objects if LTO is enabled
+ if lto && looks_like_rust_object_file(fname) {
+ return true;
+ }
- // Otherwise if this is *not* a rust object and we're skipping
- // objects then skip this file
- if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
- return true;
- }
+ // Otherwise if this is *not* a rust object and we're skipping
+ // objects then skip this file
+ if skip_object_files
+ && (!fname.starts_with(&obj_start) || !fname.ends_with(".o"))
+ {
+ return true;
+ }
- // ok, don't skip this
- false
- }),
- )
- .unwrap();
+ // ok, don't skip this
+ false
+ }),
+ )
+ .unwrap();
- all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
- });
+ all_native_libs
+ .extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
+ },
+ );
if let Err(e) = res {
sess.emit_fatal(e);
}
@@ -607,21 +610,21 @@ fn link_dwarf_object<'a>(
}
impl<Relocations> ThorinSession<Relocations> {
- fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+ fn alloc_mmap(&self, data: Mmap) -> &Mmap {
(*self.arena_mmap.alloc(data)).borrow()
}
}
impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
- fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+ fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
(*self.arena_data.alloc(data)).borrow()
}
- fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+ fn alloc_relocation(&self, data: Relocations) -> &Relocations {
(*self.arena_relocations.alloc(data)).borrow()
}
- fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+ fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
let file = File::open(&path)?;
let mmap = (unsafe { Mmap::map(file) })?;
Ok(self.alloc_mmap(mmap))
@@ -722,7 +725,7 @@ fn link_natively<'a>(
linker::disable_localization(&mut cmd);
- for &(ref k, ref v) in sess.target.link_env.as_ref() {
+ for (k, v) in sess.target.link_env.as_ref() {
cmd.env(k.as_ref(), v.as_ref());
}
for k in sess.target.link_env_remove.as_ref() {
@@ -1194,7 +1197,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
// On historical Solaris systems, "cc" may have
// been Sun Studio, which is not flag-compatible
- // with "gcc". This history casts a long shadow,
+ // with "gcc". This history casts a long shadow,
// and many modern illumos distributions today
// ship GCC as "gcc" without also making it
// available as "cc".
@@ -1228,12 +1231,23 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
sess.emit_fatal(errors::LinkerFileStem);
});
+ // Remove any version postfix.
+ let stem = stem
+ .rsplit_once('-')
+ .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
+ .unwrap_or(stem);
+
+ // GCC/Clang can have an optional target prefix.
let flavor = if stem == "emcc" {
LinkerFlavor::EmCc
} else if stem == "gcc"
|| stem.ends_with("-gcc")
+ || stem == "g++"
+ || stem.ends_with("-g++")
|| stem == "clang"
|| stem.ends_with("-clang")
+ || stem == "clang++"
+ || stem.ends_with("-clang++")
{
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
@@ -1354,7 +1368,8 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
if !lib_args.is_empty() {
sess.emit_note(errors::StaticLibraryNativeArtifacts);
// Prefix for greppability
- sess.emit_note(errors::NativeStaticLibs { arguments: lib_args.join(" ") });
+ // Note: This must not be translated as tools are allowed to depend on this exact string.
+ sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
}
}
@@ -2612,7 +2627,7 @@ fn add_static_crate<'a>(
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(
+ if let Err(error) = archive.add_archive(
cratepath,
Box::new(move |f| {
if f == METADATA_FILENAME {
@@ -2652,7 +2667,7 @@ fn add_static_crate<'a>(
false
}),
) {
- sess.fatal(&format!("failed to build archive from rlib: {}", e));
+ sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
}
if archive.build(&dst) {
link_upstream(&dst);
@@ -2822,11 +2837,30 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
+
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
- cmd.arg(format!("--target={}", sess.target.llvm_target));
+ //
+ // Note that we don't want to do that by default on macOS: e.g. passing a
+ // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+ // shown in issue #101653 and the discussion in PR #101792.
+ //
+ // It could be required in some cases of cross-compiling with
+ // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+ // which specific versions of clang, macOS SDK, host and target OS
+ // combinations impact us here.
+ //
+ // So we do a simple first-approximation until we know more of what the
+ // Apple targets require (and which would be handled prior to hitting this
+ // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+ // this should be manually passed if needed. We specify the target when
+ // targeting a different linker flavor on macOS, and that's also always
+ // the case when targeting WASM.
+ if sess.target.linker_flavor != sess.host.linker_flavor {
+ cmd.arg(format!("--target={}", sess.target.llvm_target));
+ }
}
}
}