about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src/back
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs73
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs124
3 files changed, 148 insertions, 65 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index c477ac6462a..c197d48d4ea 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -4,11 +4,19 @@ use rustc_span::symbol::Symbol;
 use std::io;
 use std::path::{Path, PathBuf};
 
-pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf {
+pub fn find_library(
+    name: Symbol,
+    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 =
-        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix);
+    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 {
@@ -45,7 +53,7 @@ pub trait ArchiveBuilder<'a> {
         lto: bool,
         skip_objects: bool,
     ) -> io::Result<()>;
-    fn add_native_library(&mut self, name: Symbol);
+    fn add_native_library(&mut self, name: Symbol, verbatim: bool);
     fn update_symbols(&mut self);
 
     fn build(self);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index dcdd0910aa6..59f66c55572 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -329,15 +329,15 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
     // metadata of the rlib we're generating somehow.
     for lib in codegen_results.crate_info.used_libraries.iter() {
         match lib.kind {
-            NativeLibKind::StaticBundle => {}
-            NativeLibKind::StaticNoBundle
-            | NativeLibKind::Dylib
-            | NativeLibKind::Framework
+            NativeLibKind::Static { bundle: None | Some(true), .. } => {}
+            NativeLibKind::Static { bundle: Some(false), .. }
+            | NativeLibKind::Dylib { .. }
+            | NativeLibKind::Framework { .. }
             | NativeLibKind::RawDylib
             | NativeLibKind::Unspecified => continue,
         }
         if let Some(name) = lib.name {
-            ab.add_native_library(name);
+            ab.add_native_library(name, lib.verbatim.unwrap_or(false));
         }
     }
 
@@ -430,9 +430,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
         // 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| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        let skip_object_files = native_libs.iter().any(|lib| {
+            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                && !relevant_lib(sess, lib)
+        });
         ab.add_rlib(
             path,
             &name.as_str(),
@@ -931,7 +932,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
         let path = find_sanitizer_runtime(&sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-        linker.link_dylib(Symbol::intern(&filename));
+        linker.link_dylib(Symbol::intern(&filename), false, true);
     } else {
         let filename = format!("librustc{}_rt.{}.a", channel, name);
         let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
@@ -1080,21 +1081,25 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
         .filter_map(|lib| {
             let name = lib.name?;
             match lib.kind {
-                NativeLibKind::StaticNoBundle
-                | NativeLibKind::Dylib
+                NativeLibKind::Static { bundle: Some(false), .. }
+                | NativeLibKind::Dylib { .. }
                 | NativeLibKind::Unspecified => {
+                    let verbatim = lib.verbatim.unwrap_or(false);
                     if sess.target.is_like_msvc {
-                        Some(format!("{}.lib", name))
+                        Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
+                    } else if sess.target.linker_is_gnu {
+                        Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
                     } else {
                         Some(format!("-l{}", name))
                     }
                 }
-                NativeLibKind::Framework => {
+                NativeLibKind::Framework { .. } => {
                     // ld-only syntax, since there are no frameworks in MSVC
                     Some(format!("-framework {}", name))
                 }
                 // These are included, no need to print them
-                NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None,
+                NativeLibKind::Static { bundle: None | Some(true), .. }
+                | NativeLibKind::RawDylib => None,
             }
         })
         .collect();
@@ -1812,11 +1817,20 @@ fn add_local_native_libraries(
             Some(l) => l,
             None => continue,
         };
+        let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
-            NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-            NativeLibKind::Framework => cmd.link_framework(name),
-            NativeLibKind::StaticNoBundle => cmd.link_staticlib(name),
-            NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path),
+            NativeLibKind::Dylib { as_needed } => {
+                cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+            NativeLibKind::Framework { as_needed } => {
+                cmd.link_framework(name, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Static { bundle: None | Some(true), .. }
+            | NativeLibKind::Static { whole_archive: Some(true), .. } => {
+                cmd.link_whole_staticlib(name, verbatim, &search_path);
+            }
+            NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
             NativeLibKind::RawDylib => {
                 // FIXME(#58713): Proper handling for raw dylibs.
                 bug!("raw_dylib feature not yet implemented");
@@ -2000,9 +2014,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         // 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| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        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))
@@ -2144,22 +2159,28 @@ fn add_upstream_native_libraries(
             if !relevant_lib(sess, &lib) {
                 continue;
             }
+            let verbatim = lib.verbatim.unwrap_or(false);
             match lib.kind {
-                NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-                NativeLibKind::Framework => cmd.link_framework(name),
-                NativeLibKind::StaticNoBundle => {
+                NativeLibKind::Dylib { as_needed } => {
+                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                }
+                NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+                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)
+                        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::StaticBundle => {}
+                NativeLibKind::Static { bundle: None | Some(true), .. } => {}
                 NativeLibKind::RawDylib => {
                     // FIXME(#58713): Proper handling for raw dylibs.
                     bug!("raw_dylib feature not yet implemented");
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 8ba124a1fa8..401d379b0d1 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -103,18 +103,19 @@ impl LinkerInfo {
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib(&mut self, lib: Symbol);
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
-    fn link_framework(&mut self, framework: Symbol);
-    fn link_staticlib(&mut self, lib: Symbol);
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool);
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
     fn link_rlib(&mut self, lib: &Path);
     fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
     fn gc_sections(&mut self, keep_metadata: bool);
+    fn no_gc_sections(&mut self);
     fn full_relro(&mut self);
     fn partial_relro(&mut self);
     fn no_relro(&mut self);
@@ -338,13 +339,32 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // FIXME(81490): ld64 doesn't support these flags but macOS 11
+                // has -needed-l{} / -needed_library {}
+                // but we have no way to detect that here.
+                self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--no-as-needed");
+            } else {
+                self.sess.warn("`as-needed` modifier not supported for current linker");
+            }
+        }
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // See above FIXME comment
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--as-needed");
+            }
+        }
     }
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
         self.hint_static();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
     }
     fn link_rlib(&mut self, lib: &Path) {
         self.hint_static();
@@ -378,8 +398,14 @@ impl<'a> Linker for GccLinker<'a> {
         self.cmd.arg(format!("-l{}", lib));
     }
 
-    fn link_framework(&mut self, framework: Symbol) {
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
         self.hint_dynamic();
+        if !as_needed {
+            // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
+            // flag but we have no way to detect that here.
+            // self.cmd.arg("-needed_framework").sym_arg(framework);
+            self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+        }
         self.cmd.arg("-framework").sym_arg(framework);
     }
 
@@ -389,17 +415,21 @@ impl<'a> Linker for GccLinker<'a> {
     // don't otherwise explicitly reference them. This can occur for
     // libraries which are just providing bindings, libraries with generic
     // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target;
         if !target.is_like_osx {
-            self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
+            self.linker_arg("--whole-archive").cmd.arg(format!(
+                "-l{}{}",
+                if verbatim { ":" } else { "" },
+                lib
+            ));
             self.linker_arg("--no-whole-archive");
         } else {
             // -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, search_path, &self.sess);
+            let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
             self.linker_arg(&lib);
         }
     }
@@ -443,6 +473,16 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
+    fn no_gc_sections(&mut self) {
+        if self.sess.target.is_like_osx {
+            self.linker_arg("-no_dead_strip");
+        } else if self.sess.target.is_like_solaris {
+            self.linker_arg("-zrecord");
+        } else {
+            self.linker_arg("--no-gc-sections");
+        }
+    }
+
     fn optimize(&mut self) {
         if !self.sess.target.linker_is_gnu {
             return;
@@ -710,8 +750,12 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("/OPT:NOREF,NOICF");
+    }
+
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
@@ -725,8 +769,8 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn full_relro(&mut self) {
@@ -764,13 +808,13 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on windows")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
-        self.link_staticlib(lib);
-        self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
+        self.link_staticlib(lib, verbatim);
+        self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
         self.link_rlib(path);
@@ -919,7 +963,7 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg("-L").arg(path);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -931,14 +975,14 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
         // not supported?
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
@@ -947,7 +991,7 @@ impl<'a> Linker for EmLinker<'a> {
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
-        self.link_dylib(lib);
+        self.link_dylib(lib, false, true);
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -970,7 +1014,7 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on Emscripten")
     }
 
@@ -978,6 +1022,10 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
+    fn no_gc_sections(&mut self) {
+        // noop
+    }
+
     fn optimize(&mut self) {
         // Emscripten performs own optimizations
         self.cmd.arg(match self.sess.opts.optimize {
@@ -1121,11 +1169,11 @@ impl<'a> Linker for WasmLd<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1159,11 +1207,11 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1175,6 +1223,10 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg("--gc-sections");
     }
 
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("--no-gc-sections");
+    }
+
     fn optimize(&mut self) {
         self.cmd.arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
@@ -1329,7 +1381,7 @@ impl<'a> Linker for PtxLinker<'a> {
         });
     }
 
-    fn link_dylib(&mut self, _lib: Symbol) {
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
         panic!("external dylibs not supported")
     }
 
@@ -1337,11 +1389,11 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: Symbol) {
+    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1349,7 +1401,7 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
@@ -1361,6 +1413,8 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
+    fn no_gc_sections(&mut self) {}
+
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}