]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/build_system/tests.rs
Auto merge of #103431 - Dylan-DPC:rollup-oozfo89, r=Dylan-DPC
[rust.git] / compiler / rustc_codegen_cranelift / build_system / tests.rs
1 use super::build_sysroot;
2 use super::config;
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;
6 use std::env;
7 use std::ffi::OsStr;
8 use std::fs;
9 use std::path::{Path, PathBuf};
10 use std::process::Command;
11
12 struct TestCase {
13     config: &'static str,
14     func: &'static dyn Fn(&TestRunner),
15 }
16
17 impl TestCase {
18     const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
19         Self { config, func }
20     }
21 }
22
23 const NO_SYSROOT_SUITE: &[TestCase] = &[
24     TestCase::new("build.mini_core", &|runner| {
25         runner.run_rustc([
26             "example/mini_core.rs",
27             "--crate-name",
28             "mini_core",
29             "--crate-type",
30             "lib,dylib",
31             "--target",
32             &runner.target_triple,
33         ]);
34     }),
35     TestCase::new("build.example", &|runner| {
36         runner.run_rustc([
37             "example/example.rs",
38             "--crate-type",
39             "lib",
40             "--target",
41             &runner.target_triple,
42         ]);
43     }),
44     TestCase::new("jit.mini_core_hello_world", &|runner| {
45         let mut jit_cmd = runner.rustc_command([
46             "-Zunstable-options",
47             "-Cllvm-args=mode=jit",
48             "-Cprefer-dynamic",
49             "example/mini_core_hello_world.rs",
50             "--cfg",
51             "jit",
52             "--target",
53             &runner.host_triple,
54         ]);
55         jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
56         spawn_and_wait(jit_cmd);
57
58         eprintln!("[JIT-lazy] mini_core_hello_world");
59         let mut jit_cmd = runner.rustc_command([
60             "-Zunstable-options",
61             "-Cllvm-args=mode=jit-lazy",
62             "-Cprefer-dynamic",
63             "example/mini_core_hello_world.rs",
64             "--cfg",
65             "jit",
66             "--target",
67             &runner.host_triple,
68         ]);
69         jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
70         spawn_and_wait(jit_cmd);
71     }),
72     TestCase::new("aot.mini_core_hello_world", &|runner| {
73         runner.run_rustc([
74             "example/mini_core_hello_world.rs",
75             "--crate-name",
76             "mini_core_hello_world",
77             "--crate-type",
78             "bin",
79             "-g",
80             "--target",
81             &runner.target_triple,
82         ]);
83         runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
84     }),
85 ];
86
87 const BASE_SYSROOT_SUITE: &[TestCase] = &[
88     TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
89         runner.run_rustc([
90             "example/arbitrary_self_types_pointers_and_wrappers.rs",
91             "--crate-name",
92             "arbitrary_self_types_pointers_and_wrappers",
93             "--crate-type",
94             "bin",
95             "--target",
96             &runner.target_triple,
97         ]);
98         runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
99     }),
100     TestCase::new("aot.issue_91827_extern_types", &|runner| {
101         runner.run_rustc([
102             "example/issue-91827-extern-types.rs",
103             "--crate-name",
104             "issue_91827_extern_types",
105             "--crate-type",
106             "bin",
107             "--target",
108             &runner.target_triple,
109         ]);
110         runner.run_out_command("issue_91827_extern_types", []);
111     }),
112     TestCase::new("build.alloc_system", &|runner| {
113         runner.run_rustc([
114             "example/alloc_system.rs",
115             "--crate-type",
116             "lib",
117             "--target",
118             &runner.target_triple,
119         ]);
120     }),
121     TestCase::new("aot.alloc_example", &|runner| {
122         runner.run_rustc([
123             "example/alloc_example.rs",
124             "--crate-type",
125             "bin",
126             "--target",
127             &runner.target_triple,
128         ]);
129         runner.run_out_command("alloc_example", []);
130     }),
131     TestCase::new("jit.std_example", &|runner| {
132         runner.run_rustc([
133             "-Zunstable-options",
134             "-Cllvm-args=mode=jit",
135             "-Cprefer-dynamic",
136             "example/std_example.rs",
137             "--target",
138             &runner.host_triple,
139         ]);
140
141         eprintln!("[JIT-lazy] std_example");
142         runner.run_rustc([
143             "-Zunstable-options",
144             "-Cllvm-args=mode=jit-lazy",
145             "-Cprefer-dynamic",
146             "example/std_example.rs",
147             "--target",
148             &runner.host_triple,
149         ]);
150     }),
151     TestCase::new("aot.std_example", &|runner| {
152         runner.run_rustc([
153             "example/std_example.rs",
154             "--crate-type",
155             "bin",
156             "--target",
157             &runner.target_triple,
158         ]);
159         runner.run_out_command("std_example", ["arg"]);
160     }),
161     TestCase::new("aot.dst_field_align", &|runner| {
162         runner.run_rustc([
163             "example/dst-field-align.rs",
164             "--crate-name",
165             "dst_field_align",
166             "--crate-type",
167             "bin",
168             "--target",
169             &runner.target_triple,
170         ]);
171         runner.run_out_command("dst_field_align", []);
172     }),
173     TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
174         runner.run_rustc([
175             "example/subslice-patterns-const-eval.rs",
176             "--crate-type",
177             "bin",
178             "-Cpanic=abort",
179             "--target",
180             &runner.target_triple,
181         ]);
182         runner.run_out_command("subslice-patterns-const-eval", []);
183     }),
184     TestCase::new("aot.track-caller-attribute", &|runner| {
185         runner.run_rustc([
186             "example/track-caller-attribute.rs",
187             "--crate-type",
188             "bin",
189             "-Cpanic=abort",
190             "--target",
191             &runner.target_triple,
192         ]);
193         runner.run_out_command("track-caller-attribute", []);
194     }),
195     TestCase::new("aot.float-minmax-pass", &|runner| {
196         runner.run_rustc([
197             "example/float-minmax-pass.rs",
198             "--crate-type",
199             "bin",
200             "-Cpanic=abort",
201             "--target",
202             &runner.target_triple,
203         ]);
204         runner.run_out_command("float-minmax-pass", []);
205     }),
206     TestCase::new("aot.mod_bench", &|runner| {
207         runner.run_rustc([
208             "example/mod_bench.rs",
209             "--crate-type",
210             "bin",
211             "--target",
212             &runner.target_triple,
213         ]);
214         runner.run_out_command("mod_bench", []);
215     }),
216 ];
217
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"]);
222
223             if runner.host_triple == runner.target_triple {
224                 eprintln!("[TEST] rust-random/rand");
225                 runner.run_cargo(["test", "--workspace"]);
226             } else {
227                 eprintln!("[AOT] rust-random/rand");
228                 runner.run_cargo([
229                     "build",
230                     "--workspace",
231                     "--target",
232                     &runner.target_triple,
233                     "--tests",
234                 ]);
235             }
236         });
237     }),
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());
241
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"])));
251
252                 if cfg!(windows) {
253                     bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\"");
254                 } else {
255                     bench_compile.arg("RUSTFLAGS='' cargo build");
256                 }
257
258                 bench_compile.arg(format!("{:?}", runner.cargo_command(["build"])));
259                 spawn_and_wait(bench_compile);
260
261                 eprintln!("[BENCH RUN] ebobby/simple-raytracer");
262                 fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
263                     .unwrap();
264
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);
271             } else {
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)");
277             }
278         });
279     }),
280     TestCase::new("test.libcore", &|runner| {
281         runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| {
282             runner.run_cargo(["clean"]);
283
284             if runner.host_triple == runner.target_triple {
285                 runner.run_cargo(["test"]);
286             } else {
287                 eprintln!("Cross-Compiling: Not running tests");
288                 runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]);
289             }
290         });
291     }),
292     TestCase::new("test.regex-shootout-regex-dna", &|runner| {
293         runner.in_dir(["regex"], |runner| {
294             runner.run_cargo(["clean"]);
295
296             // newer aho_corasick versions throw a deprecation warning
297             let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
298
299             let mut build_cmd = runner.cargo_command([
300                 "build",
301                 "--example",
302                 "shootout-regex-dna",
303                 "--target",
304                 &runner.target_triple,
305             ]);
306             build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
307             spawn_and_wait(build_cmd);
308
309             if runner.host_triple == runner.target_triple {
310                 let mut run_cmd = runner.cargo_command([
311                     "run",
312                     "--example",
313                     "shootout-regex-dna",
314                     "--target",
315                     &runner.target_triple,
316                 ]);
317                 run_cmd.env("RUSTFLAGS", lint_rust_flags);
318
319                 let input =
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();
323
324                 let output = spawn_and_wait_with_input(run_cmd, input);
325                 // Make sure `[codegen mono items] start` doesn't poison the diff
326                 let output = output
327                     .lines()
328                     .filter(|line| !line.contains("codegen mono items"))
329                     .chain(Some("")) // This just adds the trailing newline
330                     .collect::<Vec<&str>>()
331                     .join("\r\n");
332
333                 let output_matches = expected.lines().eq(output.lines());
334                 if !output_matches {
335                     let res_path = PathBuf::from("res.txt");
336                     fs::write(&res_path, &output).unwrap();
337
338                     if cfg!(windows) {
339                         println!("Output files don't match!");
340                         println!("Expected Output:\n{}", expected);
341                         println!("Actual Output:\n{}", output);
342                     } else {
343                         let mut diff = Command::new("diff");
344                         diff.arg("-u");
345                         diff.arg(res_path);
346                         diff.arg(expected_path);
347                         spawn_and_wait(diff);
348                     }
349
350                     std::process::exit(1);
351                 }
352             }
353         });
354     }),
355     TestCase::new("test.regex", &|runner| {
356         runner.in_dir(["regex"], |runner| {
357             runner.run_cargo(["clean"]);
358
359             // newer aho_corasick versions throw a deprecation warning
360             let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
361
362             if runner.host_triple == runner.target_triple {
363                 let mut run_cmd = runner.cargo_command([
364                     "test",
365                     "--tests",
366                     "--",
367                     "--exclude-should-panic",
368                     "--test-threads",
369                     "1",
370                     "-Zunstable-options",
371                     "-q",
372                 ]);
373                 run_cmd.env("RUSTFLAGS", lint_rust_flags);
374                 spawn_and_wait(run_cmd);
375             } else {
376                 eprintln!("Cross-Compiling: Not running tests");
377                 let mut build_cmd =
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);
381             }
382         });
383     }),
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]);
388
389             if runner.host_triple == runner.target_triple {
390                 runner.run_cargo(["test", "-q"]);
391             }
392         });
393     }),
394 ];
395
396 pub(crate) fn run_tests(
397     channel: &str,
398     sysroot_kind: SysrootKind,
399     target_dir: &Path,
400     cg_clif_build_dir: &Path,
401     host_triple: &str,
402     target_triple: &str,
403 ) {
404     let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
405
406     if config::get_bool("testsuite.no_sysroot") {
407         build_sysroot::build_sysroot(
408             channel,
409             SysrootKind::None,
410             &target_dir,
411             cg_clif_build_dir,
412             &host_triple,
413             &target_triple,
414         );
415
416         let _ = fs::remove_dir_all(Path::new("target").join("out"));
417         runner.run_testsuite(NO_SYSROOT_SUITE);
418     } else {
419         eprintln!("[SKIP] no_sysroot tests");
420     }
421
422     let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
423     let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
424
425     if run_base_sysroot || run_extended_sysroot {
426         build_sysroot::build_sysroot(
427             channel,
428             sysroot_kind,
429             &target_dir,
430             cg_clif_build_dir,
431             &host_triple,
432             &target_triple,
433         );
434     }
435
436     if run_base_sysroot {
437         runner.run_testsuite(BASE_SYSROOT_SUITE);
438     } else {
439         eprintln!("[SKIP] base_sysroot tests");
440     }
441
442     if run_extended_sysroot {
443         runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
444     } else {
445         eprintln!("[SKIP] extended_sysroot tests");
446     }
447 }
448
449 struct TestRunner {
450     root_dir: PathBuf,
451     out_dir: PathBuf,
452     jit_supported: bool,
453     rust_flags: String,
454     run_wrapper: Vec<String>,
455     host_triple: String,
456     target_triple: String,
457 }
458
459 impl TestRunner {
460     pub fn new(host_triple: String, target_triple: String) -> Self {
461         let root_dir = env::current_dir().unwrap();
462
463         let mut out_dir = root_dir.clone();
464         out_dir.push("target");
465         out_dir.push("out");
466
467         let is_native = host_triple == target_triple;
468         let jit_supported =
469             target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
470
471         let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
472         let mut run_wrapper = Vec::new();
473
474         if !is_native {
475             match target_triple.as_str() {
476                 "aarch64-unknown-linux-gnu" => {
477                     // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
478                     rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
479                     run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
480                 }
481                 "x86_64-pc-windows-gnu" => {
482                     // We are cross-compiling for Windows. Run tests in wine.
483                     run_wrapper = vec!["wine"];
484                 }
485                 _ => {
486                     println!("Unknown non-native platform");
487                 }
488             }
489         }
490
491         // FIXME fix `#[linkage = "extern_weak"]` without this
492         if host_triple.contains("darwin") {
493             rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
494         }
495
496         Self {
497             root_dir,
498             out_dir,
499             jit_supported,
500             rust_flags,
501             run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
502             host_triple,
503             target_triple,
504         }
505     }
506
507     pub fn run_testsuite(&self, tests: &[TestCase]) {
508         for &TestCase { config, func } in tests {
509             let (tag, testname) = config.split_once('.').unwrap();
510             let tag = tag.to_uppercase();
511             let is_jit_test = tag == "JIT";
512
513             if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
514                 eprintln!("[{tag}] {testname} (skipped)");
515                 continue;
516             } else {
517                 eprintln!("[{tag}] {testname}");
518             }
519
520             func(self);
521         }
522     }
523
524     fn in_dir<'a, I, F>(&self, dir: I, callback: F)
525     where
526         I: IntoIterator<Item = &'a str>,
527         F: FnOnce(&TestRunner),
528     {
529         let current = env::current_dir().unwrap();
530         let mut new = current.clone();
531         for d in dir {
532             new.push(d);
533         }
534
535         env::set_current_dir(new).unwrap();
536         callback(self);
537         env::set_current_dir(current).unwrap();
538     }
539
540     fn rustc_command<I, S>(&self, args: I) -> Command
541     where
542         I: IntoIterator<Item = S>,
543         S: AsRef<OsStr>,
544     {
545         let mut rustc_clif = self.root_dir.clone();
546         rustc_clif.push("build");
547         rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
548
549         let mut cmd = Command::new(rustc_clif);
550         cmd.args(self.rust_flags.split_whitespace());
551         cmd.arg("-L");
552         cmd.arg(format!("crate={}", self.out_dir.display()));
553         cmd.arg("--out-dir");
554         cmd.arg(format!("{}", self.out_dir.display()));
555         cmd.arg("-Cdebuginfo=2");
556         cmd.args(args);
557         cmd
558     }
559
560     fn run_rustc<I, S>(&self, args: I)
561     where
562         I: IntoIterator<Item = S>,
563         S: AsRef<OsStr>,
564     {
565         spawn_and_wait(self.rustc_command(args));
566     }
567
568     fn run_out_command<'a, I>(&self, name: &str, args: I)
569     where
570         I: IntoIterator<Item = &'a str>,
571     {
572         let mut full_cmd = vec![];
573
574         // Prepend the RUN_WRAPPER's
575         if !self.run_wrapper.is_empty() {
576             full_cmd.extend(self.run_wrapper.iter().cloned());
577         }
578
579         full_cmd.push({
580             let mut out_path = self.out_dir.clone();
581             out_path.push(name);
582             out_path.to_str().unwrap().to_string()
583         });
584
585         for arg in args.into_iter() {
586             full_cmd.push(arg.to_string());
587         }
588
589         let mut cmd_iter = full_cmd.into_iter();
590         let first = cmd_iter.next().unwrap();
591
592         let mut cmd = Command::new(first);
593         cmd.args(cmd_iter);
594
595         spawn_and_wait(cmd);
596     }
597
598     fn cargo_command<I, S>(&self, args: I) -> Command
599     where
600         I: IntoIterator<Item = S>,
601         S: AsRef<OsStr>,
602     {
603         let mut cargo_clif = self.root_dir.clone();
604         cargo_clif.push("build");
605         cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
606
607         let mut cmd = Command::new(cargo_clif);
608         cmd.args(args);
609         cmd.env("RUSTFLAGS", &self.rust_flags);
610         cmd
611     }
612
613     fn run_cargo<'a, I>(&self, args: I)
614     where
615         I: IntoIterator<Item = &'a str>,
616     {
617         spawn_and_wait(self.cargo_command(args));
618     }
619 }