Skip to content

Commit 9f3ce40

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#123436. try-job: x86_64-msvc
2 parents defc245 + ac8f132 commit 9f3ce40

File tree

8 files changed

+130
-62
lines changed

8 files changed

+130
-62
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+15-46
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
22
use std::ffi::OsString;
33
use std::fs::{read, File, OpenOptions};
44
use std::io::{BufWriter, Write};
5-
use std::ops::Deref;
5+
use std::ops::{ControlFlow, Deref};
66
use std::path::{Path, PathBuf};
77
use std::process::{ExitStatus, Output, Stdio};
88
use std::{env, fmt, fs, io, mem, str};
@@ -18,8 +18,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
1818
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
1919
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
2020
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
21-
use rustc_metadata::find_native_static_library;
2221
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
22+
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
2323
use rustc_middle::bug;
2424
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2525
use rustc_middle::middle::dependency_format::Linkage;
@@ -2110,50 +2110,19 @@ fn add_library_search_dirs(
21102110
return;
21112111
}
21122112

2113-
// Library search paths explicitly supplied by user (`-L` on the command line).
2114-
for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
2115-
cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
2116-
}
2117-
for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
2118-
// Contrary to the `-L` docs only framework-specific paths are considered here.
2119-
if search_path.kind != PathKind::All {
2120-
cmd.framework_path(&search_path.dir);
2121-
}
2122-
}
2123-
2124-
// The toolchain ships some native library components and self-contained linking was enabled.
2125-
// Add the self-contained library directory to search paths.
2126-
if self_contained_components.intersects(
2127-
LinkSelfContainedComponents::LIBC
2128-
| LinkSelfContainedComponents::UNWIND
2129-
| LinkSelfContainedComponents::MINGW,
2130-
) {
2131-
let lib_path = sess.target_tlib_path.dir.join("self-contained");
2132-
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
2133-
}
2134-
2135-
// Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
2136-
// library directory instead of the self-contained directories.
2137-
// Sanitizer libraries have the same issue and are also linked by name on Apple targets.
2138-
// The targets here should be in sync with `copy_third_party_objects` in bootstrap.
2139-
// FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
2140-
// and sanitizers to self-contained directory, and stop adding this search path.
2141-
if sess.target.vendor == "fortanix"
2142-
|| sess.target.os == "linux"
2143-
|| sess.target.os == "fuchsia"
2144-
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
2145-
{
2146-
cmd.include_path(&fix_windows_verbatim_for_gcc(&sess.target_tlib_path.dir));
2147-
}
2148-
2149-
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
2150-
// we must have the support library stubs in the library search path (#121430).
2151-
if let Some(sdk_root) = apple_sdk_root
2152-
&& sess.target.llvm_target.contains("macabi")
2153-
{
2154-
cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
2155-
cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
2156-
}
2113+
walk_native_lib_search_dirs(
2114+
sess,
2115+
self_contained_components,
2116+
apple_sdk_root,
2117+
|dir, is_framework| {
2118+
if is_framework {
2119+
cmd.framework_path(dir);
2120+
} else {
2121+
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
2122+
}
2123+
ControlFlow::<()>::Continue(())
2124+
},
2125+
);
21572126
}
21582127

21592128
/// Add options making relocation sections in the produced ELF files read-only

compiler/rustc_codegen_ssa/src/back/linker.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{env, iter, mem, str};
77

88
use cc::windows_registry;
99
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
10-
use rustc_metadata::find_native_static_library;
10+
use rustc_metadata::{find_native_static_library, try_find_native_static_library};
1111
use rustc_middle::bug;
1212
use rustc_middle::middle::dependency_format::Linkage;
1313
use rustc_middle::middle::exported_symbols;
@@ -891,9 +891,15 @@ impl<'a> Linker for MsvcLinker<'a> {
891891
}
892892

893893
fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
894-
let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
895-
let suffix = if verbatim { "" } else { ".lib" };
896-
self.link_arg(format!("{prefix}{name}{suffix}"));
894+
// On MSVC-like targets rustc supports static libraries using alternative naming
895+
// scheme (`libfoo.a`) unsupported by linker, search for such libraries manually.
896+
if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
897+
self.link_staticlib_by_path(&path, whole_archive);
898+
} else {
899+
let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
900+
let suffix = if verbatim { "" } else { ".lib" };
901+
self.link_arg(format!("{prefix}{name}{suffix}"));
902+
}
897903
}
898904

