diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index be50911f4e143..b6e76430d0a95 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,6 +3,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; +use rustc_metadata::locator::{get_dylib_symbol_name, unlib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -17,7 +18,7 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::Endian; use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo}; -use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet}; use super::archive::{find_library, ArchiveBuilder}; use super::command::Command; @@ -2252,11 +2253,6 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( add_static_crate::(cmd, sess, codegen_results, tmpdir, crate_type, cnum); } - // Converts a library file-stem into a cc -l argument - fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str { - if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem } - } - // 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. @@ -2379,11 +2375,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( if let Some(dir) = parent { cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); } - let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); - cmd.link_rust_dylib( - Symbol::intern(&unlib(&sess.target, filestem)), - parent.unwrap_or_else(|| Path::new("")), - ); + let filename = cratepath.file_name().unwrap().to_str().unwrap(); + let symbol_name = get_dylib_symbol_name(filename, &sess.target) + .unwrap_or(unlib(&sess.target, cratepath.file_stem().unwrap().to_str().unwrap())); + cmd.link_rust_dylib(Symbol::intern(symbol_name), cratepath); } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 429dc45d6a4c4..3a52df2542ed1 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -464,9 +464,9 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("-znorelro"); } - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { + fn link_rust_dylib(&mut self, _lib: Symbol, path: &Path) { self.hint_dynamic(); - self.cmd.arg(format!("-l{}", lib)); + self.cmd.arg(format!("-l:{}", path.file_name().unwrap().to_str().unwrap())); } fn link_framework(&mut self, framework: Symbol, as_needed: bool) { @@ -837,7 +837,7 @@ impl<'a> Linker for MsvcLinker<'a> { // check to see if the file is there and just omit linking to it if it's // not present. let name = format!("{}.dll.lib", lib); - if path.join(&name).exists() { + if path.parent().unwrap_or_else(|| Path::new("")).join(&name).exists() { self.cmd.arg(name); } } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index bbd30c9327a6c..5e56a4a909449 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -238,6 +238,35 @@ use std::path::{Path, PathBuf}; use std::{cmp, fmt, fs}; use tracing::{debug, info, warn}; +// Converts a library file-stem into a cc -l argument +pub fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str { + if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem } +} + +/// Returns Some(symbol_name) if `file` could be a valid dylib +/// Example (assuming target is GNU/Linux): +/// - `libsomecrate.asdf` -> `None` +/// - `libsomecrate.so` -> `Some(somecreate)` +/// - `libsomecrate.so.0.1` -> `Some(somecreate)` +/// - `libsomecrate.so.a.4` -> `None` +pub fn get_dylib_symbol_name<'a>(file: &'a str, target: &Target) -> Option<&'a str> { + // test if the targets dll_suffix is found within the filename. If it + // is check if all of the chars following it are either a digit (0-9) + // or a dot. + file.find(&target.dll_suffix) + .map(|idx| { + match file + .chars() + .skip(idx + idx + target.dll_suffix.len()) + .all(|c| c.is_ascii_digit() || c == '.') + { + true => file.get(0..idx).map(|s| unlib(target, s)), + false => None, + } + }) + .flatten() +} + #[derive(Clone)] crate struct CrateLocator<'a> { // Immutable per-session configuration. @@ -402,7 +431,9 @@ impl<'a> CrateLocator<'a> { (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") { (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) - } else if file.starts_with(&dylib_prefix) && file.ends_with(&self.target.dll_suffix) { + } else if file.starts_with(&dylib_prefix) + && get_dylib_symbol_name(file, &self.target).is_some() + { ( &file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())], CrateFlavor::Dylib, @@ -682,7 +713,7 @@ impl<'a> CrateLocator<'a> { if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta")) || file.starts_with(&self.target.dll_prefix) - && file.ends_with(&self.target.dll_suffix) + && get_dylib_symbol_name(file, &self.target).is_some() { // Make sure there's at most one rlib and at most one dylib. // Note to take care and match against the non-canonicalized name: