Skip to content

Commit 94da7b1

Browse files
committed
rewrite stable-symbol-names to rmake
1 parent b485dd1 commit 94da7b1

File tree

6 files changed

+105
-82
lines changed

6 files changed

+105
-82
lines changed

src/tools/run-make-support/src/external_deps/llvm.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ impl LlvmReadobj {
137137
self
138138
}
139139

140-
/// Pass `--symbols` to display the symbol.
140+
/// Pass `--symbols` to display the symbol table, including both local
141+
/// and global symbols.
141142
pub fn symbols(&mut self) -> &mut Self {
142143
self.cmd.arg("--symbols");
143144
self

src/tools/run-make-support/src/fs.rs

+21-27
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,19 @@ pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
99
if link.as_ref().exists() {
1010
std::fs::remove_dir(link.as_ref()).unwrap();
1111
}
12-
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
13-
"failed to create symlink {:?} for {:?}",
14-
link.as_ref().display(),
15-
original.as_ref().display(),
16-
));
12+
if original.as_ref().is_file() {
13+
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
14+
"failed to create symlink {:?} for {:?}",
15+
link.as_ref().display(),
16+
original.as_ref().display(),
17+
));
18+
} else {
19+
std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
20+
"failed to create symlink {:?} for {:?}",
21+
link.as_ref().display(),
22+
original.as_ref().display(),
23+
));
24+
}
1725
}
1826

1927
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
@@ -41,6 +49,8 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
4149
let ty = entry.file_type()?;
4250
if ty.is_dir() {
4351
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
52+
} else if ty.is_symlink() {
53+
copy_symlink(entry.path(), dst.join(entry.file_name()))?;
4454
} else {
4555
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
4656
}
@@ -59,6 +69,12 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
5969
}
6070
}
6171

72+
fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
73+
let target_path = std::fs::read_link(from).unwrap();
74+
create_symlink(target_path, to);
75+
Ok(())
76+
}
77+
6278
/// Helper for reading entries in a given directory.
6379
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
6480
for entry in read_dir(dir) {
@@ -83,28 +99,6 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
8399
));
84100
}
85101

86-
#[track_caller]
87-
/// An extension of [`std::fs::copy`] which can copy a directory recursively.
88-
pub fn copy_dir_all<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
89-
create_dir_all(&to);
90-
for entry in read_dir(from) {
91-
let entry = entry.unwrap();
92-
let ty = entry.file_type().unwrap();
93-
if ty.is_dir() {
94-
copy_dir_all(entry.path(), to.as_ref().join(entry.file_name()));
95-
} else if ty.is_symlink() {
96-
copy_symlink(entry.path(), to.as_ref().join(entry.file_name()));
97-
} else {
98-
copy(entry.path(), to.as_ref().join(entry.file_name()));
99-
}
100-
}
101-
}
102-
103-
fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
104-
let target_path = fs::read_link(from).unwrap();
105-
std::os::unix::fs::symlink(target_path, to).unwrap();
106-
}
107-
108102
/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.
109103
#[track_caller]
110104
pub fn create_file<P: AsRef<Path>>(path: P) {

src/tools/tidy/src/allowed_run_make_makefiles.txt

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ run-make/reproducible-build/Makefile
4545
run-make/rlib-format-packed-bundled-libs/Makefile
4646
run-make/simd-ffi/Makefile
4747
run-make/split-debuginfo/Makefile
48-
run-make/stable-symbol-names/Makefile
4948
run-make/staticlib-dylib-linkage/Makefile
5049
run-make/symbol-mangling-hashed/Makefile
5150
run-make/sysroot-crates-are-unstable/Makefile

tests/run-make/reproducible-build-2/rmake.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,22 @@
66
// Outputs should be identical.
77
// See https://github.com/rust-lang/rust/issues/34902
88

9-
//FIXME(Oneirical): excluded ignore-musl ignore-windows ignore-cross-compile
9+
//@ ignore-windows
10+
// Reasons:
11+
// 1. The object files are reproducible, but their paths are not, which causes
12+
// the first assertion in the test to fail.
13+
// 2. When the sysroot gets copied, some symlinks must be re-created,
14+
// which is a privileged action on Windows.
1015

11-
use run_make_support::{fs_wrapper, rust_lib_name, rustc};
16+
use run_make_support::{bin_name, rfs, rust_lib_name, rustc};
1217

1318
fn main() {
1419
// test 1: fat lto
1520
rustc().input("reproducible-build-aux.rs").run();
16-
rustc().input("reproducible-build.rs").arg("-Clto=fat").run();
17-
fs_wrapper::rename("reproducible-build", "reproducible-build-a");
18-
rustc().input("reproducible-build.rs").arg("-Clto=fat").run();
19-
assert_eq!(fs_wrapper::read("reproducible-build"), fs_wrapper::read("reproducible-build-a"));
21+
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
22+
rfs::rename("reproducible-build", "reproducible-build-a");
23+
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
24+
assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));
2025

