diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8fc83908efbcc..6b1801e98bc38 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -6,9 +6,7 @@ use std::{env, io, iter, mem, str}; use cc::windows_registry; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_metadata::{ - find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, -}; +use rustc_metadata::{try_find_native_dynamic_library, try_find_native_static_library}; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols; @@ -615,15 +613,15 @@ impl<'a> Linker for GccLinker<'a> { } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { + if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { + return self.link_staticlib_by_path(&path, whole_archive); + } self.hint_static(); let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { self.link_or_cc_arg(format!("-l{colon}{name}")); } else if self.sess.target.is_like_darwin { - // -force_load is the macOS equivalent of --whole-archive, but it - // involves passing the full path to the library to link. - self.link_arg("-force_load"); - self.link_arg(find_native_static_library(name, verbatim, self.sess)); + self.link_args(&["-force_load", name]); } else { self.link_arg("--whole-archive") .link_or_cc_arg(format!("-l{colon}{name}")) @@ -956,15 +954,12 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { - // On MSVC-like targets rustc supports static libraries using alternative naming - // scheme (`libfoo.a`) unsupported by linker, search for such libraries manually. if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { - self.link_staticlib_by_path(&path, whole_archive); - } else { - let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let (prefix, suffix) = self.sess.staticlib_components(verbatim); - self.link_arg(format!("{opts}{prefix}{name}{suffix}")); + return self.link_staticlib_by_path(&path, whole_archive); } + let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let (prefix, suffix) = self.sess.staticlib_components(verbatim); + self.link_arg(format!("{opts}{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { @@ -1193,7 +1188,10 @@ impl<'a> Linker for EmLinker<'a> { self.link_or_cc_arg(path); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { + if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { + return self.link_staticlib_by_path(&path, whole_archive); + } self.link_or_cc_args(&["-l", name]); } @@ -1359,7 +1357,10 @@ impl<'a> Linker for WasmLd<'a> { self.link_or_cc_arg(path); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { + if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { + return self.link_staticlib_by_path(&path, whole_archive); + } if !whole_archive { self.link_or_cc_args(&["-l", name]); } else { @@ -1493,7 +1494,10 @@ impl<'a> Linker for L4Bender<'a> { ) { } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { + if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { + return self.link_staticlib_by_path(&path, whole_archive); + } self.hint_static(); if !whole_archive { self.link_arg(format!("-PC{name}")); @@ -1667,12 +1671,15 @@ impl<'a> Linker for AixLinker<'a> { } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { + if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { + return self.link_staticlib_by_path(&path, whole_archive); + } self.hint_static(); if !whole_archive { self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } else { let mut arg = OsString::from("-bkeepfile:"); - arg.push(find_native_static_library(name, verbatim, self.sess)); + arg.push(name); self.link_or_cc_arg(arg); } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index f10d71f4c6540..a7abde3506db6 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -96,13 +96,14 @@ pub fn try_find_native_static_library( verbatim: bool, ) -> Option { let default = sess.staticlib_components(verbatim); + let unix = ("lib", ".a"); let formats = if verbatim { vec![default] + } else if default != unix && sess.target.is_like_msvc { + // On Windows MSVC naming scheme `libfoo.a` is used as a fallback from default `foo.lib`. + vec![default, unix] } else { - // On Windows, static libraries sometimes show up as libfoo.a and other - // times show up as foo.lib - let unix = ("lib", ".a"); - if default == unix { vec![default] } else { vec![default, unix] } + vec![default] }; walk_native_lib_search_dirs(sess, None, |dir, is_framework| { diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d45ad1be27b8c..785203e36813a 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -82,6 +82,12 @@ The name used in a `link` attribute may be overridden using the form `-l ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute, and `LINK_NAME` is the name of the actual library that will be linked. +The compiler may attempt to search for the library in native library search directories +(controlled by `-L`), and pass it to linker by full path if the search is successful. +Otherwise the library will be passed to linker by name, so it can perform its own search. +In some cases this enables use of alternative library naming schemes or `+verbatim` modifier +even if they are not natively supported by linker. + [link-attribute]: ../reference/items/external-blocks.html#the-link-attribute ### Linking modifiers: `whole-archive` diff --git a/tests/run-make/native-link-modifier-bundle/rmake.rs b/tests/run-make/native-link-modifier-bundle/rmake.rs index 058b66b15f12f..b246d8bcc3edd 100644 --- a/tests/run-make/native-link-modifier-bundle/rmake.rs +++ b/tests/run-make/native-link-modifier-bundle/rmake.rs @@ -68,7 +68,7 @@ fn main() { .crate_type("cdylib") .print("link-args") .run() - .assert_stdout_not_contains(r#"-l[" ]*native-staticlib"#); + .assert_stdout_not_contains("libnative-staticlib.a"); llvm_nm() .input(dynamic_lib_name("cdylib_bundled")) .run() @@ -81,7 +81,7 @@ fn main() { .crate_type("cdylib") .print("link-args") .run() - .assert_stdout_contains_regex(r#"-l[" ]*native-staticlib"#); + .assert_stdout_contains_regex(r"libnative-staticlib.a"); llvm_nm() .input(dynamic_lib_name("cdylib_non_bundled")) .run() diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs index 4fb0690531a10..0cc2073c68368 100644 --- a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -4,9 +4,6 @@ // See https://github.com/rust-lang/rust/issues/99425 //@ ignore-cross-compile -//@ ignore-apple -//@ ignore-wasm -// Reason: linking fails due to the unusual ".ext" staticlib name. use run_make_support::rustc; diff --git a/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs index 67e839bec703d..9026165671aa4 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs +++ b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs @@ -16,6 +16,7 @@ use run_make_support::{ //@ only-linux // Reason: differences in the native lib compilation process causes differences // in the --print link-args output +// FIXME: The test actually passes on windows-gnu, enable it there. fn main() { build_native_static_lib("native_dep_1"); @@ -77,8 +78,10 @@ fn main() { .stdout_utf8(); let re = regex::Regex::new( -"--whole-archive.*native_dep_1.*--whole-archive.*lnative_dep_2.*no-whole-archive.*lnative_dep_4" - ).unwrap(); + "--whole-archive.*native_dep_1.*--whole-archive.*libnative_dep_2.a\ + .*no-whole-archive.*libnative_dep_4.a", + ) + .unwrap(); assert!(re.is_match(&out)); }