899905
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {

compiler/rustc_metadata/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![allow(rustc::potential_query_instability)]
44
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
55
#![doc(rust_logo)]
6+
#![feature(control_flow_enum)]
67
#![feature(coroutines)]
78
#![feature(decl_macro)]
89
#![feature(error_iter)]
@@ -35,7 +36,9 @@ pub mod locator;
3536

3637
pub use creader::{load_symbol_from_dylib, DylibError};
3738
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
38-
pub use native_libs::find_native_static_library;
39+
pub use native_libs::{
40+
find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs,
41+
};
3942
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
4043

4144
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

compiler/rustc_metadata/src/native_libs.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use std::path::PathBuf;
1+
use std::ops::ControlFlow;
2+
use std::path::{Path, PathBuf};
23

34
use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
45
use rustc_attr as attr;
@@ -16,10 +17,68 @@ use rustc_session::Session;
1617
use rustc_span::def_id::{DefId, LOCAL_CRATE};
1718
use rustc_span::symbol::{sym, Symbol};
1819
use rustc_target::spec::abi::Abi;
20+
use rustc_target::spec::LinkSelfContainedComponents;
1921

2022
use crate::{errors, fluent_generated};
2123

22-
pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
24+
pub fn walk_native_lib_search_dirs<R>(
25+
sess: &Session,
26+
self_contained_components: LinkSelfContainedComponents,
27+
apple_sdk_root: Option<&Path>,
28+
mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
29+
) -> ControlFlow<R> {
30+
// Library search paths explicitly supplied by user (`-L` on the command line).
31+
for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
32+
f(&search_path.dir, false)?;
33+
}
34+
for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
35+
// Frameworks are looked up strictly in framework-specific paths.
36+
if search_path.kind != PathKind::All {
37+
f(&search_path.dir, true)?;
38+
}
39+
}
40+
41+
// The toolchain ships some native library components and self-contained linking was enabled.
42+
// Add the self-contained library directory to search paths.
43+
if self_contained_components.intersects(
44+
LinkSelfContainedComponents::LIBC
45+
| LinkSelfContainedComponents::UNWIND
46+
| LinkSelfContainedComponents::MINGW,
47+
) {
48+
f(&sess.target_tlib_path.dir.join("self-contained"), false)?;
49+
}
50+
51+
// Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
52+
// library directory instead of the self-contained directories.
53+
// Sanitizer libraries have the same issue and are also linked by name on Apple targets.
54+
// The targets here should be in sync with `copy_third_party_objects` in bootstrap.
55+
// FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
56+
// and sanitizers to self-contained directory, and stop adding this search path.
57+
if sess.target.vendor == "fortanix"
58+
|| sess.target.os == "linux"
59+
|| sess.target.os == "fuchsia"
60+
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
61+
{
62+
f(&sess.target_tlib_path.dir, false)?;
63+
}
64+
65+
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
66+
// we must have the support library stubs in the library search path (#121430).
67+
if let Some(sdk_root) = apple_sdk_root
68+
&& sess.target.llvm_target.contains("macabi")
69+
{
70+
f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
71+
f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
72+
}
73+
74+
ControlFlow::Continue(())
75+
}
76+
77+
pub fn try_find_native_static_library(
78+
sess: &Session,
79+
name: &str,
80+
verbatim: bool,
81+
) -> Option<PathBuf> {
2382
let formats = if verbatim {
2483
vec![("".into(), "".into())]
2584
} else {
@@ -30,16 +89,29 @@ pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) ->
3089
if os == unix { vec![os] } else { vec![os, unix] }
3190
};
3291

33-
for path in sess.target_filesearch(PathKind::Native).search_paths() {
34-
for (prefix, suffix) in &formats {
35-
let test = path.dir.join(format!("{prefix}{name}{suffix}"));
36-
if test.exists() {
37-
return test;
92+
// FIXME: Account for self-contained linking settings and Apple SDK.
93+
walk_native_lib_search_dirs(
94+
sess,
95+
LinkSelfContainedComponents::empty(),
96+
None,
97+
|dir, is_framework| {
98+
if !is_framework {
99+
for (prefix, suffix) in &formats {
100+
let test = dir.join(format!("{prefix}{name}{suffix}"));
101+
if test.exists() {
102+
return ControlFlow::Break(test);
103+
}
104+
}
38105
}
39-
}
40-
}
106+
ControlFlow::Continue(())
107+
},
108+
)
109+
.break_value()
110+
}
41111

42-
sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
112+
pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
113+
try_find_native_static_library(sess, name, verbatim)
114+
.unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
43115
}
44116

45117
fn find_bundled_library(

src/doc/rustc/src/command-line-arguments.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ KIND=PATH` where `KIND` may be one of:
4747
directory.
4848
- `native` — Only search for native libraries in this directory.
4949
- `framework` — Only search for macOS frameworks in this directory.
50-
- `all` — Search for all library kinds in this directory. This is the default
50+
- `all` — Search for all library kinds in this directory, except frameworks. This is the default
5151
if `KIND` is not specified.
5252

5353
<a id="option-l-link-lib"></a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#[no_mangle]
2+
pub extern "C" fn native_lib_alt_naming() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
2+
// to the default format (`foo.lib`).
3+
4+
//REMOVE@ only-msvc
5+
6+
use run_make_support::rustc;
7+
8+
fn main() {
9+
// Prepare the native library.
10+
rustc().input("native.rs").crate_type("staticlib").output("libnative.a").run();
11+
12+
// Try to link to it from both a rlib and a bin.
13+
rustc().input("rust.rs").crate_type("rlib").arg("-lstatic=native").run();
14+
rustc().input("rust.rs").crate_type("bin").arg("-lstatic=native").run();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn main() {}

0 commit comments

Comments
 (0)