Skip to content

Commit 719e1b6

Browse files
committed
update
1 parent 4afd993 commit 719e1b6

File tree

8 files changed

+136
-40
lines changed

8 files changed

+136
-40
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::{env, fmt, fs, io, mem, str};
1111

1212
use cc::windows_registry;
1313
use itertools::Itertools;
14-
use object::{Object, ObjectSection};
14+
use object::{Object, ObjectSection, ObjectSymbol};
1515
use regex::Regex;
1616
use rustc_arena::TypedArena;
1717
use rustc_ast::CRATE_NODE_ID;
@@ -2172,42 +2172,80 @@ fn add_rpath_args(
21722172
}
21732173
}
21742174

2175-
fn add_c_staticlib_symbols(sess: &Session, name: &str, out: &mut Vec<(String, SymbolExportKind)>) {
2175+
fn add_c_staticlib_symbols(
2176+
sess: &Session,
2177+
name: &str,
2178+
out: &mut Vec<(String, SymbolExportKind)>,
2179+
) -> io::Result<()> {
21762180
for search_path in sess.target_filesearch().search_paths(PathKind::Native) {
21772181
let file_path = search_path.dir.join(name);
2178-
if file_path.exists() {
2179-
let archive_data = unsafe {
2180-
Mmap::map(File::open(file_path).expect("couldn't open c staticlib"))
2181-
.expect("couldn't map c staticlib")
2182-
};
2183-
let archive = object::read::archive::ArchiveFile::parse(&*archive_data)
2184-
.expect("wanted an c staticlib");
2185-
for member in archive.members() {
2186-
let member = member.unwrap();
2187-
let data = member.data(&*archive_data).unwrap();
2188-
2189-
// clang LTO: raw LLVM bitcode
2190-
if data.len() >= 4 && &data[0..4] == b"BC\xc0\xde" {
2191-
return;
2192-
}
2182+
if !file_path.exists() {
2183+
continue;
2184+
}
21932185

2194-
// gcc / clang ELF LTO
2195-
let object = object::File::parse(&*data).unwrap();
2196-
if object.sections().into_iter().any(|s| {
2197-
s.name().unwrap().starts_with(".gnu.lto_") || s.name().unwrap() == ".llvm.lto"
2198-
}) {
2199-
return;
2200-
}
2186+
let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };
2187+
2188+
let archive = object::read::archive::ArchiveFile::parse(&*archive_map)
2189+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2190+
2191+
for member in archive.members() {
2192+
let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2193+
2194+
let data = member
2195+
.data(&*archive_map)
2196+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2197+
2198+
// clang LTO: raw LLVM bitcode
2199+
if data.starts_with(b"BC\xc0\xde") {
2200+
return Err(io::Error::new(
2201+
io::ErrorKind::InvalidData,
2202+
"LLVM bitcode object in C static library (LTO not supported)",
2203+
));
22012204
}
2202-
for symbol in archive.symbols().unwrap().unwrap() {
2203-
let symbol = symbol.unwrap();
2204-
out.push((
2205-
String::from_utf8(symbol.name().to_vec()).unwrap(),
2206-
SymbolExportKind::Text,
2205+
2206+
let object = object::File::parse(&*data)
2207+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2208+
2209+
// gcc / clang ELF / Mach-O LTO
2210+
if object.sections().any(|s| {
2211+
s.name().map(|n| n.starts_with(".gnu.lto_") || n == ".llvm.lto").unwrap_or(false)
2212+
}) {
2213+
return Err(io::Error::new(
2214+
io::ErrorKind::InvalidData,
2215+
"LTO object in C static library is not supported",
22072216
));
22082217
}
2218+
2219+
for symbol in object.symbols() {
2220+
if symbol.scope() != object::SymbolScope::Dynamic {
2221+
continue;
2222+
}
2223+
2224+
let mut name = match symbol.name() {
2225+
Ok(n) => n,
2226+
Err(_) => continue,
2227+
};
2228+
2229+
if sess.target.is_like_darwin {
2230+
if let Some(stripped) = name.strip_prefix('_') {
2231+
name = stripped;
2232+
}
2233+
}
2234+
2235+
let export_kind = match symbol.kind() {
2236+
object::SymbolKind::Text => SymbolExportKind::Text,
2237+
object::SymbolKind::Data => SymbolExportKind::Data,
2238+
_ => continue,
2239+
};
2240+
2241+
out.push((name.to_string(), export_kind));
2242+
}
22092243
}
2244+
2245+
return Ok(());
22102246
}
2247+
2248+
Ok(())
22112249
}
22122250

22132251
/// Produce the linker command line containing linker path and arguments.
@@ -2241,9 +2279,13 @@ fn linker_with_args(
22412279
let link_output_kind = link_output_kind(sess, crate_type);
22422280

22432281
let mut export_symbols = codegen_results.crate_info.exported_symbols[&crate_type].clone();
2244-
if !sess.opts.unstable_opts.include_libs.is_empty() {
2245-
for name in &sess.opts.unstable_opts.include_libs {
2246-
add_c_staticlib_symbols(&sess, name, &mut export_symbols);
2282+
if crate_type == CrateType::Cdylib
2283+
&& !sess.opts.unstable_opts.export_c_static_library_symbols.is_empty()
2284+
{
2285+
for name in &sess.opts.unstable_opts.export_c_static_library_symbols {
2286+
if let Err(err) = add_c_staticlib_symbols(&sess, name, &mut export_symbols) {
2287+
sess.dcx().fatal(format!("failed to process C static library `{}`: {}", name, err));
2288+
}
22472289
}
22482290
}
22492291

compiler/rustc_interface/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,8 @@ fn test_unstable_options_tracking_hash() {
794794
tracked!(embed_metadata, false);
795795
tracked!(embed_source, true);
796796
tracked!(emit_thin_lto, false);
797-
tracked!(emscripten_wasm_eh, true);
797+
tracked!(emscripten_wasm_eh, false);
798+
tracked!(export_c_static_library_symbols, vec![String::from("libfoo.a")]);
798799
tracked!(export_executable_symbols, true);
799800
tracked!(fewer_names, Some(true));
800801
tracked!(fixed_x18, true);
@@ -805,7 +806,6 @@ fn test_unstable_options_tracking_hash() {
805806
tracked!(function_sections, Some(false));
806807
tracked!(hint_mostly_unused, true);
807808
tracked!(human_readable_cgu_names, true);
808-
tracked!(include_libs, vec![String::from("libfoo.a")]);
809809
tracked!(incremental_ignore_spans, true);
810810
tracked!(inline_mir, Some(true));
811811
tracked!(inline_mir_hint_threshold, Some(123));

compiler/rustc_session/src/options.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,6 +2243,9 @@ options! {
22432243
"enforce the type length limit when monomorphizing instances in codegen"),
22442244
experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
22452245
"enable default bounds for experimental group of auto traits"),
2246+
export_c_static_library_symbols: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
2247+
"export all global symbols from selected upstream c staticlibs when building cdylib \
2248+
(comma separated crate names)"),
22462249
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
22472250
"export symbols from executables, as if they were dynamic libraries"),
22482251
external_clangrt: bool = (false, parse_bool, [UNTRACKED],
@@ -2286,9 +2289,6 @@ options! {
22862289
"display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
22872290
ignore_directory_in_diagnostics_source_blocks: Vec<String> = (Vec::new(), parse_string_push, [UNTRACKED],
22882291
"do not display the source code block in diagnostics for files in the directory"),
2289-
include_libs: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
2290-
"export all global symbols from selected upstream c staticlibs when building cdylib \
2291-
(comma separated crate names)"),
22922292
incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
22932293
"ignore spans during ICH computation -- used for testing (default: no)"),
22942294
incremental_info: bool = (false, parse_bool, [UNTRACKED],
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `export-c-static-library-symbols`
2+
3+
This flag is provided to export all global symbols from selected upstream c staticlibs only when building `cdylib`.
4+
5+
- This flag will select and import the `Global` symbols of the first matching library it finds.
6+
7+
- Developers should ensure that there are no libraries with the same name.
8+
9+
- By default, upstream C static libraries will not export their `Global` symbols regardless of whether `LTO` optimization is enabled. However, after enabling this flag, if the upstream C static library has `LTO` optimization enabled, the compiler will issue an error to inform the developer that the linked C library is invalid.

src/doc/unstable-book/src/compiler-flags/include-libs.md

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void my_function() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
extern "C" {
2+
pub fn my_function();
3+
}
4+
5+
#[no_mangle]
6+
pub extern "C" fn rust_entry() {
7+
unsafe { my_function(); }
8+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ ignore-nvptx64
2+
//@ ignore-wasm32-bare
3+
//@ ignore-i686-pc-windows-msvc
4+
// FIXME:The symbol mangle rules are slightly different in 32-bit Windows. Need to be resolved.
5+
//@ ignore-cross-compile
6+
// Reason: the compiled binary is executed
7+
8+
use run_make_support::{build_native_static_lib, cc, dynamic_lib_name, is_darwin, llvm_nm, rustc};
9+
10+
fn main() {
11+
cc().input("foo.c").arg("-c").out_exe("foo.o").run();
12+
build_native_static_lib("foo");
13+
14+
rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run();
15+
16+
let out = llvm_nm()
17+
.input(dynamic_lib_name("foo"))
18+
.run()
19+
.assert_stdout_not_contains_regex("T *my_function");
20+
21+
rustc()
22+
.input("foo.rs")
23+
.arg("-lstatic=foo")
24+
.crate_type("cdylib")
25+
.arg("-Zexport-c-static-library-symbols=libfoo.a")
26+
.run();
27+
28+
if is_darwin() {
29+
let out = llvm_nm()
30+
.input(dynamic_lib_name("foo"))
31+
.run()
32+
.assert_stdout_contains_regex("T _my_function");
33+
} else {
34+
let out = llvm_nm()
35+
.input(dynamic_lib_name("foo"))
36+
.run()
37+
.assert_stdout_contains_regex("T my_function");
38+
}
39+
}

0 commit comments

Comments
 (0)