]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_codegen_ssa/src/back/link.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_codegen_ssa / src / back / link.rs
index ab211e9daff3e3dd8eda34b9bbec277793f45a22..f5463bca3384c4c5e5d4934eea86c93b2e90fc6a 100644 (file)
@@ -32,6 +32,7 @@ use cc::windows_registry;
 use object::elf;
 use object::write::Object;
 use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
+use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
 use std::ffi::OsString;
@@ -672,6 +673,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     // Invoke the system linker
     info!("{:?}", &cmd);
     let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
+    let unknown_arg_regex =
+        Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
     let mut prog;
     let mut i = 0;
     loop {
@@ -688,16 +691,15 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         out.extend(&output.stdout);
         let out = String::from_utf8_lossy(&out);
 
-        // Check to see if the link failed with "unrecognized command line option:
-        // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
-        // reperform the link step without the -no-pie option. This is safe because
-        // if the linker doesn't support -no-pie then it should not default to
-        // linking executables as pie. Different versions of gcc seem to use
-        // different quotes in the error message so don't check for them.
+        // Check to see if the link failed with an error message that indicates it
+        // doesn't recognize the -no-pie option. If so, reperform the link step
+        // without it. This is safe because if the linker doesn't support -no-pie
+        // then it should not default to linking executables as pie. Different
+        // versions of gcc seem to use different quotes in the error message so
+        // don't check for them.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && out.contains("-no-pie")
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
         {
@@ -716,8 +718,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         // Fallback from '-static-pie' to '-static' in that case.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
         {
@@ -1802,15 +1803,16 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         add_local_native_libraries(cmd, sess, codegen_results);
     }
 
-    // Rust libraries.
+    // Upstream rust libraries and their nobundle static libraries
     add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
 
-    // Native libraries linked with `#[link]` attributes at and `-l` command line options.
+    // Upstream dymamic native libraries linked with `#[link]` attributes at and `-l`
+    // command line options.
     // If -Zlink-native-libraries=false is set, then the assumption is that an
     // external build system already has the native dependencies defined, and it
     // will provide them to the linker itself.
     if sess.opts.debugging_opts.link_native_libraries {
-        add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
+        add_upstream_native_libraries(cmd, sess, codegen_results);
     }
 
     // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -2032,7 +2034,7 @@ fn add_local_native_libraries(
     }
 }
 
-/// # Rust Crate linking
+/// # Linking Rust crates and their nobundle static libraries
 ///
 /// Rust crates are not considered at all when creating an rlib output. All dependencies will be
 /// linked when producing the final output (instead of the intermediate rlib version).
@@ -2137,6 +2139,29 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
             Linkage::Static => {
                 add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+
+                // 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
+                // or is an rlib already included via some other dylib crate, the symbols from
+                // native libs will have already been included in that dylib.
+                //
+                // If -Zlink-native-libraries=false is set, then the assumption is that an
+                // external build system already has the native dependencies defined, and it
+                // will provide them to the linker itself.
+                if sess.opts.debugging_opts.link_native_libraries {
+                    // Skip if this library is the same as the last.
+                    let mut last = None;
+                    for lib in &codegen_results.crate_info.native_libraries[&cnum] {
+                        if lib.name.is_some()
+                            && relevant_lib(sess, lib)
+                            && matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
+                            && last != lib.name
+                        {
+                            cmd.link_staticlib(lib.name.unwrap(), lib.verbatim.unwrap_or(false));
+                            last = lib.name;
+                        }
+                    }
+                }
             }
             Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
         }
@@ -2309,27 +2334,9 @@ fn add_upstream_native_libraries(
     cmd: &mut dyn Linker,
     sess: &Session,
     codegen_results: &CodegenResults,
-    crate_type: CrateType,
 ) {
-    // Be sure to use a topological sorting of crates because there may be
-    // interdependencies between native libraries. When passing -nodefaultlibs,
-    // for example, almost all native libraries depend on libc, so we have to
-    // make sure that's all the way at the right (liblibc is near the base of
-    // the dependency chain).
-    //
-    // This passes RequireStatic, but the actual requirement doesn't matter,
-    // we're just getting an ordering of crate numbers, we're not worried about
-    // the paths.
-    let (_, data) = codegen_results
-        .crate_info
-        .dependency_formats
-        .iter()
-        .find(|(ty, _)| *ty == crate_type)
-        .expect("failed to find crate type in dependency format list");
-
-    let crates = &codegen_results.crate_info.used_crates;
     let mut last = (NativeLibKind::Unspecified, None);
-    for &cnum in crates {
+    for &cnum in &codegen_results.crate_info.used_crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
             let name = match lib.name {
                 Some(l) => l,
@@ -2351,19 +2358,10 @@ fn add_upstream_native_libraries(
                 NativeLibKind::Framework { as_needed } => {
                     cmd.link_framework(name, as_needed.unwrap_or(true))
                 }
-                NativeLibKind::Static { bundle: Some(false), .. } => {
-                    // Link "static-nobundle" native libs only if the crate they originate from
-                    // is being linked statically to the current crate.  If it's linked dynamically
-                    // or is an rlib already included via some other dylib crate, the symbols from
-                    // native libs will have already been included in that dylib.
-                    if data[cnum.as_usize() - 1] == Linkage::Static {
-                        cmd.link_staticlib(name, verbatim)
-                    }
-                }
-                // ignore statically included native libraries here as we've
-                // already included them when we included the rust library
-                // previously
-                NativeLibKind::Static { bundle: None | Some(true), .. } => {}
+                // ignore static native libraries here as we've
+                // already included them in add_local_native_libraries and
+                // add_upstream_rust_crates
+                NativeLibKind::Static { .. } => {}
                 NativeLibKind::RawDylib => {}
             }
         }
@@ -2484,20 +2482,39 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         if let LinkerFlavor::Gcc = flavor {
             match ld_impl {
                 LdImpl::Lld => {
-                    let tools_path =
-                        sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
-                    let lld_path = tools_path
-                        .into_iter()
-                        .map(|p| p.join("gcc-ld"))
-                        .find(|p| {
-                            p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
-                        })
-                        .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
-                    cmd.cmd().arg({
-                        let mut arg = OsString::from("-B");
-                        arg.push(lld_path);
-                        arg
-                    });
+                    if sess.target.lld_flavor == LldFlavor::Ld64 {
+                        let tools_path =
+                            sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+                        let ld64_exe = tools_path
+                            .into_iter()
+                            .map(|p| p.join("gcc-ld"))
+                            .map(|p| {
+                                p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" })
+                            })
+                            .find(|p| p.exists())
+                            .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found"));
+                        cmd.cmd().arg({
+                            let mut arg = OsString::from("-fuse-ld=");
+                            arg.push(ld64_exe);
+                            arg
+                        });
+                    } else {
+                        let tools_path =
+                            sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+                        let lld_path = tools_path
+                            .into_iter()
+                            .map(|p| p.join("gcc-ld"))
+                            .find(|p| {
+                                p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" })
+                                    .exists()
+                            })
+                            .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
+                        cmd.cmd().arg({
+                            let mut arg = OsString::from("-B");
+                            arg.push(lld_path);
+                            arg
+                        });
+                    }
                 }
             }
         } else {