Rollup merge of #129366 - petrochenkov:libsearch, r=jieyouxu
linker: Synchronize native library search in rustc and linker Also search for static libraries with alternative naming (`libname.a`) on MSVC when producing executables or dynamic libraries, and not just rlibs. This unblocks https://github.com/rust-lang/rust/pull/123436. try-job: x86_64-msvc
This commit is contained in:
commit
9f3ce40718
8 changed files with 130 additions and 62 deletions
|
@ -2,7 +2,7 @@ use std::collections::BTreeSet;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{read, File, OpenOptions};
|
use std::fs::{read, File, OpenOptions};
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::{ControlFlow, Deref};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{ExitStatus, Output, Stdio};
|
use std::process::{ExitStatus, Output, Stdio};
|
||||||
use std::{env, fmt, fs, io, mem, str};
|
use std::{env, fmt, fs, io, mem, str};
|
||||||
|
@ -18,8 +18,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
|
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
|
||||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_metadata::find_native_static_library;
|
|
||||||
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
|
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
|
||||||
|
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::dependency_format::Linkage;
|
use rustc_middle::middle::dependency_format::Linkage;
|
||||||
|
@ -2110,50 +2110,19 @@ fn add_library_search_dirs(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Library search paths explicitly supplied by user (`-L` on the command line).
|
walk_native_lib_search_dirs(
|
||||||
for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
|
sess,
|
||||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
|
self_contained_components,
|
||||||
}
|
apple_sdk_root,
|
||||||
for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
|
|dir, is_framework| {
|
||||||
// Contrary to the `-L` docs only framework-specific paths are considered here.
|
if is_framework {
|
||||||
if search_path.kind != PathKind::All {
|
cmd.framework_path(dir);
|
||||||
cmd.framework_path(&search_path.dir);
|
} else {
|
||||||
}
|
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
|
||||||
}
|
|
||||||
|
|
||||||
// The toolchain ships some native library components and self-contained linking was enabled.
|
|
||||||
// Add the self-contained library directory to search paths.
|
|
||||||
if self_contained_components.intersects(
|
|
||||||
LinkSelfContainedComponents::LIBC
|
|
||||||
| LinkSelfContainedComponents::UNWIND
|
|
||||||
| LinkSelfContainedComponents::MINGW,
|
|
||||||
) {
|
|
||||||
let lib_path = sess.target_tlib_path.dir.join("self-contained");
|
|
||||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
|
|
||||||
// library directory instead of the self-contained directories.
|
|
||||||
// Sanitizer libraries have the same issue and are also linked by name on Apple targets.
|
|
||||||
// The targets here should be in sync with `copy_third_party_objects` in bootstrap.
|
|
||||||
// FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
|
|
||||||
// and sanitizers to self-contained directory, and stop adding this search path.
|
|
||||||
if sess.target.vendor == "fortanix"
|
|
||||||
|| sess.target.os == "linux"
|
|
||||||
|| sess.target.os == "fuchsia"
|
|
||||||
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
|
|
||||||
{
|
|
||||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&sess.target_tlib_path.dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
|
|
||||||
// we must have the support library stubs in the library search path (#121430).
|
|
||||||
if let Some(sdk_root) = apple_sdk_root
|
|
||||||
&& sess.target.llvm_target.contains("macabi")
|
|
||||||
{
|
|
||||||
cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
|
|
||||||
cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
|
|
||||||
}
|
}
|
||||||
|
ControlFlow::<()>::Continue(())
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add options making relocation sections in the produced ELF files read-only
|
/// Add options making relocation sections in the produced ELF files read-only
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::{env, iter, mem, str};
|
||||||
|
|
||||||
use cc::windows_registry;
|
use cc::windows_registry;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_metadata::find_native_static_library;
|
use rustc_metadata::{find_native_static_library, try_find_native_static_library};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::middle::dependency_format::Linkage;
|
use rustc_middle::middle::dependency_format::Linkage;
|
||||||
use rustc_middle::middle::exported_symbols;
|
use rustc_middle::middle::exported_symbols;
|
||||||
|
@ -891,10 +891,16 @@ impl<'a> Linker for MsvcLinker<'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) {
|
||||||
|
// 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 prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
|
||||||
let suffix = if verbatim { "" } else { ".lib" };
|
let suffix = if verbatim { "" } else { ".lib" };
|
||||||
self.link_arg(format!("{prefix}{name}{suffix}"));
|
self.link_arg(format!("{prefix}{name}{suffix}"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
|
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
|
||||||
if !whole_archive {
|
if !whole_archive {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![doc(rust_logo)]
|
#![doc(rust_logo)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
#![feature(coroutines)]
|
#![feature(coroutines)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(error_iter)]
|
#![feature(error_iter)]
|
||||||
|
@ -35,7 +36,9 @@ pub mod locator;
|
||||||
|
|
||||||
pub use creader::{load_symbol_from_dylib, DylibError};
|
pub use creader::{load_symbol_from_dylib, DylibError};
|
||||||
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
|
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
|
||||||
pub use native_libs::find_native_static_library;
|
pub use native_libs::{
|
||||||
|
find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs,
|
||||||
|
};
|
||||||
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
|
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
|
||||||
|
|
||||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::path::PathBuf;
|
use std::ops::ControlFlow;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
|
use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
|
@ -16,10 +17,68 @@ use rustc_session::Session;
|
||||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
use rustc_target::spec::LinkSelfContainedComponents;
|
||||||
|
|
||||||
use crate::{errors, fluent_generated};
|
use crate::{errors, fluent_generated};
|
||||||
|
|
||||||
pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
|
pub fn walk_native_lib_search_dirs<R>(
|
||||||
|
sess: &Session,
|
||||||
|
self_contained_components: LinkSelfContainedComponents,
|
||||||
|
apple_sdk_root: Option<&Path>,
|
||||||
|
mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
|
||||||
|
) -> ControlFlow<R> {
|
||||||
|
// Library search paths explicitly supplied by user (`-L` on the command line).
|
||||||
|
for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
|
||||||
|
f(&search_path.dir, false)?;
|
||||||
|
}
|
||||||
|
for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
|
||||||
|
// Frameworks are looked up strictly in framework-specific paths.
|
||||||
|
if search_path.kind != PathKind::All {
|
||||||
|
f(&search_path.dir, true)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The toolchain ships some native library components and self-contained linking was enabled.
|
||||||
|
// Add the self-contained library directory to search paths.
|
||||||
|
if self_contained_components.intersects(
|
||||||
|
LinkSelfContainedComponents::LIBC
|
||||||
|
| LinkSelfContainedComponents::UNWIND
|
||||||
|
| LinkSelfContainedComponents::MINGW,
|
||||||
|
) {
|
||||||
|
f(&sess.target_tlib_path.dir.join("self-contained"), false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
|
||||||
|
// library directory instead of the self-contained directories.
|
||||||
|
// Sanitizer libraries have the same issue and are also linked by name on Apple targets.
|
||||||
|
// The targets here should be in sync with `copy_third_party_objects` in bootstrap.
|
||||||
|
// FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
|
||||||
|
// and sanitizers to self-contained directory, and stop adding this search path.
|
||||||
|
if sess.target.vendor == "fortanix"
|
||||||
|
|| sess.target.os == "linux"
|
||||||
|
|| sess.target.os == "fuchsia"
|
||||||
|
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
|
||||||
|
{
|
||||||
|
f(&sess.target_tlib_path.dir, false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
|
||||||
|
// we must have the support library stubs in the library search path (#121430).
|
||||||
|
if let Some(sdk_root) = apple_sdk_root
|
||||||
|
&& sess.target.llvm_target.contains("macabi")
|
||||||
|
{
|
||||||
|
f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
|
||||||
|
f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_find_native_static_library(
|
||||||
|
sess: &Session,
|
||||||
|
name: &str,
|
||||||
|
verbatim: bool,
|
||||||
|
) -> Option<PathBuf> {
|
||||||
let formats = if verbatim {
|
let formats = if verbatim {
|
||||||
vec![("".into(), "".into())]
|
vec![("".into(), "".into())]
|
||||||
} else {
|
} else {
|
||||||
|
@ -30,16 +89,29 @@ pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) ->
|
||||||
if os == unix { vec![os] } else { vec![os, unix] }
|
if os == unix { vec![os] } else { vec![os, unix] }
|
||||||
};
|
};
|
||||||
|
|
||||||
for path in sess.target_filesearch(PathKind::Native).search_paths() {
|
// FIXME: Account for self-contained linking settings and Apple SDK.
|
||||||
|
walk_native_lib_search_dirs(
|
||||||
|
sess,
|
||||||
|
LinkSelfContainedComponents::empty(),
|
||||||
|
None,
|
||||||
|
|dir, is_framework| {
|
||||||
|
if !is_framework {
|
||||||
for (prefix, suffix) in &formats {
|
for (prefix, suffix) in &formats {
|
||||||
let test = path.dir.join(format!("{prefix}{name}{suffix}"));
|
let test = dir.join(format!("{prefix}{name}{suffix}"));
|
||||||
if test.exists() {
|
if test.exists() {
|
||||||
return test;
|
return ControlFlow::Break(test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.break_value()
|
||||||
|
}
|
||||||
|
|
||||||
sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
|
pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
|
||||||
|
try_find_native_static_library(sess, name, verbatim)
|
||||||
|
.unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_bundled_library(
|
fn find_bundled_library(
|
||||||
|
|
|
@ -47,7 +47,7 @@ KIND=PATH` where `KIND` may be one of:
|
||||||
directory.
|
directory.
|
||||||
- `native` — Only search for native libraries in this directory.
|
- `native` — Only search for native libraries in this directory.
|
||||||
- `framework` — Only search for macOS frameworks in this directory.
|
- `framework` — Only search for macOS frameworks in this directory.
|
||||||
- `all` — Search for all library kinds in this directory. This is the default
|
- `all` — Search for all library kinds in this directory, except frameworks. This is the default
|
||||||
if `KIND` is not specified.
|
if `KIND` is not specified.
|
||||||
|
|
||||||
<a id="option-l-link-lib"></a>
|
<a id="option-l-link-lib"></a>
|
||||||
|
|
2
tests/run-make/native-lib-alt-naming/native.rs
Normal file
2
tests/run-make/native-lib-alt-naming/native.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn native_lib_alt_naming() {}
|
15
tests/run-make/native-lib-alt-naming/rmake.rs
Normal file
15
tests/run-make/native-lib-alt-naming/rmake.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
|
||||||
|
// to the default format (`foo.lib`).
|
||||||
|
|
||||||
|
//REMOVE@ only-msvc
|
||||||
|
|
||||||
|
use run_make_support::rustc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Prepare the native library.
|
||||||
|
rustc().input("native.rs").crate_type("staticlib").output("libnative.a").run();
|
||||||
|
|
||||||
|
// Try to link to it from both a rlib and a bin.
|
||||||
|
rustc().input("rust.rs").crate_type("rlib").arg("-lstatic=native").run();
|
||||||
|
rustc().input("rust.rs").crate_type("bin").arg("-lstatic=native").run();
|
||||||
|
}
|
1
tests/run-make/native-lib-alt-naming/rust.rs
Normal file
1
tests/run-make/native-lib-alt-naming/rust.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue