authorbors <bors@rust-lang.org> 2025-01-16 02:31:22 UTC
committerbors <bors@rust-lang.org> 2025-01-16 02:31:22 UTC
log5cd16b7f2bc3624f2d658aa87151279878d2652a
tree6180a5f11979ce30f0495a64c57ca6d265a4f670
parent6fc8a27931b3806d38143c518c91c7f97b4cfb83
parent98f673e93a47b33a451f6b2cd99e5d5b03b57563

Auto merge of #135458 - jieyouxu:migrate-extern-fn-reachable, r=lqd

tests: Port `extern-fn-reachable` to rmake.rs Part of #121876. ## Summary This PR ports `tests/run-make/extern-fn-reachable` to use `rmake.rs`. Notable changes: - We now use the `object` crate and look at the exported symbols specifically. - This test's coverage regressed against windows-msvc back in [replace dynamic library module with libloading #90716](https://github.com/rust-lang/rust/pull/90716), but since we use `object` now, we're able to claw the test coverage back. - The checks are now stricter: 1. It no longer looks for substring symbol matches in `nm` textual outputs, it inspects the symbol names precisely. 2. We now also explicitly check for the presence of leading underscore in exported symbol names on apple vs non-apple targets. - Added another case of `#[no_mangle] fn fun6() {}` (note the lack of `pub`) to check that Rust nameres visibility is orthogonal to symbol visibility in dylib. ## History - Test was initially introduced as a run-pass[^run-pass] test as part of [Don't mark reachable extern fns as internal #10539](https://github.com/rust-lang/rust/pull/10539). - Test re-introduced as a run-make test in https://github.com/rust-lang/rust/pull/13741. - Later, the test coverage regressed in https://github.com/rust-lang/rust/pull/90716. [^run-pass]: no longer a thing nowadays Supersedes #128314. Co-authored with `@lolbinarycat.` try-job: x86_64-msvc try-job: i686-msvc try-job: i686-mingw try-job: x86_64-mingw-1 try-job: x86_64-apple-1 try-job: aarch64-apple try-job: test-various

4 files changed, 61 insertions(+), 27 deletions(-)

src/tools/tidy/src/allowed_run_make_makefiles.txt-1
......@@ -1,5 +1,4 @@
11run-make/cat-and-grep-sanity-check/Makefile
2run-make/extern-fn-reachable/Makefile
32run-make/jobserver-error/Makefile
43run-make/split-debuginfo/Makefile
54run-make/symbol-mangling-hashed/Makefile
tests/run-make/extern-fn-reachable/Makefile deleted-26
......@@ -1,26 +0,0 @@
1# ignore-cross-compile
2include ../tools.mk
3
4# ignore-windows-msvc
5
6NM=nm -D
7
8ifeq ($(UNAME),Darwin)
9NM=nm -gU
10endif
11
12ifdef IS_WINDOWS
13NM=nm -g
14endif
15
16# This overrides the LD_LIBRARY_PATH for RUN
17TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)
18
19all:
20 $(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so -C prefer-dynamic
21
22 [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun1)" -eq "1" ]
23 [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun2)" -eq "1" ]
24 [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun3)" -eq "1" ]
25 [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun4)" -eq "1" ]
26 [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun5)" -eq "1" ]
tests/run-make/extern-fn-reachable/dylib.rs+15
......@@ -1,19 +1,34 @@
11#![crate_type = "dylib"]
22#![allow(dead_code)]
33
4// `pub` extern fn here is a Rust nameres visibility concept, and should not affect symbol
5// visibility in the dylib.
46#[no_mangle]
57pub extern "C" fn fun1() {}
8
9// (Lack of) `pub` for the extern fn here is a Rust nameres visibility concept, and should not
10// affect symbol visibility in the dylib.
611#[no_mangle]
712extern "C" fn fun2() {}
813
14// Modules are a Rust nameres concept, and should not affect symbol visibility in the dylib if the
15// extern fn is nested inside a module.
916mod foo {
1017 #[no_mangle]
1118 pub extern "C" fn fun3() {}
1219}
20
21// Similarly, the Rust visibility of the containing module is a Rust nameres concept, and should not
22// affect symbol visibility in the dylib.
1323pub mod bar {
1424 #[no_mangle]
1525 pub extern "C" fn fun4() {}
1626}
1727
28// Non-extern `#[no_mangle]` fn should induce a symbol visible in the dylib.
1829#[no_mangle]
1930pub fn fun5() {}
31
32// The Rust visibility of the fn should not affect is symbol visibility in the dylib.
33#[no_mangle]
34fn fun6() {}
tests/run-make/extern-fn-reachable/rmake.rs created+46
......@@ -0,0 +1,46 @@
1//! Smoke test to check that that symbols of `extern "C"` functions and `#[no_mangle]` rust
2//! functions:
3//!
4//! 1. Are externally visible in the dylib produced.
5//! 2. That the symbol visibility is orthogonal to the Rust nameres visibility of the functions
6//! involved.
7
8//@ ignore-cross-compile
9
10use std::collections::BTreeSet;
11
12use run_make_support::object::{self, Object};
13use run_make_support::{dynamic_lib_name, is_darwin, path, rfs, rustc};
14
15fn main() {
16 let dylib = dynamic_lib_name("dylib");
17 rustc().input("dylib.rs").output(&dylib).arg("-Cprefer-dynamic").run();
18
19 let expected_symbols = if is_darwin() {
20 // Mach-O states that all exported symbols should have an underscore as prefix. At the
21 // same time dlsym will implicitly add it, so outside of compilers, linkers and people
22 // writing assembly, nobody needs to be aware of this.
23 BTreeSet::from(["_fun1", "_fun2", "_fun3", "_fun4", "_fun5", "_fun6"])
24 } else {
25 BTreeSet::from(["fun1", "fun2", "fun3", "fun4", "fun5", "fun6"])
26 };
27
28 let mut found_symbols = BTreeSet::new();
29
30 let blob = rfs::read(path(dylib));
31 let file = object::File::parse(&*blob).unwrap();
32 for export in file.exports().unwrap() {
33 let sym_name = export.name();
34 let sym_name = std::str::from_utf8(sym_name).unwrap();
35 found_symbols.insert(sym_name);
36 }
37
38 println!("expected_symbols = {:?}", expected_symbols);
39 println!("found_symbols = {:?}", found_symbols);
40 if !found_symbols.is_superset(&expected_symbols) {
41 for diff in expected_symbols.difference(&found_symbols) {
42 eprintln!("missing symbol: {}", diff);
43 }
44 panic!("missing expected symbols");
45 }
46}