diff options
| author | Laurențiu Nicola <lnicola@dend.ro> | 2024-07-11 20:06:05 +0300 |
|---|---|---|
| committer | Laurențiu Nicola <lnicola@dend.ro> | 2024-07-11 20:06:05 +0300 |
| commit | 62bbce2ad2b20d5cf1282da407d01de5c54161f1 (patch) | |
| tree | 24923a8226aad3064a6c5739540c2d404d64f76e /compiler/rustc_codegen_ssa/src/back | |
| parent | b159b3fd80f7aac6aef57c64f820adbc11bc692c (diff) | |
| parent | bcf1f6db4594ae6132378b179a30cdb3599a863d (diff) | |
| download | rust-62bbce2ad2b20d5cf1282da407d01de5c54161f1.tar.gz rust-62bbce2ad2b20d5cf1282da407d01de5c54161f1.zip | |
Merge from rust-lang/rust
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 124 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/linker.rs | 742 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/rpath.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/rpath/tests.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/write.rs | 2 |
5 files changed, 408 insertions, 469 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c352100b01b..1f627353d54 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::collections::BTreeSet; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -1306,12 +1306,12 @@ 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.args(&["-Wl,-rpath", "-Xlinker", rpath]); + linker.cc_args(&["-Wl,-rpath", "-Xlinker", 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 // compatible ASAN library. - linker.arg("/INFERASANLIBS"); + linker.link_arg("/INFERASANLIBS"); } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); @@ -1490,11 +1490,6 @@ fn print_native_static_libs( let mut lib_args: Vec<_> = all_native_libs .iter() .filter(|l| relevant_lib(sess, l)) - // Deduplication of successive repeated libraries, see rust-lang/rust#113209 - // - // note: we don't use PartialEq/Eq because NativeLib transitively depends on local - // elements like spans, which we don't care about and would make the deduplication impossible - .dedup_by(|l1, l2| l1.name == l2.name && l1.kind == l2.kind && l1.verbatim == l2.verbatim) .filter_map(|lib| { let name = lib.name; match lib.kind { @@ -1521,6 +1516,8 @@ fn print_native_static_libs( | NativeLibKind::RawDylib => None, } }) + // deduplication of consecutive repeated libraries, see rust-lang/rust#113209 + .dedup() .collect(); for path in all_rust_dylibs { // FIXME deduplicate with add_dynamic_crate @@ -1891,9 +1888,9 @@ fn add_post_link_objects( /// FIXME: Determine where exactly these args need to be inserted. fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.pre_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } - cmd.args(&sess.opts.unstable_opts.pre_link_args); + cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args); } /// Add a link script embedded in the target, if applicable. @@ -1911,8 +1908,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error }); } - cmd.arg("--script"); - cmd.arg(path); + cmd.link_arg("--script").link_arg(path); } _ => {} } @@ -1921,7 +1917,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty /// Add arbitrary "user defined" args defined from command line. /// FIXME: Determine where exactly these args need to be inserted. fn add_user_defined_link_args(cmd: &mut dyn Linker, sess: &Session) { - cmd.args(&sess.opts.cg.link_args); + cmd.verbatim_args(&sess.opts.cg.link_args); } /// Add arbitrary "late link" args defined by the target spec. @@ -1939,15 +1935,15 @@ fn add_late_link_args( }); if any_dynamic_crate { if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } else { if let Some(args) = sess.target.late_link_args_static.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } if let Some(args) = sess.target.late_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -1955,7 +1951,7 @@ fn add_late_link_args( /// FIXME: Determine where exactly these args need to be inserted. fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.post_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -2100,6 +2096,10 @@ fn add_rpath_args( codegen_results: &CodegenResults, out_filename: &Path, ) { + if !sess.target.has_rpath { + return; + } + // FIXME (#2397): At some point we want to rpath our guesses as to // where extern libraries might live, based on the // add_lib_search_paths @@ -2118,11 +2118,10 @@ fn add_rpath_args( let rpath_config = RPathConfig { libs: &*libs, out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.has_rpath, is_like_osx: sess.target.is_like_osx, linker_is_gnu: sess.target.linker_flavor.is_gnu(), }; - cmd.args(&rpath::get_rpath_flags(&rpath_config)); + cmd.cc_args(&rpath::get_rpath_flags(&rpath_config)); } } @@ -2381,7 +2380,7 @@ fn add_order_independent_options( } else { "" }; - cmd.arg(format!("--dynamic-linker={prefix}ld.so.1")); + cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1")); } if sess.target.eh_frame_header { @@ -2396,8 +2395,7 @@ fn add_order_independent_options( } if sess.target.os == "emscripten" { - cmd.arg("-s"); - cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { + cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort { "DISABLE_EXCEPTION_CATCHING=1" } else { "DISABLE_EXCEPTION_CATCHING=0" @@ -2405,22 +2403,21 @@ fn add_order_independent_options( } if flavor == LinkerFlavor::Llbc { - cmd.arg("--target"); - cmd.arg(sess.target.llvm_target.as_ref()); - cmd.arg("--target-cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&[ + "--target", + sess.target.llvm_target.as_ref(), + "--target-cpu", + &codegen_results.crate_info.target_cpu, + ]); } else if flavor == LinkerFlavor::Ptx { - cmd.arg("--fallback-arch"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]); } else if flavor == LinkerFlavor::Bpf { - cmd.arg("--cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--cpu", &codegen_results.crate_info.target_cpu]); if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features] .into_iter() .find(|feat| !feat.is_empty()) { - cmd.arg("--cpu-features"); - cmd.arg(feat); + cmd.link_args(&["--cpu-features", feat]); } } @@ -2621,7 +2618,11 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.linker_arg(OsStr::new(name), verbatim); + if verbatim { + cmd.verbatim_arg(name); + } else { + cmd.link_arg(name); + } } } } @@ -2816,6 +2817,15 @@ fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf { } } +fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf { + if let Some(dir) = path.parent() { + let file_name = path.file_name().expect("library path has no file name component"); + rehome_sysroot_lib_dir(sess, dir).join(file_name) + } else { + fix_windows_verbatim_for_gcc(path) + } +} + // Adds the static "rlib" versions of all crates to the command line. // There's a bit of magic which happens here specifically related to LTO, // namely that we remove upstream object files. @@ -2846,15 +2856,8 @@ fn add_static_crate( let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; - let mut link_upstream = |path: &Path| { - let rlib_path = if let Some(dir) = path.parent() { - let file_name = path.file_name().expect("rlib path has no file name path component"); - rehome_sysroot_lib_dir(sess, dir).join(file_name) - } else { - fix_windows_verbatim_for_gcc(path) - }; - cmd.link_staticlib_by_path(&rlib_path, false); - }; + let mut link_upstream = + |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false); if !are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum) @@ -2918,27 +2921,7 @@ fn add_static_crate( // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // Just need to tell the linker about where the library lives and - // what its name is - let parent = cratepath.parent(); - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() { - return; - } - if let Some(dir) = parent { - cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); - } - // "<dir>/name.dll -> name.dll" on windows-msvc - // "<dir>/name.dll -> name" on windows-gnu - // "<dir>/libname.<ext> -> name" elsewhere - let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; - let stem = stem.unwrap().to_str().unwrap(); - // Convert library file-stem into a cc -l argument. - let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_dylib_by_name(&stem[prefix..], false, true); + cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true); } fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { @@ -3015,10 +2998,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // This is admittedly a bit strange, as on most targets // `-isysroot` only applies to include header files, but on Apple // targets this also applies to libraries and frameworks. - cmd.args(&["-isysroot", &sdk_root]); + cmd.cc_args(&["-isysroot", &sdk_root]); } LinkerFlavor::Darwin(Cc::No, _) => { - cmd.args(&["-syslibroot", &sdk_root]); + cmd.link_args(&["-syslibroot", &sdk_root]); } _ => unreachable!(), } @@ -3029,8 +3012,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // search path. // The flags are called `-L` and `-F` both in Clang, ld64 and ldd. - cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib")); - cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks")); + let sdk_root = Path::new(&sdk_root); + cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib")); + cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks")); } } @@ -3145,7 +3129,7 @@ fn add_lld_args( for path in sess.get_tools_search_paths(false) { let linker_path = path.join("gcc-ld"); linker_path_exists |= linker_path.exists(); - cmd.arg({ + cmd.cc_arg({ let mut arg = OsString::from("-B"); arg.push(linker_path); arg @@ -3165,7 +3149,7 @@ fn add_lld_args( // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { - cmd.arg("-fuse-ld=lld"); + cmd.cc_arg("-fuse-ld=lld"); } if !flavor.is_gnu() { @@ -3189,7 +3173,7 @@ fn add_lld_args( // targeting a different linker flavor on macOS, and that's also always // the case when targeting WASM. if sess.target.linker_flavor != sess.host.linker_flavor { - cmd.arg(format!("--target={}", sess.target.llvm_target)); + cmd.cc_arg(format!("--target={}", sess.target.llvm_target)); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a82478900b1..2bd5dfdce83 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -8,7 +8,7 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use std::{env, mem, str}; +use std::{env, iter, mem, str}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -159,6 +159,102 @@ pub fn get_linker<'a>( } } +// Note: Ideally neither these helper function, nor the macro-generated inherent methods below +// would exist, and these functions would live in `trait Linker`. +// Unfortunately, adding these functions to `trait Linker` make it `dyn`-incompatible. +// If the methods are added to the trait with `where Self: Sized` bounds, then even a separate +// implementation of them for `dyn Linker {}` wouldn't work due to a conflict with those +// uncallable methods in the trait. + +/// Just pass the arguments to the linker as is. +/// It is assumed that they are correctly prepared in advance. +fn verbatim_args<L: Linker + ?Sized>( + l: &mut L, + args: impl IntoIterator<Item: AsRef<OsStr>>, +) -> &mut L { + for arg in args { + l.cmd().arg(arg); + } + l +} +/// 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>, IntoIter: ExactSizeIterator>, +) -> &mut L { + let args = args.into_iter(); + 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); + } + l +} +/// Arguments for the cc wrapper specifically. +/// Check that it's indeed a cc wrapper and pass verbatim. +fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L { + assert!(l.is_cc()); + verbatim_args(l, args) +} +/// Arguments supported by both underlying linker and cc wrapper, pass verbatim. +fn link_or_cc_args<L: Linker + ?Sized>( + l: &mut L, + args: impl IntoIterator<Item: AsRef<OsStr>>, +) -> &mut L { + verbatim_args(l, args) +} + +macro_rules! generate_arg_methods { + ($($ty:ty)*) => { $( + impl $ty { + pub fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + verbatim_args(self, args) + } + pub fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + verbatim_args(self, iter::once(arg)) + } + pub fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self { + link_args(self, args) + } + pub fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + link_args(self, iter::once(arg)) + } + pub fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + cc_args(self, args) + } + pub fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + cc_args(self, iter::once(arg)) + } + pub fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + link_or_cc_args(self, args) + } + pub fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + link_or_cc_args(self, iter::once(arg)) + } + } + )* } +} + +generate_arg_methods! { + GccLinker<'_> + MsvcLinker<'_> + EmLinker<'_> + WasmLd<'_> + L4Bender<'_> + AixLinker<'_> + LlbcLinker<'_> + PtxLinker<'_> + BpfLinker<'_> + dyn Linker + '_ +} + /// Linker abstraction used by `back::link` to build up the command to invoke a /// linker. /// @@ -168,17 +264,33 @@ pub fn get_linker<'a>( /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { fn cmd(&mut self) -> &mut Command; + fn is_cc(&self) -> bool { + false + } fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } + fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("framework linked with unsupported linker") } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool); fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool); - fn include_path(&mut self, path: &Path); - fn framework_path(&mut self, path: &Path); - fn output_filename(&mut self, path: &Path); - fn add_object(&mut self, path: &Path); + fn include_path(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]); + } + fn framework_path(&mut self, _path: &Path) { + bug!("framework path set with unsupported linker") + } + fn output_filename(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]); + } + fn add_object(&mut self, path: &Path) { + link_or_cc_args(self, &[path]); + } fn gc_sections(&mut self, keep_metadata: bool); fn no_gc_sections(&mut self); fn full_relro(&mut self); @@ -198,25 +310,9 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&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 + '_ { - pub fn arg(&mut self, arg: impl AsRef<OsStr>) { - self.cmd().arg(arg); - } - - pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) { - self.cmd().args(args); - } - pub fn take_cmd(&mut self) -> Command { mem::replace(self.cmd(), Command::new("")) } @@ -233,14 +329,6 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - fn linker_arg(&mut self, arg: impl AsRef<OsStr>) { - Linker::linker_arg(self, arg.as_ref(), false); - } - fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) { - let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); - Linker::linker_args(self, &args_vec, false); - } - fn takes_hints(&self) -> bool { // Really this function only returns true if the underlying linker // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We @@ -262,7 +350,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(true) { - self.linker_arg("-Bstatic"); + self.link_arg("-Bstatic"); self.hinted_static = Some(true); } } @@ -272,7 +360,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(false) { - self.linker_arg("-Bdynamic"); + self.link_arg("-Bdynamic"); self.hinted_static = Some(false); } } @@ -281,7 +369,7 @@ impl<'a> GccLinker<'a> { if let Some(plugin_path) = plugin_path { let mut arg = OsString::from("-plugin="); arg.push(plugin_path); - self.linker_arg(&arg); + self.link_arg(&arg); } let opt_level = match self.sess.opts.optimize { @@ -292,9 +380,9 @@ impl<'a> GccLinker<'a> { }; if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { - self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); + self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; - self.linker_args(&[ + self.link_args(&[ &format!("-plugin-opt={opt_level}"), &format!("-plugin-opt=mcpu={}", self.target_cpu), ]); @@ -304,10 +392,10 @@ impl<'a> GccLinker<'a> { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { if !self.is_ld { - self.cmd.arg("-dynamiclib"); + self.cc_arg("-dynamiclib"); } - self.linker_arg("-dylib"); + self.link_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack // purely to support rustbuild right now, we should get a more @@ -316,105 +404,110 @@ impl<'a> GccLinker<'a> { if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { let mut rpath = OsString::from("@rpath/"); rpath.push(out_filename.file_name().unwrap()); - self.linker_args(&[OsString::from("-install_name"), rpath]); + self.link_arg("-install_name").link_arg(rpath); } } else { - self.cmd.arg("-shared"); - if self.sess.target.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.staticlib_prefix, - file, - self.sess.target.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); - } + self.link_or_cc_arg("-shared"); + if let Some(name) = out_filename.file_name() { + if self.sess.target.is_like_windows { + // The output filename already contains `dll_suffix` so + // the resulting import library will have a name in the + // form of libfoo.dll.a + let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix); + implib_name.push(name); + implib_name.push(&*self.sess.target.staticlib_suffix); + let mut out_implib = OsString::from("--out-implib="); + out_implib.push(out_filename.with_file_name(implib_name)); + self.link_arg(out_implib); + } else { + // When dylibs are linked by a full path this value will get into `DT_NEEDED` + // instead of the full path, so the library can be later found in some other + // location than that specific path. + let mut soname = OsString::from("-soname="); + soname.push(name); + self.link_arg(soname); } } } } -} -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 with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) { + if !as_needed { + if self.sess.target.is_like_osx { + // FIXME(81490): ld64 doesn't support these flags but macOS 11 + // has -needed-l{} / -needed_library {} + // but we have no way to detect that here. + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--no-as-needed"); + } else { + self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); + } + } + + f(self); + + if !as_needed { + if self.sess.target.is_like_osx { + // See above FIXME comment + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--as-needed"); } } } +} +impl<'a> Linker for GccLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + fn is_cc(&self) -> bool { + !self.is_ld + } + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::DynamicPicExe => { // noop on windows w/ gcc & ld, error w/ lld if !self.sess.target.is_like_windows { // `-pie` works for both gcc wrapper and ld. - self.cmd.arg("-pie"); + self.link_or_cc_arg("-pie"); } } LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::StaticPicExe => { if !self.is_ld { // Note that combination `-static -pie` doesn't work as expected // for the gcc wrapper, `-static` in that case suppresses `-pie`. - self.cmd.arg("-static-pie"); + self.cc_arg("-static-pie"); } else { // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing // a static pie, but currently passed because gcc and clang pass them. // The former suppresses the `INTERP` ELF header specifying dynamic linker, // which is otherwise implicitly injected by ld (but not lld). // The latter doesn't change anything, only ensures that everything is pic. - self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); + self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); } } LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), LinkOutputKind::StaticDylib => { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.build_dylib(out_filename); } LinkOutputKind::WasiReactorExe => { - self.linker_args(&["--entry", "_initialize"]); + self.link_args(&["--entry", "_initialize"]); } } // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, @@ -430,7 +523,7 @@ impl<'a> Linker for GccLinker<'a> { | LinkOutputKind::StaticDylib ) { - self.cmd.arg("--static-crt"); + self.cc_arg("--static-crt"); } } @@ -443,27 +536,18 @@ impl<'a> Linker for GccLinker<'a> { // to the linker. return; } - if !as_needed { - if self.sess.target.is_like_osx { - // FIXME(81490): ld64 doesn't support these flags but macOS 11 - // has -needed-l{} / -needed_library {} - // but we have no way to detect that here. - self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--no-as-needed"); - } else { - self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); - } - } self.hint_dynamic(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - if !as_needed { - if self.sess.target.is_like_osx { - // See above FIXME comment - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); - } - } + self.with_as_needed(as_needed, |this| { + let colon = if verbatim && this.is_gnu { ":" } else { "" }; + this.link_or_cc_arg(format!("-l{colon}{name}")); + }); + } + + fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) { + self.hint_dynamic(); + self.with_as_needed(as_needed, |this| { + this.link_or_cc_arg(path); + }) } fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { @@ -471,63 +555,51 @@ impl<'a> Linker for GccLinker<'a> { if !as_needed { // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework // flag but we have no way to detect that here. - // self.cmd.arg("-needed_framework").arg(name); + // self.link_or_cc_arg("-needed_framework").link_or_cc_arg(name); self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } - self.cmd.arg("-framework").arg(name); + self.link_or_cc_args(&["-framework", name]); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { - self.cmd.arg(format!("-l{colon}{name}")); + self.link_or_cc_arg(format!("-l{colon}{name}")); } else if self.sess.target.is_like_osx { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. - self.linker_arg("-force_load"); - self.linker_arg(find_native_static_library(name, verbatim, self.sess)); + self.link_arg("-force_load"); + self.link_arg(find_native_static_library(name, verbatim, self.sess)); } else { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{colon}{name}")); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{colon}{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else if self.sess.target.is_like_osx { - self.linker_arg("-force_load"); - self.linker_arg(path); + self.link_arg("-force_load").link_arg(path); } else { - self.linker_arg("--whole-archive"); - self.linker_arg(path); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } fn framework_path(&mut self, path: &Path) { - self.cmd.arg("-F").arg(path); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_or_cc_arg("-F").link_or_cc_arg(path); } fn full_relro(&mut self) { - self.linker_args(&["-z", "relro", "-z", "now"]); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.linker_args(&["-z", "relro"]); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.linker_args(&["-z", "norelro"]); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { @@ -546,7 +618,7 @@ impl<'a> Linker for GccLinker<'a> { // for partial linking when using multiple codegen units (-r). So we // insert it here. if self.sess.target.is_like_osx { - self.linker_arg("-dead_strip"); + self.link_arg("-dead_strip"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -554,13 +626,13 @@ impl<'a> Linker for GccLinker<'a> { // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata { - self.linker_arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { if self.is_gnu || self.sess.target.is_like_wasm { - self.linker_arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } } @@ -574,7 +646,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.linker_arg("-O1"); + self.link_arg("-O1"); } } @@ -594,8 +666,7 @@ impl<'a> Linker for GccLinker<'a> { // // Though it may be worth to try to revert those changes upstream, since // the overhead of the initialization should be minor. - self.cmd.arg("-u"); - self.cmd.arg("__llvm_profile_runtime"); + self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]); } fn control_flow_guard(&mut self) {} @@ -616,33 +687,33 @@ impl<'a> Linker for GccLinker<'a> { // The --strip-debug case is handled by running an external // `strip` utility as a separate step after linking. if !self.sess.target.is_like_solaris { - self.linker_arg("--strip-debug"); + self.link_arg("--strip-debug"); } } Strip::Symbols => { - self.linker_arg("--strip-all"); + self.link_arg("--strip-all"); } } match self.sess.opts.unstable_opts.debuginfo_compression { config::DebugInfoCompression::None => {} config::DebugInfoCompression::Zlib => { - self.linker_arg("--compress-debug-sections=zlib"); + self.link_arg("--compress-debug-sections=zlib"); } config::DebugInfoCompression::Zstd => { - self.linker_arg("--compress-debug-sections=zstd"); + self.link_arg("--compress-debug-sections=zstd"); } } } fn no_crt_objects(&mut self) { if !self.is_ld { - self.cmd.arg("-nostartfiles"); + self.cc_arg("-nostartfiles"); } } fn no_default_libraries(&mut self) { if !self.is_ld { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } } @@ -718,24 +789,22 @@ impl<'a> Linker for GccLinker<'a> { } if self.sess.target.is_like_osx { - self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); + self.link_arg("-exported_symbols_list").link_arg(path); } else if self.sess.target.is_like_solaris { - self.linker_args(&[OsString::from("-M"), path.into()]); + self.link_arg("-M").link_arg(path); } else { if is_windows { - self.linker_arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("--version-script="); arg.push(path); - self.linker_arg(arg); - self.linker_arg("--no-undefined-version"); + self.link_arg(arg).link_arg("--no-undefined-version"); } } } fn subsystem(&mut self, subsystem: &str) { - self.linker_arg("--subsystem"); - self.linker_arg(&subsystem); + self.link_args(&["--subsystem", subsystem]); } fn reset_per_library_state(&mut self) { @@ -760,23 +829,23 @@ impl<'a> Linker for GccLinker<'a> { // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, // so we just always add it. fn add_eh_frame_header(&mut self) { - self.linker_arg("--eh-frame-hdr"); + self.link_arg("--eh-frame-hdr"); } fn add_no_exec(&mut self) { if self.sess.target.is_like_windows { - self.linker_arg("--nxcompat"); + self.link_arg("--nxcompat"); } else if self.is_gnu { - self.linker_args(&["-z", "noexecstack"]); + self.link_args(&["-z", "noexecstack"]); } } fn add_as_needed(&mut self) { if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); + self.link_arg("--as-needed"); } else if self.sess.target.is_like_solaris { // -z ignore is the Solaris equivalent to the GNU ld --as-needed option - self.linker_args(&["-z", "ignore"]); + self.link_args(&["-z", "ignore"]); } } } @@ -798,10 +867,10 @@ impl<'a> Linker for MsvcLinker<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("/DLL"); + self.link_arg("/DLL"); let mut arg: OsString = "/IMPLIB:".into(); arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); + self.link_arg(arg); } LinkOutputKind::WasiReactorExe => { panic!("can't link as reactor on non-wasi target"); @@ -810,44 +879,49 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } + + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export + // any symbols, so we skip linking if the implib file is not present. + let implib_path = path.with_extension("dll.lib"); + if implib_path.exists() { + self.link_or_cc_arg(implib_path); + } } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; - self.cmd.arg(format!("{prefix}{name}{suffix}")); + self.link_arg(format!("{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("/WHOLEARCHIVE:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn gc_sections(&mut self, _keep_metadata: bool) { // MSVC's ICF (Identical COMDAT Folding) link optimization is // slow for Rust and thus we disable it by default when not in // optimization build. if self.sess.opts.optimize != config::OptLevel::No { - self.cmd.arg("/OPT:REF,ICF"); + self.link_arg("/OPT:REF,ICF"); } else { // It is necessary to specify NOICF here, because /OPT:REF // implies ICF by default. - self.cmd.arg("/OPT:REF,NOICF"); + self.link_arg("/OPT:REF,NOICF"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("/OPT:NOREF,NOICF"); + self.link_arg("/OPT:NOREF,NOICF"); } fn full_relro(&mut self) { @@ -867,23 +941,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn no_default_libraries(&mut self) { - self.cmd.arg("/NODEFAULTLIB"); + self.link_arg("/NODEFAULTLIB"); } fn include_path(&mut self, path: &Path) { let mut arg = OsString::from("/LIBPATH:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn output_filename(&mut self, path: &Path) { let mut arg = OsString::from("/OUT:"); arg.push(path); - self.cmd.arg(&arg); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on windows") + self.link_arg(&arg); } fn optimize(&mut self) { @@ -895,19 +965,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn control_flow_guard(&mut self) { - self.cmd.arg("/guard:cf"); + self.link_arg("/guard:cf"); } fn ehcont_guard(&mut self) { if self.sess.target.pointer_width == 64 { - self.cmd.arg("/guard:ehcont"); + self.link_arg("/guard:ehcont"); } } fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { // This will cause the Microsoft linker to generate a PDB file // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); + self.link_arg("/DEBUG"); // Default to emitting only the file name of the PDB file into // the binary instead of the full path. Emitting the full path @@ -916,7 +986,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // This default behavior can be overridden by explicitly passing // `-Clink-arg=/PDBALTPATH:...` to rustc. - self.cmd.arg("/PDBALTPATH:%_PDB%"); + self.link_arg("/PDBALTPATH:%_PDB%"); // This will cause the Microsoft linker to embed .natvis info into the PDB file let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); @@ -928,7 +998,7 @@ impl<'a> Linker for MsvcLinker<'a> { if path.extension() == Some("natvis".as_ref()) { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } Err(error) => { @@ -942,7 +1012,7 @@ impl<'a> Linker for MsvcLinker<'a> { for path in natvis_debugger_visualizers { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } @@ -986,13 +1056,13 @@ impl<'a> Linker for MsvcLinker<'a> { } let mut arg = OsString::from("/DEF:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn subsystem(&mut self, subsystem: &str) { // Note that previous passes of the compiler validated this subsystem, // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}")); + self.link_arg(&format!("/SUBSYSTEM:{subsystem}")); // Windows has two subsystems we're interested in right now, the console // and windows subsystems. These both implicitly have different entry @@ -1009,7 +1079,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // For more information see RFC #1665 if subsystem == "windows" { - self.cmd.arg("/ENTRY:mainCRTStartup"); + self.link_arg("/ENTRY:mainCRTStartup"); } } @@ -1018,7 +1088,7 @@ impl<'a> Linker for MsvcLinker<'a> { } fn add_no_exec(&mut self) { - self.cmd.arg("/NXCOMPAT"); + self.link_arg("/NXCOMPAT"); } } @@ -1032,31 +1102,27 @@ impl<'a> Linker for EmLinker<'a> { &mut self.cmd } + fn is_cc(&self) -> bool { + true + } + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { - self.cmd.arg("-l").arg(name); + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); } - fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { + self.link_or_cc_args(&["-l", name]); } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { + self.link_or_cc_arg(path); } fn full_relro(&mut self) { @@ -1071,10 +1137,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on Emscripten") - } - fn gc_sections(&mut self, _keep_metadata: bool) { // noop } @@ -1085,7 +1147,7 @@ impl<'a> Linker for EmLinker<'a> { fn optimize(&mut self) { // Emscripten performs own optimizations - self.cmd.arg(match self.sess.opts.optimize { + self.cc_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1106,7 +1168,7 @@ impl<'a> Linker for EmLinker<'a> { fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g - self.cmd.arg(match self.sess.opts.debuginfo { + self.cc_arg(match self.sess.opts.debuginfo { DebugInfo::None => "-g0", DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => { "--profiling-funcs" @@ -1118,13 +1180,13 @@ impl<'a> Linker for EmLinker<'a> { fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { debug!("EXPORTED SYMBOLS:"); - self.cmd.arg("-s"); + self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( @@ -1135,7 +1197,7 @@ impl<'a> Linker for EmLinker<'a> { arg.push(encoded); - self.cmd.arg(arg); + self.cc_arg(arg); } fn subsystem(&mut self, _subsystem: &str) { @@ -1153,7 +1215,7 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { + fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { // If the atomics feature is enabled for wasm then we need a whole bunch // of flags: // @@ -1172,18 +1234,19 @@ impl<'a> WasmLd<'a> { // On wasm32-unknown-unknown, we also export symbols for glue code to use: // * `--export=*tls*` - when `#[thread_local]` symbols are used these // symbols are how the TLS segments are initialized and configured. + let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { - cmd.arg("--shared-memory"); - cmd.arg("--max-memory=1073741824"); - cmd.arg("--import-memory"); + wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); if sess.target.os == "unknown" { - cmd.arg("--export=__wasm_init_tls"); - cmd.arg("--export=__tls_size"); - cmd.arg("--export=__tls_align"); - cmd.arg("--export=__tls_base"); + wasm_ld.link_args(&[ + "--export=__wasm_init_tls", + "--export=__tls_size", + "--export=__tls_align", + "--export=__tls_base", + ]); } } - WasmLd { cmd, sess } + wasm_ld } } @@ -1199,51 +1262,40 @@ impl<'a> Linker for WasmLd<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("--no-entry"); + self.link_arg("--no-entry"); } LinkOutputKind::WasiReactorExe => { - self.cmd.arg("--entry"); - self.cmd.arg("_initialize"); + self.link_args(&["--entry", "_initialize"]); } } } fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); + } + + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } else { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_args(&["-l", name]) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1251,17 +1303,17 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and // only differentiates -O0 and -O1. It does not apply to LTO. - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1279,10 +1331,10 @@ impl<'a> Linker for WasmLd<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd.arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd.arg("--strip-all"); + self.link_arg("--strip-all"); } } } @@ -1297,7 +1349,7 @@ impl<'a> Linker for WasmLd<'a> { fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { for sym in symbols { - self.cmd.arg("--export").arg(&sym); + self.link_args(&["--export", sym]); } // LLD will hide these otherwise-internal symbols since it only exports @@ -1305,8 +1357,7 @@ impl<'a> Linker for WasmLd<'a> { // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. if self.sess.target.os == "unknown" { - self.cmd.arg("--export=__heap_base"); - self.cmd.arg("--export=__data_end"); + self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } @@ -1337,7 +1388,7 @@ impl<'a> WasmLd<'a> { // wasm-ld only handles integer LTO opt levels. Use O2 config::OptLevel::Size | config::OptLevel::SizeMin => "O2", }; - self.cmd.arg(&format!("--lto-{opt_level}")); + self.link_arg(&format!("--lto-{opt_level}")); } } @@ -1355,63 +1406,46 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - bug!("dylibs are not supported on L4Re"); - } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-PC{name}")); + self.link_arg(format!("-PC{name}")); } else { - self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on L4Re"); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); - self.cmd.arg("-z").arg("now"); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.cmd.arg("-z").arg("norelro"); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { if !keep_metadata { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { @@ -1420,7 +1454,7 @@ impl<'a> Linker for L4Bender<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.cmd.arg("-O1"); + self.link_arg("-O1"); } } @@ -1430,16 +1464,16 @@ impl<'a> Linker for L4Bender<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd().arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd().arg("--strip-all"); + self.link_arg("--strip-all"); } } } fn no_default_libraries(&mut self) { - self.cmd.arg("-nostdlib"); + self.cc_arg("-nostdlib"); } fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { @@ -1449,7 +1483,7 @@ impl<'a> Linker for L4Bender<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem {subsystem}")); + self.link_arg(&format!("--subsystem {subsystem}")); } fn reset_per_library_state(&mut self) { @@ -1467,12 +1501,12 @@ impl<'a> Linker for L4Bender<'a> { impl<'a> L4Bender<'a> { pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { - L4Bender { cmd: cmd, sess: sess, hinted_static: false } + L4Bender { cmd, sess: sess, hinted_static: false } } fn hint_static(&mut self) { if !self.hinted_static { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.hinted_static = true; } } @@ -1487,29 +1521,28 @@ pub struct AixLinker<'a> { impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: None } + AixLinker { cmd, sess: sess, hinted_static: None } } fn hint_static(&mut self) { if self.hinted_static != Some(true) { - self.cmd.arg("-bstatic"); + self.link_arg("-bstatic"); self.hinted_static = Some(true); } } fn hint_dynamic(&mut self) { if self.hinted_static != Some(false) { - self.cmd.arg("-bdynamic"); + self.link_arg("-bdynamic"); self.hinted_static = Some(false); } } fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("-bM:SRE"); - self.cmd.arg("-bnoentry"); + self.link_args(&["-bM:SRE", "-bnoentry"]); // FIXME: Use CreateExportList utility to create export list // and remove -bexpfull. - self.cmd.arg("-bexpfull"); + self.link_arg("-bexpfull"); } } @@ -1534,47 +1567,36 @@ impl<'a> Linker for AixLinker<'a> { fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); + } + + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.hint_dynamic(); + self.link_or_cc_arg(path); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); - self.cmd.arg(arg); + self.link_or_cc_arg(arg); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on AIX"); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1582,17 +1604,17 @@ impl<'a> Linker for AixLinker<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("-bgc"); + self.link_arg("-bgc"); } fn no_gc_sections(&mut self) { - self.cmd.arg("-bnogc"); + self.link_arg("-bnogc"); } fn optimize(&mut self) {} fn pgo_gen(&mut self) { - self.cmd.arg("-bdbg:namedsects:ss"); + self.link_arg("-bdbg:namedsects:ss"); } fn control_flow_guard(&mut self) {} @@ -1618,7 +1640,7 @@ impl<'a> Linker for AixLinker<'a> { if let Err(e) = res { self.sess.dcx().fatal(format!("failed to write export file: {e}")); } - self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); + self.link_arg(format!("-bE:{}", path.to_str().unwrap())); } fn subsystem(&mut self, _subsystem: &str) {} @@ -1738,48 +1760,32 @@ impl<'a> Linker for PtxLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg("--rlib").arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_arg("--rlib").link_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); + self.link_arg("--debug"); } fn add_object(&mut self, path: &Path) { - self.cmd.arg("--bitcode").arg(path); + self.link_arg("--bitcode").link_arg(path); } fn optimize(&mut self) { match self.sess.lto() { Lto::Thin | Lto::Fat | Lto::ThinLocal => { - self.cmd.arg("-Olto"); + self.link_arg("-Olto"); } Lto::No => {} } } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1820,28 +1826,16 @@ impl<'a> Linker for LlbcLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { @@ -1855,14 +1849,6 @@ impl<'a> Linker for LlbcLinker<'a> { }; } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1887,7 +1873,7 @@ impl<'a> Linker for LlbcLinker<'a> { match _crate_type { CrateType::Cdylib => { for sym in symbols { - self.cmd.arg("--export-symbol").arg(sym); + self.link_args(&["--export-symbol", sym]); } } _ => (), @@ -1911,32 +1897,20 @@ impl<'a> Linker for BpfLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1946,14 +1920,6 @@ impl<'a> Linker for BpfLinker<'a> { }); } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1985,7 +1951,7 @@ impl<'a> Linker for BpfLinker<'a> { if let Err(error) = res { self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error }); } else { - self.cmd.arg("--export-symbols").arg(&path); + self.link_arg("--export-symbols").link_arg(&path); } } diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index f499bbcf853..82070d4453b 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -9,16 +9,10 @@ pub struct RPathConfig<'a> { pub libs: &'a [&'a Path], pub out_filename: PathBuf, pub is_like_osx: bool, - pub has_rpath: bool, pub linker_is_gnu: bool, } pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - debug!("preparing the RPATH!"); let rpaths = get_rpaths(config); diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 0de90a1036e..c620e92db1f 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -37,7 +37,6 @@ fn test_rpath_relative() { if cfg!(target_os = "macos") { let config = &mut RPathConfig { libs: &[], - has_rpath: true, is_like_osx: true, linker_is_gnu: false, out_filename: PathBuf::from("bin/rustc"), @@ -48,7 +47,6 @@ fn test_rpath_relative() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("bin/rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; @@ -62,7 +60,6 @@ fn test_rpath_relative_issue_119571() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 064be4988bd..0e48eee3dd5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -120,7 +120,6 @@ pub struct ModuleConfig { pub vectorize_loop: bool, pub vectorize_slp: bool, pub merge_functions: bool, - pub inline_threshold: Option<u32>, pub emit_lifetime_markers: bool, pub llvm_plugins: Vec<String>, } @@ -280,7 +279,6 @@ impl ModuleConfig { } }, - inline_threshold: sess.opts.cg.inline_threshold, emit_lifetime_markers: sess.emit_lifetime_markers(), llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]), } |
