Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate reproducible-build-2 and stable-symbol-names run-make tests to rmake #127095

Merged
merged 2 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/tools/run-make-support/src/external_deps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ impl LlvmReadobj {
self
}

/// Pass `--symbols` to display the symbol.
/// Pass `--symbols` to display the symbol table, including both local
/// and global symbols.
pub fn symbols(&mut self) -> &mut Self {
self.cmd.arg("--symbols");
self
Expand Down
26 changes: 21 additions & 5 deletions src/tools/run-make-support/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
if original.as_ref().is_file() {
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
} else {
std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
}

/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
Expand Down Expand Up @@ -41,6 +49,8 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
} else if ty.is_symlink() {
copy_symlink(entry.path(), dst.join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
}
Expand All @@ -59,6 +69,12 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
}
}

fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let target_path = std::fs::read_link(from).unwrap();
create_symlink(target_path, to);
Ok(())
}

/// Helper for reading entries in a given directory.
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
for entry in read_dir(dir) {
Expand Down
2 changes: 0 additions & 2 deletions src/tools/tidy/src/allowed_run_make_makefiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ run-make/raw-dylib-alt-calling-convention/Makefile
run-make/raw-dylib-c/Makefile
run-make/redundant-libs/Makefile
run-make/remap-path-prefix-dwarf/Makefile
run-make/reproducible-build-2/Makefile
run-make/reproducible-build/Makefile
run-make/rlib-format-packed-bundled-libs/Makefile
run-make/simd-ffi/Makefile
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/sysroot-crates-are-unstable/Makefile
Expand Down
27 changes: 0 additions & 27 deletions tests/run-make/reproducible-build-2/Makefile

This file was deleted.

47 changes: 47 additions & 0 deletions tests/run-make/reproducible-build-2/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Builds with fat link-time-optimizations and the --sysroot flag used to be
// non-deterministic - that means, compiling twice with no changes would create
// slightly different outputs. This has been fixed by #63352 and #63505.
// Test 1: Compile with fat-lto twice, check that both compilation outputs are identical.
// Test 2: Compile with sysroot, then change the sysroot path from absolute to relative.
// Outputs should be identical.
// See https://github.com/rust-lang/rust/issues/34902

//@ ignore-windows
// Reasons:
// 1. The object files are reproducible, but their paths are not, which causes
// the first assertion in the test to fail.
// 2. When the sysroot gets copied, some symlinks must be re-created,
// which is a privileged action on Windows.

use run_make_support::{bin_name, rfs, rust_lib_name, rustc};

fn main() {
// test 1: fat lto
rustc().input("reproducible-build-aux.rs").run();
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
rfs::rename("reproducible-build", "reproducible-build-a");
rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));

// test 2: sysroot
let sysroot = rustc().print("sysroot").run().stdout_utf8();
let sysroot = sysroot.trim();

rustc().input("reproducible-build-aux.rs").run();
rustc()
.input("reproducible-build.rs")
.crate_type("rlib")
.sysroot(&sysroot)
.arg(format!("--remap-path-prefix={sysroot}=/sysroot"))
.run();
rfs::copy_dir_all(&sysroot, "sysroot");
rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
rustc()
.input("reproducible-build.rs")
.crate_type("rlib")
.sysroot("sysroot")
.arg("--remap-path-prefix=/sysroot=/sysroot")
.run();

assert_eq!(rfs::read(rust_lib_name("reproducible_build")), rfs::read(rust_lib_name("foo")));
}
41 changes: 0 additions & 41 deletions tests/run-make/stable-symbol-names/Makefile

This file was deleted.

68 changes: 68 additions & 0 deletions tests/run-make/stable-symbol-names/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// A typo in rustc caused generic symbol names to be non-deterministic -
// that is, it was possible to compile the same file twice with no changes
// and get outputs with different symbol names.
// This test compiles each of the two crates twice, and checks that each output
// contains exactly the same symbol names.
// Additionally, both crates should agree on the same symbol names for monomorphic
// functions.
// See https://github.com/rust-lang/rust/issues/32554

use std::collections::HashSet;

use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};

static LEGACY_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
static V0_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();

fn main() {
LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
V0_PATTERN.set(regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap()).unwrap();
// test 1: first file
rustc().input("stable-symbol-names1.rs").run();
let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
rfs::remove_file(rust_lib_name("stable_symbol_names1"));
rustc().input("stable-symbol-names1.rs").run();
let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
assert_eq!(sym1, sym2);

// test 2: second file
rustc().input("stable-symbol-names2.rs").run();
let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
rfs::remove_file(rust_lib_name("stable_symbol_names2"));
rustc().input("stable-symbol-names2.rs").run();
let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
assert_eq!(sym1, sym2);

// test 3: crossed files
let sym1 = process_symbols("stable_symbol_names1", "mono_");
let sym2 = process_symbols("stable_symbol_names2", "mono_");
assert_eq!(sym1, sym2);
}

#[track_caller]
fn process_symbols(path: &str, symbol: &str) -> Vec<String> {
// Dump all symbols.
let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
// Extract only lines containing `symbol`.
let symbol_regex = regex::Regex::new(symbol).unwrap();
let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());

// HashSet - duplicates should be excluded!
let mut symbols: HashSet<String> = HashSet::new();
// From those lines, extract just the symbol name via `regex`, which:
// * always starts with "_ZN" and ends with "E" (`legacy` mangling)
// * always starts with "_R" (`v0` mangling)
for line in out {
if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
symbols.insert(mat.as_str().to_string());
}
if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
symbols.insert(mat.as_str().to_string());
}
}

let mut symbols: Vec<String> = symbols.into_iter().collect();
// Sort those symbol names for deterministic comparison.
symbols.sort();
symbols
}
Loading