]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_codegen_ssa/src/back/linker.rs
Rollup merge of #85766 - workingjubilee:file-options, r=yaahc
[rust.git] / compiler / rustc_codegen_ssa / src / back / linker.rs
index 429dc45d6a4c40e4d971c961358506443076d692..15d16e7d3d61aea74ead8c0e3a9a9110c083ceb8 100644 (file)
@@ -219,19 +219,36 @@ pub struct GccLinker<'a> {
 }
 
 impl<'a> GccLinker<'a> {
-    /// Argument that must be passed *directly* to the linker
+    /// Passes an argument directly to the linker.
     ///
-    /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
-    fn linker_arg<S>(&mut self, arg: S) -> &mut Self
-    where
-        S: AsRef<OsStr>,
-    {
-        if !self.is_ld {
-            let mut os = OsString::from("-Wl,");
-            os.push(arg.as_ref());
-            self.cmd.arg(os);
+    /// When the linker is not ld-like such as when using a compiler as a linker, the argument is
+    /// prepended by `-Wl,`.
+    fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+        self.linker_args(&[arg]);
+        self
+    }
+
+    /// Passes a series of arguments directly to the linker.
+    ///
+    /// When the linker is ld-like, the arguments are simply appended to the command. When the
+    /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
+    /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
+    /// single argument is appended to the command to ensure that the order of the arguments is
+    /// preserved by the compiler.
+    fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
+        if self.is_ld {
+            args.into_iter().for_each(|a| {
+                self.cmd.arg(a);
+            });
         } else {
-            self.cmd.arg(arg);
+            if !args.is_empty() {
+                let mut s = OsString::from("-Wl");
+                for a in args {
+                    s.push(",");
+                    s.push(a);
+                }
+                self.cmd.arg(s);
+            }
         }
         self
     }
@@ -289,14 +306,19 @@ fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
         if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
             self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
         };
-        self.linker_arg(&format!("-plugin-opt={}", opt_level));
-        self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
+        self.linker_args(&[
+            &format!("-plugin-opt={}", opt_level),
+            &format!("-plugin-opt=mcpu={}", self.target_cpu),
+        ]);
     }
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.is_like_osx {
-            self.cmd.arg("-dynamiclib");
+            if !self.is_ld {
+                self.cmd.arg("-dynamiclib");
+            }
+
             self.linker_arg("-dylib");
 
             // Note that the `osx_rpath_install_name` option here is a hack
@@ -304,10 +326,9 @@ fn build_dylib(&mut self, out_filename: &Path) {
             // principled solution at some point to force the compiler to pass
             // the right `-Wl,-install_name` with an `@rpath` in it.
             if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
-                self.linker_arg("-install_name");
-                let mut v = OsString::from("@rpath/");
-                v.push(out_filename.file_name().unwrap());
-                self.linker_arg(&v);
+                let mut rpath = OsString::from("@rpath/");
+                rpath.push(out_filename.file_name().unwrap());
+                self.linker_args(&[OsString::from("-install_name"), rpath]);
             }
         } else {
             self.cmd.arg("-shared");
@@ -381,8 +402,7 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
                 self.build_dylib(out_filename);
             }
             LinkOutputKind::WasiReactorExe => {
-                self.linker_arg("--entry");
-                self.linker_arg("_initialize");
+                self.linker_args(&["--entry", "_initialize"]);
             }
         }
         // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
@@ -454,8 +474,7 @@ fn add_object(&mut self, path: &Path) {
         self.cmd.arg(path);
     }
     fn full_relro(&mut self) {
-        self.linker_arg("-zrelro");
-        self.linker_arg("-znow");
+        self.linker_args(&["-zrelro", "-znow"]);
     }
     fn partial_relro(&mut self) {
         self.linker_arg("-zrelro");
@@ -639,7 +658,6 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
 
         let is_windows = self.sess.target.is_like_windows;
-        let mut arg = OsString::new();
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
         debug!("EXPORTED SYMBOLS:");
@@ -691,27 +709,18 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
 
         if self.sess.target.is_like_osx {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-exported_symbols_list,");
+            self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
         } else if self.sess.target.is_like_solaris {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-M,");
+            self.linker_args(&[OsString::from("-M"), path.into()]);
         } else {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            // Both LD and LLD accept export list in *.def file form, there are no flags required
-            if !is_windows {
-                arg.push("--version-script=")
+            if is_windows {
+                self.linker_arg(path);
+            } else {
+                let mut arg = OsString::from("--version-script=");
+                arg.push(path);
+                self.linker_arg(arg);
             }
         }
-
-        arg.push(&path);
-        self.cmd.arg(arg);
     }
 
     fn subsystem(&mut self, subsystem: &str) {
@@ -769,8 +778,7 @@ fn add_as_needed(&mut self) {
             self.linker_arg("--as-needed");
         } else if self.sess.target.is_like_solaris {
             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
-            self.linker_arg("-z");
-            self.linker_arg("ignore");
+            self.linker_args(&["-z", "ignore"]);
         }
     }
 }