mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-10 08:57:36 +00:00
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](https://github.com/rust-lang/rust/pull/38798), but it only implemented this in certain cases when passing `-rpath`. r? compiler
This commit is contained in:
commit
ae6a7dba2a
@ -1386,7 +1386,7 @@ fn link_sanitizer_runtime(
|
|||||||
let filename = format!("rustc{channel}_rt.{name}");
|
let filename = format!("rustc{channel}_rt.{name}");
|
||||||
let path = find_sanitizer_runtime(sess, &filename);
|
let path = find_sanitizer_runtime(sess, &filename);
|
||||||
let rpath = path.to_str().expect("non-utf8 component in path");
|
let rpath = path.to_str().expect("non-utf8 component in path");
|
||||||
linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
|
linker.link_args(&["-rpath", rpath]);
|
||||||
linker.link_dylib_by_name(&filename, false, true);
|
linker.link_dylib_by_name(&filename, false, true);
|
||||||
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
|
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
|
||||||
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
|
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
|
||||||
@ -2210,7 +2210,7 @@ fn add_rpath_args(
|
|||||||
is_like_osx: sess.target.is_like_osx,
|
is_like_osx: sess.target.is_like_osx,
|
||||||
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
|
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
|
||||||
};
|
};
|
||||||
cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
|
cmd.link_args(&rpath::get_rpath_linker_args(&rpath_config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ use super::command::Command;
|
|||||||
use super::symbol_export;
|
use super::symbol_export;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
/// Disables non-English messages from localized linkers.
|
/// Disables non-English messages from localized linkers.
|
||||||
/// Such messages may cause issues with text encoding on Windows (#35785)
|
/// Such messages may cause issues with text encoding on Windows (#35785)
|
||||||
/// and prevent inspection of linker output in case of errors, which we occasionally do.
|
/// and prevent inspection of linker output in case of errors, which we occasionally do.
|
||||||
@ -178,23 +181,42 @@ fn verbatim_args<L: Linker + ?Sized>(
|
|||||||
}
|
}
|
||||||
l
|
l
|
||||||
}
|
}
|
||||||
/// Arguments for the underlying linker.
|
/// Add underlying linker arguments to C compiler command, by wrapping them in
|
||||||
/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
|
/// `-Wl` or `-Xlinker`.
|
||||||
fn link_args<L: Linker + ?Sized>(
|
fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
|
||||||
l: &mut L,
|
let mut combined_arg = OsString::from("-Wl");
|
||||||
args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>,
|
for arg in args {
|
||||||
) -> &mut L {
|
// If the argument itself contains a comma, we need to emit it
|
||||||
let args = args.into_iter();
|
// as `-Xlinker`, otherwise we can use `-Wl`.
|
||||||
if !l.is_cc() {
|
if arg.as_ref().as_encoded_bytes().contains(&b',') {
|
||||||
verbatim_args(l, args);
|
// Emit current `-Wl` argument, if any has been built.
|
||||||
} else if args.len() != 0 {
|
if combined_arg != OsStr::new("-Wl") {
|
||||||
// FIXME: Support arguments with commas, see `rpaths_to_flags` for the example.
|
cmd.arg(combined_arg);
|
||||||
let mut combined_arg = OsString::from("-Wl");
|
// Begin next `-Wl` argument.
|
||||||
for arg in args {
|
combined_arg = OsString::from("-Wl");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit `-Xlinker` argument.
|
||||||
|
cmd.arg("-Xlinker");
|
||||||
|
cmd.arg(arg);
|
||||||
|
} else {
|
||||||
|
// Append to `-Wl` argument.
|
||||||
combined_arg.push(",");
|
combined_arg.push(",");
|
||||||
combined_arg.push(arg);
|
combined_arg.push(arg);
|
||||||
}
|
}
|
||||||
l.cmd().arg(combined_arg);
|
}
|
||||||
|
// Emit final `-Wl` argument.
|
||||||
|
if combined_arg != OsStr::new("-Wl") {
|
||||||
|
cmd.arg(combined_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Arguments for the underlying linker.
|
||||||
|
/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
|
||||||
|
fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
|
||||||
|
if !l.is_cc() {
|
||||||
|
verbatim_args(l, args);
|
||||||
|
} else {
|
||||||
|
convert_link_args_to_cc_args(l.cmd(), args);
|
||||||
}
|
}
|
||||||
l
|
l
|
||||||
}
|
}
|
||||||
@ -224,7 +246,7 @@ macro_rules! generate_arg_methods {
|
|||||||
verbatim_args(self, iter::once(arg))
|
verbatim_args(self, iter::once(arg))
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self {
|
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
|
||||||
link_args(self, args)
|
link_args(self, args)
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
32
compiler/rustc_codegen_ssa/src/back/linker/tests.rs
Normal file
32
compiler/rustc_codegen_ssa/src/back/linker/tests.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpaths_to_args() {
|
||||||
|
let mut cmd = Command::new("foo");
|
||||||
|
convert_link_args_to_cc_args(&mut cmd, &["-rpath", "path1", "-rpath", "path2"]);
|
||||||
|
assert_eq!(cmd.get_args(), [OsStr::new("-Wl,-rpath,path1,-rpath,path2")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xlinker() {
|
||||||
|
let mut cmd = Command::new("foo");
|
||||||
|
convert_link_args_to_cc_args(&mut cmd, &[
|
||||||
|
"arg1",
|
||||||
|
"arg2",
|
||||||
|
"arg3,with,comma",
|
||||||
|
"arg4,with,comma",
|
||||||
|
"arg5",
|
||||||
|
"arg6,with,comma",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(cmd.get_args(), [
|
||||||
|
OsStr::new("-Wl,arg1,arg2"),
|
||||||
|
OsStr::new("-Xlinker"),
|
||||||
|
OsStr::new("arg3,with,comma"),
|
||||||
|
OsStr::new("-Xlinker"),
|
||||||
|
OsStr::new("arg4,with,comma"),
|
||||||
|
OsStr::new("-Wl,arg5"),
|
||||||
|
OsStr::new("-Xlinker"),
|
||||||
|
OsStr::new("arg6,with,comma"),
|
||||||
|
]);
|
||||||
|
}
|
@ -13,39 +13,27 @@ pub(super) struct RPathConfig<'a> {
|
|||||||
pub linker_is_gnu: bool,
|
pub linker_is_gnu: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
|
pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
|
||||||
debug!("preparing the RPATH!");
|
debug!("preparing the RPATH!");
|
||||||
|
|
||||||
let rpaths = get_rpaths(config);
|
let rpaths = get_rpaths(config);
|
||||||
let mut flags = rpaths_to_flags(rpaths);
|
let mut args = Vec::with_capacity(rpaths.len() * 2); // the minimum needed capacity
|
||||||
|
|
||||||
|
for rpath in rpaths {
|
||||||
|
args.push("-rpath".into());
|
||||||
|
args.push(rpath);
|
||||||
|
}
|
||||||
|
|
||||||
if config.linker_is_gnu {
|
if config.linker_is_gnu {
|
||||||
// Use DT_RUNPATH instead of DT_RPATH if available
|
// Use DT_RUNPATH instead of DT_RPATH if available
|
||||||
flags.push("-Wl,--enable-new-dtags".into());
|
args.push("--enable-new-dtags".into());
|
||||||
|
|
||||||
// Set DF_ORIGIN for substitute $ORIGIN
|
// Set DF_ORIGIN for substitute $ORIGIN
|
||||||
flags.push("-Wl,-z,origin".into());
|
args.push("-z".into());
|
||||||
|
args.push("origin".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
flags
|
args
|
||||||
}
|
|
||||||
|
|
||||||
fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
|
|
||||||
let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
|
|
||||||
|
|
||||||
for rpath in rpaths {
|
|
||||||
if rpath.to_string_lossy().contains(',') {
|
|
||||||
ret.push("-Wl,-rpath".into());
|
|
||||||
ret.push("-Xlinker".into());
|
|
||||||
ret.push(rpath);
|
|
||||||
} else {
|
|
||||||
let mut single_arg = OsString::from("-Wl,-rpath,");
|
|
||||||
single_arg.push(rpath);
|
|
||||||
ret.push(single_arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {
|
fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {
|
||||||
|
@ -1,13 +1,4 @@
|
|||||||
use std::ffi::OsString;
|
use super::*;
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use super::{RPathConfig, get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rpaths_to_flags() {
|
|
||||||
let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
|
|
||||||
assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_minimize1() {
|
fn test_minimize1() {
|
||||||
@ -69,15 +60,3 @@ fn test_rpath_relative_issue_119571() {
|
|||||||
// Should not panic when lib only contains filename.
|
// Should not panic when lib only contains filename.
|
||||||
let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
|
let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_xlinker() {
|
|
||||||
let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
|
|
||||||
|
|
||||||
assert_eq!(args, vec![
|
|
||||||
OsString::from("-Wl,-rpath,a/normal/path"),
|
|
||||||
OsString::from("-Wl,-rpath"),
|
|
||||||
OsString::from("-Xlinker"),
|
|
||||||
OsString::from("a,comma,path")
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user