Skip to content

Commit 032462e

Browse files
committed
linker: Combine argument building into a single function
1 parent ce25dab commit 032462e

File tree

2 files changed

+118
-115
lines changed

2 files changed

+118
-115
lines changed

src/librustc_codegen_ssa/back/link.rs

Lines changed: 107 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
154154
// The third parameter is for env vars, used on windows to set up the
155155
// path for MSVC to find its DLLs, and gcc to find its bundled
156156
// toolchain
157-
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
157+
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
158158
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
159159

160160
// If our linker looks like a batch script on Windows then to execute this
@@ -232,7 +232,7 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB
232232
}
233233
cmd.env("PATH", env::join_paths(new_path).unwrap());
234234

235-
(linker.to_path_buf(), cmd)
235+
cmd
236236
}
237237

238238
pub fn each_linked_rlib(
@@ -487,95 +487,18 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
487487
target_cpu: &str,
488488
) {
489489
info!("preparing {:?} to {:?}", crate_type, out_filename);
490-
let (linker, flavor) = linker_and_flavor(sess);
491-
492-
let any_dynamic_crate = crate_type == config::CrateType::Dylib
493-
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
494-
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
495-
});
496-
497-
// The invocations of cc share some flags across platforms
498-
let (pname, mut cmd) = get_linker(sess, &linker, flavor);
499-
500-
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
501-
cmd.args(args);
502-
}
503-
if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
504-
if sess.crt_static(Some(crate_type)) {
505-
cmd.args(args);
506-
}
507-
}
508-
cmd.args(&sess.opts.debugging_opts.pre_link_args);
509-
510-
if sess.target.target.options.is_like_fuchsia {
511-
let prefix = match sess.opts.debugging_opts.sanitizer {
512-
Some(Sanitizer::Address) => "asan/",
513-
_ => "",
514-
};
515-
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
516-
}
517-
518-
let pre_link_objects = if crate_type == config::CrateType::Executable {
519-
&sess.target.target.options.pre_link_objects_exe
520-
} else {
521-
&sess.target.target.options.pre_link_objects_dll
522-
};
523-
for obj in pre_link_objects {
524-
cmd.arg(get_file_path(sess, obj));
525-
}
526-
527-
if crate_type == config::CrateType::Executable && sess.crt_static(Some(crate_type)) {
528-
for obj in &sess.target.target.options.pre_link_objects_exe_crt {
529-
cmd.arg(get_file_path(sess, obj));
530-
}
531-
}
532-
533-
if sess.target.target.options.is_like_emscripten {
534-
cmd.arg("-s");
535-
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
536-
"DISABLE_EXCEPTION_CATCHING=1"
537-
} else {
538-
"DISABLE_EXCEPTION_CATCHING=0"
539-
});
540-
}
490+
let (linker_path, flavor) = linker_and_flavor(sess);
491+
let mut cmd = linker_with_args::<B>(
492+
&linker_path,
493+
flavor,
494+
sess,
495+
crate_type,
496+
tmpdir,
497+
out_filename,
498+
codegen_results,
499+
target_cpu,
500+
);
541501

