diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs_wrapper.rs index 806a6985f07c6..3d758b232dcb5 100644 --- a/src/tools/run-make-support/src/fs_wrapper.rs +++ b/src/tools/run-make-support/src/fs_wrapper.rs @@ -18,6 +18,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) { )); } +#[track_caller] /// An extension of copy which can copy a directory recursively. pub fn copy_dir_all, Q: AsRef>(from: P, to: Q) { create_dir_all(&to); @@ -26,12 +27,19 @@ pub fn copy_dir_all, Q: AsRef>(from: P, to: Q) { let ty = entry.file_type().unwrap(); if ty.is_dir() { copy_dir_all(entry.path(), to.as_ref().join(entry.file_name())); + } else if ty.is_symlink() { + copy_symlink(entry.path(), to.as_ref().join(entry.file_name())); } else { copy(entry.path(), to.as_ref().join(entry.file_name())); } } } +fn copy_symlink, Q: AsRef>(from: P, to: Q) { + let target_path = fs::read_link(from).unwrap(); + std::os::unix::fs::symlink(target_path, to).unwrap(); +} + /// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.. #[track_caller] pub fn create_file>(path: P) { diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index bf68c3144e1d4..0f8b844c1d817 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -151,7 +151,6 @@ run-make/share-generics-dylib/Makefile run-make/silly-file-names/Makefile run-make/simd-ffi/Makefile run-make/split-debuginfo/Makefile -run-make/stable-symbol-names/Makefile run-make/static-dylib-by-default/Makefile run-make/static-extern-type/Makefile run-make/staticlib-blank-lib/Makefile diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs index 6286b60760549..8f38c0058b842 100644 --- a/tests/run-make/reproducible-build-2/rmake.rs +++ b/tests/run-make/reproducible-build-2/rmake.rs @@ -6,16 +6,20 @@ // Outputs should be identical. // See https://github.com/rust-lang/rust/issues/34902 -//FIXME(Oneirical): excluded ignore-musl ignore-windows ignore-cross-compile +//FIXME(Oneirical): excluded ignore-musl ignore-cross-compile -use run_make_support::{fs_wrapper, rust_lib_name, rustc}; +//@ ignore-windows +// Reason: When the sysroot gets copied, some symlinks must be re-created, +// which is a privileged action on Windows. + +use run_make_support::{bin_name, fs_wrapper, 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").run(); + rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run(); fs_wrapper::rename("reproducible-build", "reproducible-build-a"); - rustc().input("reproducible-build.rs").arg("-Clto=fat").run(); + rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run(); assert_eq!(fs_wrapper::read("reproducible-build"), fs_wrapper::read("reproducible-build-a")); // test 2: sysroot diff --git a/tests/run-make/stable-symbol-names/Makefile b/tests/run-make/stable-symbol-names/Makefile deleted file mode 100644 index bbfb8e3888171..0000000000000 --- a/tests/run-make/stable-symbol-names/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -include ../tools.mk - -# The following command will: -# 1. dump the symbols of a library using `nm` -# 2. extract only those lines that we are interested in via `grep` -# 3. from those lines, extract just the symbol name via `sed`, which: -# * always starts with "_ZN" and ends with "E" (`legacy` mangling) -# * always starts with "_R" (`v0` mangling) -# 4. sort those symbol names for deterministic comparison -# 5. write the result into a file - -dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \ - | grep -E "$(2)" \ - | sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \ - | sort \ - > "$(TMPDIR)/$(1)$(3).nm" - -# This test -# - compiles each of the two crates 2 times and makes sure each time we get -# exactly the same symbol names -# - makes sure that both crates agree on the same symbol names for monomorphic -# functions - -all: - $(RUSTC) stable-symbol-names1.rs - $(call dump-symbols,stable_symbol_names1,generic_|mono_,_v1) - rm $(TMPDIR)/libstable_symbol_names1.rlib - $(RUSTC) stable-symbol-names1.rs - $(call dump-symbols,stable_symbol_names1,generic_|mono_,_v2) - cmp "$(TMPDIR)/stable_symbol_names1_v1.nm" "$(TMPDIR)/stable_symbol_names1_v2.nm" - - $(RUSTC) stable-symbol-names2.rs - $(call dump-symbols,stable_symbol_names2,generic_|mono_,_v1) - rm $(TMPDIR)/libstable_symbol_names2.rlib - $(RUSTC) stable-symbol-names2.rs - $(call dump-symbols,stable_symbol_names2,generic_|mono_,_v2) - cmp "$(TMPDIR)/stable_symbol_names2_v1.nm" "$(TMPDIR)/stable_symbol_names2_v2.nm" - - $(call dump-symbols,stable_symbol_names1,mono_,_cross) - $(call dump-symbols,stable_symbol_names2,mono_,_cross) - cmp "$(TMPDIR)/stable_symbol_names1_cross.nm" "$(TMPDIR)/stable_symbol_names2_cross.nm" diff --git a/tests/run-make/stable-symbol-names/rmake.rs b/tests/run-make/stable-symbol-names/rmake.rs new file mode 100644 index 0000000000000..ca6e85062f48c --- /dev/null +++ b/tests/run-make/stable-symbol-names/rmake.rs @@ -0,0 +1,64 @@ +// 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 run_make_support::{fs_wrapper, llvm_readobj, regex, rust_lib_name, rustc}; +use std::collections::HashSet; + +fn main() { + // test 1: first file + rustc().input("stable-symbol-names1.rs").run(); + let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_"); + fs_wrapper::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_"); + fs_wrapper::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 { + // Dump all symbols. + let out = llvm_readobj().input(rust_lib_name(path)).arg("--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()); + // 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) + let legacy_pattern = regex::Regex::new(r"_ZN.*E").unwrap(); + let v0_pattern = regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap(); + + // HashSet - duplicates should be excluded! + let mut symbols: HashSet = HashSet::new(); + for line in out { + if let Some(mat) = legacy_pattern.find(line) { + symbols.insert(mat.as_str().to_string()); + } + if let Some(mat) = v0_pattern.find(line) { + symbols.insert(mat.as_str().to_string()); + } + } + + let mut symbols: Vec = symbols.into_iter().collect(); + // Sort those symbol names for deterministic comparison. + symbols.sort(); + symbols +}