linker: Synchronize native library search in rustc and linker

This commit is contained in:
Vadim Petrochenkov 2024-08-14 20:16:28 +03:00
parent 600edc948a
commit a1c36c6ae9
3 changed files with 101 additions and 57 deletions

View File

@ -2,7 +2,7 @@
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_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));
} }
ControlFlow::<()>::Continue(())
// 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"));
}
} }
/// Add options making relocation sections in the produced ELF files read-only /// Add options making relocation sections in the produced ELF files read-only

View File

@ -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)]
@ -34,7 +35,9 @@
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" }

View File

@ -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_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.
for (prefix, suffix) in &formats { walk_native_lib_search_dirs(
let test = path.dir.join(format!("{prefix}{name}{suffix}")); sess,
if test.exists() { LinkSelfContainedComponents::empty(),
return test; None,
|dir, is_framework| {
if !is_framework {
for (prefix, suffix) in &formats {
let test = dir.join(format!("{prefix}{name}{suffix}"));
if test.exists() {
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(