1 use super::build_sysroot;
3 use super::rustc_info::get_wrapper_file_name;
4 use super::utils::{spawn_and_wait, spawn_and_wait_with_input};
5 use build_system::SysrootKind;
9 use std::path::{Path, PathBuf};
10 use std::process::Command;
14 func: &'static dyn Fn(&TestRunner),
18 const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
23 const NO_SYSROOT_SUITE: &[TestCase] = &[
24 TestCase::new("build.mini_core", &|runner| {
26 "example/mini_core.rs",
32 &runner.target_triple,
35 TestCase::new("build.example", &|runner| {
41 &runner.target_triple,
44 TestCase::new("jit.mini_core_hello_world", &|runner| {
45 let mut jit_cmd = runner.rustc_command([
47 "-Cllvm-args=mode=jit",
49 "example/mini_core_hello_world.rs",
55 jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
56 spawn_and_wait(jit_cmd);
58 eprintln!("[JIT-lazy] mini_core_hello_world");
59 let mut jit_cmd = runner.rustc_command([
61 "-Cllvm-args=mode=jit-lazy",
63 "example/mini_core_hello_world.rs",
69 jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
70 spawn_and_wait(jit_cmd);
72 TestCase::new("aot.mini_core_hello_world", &|runner| {
74 "example/mini_core_hello_world.rs",
76 "mini_core_hello_world",
81 &runner.target_triple,
83 runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
87 const BASE_SYSROOT_SUITE: &[TestCase] = &[
88 TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
90 "example/arbitrary_self_types_pointers_and_wrappers.rs",
92 "arbitrary_self_types_pointers_and_wrappers",
96 &runner.target_triple,
98 runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
100 TestCase::new("aot.issue_91827_extern_types", &|runner| {
102 "example/issue-91827-extern-types.rs",
104 "issue_91827_extern_types",
108 &runner.target_triple,
110 runner.run_out_command("issue_91827_extern_types", []);
112 TestCase::new("build.alloc_system", &|runner| {
114 "example/alloc_system.rs",
118 &runner.target_triple,
121 TestCase::new("aot.alloc_example", &|runner| {
123 "example/alloc_example.rs",
127 &runner.target_triple,
129 runner.run_out_command("alloc_example", []);
131 TestCase::new("jit.std_example", &|runner| {
133 "-Zunstable-options",
134 "-Cllvm-args=mode=jit",
136 "example/std_example.rs",
141 eprintln!("[JIT-lazy] std_example");
143 "-Zunstable-options",
144 "-Cllvm-args=mode=jit-lazy",
146 "example/std_example.rs",
151 TestCase::new("aot.std_example", &|runner| {
153 "example/std_example.rs",
157 &runner.target_triple,
159 runner.run_out_command("std_example", ["arg"]);
161 TestCase::new("aot.dst_field_align", &|runner| {
163 "example/dst-field-align.rs",
169 &runner.target_triple,
171 runner.run_out_command("dst_field_align", []);
173 TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
175 "example/subslice-patterns-const-eval.rs",
180 &runner.target_triple,
182 runner.run_out_command("subslice-patterns-const-eval", []);
184 TestCase::new("aot.track-caller-attribute", &|runner| {
186 "example/track-caller-attribute.rs",
191 &runner.target_triple,
193 runner.run_out_command("track-caller-attribute", []);
195 TestCase::new("aot.float-minmax-pass", &|runner| {
197 "example/float-minmax-pass.rs",
202 &runner.target_triple,
204 runner.run_out_command("float-minmax-pass", []);
206 TestCase::new("aot.mod_bench", &|runner| {
208 "example/mod_bench.rs",
212 &runner.target_triple,
214 runner.run_out_command("mod_bench", []);
218 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
219 TestCase::new("test.rust-random/rand", &|runner| {
220 runner.in_dir(["rand"], |runner| {
221 runner.run_cargo(["clean"]);
223 if runner.host_triple == runner.target_triple {
224 eprintln!("[TEST] rust-random/rand");
225 runner.run_cargo(["test", "--workspace"]);
227 eprintln!("[AOT] rust-random/rand");
232 &runner.target_triple,
238 TestCase::new("bench.simple-raytracer", &|runner| {
239 runner.in_dir(["simple-raytracer"], |runner| {
240 let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string());
242 if runner.host_triple == runner.target_triple {
243 eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
244 let mut bench_compile = Command::new("hyperfine");
245 bench_compile.arg("--runs");
246 bench_compile.arg(&run_runs);
247 bench_compile.arg("--warmup");
248 bench_compile.arg("1");
249 bench_compile.arg("--prepare");
250 bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"])));
253 bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\"");
255 bench_compile.arg("RUSTFLAGS='' cargo build");
258 bench_compile.arg(format!("{:?}", runner.cargo_command(["build"])));
259 spawn_and_wait(bench_compile);
261 eprintln!("[BENCH RUN] ebobby/simple-raytracer");
262 fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
265 let mut bench_run = Command::new("hyperfine");
266 bench_run.arg("--runs");
267 bench_run.arg(&run_runs);
268 bench_run.arg(PathBuf::from("./raytracer_cg_llvm"));
269 bench_run.arg(PathBuf::from("./raytracer_cg_clif"));
270 spawn_and_wait(bench_run);
272 runner.run_cargo(["clean"]);
273 eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
274 eprintln!("[COMPILE] ebobby/simple-raytracer");
275 runner.run_cargo(["build", "--target", &runner.target_triple]);
276 eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
280 TestCase::new("test.libcore", &|runner| {
281 runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| {
282 runner.run_cargo(["clean"]);
284 if runner.host_triple == runner.target_triple {
285 runner.run_cargo(["test"]);
287 eprintln!("Cross-Compiling: Not running tests");
288 runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]);
292 TestCase::new("test.regex-shootout-regex-dna", &|runner| {
293 runner.in_dir(["regex"], |runner| {
294 runner.run_cargo(["clean"]);
296 // newer aho_corasick versions throw a deprecation warning
297 let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
299 let mut build_cmd = runner.cargo_command([
302 "shootout-regex-dna",
304 &runner.target_triple,
306 build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
307 spawn_and_wait(build_cmd);
309 if runner.host_triple == runner.target_triple {
310 let mut run_cmd = runner.cargo_command([
313 "shootout-regex-dna",
315 &runner.target_triple,
317 run_cmd.env("RUSTFLAGS", lint_rust_flags);
320 fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
321 let expected_path = PathBuf::from("examples/regexdna-output.txt");
322 let expected = fs::read_to_string(&expected_path).unwrap();
324 let output = spawn_and_wait_with_input(run_cmd, input);
325 // Make sure `[codegen mono items] start` doesn't poison the diff
328 .filter(|line| !line.contains("codegen mono items"))
329 .chain(Some("")) // This just adds the trailing newline
330 .collect::<Vec<&str>>()
333 let output_matches = expected.lines().eq(output.lines());
335 let res_path = PathBuf::from("res.txt");
336 fs::write(&res_path, &output).unwrap();
339 println!("Output files don't match!");
340 println!("Expected Output:\n{}", expected);
341 println!("Actual Output:\n{}", output);
343 let mut diff = Command::new("diff");
346 diff.arg(expected_path);
347 spawn_and_wait(diff);
350 std::process::exit(1);
355 TestCase::new("test.regex", &|runner| {
356 runner.in_dir(["regex"], |runner| {
357 runner.run_cargo(["clean"]);
359 // newer aho_corasick versions throw a deprecation warning
360 let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
362 if runner.host_triple == runner.target_triple {
363 let mut run_cmd = runner.cargo_command([
367 "--exclude-should-panic",
370 "-Zunstable-options",
373 run_cmd.env("RUSTFLAGS", lint_rust_flags);
374 spawn_and_wait(run_cmd);
376 eprintln!("Cross-Compiling: Not running tests");
378 runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]);
379 build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
380 spawn_and_wait(build_cmd);
384 TestCase::new("test.portable-simd", &|runner| {
385 runner.in_dir(["portable-simd"], |runner| {
386 runner.run_cargo(["clean"]);
387 runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]);
389 if runner.host_triple == runner.target_triple {
390 runner.run_cargo(["test", "-q"]);
396 pub(crate) fn run_tests(
398 sysroot_kind: SysrootKind,
400 cg_clif_build_dir: &Path,
404 let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
406 if config::get_bool("testsuite.no_sysroot") {
407 build_sysroot::build_sysroot(
416 let _ = fs::remove_dir_all(Path::new("target").join("out"));
417 runner.run_testsuite(NO_SYSROOT_SUITE);
419 eprintln!("[SKIP] no_sysroot tests");
422 let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
423 let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
425 if run_base_sysroot || run_extended_sysroot {
426 build_sysroot::build_sysroot(
436 if run_base_sysroot {
437 runner.run_testsuite(BASE_SYSROOT_SUITE);
439 eprintln!("[SKIP] base_sysroot tests");
442 if run_extended_sysroot {
443 runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
445 eprintln!("[SKIP] extended_sysroot tests");
454 run_wrapper: Vec<String>,
456 target_triple: String,
460 pub fn new(host_triple: String, target_triple: String) -> Self {
461 let root_dir = env::current_dir().unwrap();
463 let mut out_dir = root_dir.clone();
464 out_dir.push("target");
467 let is_native = host_triple == target_triple;
468 let jit_supported = target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
470 let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
471 let mut run_wrapper = Vec::new();
474 match target_triple.as_str() {
475 "aarch64-unknown-linux-gnu" => {
476 // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
477 rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
478 run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
480 "x86_64-pc-windows-gnu" => {
481 // We are cross-compiling for Windows. Run tests in wine.
482 run_wrapper = vec!["wine"];
485 println!("Unknown non-native platform");
490 // FIXME fix `#[linkage = "extern_weak"]` without this
491 if host_triple.contains("darwin") {
492 rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
500 run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
506 pub fn run_testsuite(&self, tests: &[TestCase]) {
507 for &TestCase { config, func } in tests {
508 let (tag, testname) = config.split_once('.').unwrap();
509 let tag = tag.to_uppercase();
510 let is_jit_test = tag == "JIT";
512 if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
513 eprintln!("[{tag}] {testname} (skipped)");
516 eprintln!("[{tag}] {testname}");
523 fn in_dir<'a, I, F>(&self, dir: I, callback: F)
525 I: IntoIterator<Item = &'a str>,
526 F: FnOnce(&TestRunner),
528 let current = env::current_dir().unwrap();
529 let mut new = current.clone();
534 env::set_current_dir(new).unwrap();
536 env::set_current_dir(current).unwrap();
539 fn rustc_command<I, S>(&self, args: I) -> Command
541 I: IntoIterator<Item = S>,
544 let mut rustc_clif = self.root_dir.clone();
545 rustc_clif.push("build");
546 rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
548 let mut cmd = Command::new(rustc_clif);
549 cmd.args(self.rust_flags.split_whitespace());
551 cmd.arg(format!("crate={}", self.out_dir.display()));
552 cmd.arg("--out-dir");
553 cmd.arg(format!("{}", self.out_dir.display()));
554 cmd.arg("-Cdebuginfo=2");
559 fn run_rustc<I, S>(&self, args: I)
561 I: IntoIterator<Item = S>,
564 spawn_and_wait(self.rustc_command(args));
567 fn run_out_command<'a, I>(&self, name: &str, args: I)
569 I: IntoIterator<Item = &'a str>,
571 let mut full_cmd = vec![];
573 // Prepend the RUN_WRAPPER's
574 if !self.run_wrapper.is_empty() {
575 full_cmd.extend(self.run_wrapper.iter().cloned());
579 let mut out_path = self.out_dir.clone();
581 out_path.to_str().unwrap().to_string()
584 for arg in args.into_iter() {
585 full_cmd.push(arg.to_string());
588 let mut cmd_iter = full_cmd.into_iter();
589 let first = cmd_iter.next().unwrap();
591 let mut cmd = Command::new(first);
597 fn cargo_command<I, S>(&self, args: I) -> Command
599 I: IntoIterator<Item = S>,
602 let mut cargo_clif = self.root_dir.clone();
603 cargo_clif.push("build");
604 cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
606 let mut cmd = Command::new(cargo_clif);
608 cmd.env("RUSTFLAGS", &self.rust_flags);
612 fn run_cargo<'a, I>(&self, args: I)
614 I: IntoIterator<Item = &'a str>,
616 spawn_and_wait(self.cargo_command(args));