Skip to content

Commit ae6a7db

Browse files
authored
Rollup merge of #132974 - madsmtm:linker-arguments-with-commas, r=petrochenkov
Properly pass linker arguments that contain commas When linking with the system C compiler, we sometimes want to forward certain arguments unchanged to the linker. This can be done with `-Wl,arg1,arg2` or `-Xlinker arg1 -Xlinker arg2`. `-Wl` is used when possible, since it is more compact, but it does not support commas in the argument itself - in those cases, we need to use `-Xlinker`, and that is what this PR implements. This also fixes using sanitizers on macOS with `-Clinker-flavor=ld`, as those were previously manually using `-Wl`/`-Xlinker` (probably since the support wasn't present in the `link_args` function). Note that there has been [a previous PR for this](#38798), but it only implemented this in certain cases when passing `-rpath`. r? compiler
2 parents 6c76ed5 + 6bbf832 commit ae6a7db

File tree

5 files changed

+82
-61
lines changed

5 files changed

+82
-61
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ fn link_sanitizer_runtime(
13861386
let filename = format!("rustc{channel}_rt.{name}");
13871387
let path = find_sanitizer_runtime(sess, &filename);
13881388
let rpath = path.to_str().expect("non-utf8 component in path");
1389-
linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
1389+
linker.link_args(&["-rpath", rpath]);
13901390
linker.link_dylib_by_name(&filename, false, true);
13911391
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
13921392
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
@@ -2210,7 +2210,7 @@ fn add_rpath_args(
22102210
is_like_osx: sess.target.is_like_osx,
22112211
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
22122212
};
2213-
cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
2213+
cmd.link_args(&rpath::get_rpath_linker_args(&rpath_config));
22142214
}
22152215
}
22162216

compiler/rustc_codegen_ssa/src/back/linker.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ use super::command::Command;
2424
use super::symbol_export;
2525
use crate::errors;
2626

27+
#[cfg(test)]
28+
mod tests;
29+
2730
/// Disables non-English messages from localized linkers.
2831
/// Such messages may cause issues with text encoding on Windows (#35785)
2932
/// and prevent inspection of linker output in case of errors, which we occasionally do.
@@ -178,23 +181,42 @@ fn verbatim_args<L: Linker + ?Sized>(
178181
}
179182
l
180183
}
184+
/// Add underlying linker arguments to C compiler command, by wrapping them in
185+
/// `-Wl` or `-Xlinker`.
186+
fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
187+
let mut combined_arg = OsString::from("-Wl");
188+
for arg in args {
189+
// If the argument itself contains a comma, we need to emit it
190+
// as `-Xlinker`, otherwise we can use `-Wl`.
191+
if arg.as_ref().as_encoded_bytes().contains(&b',') {
192+
// Emit current `-Wl` argument, if any has been built.
193+
if combined_arg != OsStr::new("-Wl") {
194+
cmd.arg(combined_arg);
195+
// Begin next `-Wl` argument.
196+
combined_arg = OsString::from("-Wl");
197+
}
198+
199+
// Emit `-Xlinker` argument.
200+
cmd.arg("-Xlinker");
201+
cmd.arg(arg);
202+
} else {
203+
// Append to `-Wl` argument.
204+
combined_arg.push(",");
205+
combined_arg.push(arg);
206+
}
207+
}
208+
// Emit final `-Wl` argument.
209+
if combined_arg != OsStr::new("-Wl") {
210+
cmd.arg(combined_arg);
211+
}
212+
}
181213
/// Arguments for the underlying linker.
182214
/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
183-
fn link_args<L: Linker + ?Sized>(
184-
l: &mut L,
185-
args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>,
186-
) -> &mut L {
187-
let args = args.into_iter();
215+
fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
188216
if !l.is_cc() {
189217
verbatim_args(l, args);
190-
} else if args.len() != 0 {
191-
// FIXME: Support arguments with commas, see `rpaths_to_flags` for the example.
192-
let mut combined_arg = OsString::from("-Wl");
193-
for arg in args {
194-
combined_arg.push(",");
195-
combined_arg.push(arg);
196-
}
197-
l.cmd().arg(combined_arg);
218+
} else {
219+
convert_link_args_to_cc_args(l.cmd(), args);
198220
}
199221
l
200222
}
@@ -224,7 +246,7 @@ macro_rules! generate_arg_methods {
224246
verbatim_args(self, iter::once(arg))
225247
}
226248
#[allow(unused)]
227-
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self {
249+
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
228250
link_args(self, args)
229251
}
230252
#[allow(unused)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use super::*;
2+
3+
#[test]
4+
fn test_rpaths_to_args() {
5+
let mut cmd = Command::new("foo");
6+
convert_link_args_to_cc_args(&mut cmd, &["-rpath", "path1", "-rpath", "path2"]);
7+
assert_eq!(cmd.get_args(), [OsStr::new("-Wl,-rpath,path1,-rpath,path2")]);
8+
}
9+
10+
#[test]
11+
fn test_xlinker() {
12+
let mut cmd = Command::new("foo");
13+
convert_link_args_to_cc_args(&mut cmd, &[
14+
"arg1",
15+
"arg2",
16+
"arg3,with,comma",
17+
"arg4,with,comma",
18+
"arg5",
19+
"arg6,with,comma",
20+
]);
21+
22+
assert_eq!(cmd.get_args(), [
23+
OsStr::new("-Wl,arg1,arg2"),
24+
OsStr::new("-Xlinker"),
25+
OsStr::new("arg3,with,comma"),
26+
OsStr::new("-Xlinker"),
27+
OsStr::new("arg4,with,comma"),
28+
OsStr::new("-Wl,arg5"),
29+
OsStr::new("-Xlinker"),
30+
OsStr::new("arg6,with,comma"),
31+
]);
32+
}

