about summary refs log tree commit diff
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.rs181
1 files changed, 102 insertions, 79 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index edde1537b81..8ca7103ed48 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,
@@ -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);
     }
@@ -1354,7 +1357,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 +2616,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 +2656,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 +2826,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));
+                        }
                     }
                 }
             }