Rollup merge of #118202 - azhogin:azhogin/link_args_wrapping, r=petrochenkov

Added linker_arg(s) Linker trait methods for link-arg to be prefixed "-Wl," for cc-like linker args and not verbatim

https://github.com/rust-lang/rust/issues/99427#issuecomment-1234443468

> here's one possible improvement to -l link-arg making it more portable between linkers and useful - befriending it with the verbatim modifier (https://github.com/rust-lang/rust/issues/99425).
>
> -l link-arg:-verbatim=-foo would add -Wl,-foo (or equivalent) when C compiler is used as a linker, and just -foo when bare linker is used.
> -l link-arg:+verbatim=-bar on the other hand would always pass just -bar.
This commit is contained in:
Michael Goulet 2023-11-27 19:06:47 -05:00 committed by GitHub
commit 4936b3abdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 34 deletions

View File

@ -44,7 +44,7 @@ use tempfile::Builder as TempFileBuilder;
use itertools::Itertools; use itertools::Itertools;
use std::cell::OnceCell; use std::cell::OnceCell;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ffi::OsString; use std::ffi::{OsStr, OsString};
use std::fs::{read, File, OpenOptions}; use std::fs::{read, File, OpenOptions};
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write};
use std::ops::Deref; use std::ops::Deref;
@ -2527,7 +2527,7 @@ fn add_native_libs_from_crate(
NativeLibKind::WasmImportModule => {} NativeLibKind::WasmImportModule => {}
NativeLibKind::LinkArg => { NativeLibKind::LinkArg => {
if link_static { if link_static {
cmd.arg(name); cmd.linker_arg(OsStr::new(name), verbatim);
} }
} }
} }

View File

@ -196,6 +196,14 @@ pub trait Linker {
fn add_no_exec(&mut self) {} fn add_no_exec(&mut self) {}
fn add_as_needed(&mut self) {} fn add_as_needed(&mut self) {}
fn reset_per_library_state(&mut self) {} fn reset_per_library_state(&mut self) {}
fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) {
self.linker_args(&[arg], verbatim);
}
fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) {
args.into_iter().for_each(|a| {
self.cmd().arg(a);
});
}
} }
impl dyn Linker + '_ { impl dyn Linker + '_ {
@ -223,38 +231,12 @@ pub struct GccLinker<'a> {
} }
impl<'a> GccLinker<'a> { impl<'a> GccLinker<'a> {
/// Passes an argument directly to the linker. fn linker_arg(&mut self, arg: impl AsRef<OsStr>) {
/// Linker::linker_arg(self, arg.as_ref(), false);
/// When the linker is not ld-like such as when using a compiler as a linker, the argument is
/// prepended by `-Wl,`.
fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
self.linker_args(&[arg]);
self
} }
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) {
/// Passes a series of arguments directly to the linker. let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect();
/// Linker::linker_args(self, &args_vec, false);
/// When the linker is ld-like, the arguments are simply appended to the command. When the
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
/// single argument is appended to the command to ensure that the order of the arguments is
/// preserved by the compiler.
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
if self.is_ld {
args.into_iter().for_each(|a| {
self.cmd.arg(a);
});
} else {
if !args.is_empty() {
let mut s = OsString::from("-Wl");
for a in args {
s.push(",");
s.push(a);
}
self.cmd.arg(s);
}
}
self
} }
fn takes_hints(&self) -> bool { fn takes_hints(&self) -> bool {
@ -361,6 +343,30 @@ impl<'a> GccLinker<'a> {
} }
impl<'a> Linker for GccLinker<'a> { impl<'a> Linker for GccLinker<'a> {
/// Passes a series of arguments directly to the linker.
///
/// When the linker is ld-like, the arguments are simply appended to the command. When the
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
/// single argument is appended to the command to ensure that the order of the arguments is
/// preserved by the compiler.
fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) {
if self.is_ld || verbatim {
args.into_iter().for_each(|a| {
self.cmd.arg(a);
});
} else {
if !args.is_empty() {
let mut s = OsString::from("-Wl");
for a in args {
s.push(",");
s.push(a);
}
self.cmd.arg(s);
}
}
}
fn cmd(&mut self) -> &mut Command { fn cmd(&mut self) -> &mut Command {
&mut self.cmd &mut self.cmd
} }
@ -531,7 +537,7 @@ impl<'a> Linker for GccLinker<'a> {
self.linker_arg("-force_load"); self.linker_arg("-force_load");
self.linker_arg(&lib); self.linker_arg(&lib);
} else { } else {
self.linker_arg("--whole-archive").cmd.arg(lib); self.linker_args(&[OsString::from("--whole-archive"), lib.into()]);
self.linker_arg("--no-whole-archive"); self.linker_arg("--no-whole-archive");
} }
} }

View File

@ -0,0 +1,8 @@
# only-linux
include ../tools.mk
all:
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3'
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg:+verbatim=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3'
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=ld -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"'

View File

@ -0,0 +1 @@
fn main() {}