compiler/rustc_codegen_ssa/src/back/rpath.rs

+11-23
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,27 @@ pub(super) struct RPathConfig<'a> {
1313
pub linker_is_gnu: bool,
1414
}
1515

16-
pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
16+
pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
1717
debug!("preparing the RPATH!");
1818

1919
let rpaths = get_rpaths(config);
20-
let mut flags = rpaths_to_flags(rpaths);
20+
let mut args = Vec::with_capacity(rpaths.len() * 2); // the minimum needed capacity
21+
22+
for rpath in rpaths {
23+
args.push("-rpath".into());
24+
args.push(rpath);
25+
}
2126

2227
if config.linker_is_gnu {
2328
// Use DT_RUNPATH instead of DT_RPATH if available
24-
flags.push("-Wl,--enable-new-dtags".into());
29+
args.push("--enable-new-dtags".into());
2530

2631
// Set DF_ORIGIN for substitute $ORIGIN
27-
flags.push("-Wl,-z,origin".into());
28-
}
29-
30-
flags
31-
}
32-
33-
fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
34-
let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
35-
36-
for rpath in rpaths {
37-
if rpath.to_string_lossy().contains(',') {
38-
ret.push("-Wl,-rpath".into());
39-
ret.push("-Xlinker".into());
40-
ret.push(rpath);
41-
} else {
42-
let mut single_arg = OsString::from("-Wl,-rpath,");
43-
single_arg.push(rpath);
44-
ret.push(single_arg);
45-
}
32+
args.push("-z".into());
33+
args.push("origin".into());
4634
}
4735

48-
ret
36+
args
4937
}
5038

5139
fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {

compiler/rustc_codegen_ssa/src/back/rpath/tests.rs

+1-22
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
use std::ffi::OsString;
2-
use std::path::{Path, PathBuf};
3-
4-
use super::{RPathConfig, get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
5-
6-
#[test]
7-
fn test_rpaths_to_flags() {
8-
let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
9-
assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
10-
}
1+
use super::*;
112

123
#[test]
134
fn test_minimize1() {
@@ -69,15 +60,3 @@ fn test_rpath_relative_issue_119571() {
6960
// Should not panic when lib only contains filename.
7061
let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
7162
}
72-
73-
#[test]
74-
fn test_xlinker() {
75-
let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
76-
77-
assert_eq!(args, vec![
78-
OsString::from("-Wl,-rpath,a/normal/path"),
79-
OsString::from("-Wl,-rpath"),
80-
OsString::from("-Xlinker"),
81-
OsString::from("a,comma,path")
82-
]);
83-
}

0 commit comments

Comments
 (0)