Skip to content

Commit eab2d75

Browse files
committedNov 15, 2021
Auto merge of #90717 - kit-981:fix-ld64-flags, r=petrochenkov
Fix ld64 flags - The `-exported_symbols_list` argument appears to be malformed for `ld64` (if you are not going through `clang`). - The `-dynamiclib` argument isn't support for `ld64`. It should be guarded behind a compiler flag. These problems are fixed by these changes. I have also refactored the way linker arguments are generated to be ld/compiler agnostic and therefore less error prone. These changes are necessary to support cross-compilation to darwin targets.
2 parents d5a0c7c + f44fa63 commit eab2d75

File tree

1 file changed

+50
-42
lines changed

1 file changed

+50
-42
lines changed
 

‎compiler/rustc_codegen_ssa/src/back/linker.rs

+50-42
Original file line numberDiff line numberDiff line change
@@ -219,19 +219,36 @@ pub struct GccLinker<'a> {
219219
}
220220

221221
impl<'a> GccLinker<'a> {
222-
/// Argument that must be passed *directly* to the linker
222+
/// Passes an argument directly to the linker.
223223
///
224-
/// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
225-
fn linker_arg<S>(&mut self, arg: S) -> &mut Self
226-
where
227-
S: AsRef<OsStr>,
228-
{
229-
if !self.is_ld {
230-
let mut os = OsString::from("-Wl,");
231-
os.push(arg.as_ref());
232-
self.cmd.arg(os);
224+
/// When the linker is not ld-like such as when using a compiler as a linker, the argument is
225+
/// prepended by `-Wl,`.
226+
fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
227+
self.linker_args(&[arg]);
228+
self
229+
}
230+
231+
/// Passes a series of arguments directly to the linker.
232+
///
233+
/// When the linker is ld-like, the arguments are simply appended to the command. When the
234+
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
235+
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
236+
/// single argument is appended to the command to ensure that the order of the arguments is
237+
/// preserved by the compiler.
238+
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
239+
if self.is_ld {
240+
args.into_iter().for_each(|a| {
241+
self.cmd.arg(a);
242+
});
233243
} else {
234-
self.cmd.arg(arg);
244+
if !args.is_empty() {
245+
let mut s = OsString::from("-Wl");
246+
for a in args {
247+
s.push(",");
248+
s.push(a);
249+
}
250+
self.cmd.arg(s);
251+
}
235252
}
236253
self
237254
}
@@ -289,25 +306,29 @@ impl<'a> GccLinker<'a> {
289306
if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
290307
self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
291308
};
292-
self.linker_arg(&format!("-plugin-opt={}", opt_level));
293-
self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
309+
self.linker_args(&[
310+
&format!("-plugin-opt={}", opt_level),
311+
&format!("-plugin-opt=mcpu={}", self.target_cpu),
312+
]);
294313
}
295314

296315
fn build_dylib(&mut self, out_filename: &Path) {
297316
// On mac we need to tell the linker to let this library be rpathed
298317
if self.sess.target.is_like_osx {
299-
self.cmd.arg("-dynamiclib");
318+
if !self.is_ld {
319+
self.cmd.arg("-dynamiclib");
320+
}
321+
300322
self.linker_arg("-dylib");
301323

302324
// Note that the `osx_rpath_install_name` option here is a hack
303325
// purely to support rustbuild right now, we should get a more
304326
// principled solution at some point to force the compiler to pass
305327
// the right `-Wl,-install_name` with an `@rpath` in it.
306328
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
307-
self.linker_arg("-install_name");
308-
let mut v = OsString::from("@rpath/");
309-
v.push(out_filename.file_name().unwrap());
310-
self.linker_arg(&v);
329+
let mut rpath = OsString::from("@rpath/");
330+
rpath.push(out_filename.file_name().unwrap());
331+
self.linker_args(&[OsString::from("-install_name"), rpath]);
311332
}
312333
} else {
313334
self.cmd.arg("-shared");
@@ -381,8 +402,7 @@ impl<'a> Linker for GccLinker<'a> {
381402
self.build_dylib(out_filename);
382403
}
383404
LinkOutputKind::WasiReactorExe => {
384-
self.linker_arg("--entry");
385-
self.linker_arg("_initialize");
405+
self.linker_args(&["--entry", "_initialize"]);
386406
}
387407
}
388408
// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
@@ -454,8 +474,7 @@ impl<'a> Linker for GccLinker<'a> {
454474
self.cmd.arg(path);
455475
}
456476
fn full_relro(&mut self) {
457-
self.linker_arg("-zrelro");
458-
self.linker_arg("-znow");
477+
self.linker_args(&["-zrelro", "-znow"]);
459478
}
460479
fn partial_relro(&mut self) {
461480
self.linker_arg("-zrelro");
@@ -639,7 +658,6 @@ impl<'a> Linker for GccLinker<'a> {
639658
}
640659

641660
let is_windows = self.sess.target.is_like_windows;
642-
let mut arg = OsString::new();
643661
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
644662

645663
debug!("EXPORTED SYMBOLS:");
@@ -691,27 +709,18 @@ impl<'a> Linker for GccLinker<'a> {
691709
}
692710

693711
if self.sess.target.is_like_osx {
694-
if !self.is_ld {
695-
arg.push("-Wl,")
696-
}
697-
arg.push("-exported_symbols_list,");
712+
self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
698713
} else if self.sess.target.is_like_solaris {
699-
if !self.is_ld {
700-
arg.push("-Wl,")
701-
}
702-
arg.push("-M,");
714+
self.linker_args(&[OsString::from("-M"), path.into()]);
703715
} else {
704-
if !self.is_ld {
705-
arg.push("-Wl,")
706-
}
707-
// Both LD and LLD accept export list in *.def file form, there are no flags required
708-
if !is_windows {
709-
arg.push("--version-script=")
716+
if is_windows {
717+
self.linker_arg(path);
718+
} else {
719+
let mut arg = OsString::from("--version-script=");
720+
arg.push(path);
721+
self.linker_arg(arg);
710722
}
711723
}
712-
713-
arg.push(&path);
714-
self.cmd.arg(arg);
715724
}
716725

717726
fn subsystem(&mut self, subsystem: &str) {
@@ -769,8 +778,7 @@ impl<'a> Linker for GccLinker<'a> {
769778
self.linker_arg("--as-needed");
770779
} else if self.sess.target.is_like_solaris {
771780
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option
772-
self.linker_arg("-z");
773-
self.linker_arg("ignore");
781+
self.linker_args(&["-z", "ignore"]);
774782
}
775783
}
776784
}

0 commit comments

Comments
 (0)
Please sign in to comment.