542-
{
543-
let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu);
544-
link_sanitizer_runtime(sess, crate_type, &mut *linker);
545-
link_args::<B>(
546-
&mut *linker,
547-
flavor,
548-
sess,
549-
crate_type,
550-
tmpdir,
551-
out_filename,
552-
codegen_results,
553-
);
554-
cmd = linker.finalize();
555-
}
556-
if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
557-
cmd.args(args);
558-
}
559-
if any_dynamic_crate {
560-
if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
561-
cmd.args(args);
562-
}
563-
} else {
564-
if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
565-
cmd.args(args);
566-
}
567-
}
568-
for obj in &sess.target.target.options.post_link_objects {
569-
cmd.arg(get_file_path(sess, obj));
570-
}
571-
if sess.crt_static(Some(crate_type)) {
572-
for obj in &sess.target.target.options.post_link_objects_crt {
573-
cmd.arg(get_file_path(sess, obj));
574-
}
575-
}
576-
if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
577-
cmd.args(args);
578-
}
579502
for &(ref k, ref v) in &sess.target.target.options.link_env {
580503
cmd.env(k, v);
581504
}
@@ -597,7 +520,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
597520
let mut i = 0;
598521
loop {
599522
i += 1;
600-
prog = sess.time("run_linker", || exec_linker(sess, &mut cmd, out_filename, tmpdir));
523+
prog = sess.time("run_linker", || exec_linker(sess, &cmd, out_filename, tmpdir));
601524
let output = match prog {
602525
Ok(ref output) => output,
603526
Err(_) => break,
@@ -698,7 +621,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
698621
output.extend_from_slice(&prog.stdout);
699622
sess.struct_err(&format!(
700623
"linking with `{}` failed: {}",
701-
pname.display(),
624+
linker_path.display(),
702625
prog.status
703626
))
704627
.note(&format!("{:?}", &cmd))
@@ -714,9 +637,12 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
714637

715638
let mut linker_error = {
716639
if linker_not_found {
717-
sess.struct_err(&format!("linker `{}` not found", pname.display()))
640+
sess.struct_err(&format!("linker `{}` not found", linker_path.display()))
718641
} else {
719-
sess.struct_err(&format!("could not exec the linker `{}`", pname.display()))
642+
sess.struct_err(&format!(
643+
"could not exec the linker `{}`",
644+
linker_path.display()
645+
))
720646
}
721647
};
722648

@@ -1087,7 +1013,7 @@ pub fn get_file_path(sess: &Session, name: &str) -> PathBuf {
10871013

10881014
pub fn exec_linker(
10891015
sess: &Session,
1090-
cmd: &mut Command,
1016+
cmd: &Command,
10911017
out_filename: &Path,
10921018
tmpdir: &Path,
10931019
) -> io::Result<Output> {
@@ -1233,15 +1159,66 @@ pub fn exec_linker(
12331159
}
12341160
}
12351161

1236-
fn link_args<'a, B: ArchiveBuilder<'a>>(
1237-
cmd: &mut dyn Linker,
1162+
fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
1163+
path: &Path,
12381164
flavor: LinkerFlavor,
12391165
sess: &'a Session,
12401166
crate_type: config::CrateType,
12411167
tmpdir: &Path,
12421168
out_filename: &Path,
12431169
codegen_results: &CodegenResults,
1244-
) {
1170+
target_cpu: &str,
1171+
) -> Command {
1172+
let base_cmd = get_linker(sess, path, flavor);
1173+
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
1174+
// to the linker args construction.
1175+
assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
1176+
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
1177+
1178+
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
1179+
cmd.args(args);
1180+
}
1181+
if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
1182+
if sess.crt_static(Some(crate_type)) {
1183+
cmd.args(args);
1184+
}
1185+
}
1186+
cmd.args(&sess.opts.debugging_opts.pre_link_args);
1187+
1188+
if sess.target.target.options.is_like_fuchsia {
1189+
let prefix = match sess.opts.debugging_opts.sanitizer {
1190+
Some(Sanitizer::Address) => "asan/",
1191+
_ => "",
1192+
};
1193+
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
1194+
}
1195+
1196+
let pre_link_objects = if crate_type == config::CrateType::Executable {
1197+
&sess.target.target.options.pre_link_objects_exe
1198+
} else {
1199+
&sess.target.target.options.pre_link_objects_dll
1200+
};
1201+
for obj in pre_link_objects {
1202+
cmd.arg(get_file_path(sess, obj));
1203+
}
1204+
1205+
if crate_type == config::CrateType::Executable && sess.crt_static(Some(crate_type)) {
1206+
for obj in &sess.target.target.options.pre_link_objects_exe_crt {
1207+
cmd.arg(get_file_path(sess, obj));
1208+
}
1209+
}
1210+
1211+
if sess.target.target.options.is_like_emscripten {
1212+
cmd.arg("-s");
1213+
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
1214+
"DISABLE_EXCEPTION_CATCHING=1"
1215+
} else {
1216+
"DISABLE_EXCEPTION_CATCHING=0"
1217+
});
1218+
}
1219+
1220+
link_sanitizer_runtime(sess, crate_type, cmd);
1221+
12451222
// Linker plugins should be specified early in the list of arguments
12461223
cmd.linker_plugin_lto();
12471224

