Skip to content

Commit

Permalink
Do not lose or reorder user-provided linker arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Apr 4, 2020
1 parent cff07db commit 13bd25e
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 22 deletions.
24 changes: 8 additions & 16 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
cmd.args(args);
}
}
if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
cmd.args(args);
}
cmd.args(&sess.opts.debugging_opts.pre_link_arg);
cmd.args(&sess.opts.debugging_opts.pre_link_args);

if sess.target.target.options.is_like_fuchsia {
let prefix = match sess.opts.debugging_opts.sanitizer {
Expand Down Expand Up @@ -1302,18 +1299,17 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
cmd.gc_sections(keep_metadata);
}

let used_link_args = &codegen_results.crate_info.link_args;
let attr_link_args = codegen_results.crate_info.link_args.iter();
let user_link_args: Vec<_> =
sess.opts.cg.link_args.iter().chain(attr_link_args).cloned().collect();

if crate_type == config::CrateType::Executable {
let mut position_independent_executable = false;

if t.options.position_independent_executables {
let empty_vec = Vec::new();
let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
let more_args = &sess.opts.cg.link_arg;
let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());

if is_pic(sess) && !sess.crt_static(Some(crate_type)) && !args.any(|x| *x == "-static")
if is_pic(sess)
&& !sess.crt_static(Some(crate_type))
&& !user_link_args.iter().any(|x| x == "-static")
{
position_independent_executable = true;
}
Expand Down Expand Up @@ -1444,11 +1440,7 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(

// Finally add all the linker arguments provided on the command line along
// with any #[link_args] attributes found inside the crate
if let Some(ref args) = sess.opts.cg.link_args {
cmd.args(args);
}
cmd.args(&sess.opts.cg.link_arg);
cmd.args(&used_link_args);
cmd.args(&user_link_args);
}

// # Native library linking
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_interface/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ fn test_codegen_options_tracking_hash() {
opts.cg.linker = Some(PathBuf::from("linker"));
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());

opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
opts.cg.link_args = vec![String::from("abc"), String::from("def")];
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());

opts.cg.link_dead_code = true;
Expand Down
18 changes: 13 additions & 5 deletions src/librustc_session/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,17 @@ macro_rules! options {
use std::path::PathBuf;
use std::str::FromStr;

// Sometimes different options need to build a common structure.
// That structure can kept in one of the options' fields, the others become dummy.
macro_rules! redirect_field {
($cg:ident.link_arg) => { $cg.link_args };
($cg:ident.pre_link_arg) => { $cg.pre_link_args };
($cg:ident.$field:ident) => { $cg.$field };
}

$(
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
$parse(&mut cg.$opt, v)
$parse(&mut redirect_field!(cg.$opt), v)
}
)*

Expand Down Expand Up @@ -643,9 +651,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"this option is deprecated and does nothing"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"),
link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to append to the linker invocation (can be used several times)"),
link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
"extra arguments to append to the linker invocation (space separated)"),
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
"don't let linker strip dead code (turning it on can be used for code coverage)"),
Expand Down Expand Up @@ -876,9 +884,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"make rustc print the total optimization fuel used by a crate"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable"),
pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to prepend the linker invocation (can be used several times)"),
pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
"extra arguments to prepend to the linker invocation (space separated)"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code"),
Expand Down
10 changes: 10 additions & 0 deletions src/test/run-make-fulldeps/link-args-order/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ignore-msvc

-include ../tools.mk

RUSTC_FLAGS = -C linker-flavor=ld -C link-arg=a -C link-args="b c" -C link-args="d e" -C link-arg=f
RUSTC_FLAGS_PRE = -C linker-flavor=ld -Z pre-link-arg=a -Z pre-link-args="b c" -Z pre-link-args="d e" -Z pre-link-arg=f

all:
$(RUSTC) $(RUSTC_FLAGS) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f" "g"'
$(RUSTC) $(RUSTC_FLAGS_PRE) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f"'
6 changes: 6 additions & 0 deletions src/test/run-make-fulldeps/link-args-order/empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(link_args)]

#[link_args = "g"]
extern "C" {}

fn main() {}

0 comments on commit 13bd25e

Please sign in to comment.