diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3f5e0c1bce9c1..4fb347b10e241 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; @@ -614,15 +612,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_osx { - // -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}")) @@ -953,15 +951,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 prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let suffix = if verbatim { "" } else { ".lib" }; - self.link_arg(format!("{prefix}{name}{suffix}")); + return self.link_staticlib_by_path(&path, whole_archive); } + let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let suffix = if verbatim { "" } else { ".lib" }; + self.link_arg(format!("{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { @@ -1190,7 +1185,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]); } @@ -1356,7 +1354,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 { @@ -1490,7 +1491,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}")); @@ -1664,12 +1668,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 1671b7e06b0af..cd3508374a0a4 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -95,14 +95,15 @@ pub fn try_find_native_static_library( name: &str, verbatim: bool, ) -> Option { + let target = (&*sess.target.staticlib_prefix, &*sess.target.staticlib_suffix); + let unix = ("lib", ".a"); let formats = if verbatim { - vec![("".into(), "".into())] + vec![("", "")] + } else if target != unix && sess.target.is_like_msvc { + // On Windows MSVC naming scheme `libfoo.a` is used as a fallback from default `foo.lib`. + vec![target, unix] } else { - let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); - // On Windows, static libraries sometimes show up as libfoo.a and other - // times show up as foo.lib - let unix = ("lib".into(), ".a".into()); - if os == unix { vec![os] } else { vec![os, unix] } + vec![target] }; 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 b704cee705b05..3e7184aeccc86 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 6868cb368ccc3..1cd4675d1842a 100644 --- a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -3,9 +3,6 @@ // This test is the same as native-link-modifier-rustc, but without rlibs. // See https://github.com/rust-lang/rust/issues/99425 -//@ ignore-apple -// Reason: linking fails due to the unusual ".ext" staticlib name. - use run_make_support::rustc; fn main() { 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)); }