@@ -1440,6 +1417,38 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
14401417
// Finally add all the linker arguments provided on the command line along
14411418
// with any #[link_args] attributes found inside the crate
14421419
cmd.args(user_link_args);
1420+
1421+
cmd.finalize();
1422+
1423+
if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
1424+
cmd.args(args);
1425+
}
1426+
let any_dynamic_crate = crate_type == config::CrateType::Dylib
1427+
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
1428+
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
1429+
});
1430+
if any_dynamic_crate {
1431+
if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
1432+
cmd.args(args);
1433+
}
1434+
} else {
1435+
if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
1436+
cmd.args(args);
1437+
}
1438+
}
1439+
for obj in &sess.target.target.options.post_link_objects {
1440+
cmd.arg(get_file_path(sess, obj));
1441+
}
1442+
if sess.crt_static(Some(crate_type)) {
1443+
for obj in &sess.target.target.options.post_link_objects_crt {
1444+
cmd.arg(get_file_path(sess, obj));
1445+
}
1446+
}
1447+
if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
1448+
cmd.args(args);
1449+
}
1450+
1451+
cmd.take_cmd()
14431452
}
14441453

14451454
// # Native library linking

src/librustc_codegen_ssa/back/linker.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString};
66
use std::fs::{self, File};
77
use std::io::prelude::*;
88
use std::io::{self, BufWriter};
9+
use std::mem;
910
use std::path::{Path, PathBuf};
1011

1112
use rustc_data_structures::fx::FxHashMap;
@@ -117,8 +118,7 @@ pub trait Linker {
117118
fn group_start(&mut self);
118119
fn group_end(&mut self);
119120
fn linker_plugin_lto(&mut self);
120-
// Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
121-
fn finalize(&mut self) -> Command;
121+
fn finalize(&mut self);
122122
}
123123

124124
impl dyn Linker + '_ {
@@ -129,6 +129,10 @@ impl dyn Linker + '_ {
129129
pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) {
130130
self.cmd().args(args);
131131
}
132+
133+
pub fn take_cmd(&mut self) -> Command {
134+
mem::replace(self.cmd(), Command::new(""))
135+
}
132136
}
133137

134138
pub struct GccLinker<'a> {
@@ -515,10 +519,8 @@ impl<'a> Linker for GccLinker<'a> {
515519
self.linker_arg(&subsystem);
516520
}
517521

518-
fn finalize(&mut self) -> Command {
522+
fn finalize(&mut self) {
519523
self.hint_dynamic(); // Reset to default before returning the composed command line.
520-
521-
::std::mem::replace(&mut self.cmd, Command::new(""))
522524
}
523525

524526
fn group_start(&mut self) {
@@ -768,9 +770,7 @@ impl<'a> Linker for MsvcLinker<'a> {
768770
}
769771
}
770772

771-
fn finalize(&mut self) -> Command {
772-
::std::mem::replace(&mut self.cmd, Command::new(""))
773-
}
773+
fn finalize(&mut self) {}
774774

775775
// MSVC doesn't need group indicators
776776
fn group_start(&mut self) {}
@@ -937,9 +937,7 @@ impl<'a> Linker for EmLinker<'a> {
937937
// noop
938938
}
939939

940-
fn finalize(&mut self) -> Command {
941-
::std::mem::replace(&mut self.cmd, Command::new(""))
942-
}
940+
fn finalize(&mut self) {}
943941

944942
// Appears not necessary on Emscripten
945943
fn group_start(&mut self) {}
@@ -1107,9 +1105,7 @@ impl<'a> Linker for WasmLd<'a> {
11071105

11081106
fn no_position_independent_executable(&mut self) {}
11091107

1110-
fn finalize(&mut self) -> Command {
1111-
::std::mem::replace(&mut self.cmd, Command::new(""))
1112-
}
1108+
fn finalize(&mut self) {}
11131109

11141110
// Not needed for now with LLD
11151111
fn group_start(&mut self) {}
@@ -1209,14 +1205,12 @@ impl<'a> Linker for PtxLinker<'a> {
12091205
self.cmd.arg("-o").arg(path);
12101206
}
12111207

1212-
fn finalize(&mut self) -> Command {
1208+
fn finalize(&mut self) {
12131209
// Provide the linker with fallback to internal `target-cpu`.
12141210
self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
12151211
Some(ref s) => s,
12161212
None => &self.sess.target.target.options.cpu,
12171213
});
1218-
1219-
::std::mem::replace(&mut self.cmd, Command::new(""))
12201214
}
12211215

12221216
fn link_dylib(&mut self, _lib: Symbol) {

0 commit comments

Comments
 (0)