Skip to content

Commit

Permalink
Rollup merge of rust-lang#127095 - Oneirical:testiary-education, r=ji…
Browse files Browse the repository at this point in the history
…eyouxu

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

Part of rust-lang#121876 and the associated [Google Summer of Code project](https://blog.rust-lang.org/2024/05/01/gsoc-2024-selected-projects.html).

Needs try-jobs.

try-job: x86_64-msvc
try-job: armhf-gnu
try-job: test-various
try-job: aarch64-apple
try-job: i686-msvc
try-job: x86_64-mingw
  • Loading branch information
tgross35 authored Aug 3, 2024
2 parents 1f47624 + 94da7b1 commit ac06548
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 76 deletions.
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 @@ -151,7 +151,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 @@ -29,12 +29,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
}

0 comments on commit ac06548

Please sign in to comment.