diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5149e3a12f232..ea184bb16aa96 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1384,7 +1384,7 @@ fn link_sanitizer_runtime( let filename = format!("rustc{channel}_rt.{name}"); let path = find_sanitizer_runtime(sess, &filename); 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); } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" { // MSVC provides the `/INFERASANLIBS` argument to automatically find the @@ -2208,7 +2208,7 @@ fn add_rpath_args( is_like_osx: sess.target.is_like_osx, 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)); } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 6ee599c9964c5..05dfbd40a0ad6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -24,6 +24,9 @@ use super::command::Command; use super::symbol_export; use crate::errors; +#[cfg(test)] +mod tests; + /// Disables non-English messages from localized linkers. /// 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. @@ -178,23 +181,42 @@ fn verbatim_args( } l } +/// Add underlying linker arguments to C compiler command, by wrapping them in +/// `-Wl` or `-Xlinker`. +fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator>) { + let mut combined_arg = OsString::from("-Wl"); + for arg in args { + // If the argument itself contains a comma, we need to emit it + // as `-Xlinker`, otherwise we can use `-Wl`. + if arg.as_ref().as_encoded_bytes().contains(&b',') { + // Emit current `-Wl` argument, if any has been built. + if combined_arg != OsStr::new("-Wl") { + cmd.arg(combined_arg); + // Begin next `-Wl` argument. + 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(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: &mut L, - args: impl IntoIterator, IntoIter: ExactSizeIterator>, -) -> &mut L { - let args = args.into_iter(); +fn link_args(l: &mut L, args: impl IntoIterator>) -> &mut L { if !l.is_cc() { verbatim_args(l, args); - } else if args.len() != 0 { - // FIXME: Support arguments with commas, see `rpaths_to_flags` for the example. - let mut combined_arg = OsString::from("-Wl"); - for arg in args { - combined_arg.push(","); - combined_arg.push(arg); - } - l.cmd().arg(combined_arg); + } else { + convert_link_args_to_cc_args(l.cmd(), args); } l } @@ -224,7 +246,7 @@ macro_rules! generate_arg_methods { verbatim_args(self, iter::once(arg)) } #[allow(unused)] - pub(crate) fn link_args(&mut self, args: impl IntoIterator, IntoIter: ExactSizeIterator>) -> &mut Self { + pub(crate) fn link_args(&mut self, args: impl IntoIterator>) -> &mut Self { link_args(self, args) } #[allow(unused)] diff --git a/compiler/rustc_codegen_ssa/src/back/linker/tests.rs b/compiler/rustc_codegen_ssa/src/back/linker/tests.rs new file mode 100644 index 0000000000000..bf3e8c902009e --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/back/linker/tests.rs @@ -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"), + ]); +} diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 56a808df6b0bd..d633cc98ac87e 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -13,39 +13,27 @@ pub(super) struct RPathConfig<'a> { pub linker_is_gnu: bool, } -pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec { +pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec { debug!("preparing the RPATH!"); 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 { // 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 - flags.push("-Wl,-z,origin".into()); - } - - flags -} - -fn rpaths_to_flags(rpaths: Vec) -> Vec { - 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); - } + args.push("-z".into()); + args.push("origin".into()); } - ret + args } fn get_rpaths(config: &RPathConfig<'_>) -> Vec { diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 39034842d1086..f1a30105c5908 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -1,13 +1,4 @@ -use std::ffi::OsString; -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"]); -} +use super::*; #[test] fn test_minimize1() { @@ -69,15 +60,3 @@ fn test_rpath_relative_issue_119571() { // Should not panic when lib only contains filename. 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") - ]); -}