2126
// test 2: sysroot
2227
let sysroot = rustc().print("sysroot").run().stdout_utf8();
@@ -29,17 +34,14 @@ fn main() {
2934
.sysroot(&sysroot)
3035
.arg(format!("--remap-path-prefix={sysroot}=/sysroot"))
3136
.run();
32-
fs_wrapper::copy_dir_all(&sysroot, "sysroot");
33-
fs_wrapper::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
37+
rfs::copy_dir_all(&sysroot, "sysroot");
38+
rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
3439
rustc()
3540
.input("reproducible-build.rs")
3641
.crate_type("rlib")
3742
.sysroot("sysroot")
3843
.arg("--remap-path-prefix=/sysroot=/sysroot")
3944
.run();
4045

41-
assert_eq!(
42-
fs_wrapper::read(rust_lib_name("reproducible_build")),
43-
fs_wrapper::read(rust_lib_name("foo"))
44-
);
46+
assert_eq!(rfs::read(rust_lib_name("reproducible_build")), rfs::read(rust_lib_name("foo")));
4547
}

tests/run-make/stable-symbol-names/Makefile

-41
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// A typo in rustc caused generic symbol names to be non-deterministic -
2+
// that is, it was possible to compile the same file twice with no changes
3+
// and get outputs with different symbol names.
4+
// This test compiles each of the two crates twice, and checks that each output
5+
// contains exactly the same symbol names.
6+
// Additionally, both crates should agree on the same symbol names for monomorphic
7+
// functions.
8+
// See https://github.com/rust-lang/rust/issues/32554
9+
10+
use std::collections::HashSet;
11+
12+
use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};
13+
14+
static LEGACY_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
15+
static V0_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
16+
17+
fn main() {
18+
LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
19+
V0_PATTERN.set(regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap()).unwrap();
20+
// test 1: first file
21+
rustc().input("stable-symbol-names1.rs").run();
22+
let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
23+
rfs::remove_file(rust_lib_name("stable_symbol_names1"));
24+
rustc().input("stable-symbol-names1.rs").run();
25+
let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
26+
assert_eq!(sym1, sym2);
27+
28+
// test 2: second file
29+
rustc().input("stable-symbol-names2.rs").run();
30+
let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
31+
rfs::remove_file(rust_lib_name("stable_symbol_names2"));
32+
rustc().input("stable-symbol-names2.rs").run();
33+
let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
34+
assert_eq!(sym1, sym2);
35+
36+
// test 3: crossed files
37+
let sym1 = process_symbols("stable_symbol_names1", "mono_");
38+
let sym2 = process_symbols("stable_symbol_names2", "mono_");
39+
assert_eq!(sym1, sym2);
40+
}
41+
42+
#[track_caller]
43+
fn process_symbols(path: &str, symbol: &str) -> Vec<String> {
44+
// Dump all symbols.
45+
let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
46+
// Extract only lines containing `symbol`.
47+
let symbol_regex = regex::Regex::new(symbol).unwrap();
48+
let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());
49+
50+
// HashSet - duplicates should be excluded!
51+
let mut symbols: HashSet<String> = HashSet::new();
52+
// From those lines, extract just the symbol name via `regex`, which:
53+
// * always starts with "_ZN" and ends with "E" (`legacy` mangling)
54+
// * always starts with "_R" (`v0` mangling)
55+
for line in out {
56+
if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
57+
symbols.insert(mat.as_str().to_string());
58+
}
59+
if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
60+
symbols.insert(mat.as_str().to_string());
61+
}
62+
}
63+
64+
let mut symbols: Vec<String> = symbols.into_iter().collect();
65+
// Sort those symbol names for deterministic comparison.
66+
symbols.sort();
67+
symbols
68+
}

0 commit comments

Comments
 (0)