From e1ab6645e2b885b41be3f12f85fd8622788fa55f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Mar 2025 19:53:43 +0300 Subject: [PATCH 1/3] linker: Move native library search from linker to rustc For static libraries only, for now. Linker's search by name is still used if rustc's search fails, because linker may search in additional platform-specific directories in addition to directories known to rustc. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 43 +++++++++++-------- src/doc/rustc/src/command-line-arguments.md | 6 +++ .../native-link-modifier-bundle/rmake.rs | 4 +- .../rmake.rs | 3 -- 4 files changed, 33 insertions(+), 23 deletions(-) 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/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; From 1e1e0eef0686573ab9a8496fcadbb74f80b4707f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 20 Mar 2025 19:35:07 +0300 Subject: [PATCH 2/3] native libs: Explicitly limit foo.lib -> libfoo.a fallback to MSVC In practice this doesn't change anything for current built-in targets --- compiler/rustc_metadata/src/native_libs.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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| { From c85e510b3a4c80bc74dacf9216ce150473749e21 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 25 Mar 2025 13:43:04 +0300 Subject: [PATCH 3/3] Fix some more tests --- tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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)); }