168 lines
6.9 KiB
Rust
168 lines
6.9 KiB
Rust
// Dynamic libraries on Rust used to export a very high amount of symbols,
|
|
// going as far as filling the output with mangled names and generic function
|
|
// names. After the rework of #38117, this test checks that no mangled Rust symbols
|
|
// are exported, and that generics are only shown if explicitely requested.
|
|
// See https://github.com/rust-lang/rust/issues/37530
|
|
|
|
use run_make_support::object::read::Object;
|
|
use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc};
|
|
|
|
fn main() {
|
|
let cdylib_name = dynamic_lib_name("a_cdylib");
|
|
let rdylib_name = dynamic_lib_name("a_rust_dylib");
|
|
let exe_name = bin_name("an_executable");
|
|
let combined_cdylib_name = dynamic_lib_name("combined_rlib_dylib");
|
|
rustc().arg("-Zshare-generics=no").input("an_rlib.rs").run();
|
|
rustc().arg("-Zshare-generics=no").input("a_cdylib.rs").run();
|
|
rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();
|
|
rustc().arg("-Zshare-generics=no").input("a_proc_macro.rs").run();
|
|
rustc().arg("-Zshare-generics=no").input("an_executable.rs").run();
|
|
rustc()
|
|
.arg("-Zshare-generics=no")
|
|
.input("a_cdylib.rs")
|
|
.crate_name("combined_rlib_dylib")
|
|
.crate_type("rlib,cdylib")
|
|
.run();
|
|
|
|
// Check that a cdylib exports its public #[no_mangle] functions
|
|
symbols_check(&cdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_cdylib"), true);
|
|
// Check that a cdylib exports the public #[no_mangle] functions of dependencies
|
|
symbols_check(&cdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), true);
|
|
// Check that a cdylib DOES NOT export any public Rust functions
|
|
symbols_check(&cdylib_name, SymbolCheckType::AnyRustSymbol, false);
|
|
|
|
// Check that a Rust dylib exports its monomorphic functions
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_c_function_from_rust_dylib"),
|
|
true,
|
|
);
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_rust_function_from_rust_dylib"),
|
|
true,
|
|
);
|
|
// Check that a Rust dylib does not export generics if -Zshare-generics=no
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_generic_function_from_rust_dylib"),
|
|
false,
|
|
);
|
|
|
|
// Check that a Rust dylib exports the monomorphic functions from its dependencies
|
|
symbols_check(&rdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), true);
|
|
symbols_check(&rdylib_name, SymbolCheckType::StrSymbol("public_rust_function_from_rlib"), true);
|
|
// Check that a Rust dylib does not export generics if -Zshare-generics=no
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_generic_function_from_rlib"),
|
|
false,
|
|
);
|
|
|
|
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
|
if is_msvc() {
|
|
// Check that an executable does not export any dynamic symbols
|
|
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
|
|
symbols_check(
|
|
&exe_name,
|
|
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
|
false,
|
|
);
|
|
}
|
|
|
|
// Check the combined case, where we generate a cdylib and an rlib in the same
|
|
// compilation session:
|
|
// Check that a cdylib exports its public #[no_mangle] functions
|
|
symbols_check(
|
|
&combined_cdylib_name,
|
|
SymbolCheckType::StrSymbol("public_c_function_from_cdylib"),
|
|
true,
|
|
);
|
|
// Check that a cdylib exports the public #[no_mangle] functions of dependencies
|
|
symbols_check(
|
|
&combined_cdylib_name,
|
|
SymbolCheckType::StrSymbol("public_c_function_from_rlib"),
|
|
true,
|
|
);
|
|
// Check that a cdylib DOES NOT export any public Rust functions
|
|
symbols_check(&combined_cdylib_name, SymbolCheckType::AnyRustSymbol, false);
|
|
|
|
rustc().arg("-Zshare-generics=yes").input("an_rlib.rs").run();
|
|
rustc().arg("-Zshare-generics=yes").input("a_cdylib.rs").run();
|
|
rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
|
|
rustc().arg("-Zshare-generics=yes").input("an_executable.rs").run();
|
|
|
|
// Check that a cdylib exports its public #[no_mangle] functions
|
|
symbols_check(&cdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_cdylib"), true);
|
|
// Check that a cdylib exports the public #[no_mangle] functions of dependencies
|
|
symbols_check(&cdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), true);
|
|
// Check that a cdylib DOES NOT export any public Rust functions
|
|
symbols_check(&cdylib_name, SymbolCheckType::AnyRustSymbol, false);
|
|
|
|
// Check that a Rust dylib exports its monomorphic functions, including generics this time
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_c_function_from_rust_dylib"),
|
|
true,
|
|
);
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_rust_function_from_rust_dylib"),
|
|
true,
|
|
);
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_generic_function_from_rust_dylib"),
|
|
true,
|
|
);
|
|
|
|
// Check that a Rust dylib exports the monomorphic functions from its dependencies
|
|
symbols_check(&rdylib_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), true);
|
|
symbols_check(&rdylib_name, SymbolCheckType::StrSymbol("public_rust_function_from_rlib"), true);
|
|
symbols_check(
|
|
&rdylib_name,
|
|
SymbolCheckType::StrSymbol("public_generic_function_from_rlib"),
|
|
true,
|
|
);
|
|
|
|
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
|
if is_msvc() {
|
|
// Check that an executable does not export any dynamic symbols
|
|
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
|
|
symbols_check(
|
|
&exe_name,
|
|
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
|
false,
|
|
);
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
|
|
let binary_data = rfs::read(path);
|
|
let file = object::File::parse(&*binary_data).unwrap();
|
|
let mut found: u64 = 0;
|
|
for export in file.exports().unwrap() {
|
|
let name = std::str::from_utf8(export.name()).unwrap();
|
|
if has_symbol(name, symbol_check_type) {
|
|
found += 1;
|
|
}
|
|
}
|
|
assert_eq!(found, exists_once as u64);
|
|
}
|
|
|
|
fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool {
|
|
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
|
|
name.contains(expected)
|
|
} else {
|
|
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
|
|
regex.is_match(name)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
enum SymbolCheckType {
|
|
StrSymbol(&'static str),
|
|
AnyRustSymbol,
|
|
}
|