// This test case makes sure that two identical invocations of the compiler // (i.e. same code base, same compile-flags, same compiler-versions, etc.) // produce the same output. In the past, symbol names of monomorphized functions // were not deterministic (which we want to avoid). // // The test tries to exercise as many different paths into symbol name // generation as possible: // // - regular functions // - generic functions // - methods // - statics // - closures // - enum variant constructors // - tuple struct constructors // - drop glue // - FnOnce adapters // - Trait object shims // - Fn Pointer shims // See https://github.com/rust-lang/rust/pull/32293 // Tracking Issue: https://github.com/rust-lang/rust/issues/129080 use run_make_support::{ bin_name, cwd, diff, is_darwin, is_windows, rfs, run_in_tmpdir, rust_lib_name, rustc, }; fn main() { // Smoke tests. Simple flags, build should be reproducible. eprintln!("smoke_test => None"); smoke_test(None); eprintln!("smoke_test => SmokeFlag::Debug"); smoke_test(Some(SmokeFlag::Debug)); eprintln!("smoke_test => SmokeFlag::Opt"); smoke_test(Some(SmokeFlag::Opt)); // Builds should be reproducible even through custom library search paths // or remap path prefixes. eprintln!("paths_test => PathsFlag::Link"); paths_test(PathsFlag::Link); eprintln!("paths_test => PathsFlag::Remap"); paths_test(PathsFlag::Remap); // Builds should be reproducible even if each build is done in a different directory, // with both --remap-path-prefix and -Z remap-cwd-prefix. // FIXME(Oneirical): Building with crate type set to `bin` AND having -Cdebuginfo=2 // (or `-g`, the shorthand form) enabled will cause reproducibility failures. // See https://github.com/rust-lang/rust/issues/89911 if !is_darwin() && !is_windows() { // FIXME(Oneirical): Bin builds are not reproducible on non-Linux targets. eprintln!("diff_dir_test => Bin, Path"); diff_dir_test(CrateType::Bin, RemapType::Path); } eprintln!("diff_dir_test => Rlib, Path"); diff_dir_test(CrateType::Rlib, RemapType::Path); // FIXME(Oneirical): This specific case would fail on Linux, should -Cdebuginfo=2 // be added. // FIXME(Oneirical): Bin builds are not reproducible on non-Linux targets. // See https://github.com/rust-lang/rust/issues/89911 if !is_darwin() && !is_windows() { eprintln!("diff_dir_test => Bin, Cwd false"); diff_dir_test(CrateType::Bin, RemapType::Cwd { is_empty: false }); } eprintln!("diff_dir_test => Rlib, Cwd false"); diff_dir_test(CrateType::Rlib, RemapType::Cwd { is_empty: false }); eprintln!("diff_dir_test => Rlib, Cwd true"); diff_dir_test(CrateType::Rlib, RemapType::Cwd { is_empty: true }); eprintln!("final extern test"); // Builds should be reproducible when using the --extern flag. run_in_tmpdir(|| { rustc().input("reproducible-build-aux.rs").run(); rustc() .input("reproducible-build.rs") .crate_type("rlib") .extern_("reproducible_build_aux", rust_lib_name("reproducible_build_aux")) .run(); rfs::copy(rust_lib_name("reproducible_build"), rust_lib_name("foo")); rfs::copy(rust_lib_name("reproducible_build_aux"), rust_lib_name("bar")); rustc() .input("reproducible-build.rs") .crate_type("rlib") .extern_("reproducible_build_aux", rust_lib_name("bar")) .run(); assert!(rfs::read(rust_lib_name("foo")) == rfs::read(rust_lib_name("reproducible_build"))) }); } #[track_caller] fn smoke_test(flag: Option) { run_in_tmpdir(|| { rustc().input("linker.rs").opt().run(); rustc().input("reproducible-build-aux.rs").run(); let mut compiler1 = rustc(); let mut compiler2 = rustc(); if let Some(flag) = flag { match flag { SmokeFlag::Debug => { compiler1.arg("-g"); compiler2.arg("-g"); } SmokeFlag::Opt => { compiler1.opt(); compiler2.opt(); } }; }; compiler1 .input("reproducible-build.rs") .linker(&cwd().join(bin_name("linker")).display().to_string()) .run(); compiler2 .input("reproducible-build.rs") .linker(&cwd().join(bin_name("linker")).display().to_string()) .run(); diff().actual_file("linker-arguments1").expected_file("linker-arguments2").run(); }); } #[track_caller] fn paths_test(flag: PathsFlag) { run_in_tmpdir(|| { rustc().input("reproducible-build-aux.rs").run(); let mut compiler1 = rustc(); let mut compiler2 = rustc(); match flag { PathsFlag::Link => { compiler1.library_search_path("a"); compiler2.library_search_path("b"); } PathsFlag::Remap => { compiler1.arg("--remap-path-prefix=/a=/c"); compiler2.arg("--remap-path-prefix=/b=/c"); } } compiler1.input("reproducible-build.rs").crate_type("rlib").run(); rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo")); compiler2.input("reproducible-build.rs").crate_type("rlib").run(); assert!(rfs::read(rust_lib_name("foo")) == rfs::read(rust_lib_name("reproducible_build"))) }); } #[track_caller] fn diff_dir_test(crate_type: CrateType, remap_type: RemapType) { run_in_tmpdir(|| { let base_dir = cwd(); rustc().input("reproducible-build-aux.rs").run(); rfs::create_dir("test"); rfs::copy("reproducible-build.rs", "test/reproducible-build.rs"); let mut compiler1 = rustc(); let mut compiler2 = rustc(); match crate_type { CrateType::Bin => { compiler1.crate_type("bin"); compiler2.crate_type("bin"); } CrateType::Rlib => { compiler1.crate_type("rlib"); compiler2.crate_type("rlib"); } } match remap_type { RemapType::Path => { compiler1.arg(&format!("--remap-path-prefix={}=/b", cwd().display())); compiler2 .arg(format!("--remap-path-prefix={}=/b", base_dir.join("test").display())); } RemapType::Cwd { is_empty } => { // FIXME(Oneirical): Building with crate type set to `bin` AND having -Cdebuginfo=2 // (or `-g`, the shorthand form) enabled will cause reproducibility failures // for multiple platforms. // See https://github.com/rust-lang/rust/issues/89911 // FIXME(#129117): Windows rlib + `-Cdebuginfo=2` + `-Z remap-cwd-prefix=.` seems // to be unreproducible. if !matches!(crate_type, CrateType::Bin) && !is_windows() { compiler1.arg("-Cdebuginfo=2"); compiler2.arg("-Cdebuginfo=2"); } if is_empty { compiler1.arg("-Zremap-cwd-prefix="); compiler2.arg("-Zremap-cwd-prefix="); } else { compiler1.arg("-Zremap-cwd-prefix=."); compiler2.arg("-Zremap-cwd-prefix=."); } } } compiler1.input("reproducible-build.rs").run(); match crate_type { CrateType::Bin => { rfs::rename(bin_name("reproducible-build"), bin_name("foo")); } CrateType::Rlib => { rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo")); } } std::env::set_current_dir("test").unwrap(); compiler2 .input("reproducible-build.rs") .library_search_path(&base_dir) .out_dir(&base_dir) .run(); std::env::set_current_dir(&base_dir).unwrap(); match crate_type { CrateType::Bin => { assert!(rfs::read(bin_name("reproducible-build")) == rfs::read(bin_name("foo"))); } CrateType::Rlib => { assert!( rfs::read(rust_lib_name("foo")) == rfs::read(rust_lib_name("reproducible_build")) ); } } }); } enum SmokeFlag { Debug, Opt, } enum PathsFlag { Link, Remap, } enum CrateType { Bin, Rlib, } enum RemapType { Path, Cwd { is_empty: bool }, }