rewrite symbol-visibility to rmake

This commit is contained in:
Oneirical 2024-06-27 16:32:54 -04:00
parent 595316b400
commit 689bb118ce
5 changed files with 171 additions and 124 deletions

View File

@ -117,6 +117,7 @@
"ignore-watchos",
"ignore-windows",
"ignore-windows-gnu",
"ignore-windows-msvc",
"ignore-x32",
"ignore-x86",
"ignore-x86_64",

View File

@ -163,11 +163,13 @@ pub struct CompletedProcess {
impl CompletedProcess {
#[must_use]
#[track_caller]
pub fn stdout_utf8(&self) -> String {
String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
}
#[must_use]
#[track_caller]
pub fn stderr_utf8(&self) -> String {
String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
}

View File

@ -52,7 +52,6 @@ run-make/split-debuginfo/Makefile
run-make/stable-symbol-names/Makefile
run-make/staticlib-dylib-linkage/Makefile
run-make/symbol-mangling-hashed/Makefile
run-make/symbol-visibility/Makefile
run-make/sysroot-crates-are-unstable/Makefile
run-make/thumb-none-cortex-m/Makefile
run-make/thumb-none-qemu/Makefile

View File

@ -1,123 +0,0 @@
# ignore-cross-compile
include ../tools.mk
# ignore-windows-msvc
NM=nm -D
CDYLIB_NAME=liba_cdylib.so
RDYLIB_NAME=liba_rust_dylib.so
PROC_MACRO_NAME=liba_proc_macro.so
EXE_NAME=an_executable
COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.so
ifeq ($(UNAME),Darwin)
NM=nm -gU
CDYLIB_NAME=liba_cdylib.dylib
RDYLIB_NAME=liba_rust_dylib.dylib
PROC_MACRO_NAME=liba_proc_macro.dylib
EXE_NAME=an_executable
COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib
endif
ifdef IS_WINDOWS
NM=nm -g
CDYLIB_NAME=liba_cdylib.dll.a
RDYLIB_NAME=liba_rust_dylib.dll.a
PROC_MACRO_NAME=liba_proc_macro.dll
EXE_NAME=an_executable.exe
COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dll.a
endif
# `grep` regex for symbols produced by either `legacy` or `v0` mangling
RE_ANY_RUST_SYMBOL="_ZN.*h.*E\|_R[a-zA-Z0-9_]+"
all:
$(RUSTC) -Zshare-generics=no an_rlib.rs
$(RUSTC) -Zshare-generics=no a_cdylib.rs
$(RUSTC) -Zshare-generics=no a_rust_dylib.rs
$(RUSTC) -Zshare-generics=no a_proc_macro.rs
$(RUSTC) -Zshare-generics=no an_executable.rs
$(RUSTC) -Zshare-generics=no a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib
# Check that a cdylib exports its public #[no_mangle] functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
# Check that a Rust dylib exports its monomorphic functions
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rust_dylib)" -eq "0" ]
# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "0" ]
# Check that a proc macro exports its public #[no_mangle] functions
# FIXME(#99978) avoid exporting #[no_mangle] symbols for proc macros
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a proc macro exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a proc macro DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
# FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
ifndef IS_WINDOWS
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
endif
# 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
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
$(RUSTC) -Zshare-generics=yes an_rlib.rs
$(RUSTC) -Zshare-generics=yes a_cdylib.rs
$(RUSTC) -Zshare-generics=yes a_rust_dylib.rs
$(RUSTC) -Zshare-generics=yes a_proc_macro.rs
$(RUSTC) -Zshare-generics=yes an_executable.rs
# Check that a cdylib exports its public #[no_mangle] functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
# Check that a Rust dylib exports its monomorphic functions, including generics this time
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rust_dylib)" -eq "1" ]
# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "1" ]
# Check that a proc macro exports its public #[no_mangle] functions
# FIXME(#99978) avoid exporting #[no_mangle] symbols for proc macros
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a proc macro exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a proc macro DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
ifndef IS_WINDOWS
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
endif

View File

@ -0,0 +1,168 @@
// 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
//@ ignore-windows-msvc
use run_make_support::{bin_name, dynamic_lib_name, is_windows, llvm_readobj, regex, rustc};
fn main() {
let mut cdylib_name = dynamic_lib_name("a_cdylib");
let mut rdylib_name = dynamic_lib_name("a_rust_dylib");
let exe_name = bin_name("an_executable");
let mut 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_windows() {
// // 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_windows() {
// // 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 out = llvm_readobj().arg("--dyn-symbols").input(path).run().stdout_utf8();
assert_eq!(
out.lines()
.filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type))
.count()
== 1,
exists_once
);
}
fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool {
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
line.contains(expected)
} else {
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
regex.is_match(line)
}
}
#[derive(Clone, Copy)]
enum SymbolCheckType {
StrSymbol(&'static str),
AnyRustSymbol,
}