]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_codegen_cranelift/build_system/tests.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_codegen_cranelift / build_system / tests.rs
1 use super::build_sysroot;
2 use super::config;
3 use super::path::{Dirs, RelPath};
4 use super::prepare::GitRepo;
5 use super::rustc_info::get_host_triple;
6 use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
7 use super::SysrootKind;
8 use std::env;
9 use std::ffi::OsStr;
10 use std::fs;
11 use std::path::Path;
12 use std::process::Command;
13
14 static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
15
16 struct TestCase {
17 config: &'static str,
18 cmd: TestCaseCmd,
19 }
20
21 enum TestCaseCmd {
22 Custom { func: &'static dyn Fn(&TestRunner) },
23 BuildLib { source: &'static str, crate_types: &'static str },
24 BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
25 JitBin { source: &'static str, args: &'static str },
26 }
27
28 impl TestCase {
29 // FIXME reduce usage of custom test case commands
30 const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
31 Self { config, cmd: TestCaseCmd::Custom { func } }
32 }
33
34 const fn build_lib(
35 config: &'static str,
36 source: &'static str,
37 crate_types: &'static str,
38 ) -> Self {
39 Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } }
40 }
41
42 const fn build_bin_and_run(
43 config: &'static str,
44 source: &'static str,
45 args: &'static [&'static str],
46 ) -> Self {
47 Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } }
48 }
49
50 const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self {
51 Self { config, cmd: TestCaseCmd::JitBin { source, args } }
52 }
53 }
54
55 const NO_SYSROOT_SUITE: &[TestCase] = &[
56 TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"),
57 TestCase::build_lib("build.example", "example/example.rs", "lib"),
58 TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"),
59 TestCase::build_bin_and_run(
60 "aot.mini_core_hello_world",
61 "example/mini_core_hello_world.rs",
62 &["abc", "bcd"],
63 ),
64 ];
65
66 const BASE_SYSROOT_SUITE: &[TestCase] = &[
67 TestCase::build_bin_and_run(
68 "aot.arbitrary_self_types_pointers_and_wrappers",
69 "example/arbitrary_self_types_pointers_and_wrappers.rs",
70 &[],
71 ),
72 TestCase::build_bin_and_run(
73 "aot.issue_91827_extern_types",
74 "example/issue-91827-extern-types.rs",
75 &[],
76 ),
77 TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
78 TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
79 TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
80 TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
81 TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
82 TestCase::build_bin_and_run(
83 "aot.subslice-patterns-const-eval",
84 "example/subslice-patterns-const-eval.rs",
85 &[],
86 ),
87 TestCase::build_bin_and_run(
88 "aot.track-caller-attribute",
89 "example/track-caller-attribute.rs",
90 &[],
91 ),
92 TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
93 TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
94 TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
95 ];
96
97 // FIXME(rust-random/rand#1293): Newer rand versions fail to test on Windows. Update once this is
98 // fixed.
99 pub(crate) static RAND_REPO: GitRepo =
100 GitRepo::github("rust-random", "rand", "50b9a447410860af8d6db9a208c3576886955874", "rand");
101
102 pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
103
104 pub(crate) static REGEX_REPO: GitRepo =
105 GitRepo::github("rust-lang", "regex", "a9b2e02352db92ce1f6e5b7ecd41b8bbffbe161a", "regex");
106
107 pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
108
109 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
110 "rust-lang",
111 "portable-simd",
112 "9bd30e77b3a3c699af102ebb3df0f6110f8aa02e",
113 "portable-simd",
114 );
115
116 pub(crate) static PORTABLE_SIMD: CargoProject =
117 CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
118
119 pub(crate) static LIBCORE_TESTS_SRC: RelPath = RelPath::DOWNLOAD.join("coretests_src");
120
121 pub(crate) static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "core_tests");
122
123 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
124 TestCase::custom("test.rust-random/rand", &|runner| {
125 RAND.clean(&runner.dirs);
126
127 if runner.is_native {
128 let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
129 test_cmd.arg("--workspace").arg("--").arg("-q");
130 spawn_and_wait(test_cmd);
131 } else {
132 eprintln!("Cross-Compiling: Not running tests");
133 let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
134 build_cmd.arg("--workspace").arg("--tests");
135 spawn_and_wait(build_cmd);
136 }
137 }),
138 TestCase::custom("test.libcore", &|runner| {
139 LIBCORE_TESTS.clean(&runner.dirs);
140
141 if runner.is_native {
142 let mut test_cmd = LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs);
143 test_cmd.arg("--").arg("-q");
144 spawn_and_wait(test_cmd);
145 } else {
146 eprintln!("Cross-Compiling: Not running tests");
147 let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
148 build_cmd.arg("--tests");
149 spawn_and_wait(build_cmd);
150 }
151 }),
152 TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
153 REGEX.clean(&runner.dirs);
154
155 let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
156 build_cmd.arg("--example").arg("shootout-regex-dna");
157 spawn_and_wait(build_cmd);
158
159 if runner.is_native {
160 let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
161 run_cmd.arg("--example").arg("shootout-regex-dna");
162
163 let input = fs::read_to_string(
164 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
165 )
166 .unwrap();
167 let expected = fs::read_to_string(
168 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
169 )
170 .unwrap();
171
172 let output = spawn_and_wait_with_input(run_cmd, input);
173
174 let output_matches = expected.lines().eq(output.lines());
175 if !output_matches {
176 println!("Output files don't match!");
177 println!("Expected Output:\n{}", expected);
178 println!("Actual Output:\n{}", output);
179
180 std::process::exit(1);
181 }
182 }
183 }),
184 TestCase::custom("test.regex", &|runner| {
185 REGEX.clean(&runner.dirs);
186
187 if runner.is_native {
188 let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
189 run_cmd.args(["--workspace", "--", "-q"]);
190 spawn_and_wait(run_cmd);
191 } else {
192 eprintln!("Cross-Compiling: Not running tests");
193 let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
194 build_cmd.arg("--tests");
195 spawn_and_wait(build_cmd);
196 }
197 }),
198 TestCase::custom("test.portable-simd", &|runner| {
199 PORTABLE_SIMD.clean(&runner.dirs);
200
201 let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
202 build_cmd.arg("--all-targets");
203 spawn_and_wait(build_cmd);
204
205 if runner.is_native {
206 let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
207 test_cmd.arg("-q");
208 spawn_and_wait(test_cmd);
209 }
210 }),
211 ];
212
213 pub(crate) fn run_tests(
214 dirs: &Dirs,
215 channel: &str,
216 sysroot_kind: SysrootKind,
217 cg_clif_dylib: &Path,
218 bootstrap_host_compiler: &Compiler,
219 target_triple: String,
220 ) {
221 if config::get_bool("testsuite.no_sysroot") {
222 let target_compiler = build_sysroot::build_sysroot(
223 dirs,
224 channel,
225 SysrootKind::None,
226 cg_clif_dylib,
227 bootstrap_host_compiler,
228 target_triple.clone(),
229 );
230
231 let runner =
232 TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
233
234 BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
235 runner.run_testsuite(NO_SYSROOT_SUITE);
236 } else {
237 eprintln!("[SKIP] no_sysroot tests");
238 }
239
240 let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
241 let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
242
243 if run_base_sysroot || run_extended_sysroot {
244 let target_compiler = build_sysroot::build_sysroot(
245 dirs,
246 channel,
247 sysroot_kind,
248 cg_clif_dylib,
249 bootstrap_host_compiler,
250 target_triple.clone(),
251 );
252
253 let runner =
254 TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
255
256 if run_base_sysroot {
257 runner.run_testsuite(BASE_SYSROOT_SUITE);
258 } else {
259 eprintln!("[SKIP] base_sysroot tests");
260 }
261
262 if run_extended_sysroot {
263 runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
264 } else {
265 eprintln!("[SKIP] extended_sysroot tests");
266 }
267 }
268 }
269
270 struct TestRunner {
271 is_native: bool,
272 jit_supported: bool,
273 dirs: Dirs,
274 target_compiler: Compiler,
275 }
276
277 impl TestRunner {
278 pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
279 if let Ok(rustflags) = env::var("RUSTFLAGS") {
280 target_compiler.rustflags.push(' ');
281 target_compiler.rustflags.push_str(&rustflags);
282 }
283 if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
284 target_compiler.rustdocflags.push(' ');
285 target_compiler.rustdocflags.push_str(&rustdocflags);
286 }
287
288 // FIXME fix `#[linkage = "extern_weak"]` without this
289 if target_compiler.triple.contains("darwin") {
290 target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
291 }
292
293 let jit_supported = is_native
294 && target_compiler.triple.contains("x86_64")
295 && !target_compiler.triple.contains("windows");
296
297 Self { is_native, jit_supported, dirs, target_compiler }
298 }
299
300 pub fn run_testsuite(&self, tests: &[TestCase]) {
301 for TestCase { config, cmd } in tests {
302 let (tag, testname) = config.split_once('.').unwrap();
303 let tag = tag.to_uppercase();
304 let is_jit_test = tag == "JIT";
305
306 if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
307 eprintln!("[{tag}] {testname} (skipped)");
308 continue;
309 } else {
310 eprintln!("[{tag}] {testname}");
311 }
312
313 match *cmd {
314 TestCaseCmd::Custom { func } => func(self),
315 TestCaseCmd::BuildLib { source, crate_types } => {
316 self.run_rustc([source, "--crate-type", crate_types]);
317 }
318 TestCaseCmd::BuildBinAndRun { source, args } => {
319 self.run_rustc([source]);
320 self.run_out_command(
321 source.split('/').last().unwrap().split('.').next().unwrap(),
322 args,
323 );
324 }
325 TestCaseCmd::JitBin { source, args } => {
326 let mut jit_cmd = self.rustc_command([
327 "-Zunstable-options",
328 "-Cllvm-args=mode=jit",
329 "-Cprefer-dynamic",
330 source,
331 "--cfg",
332 "jit",
333 ]);
334 if !args.is_empty() {
335 jit_cmd.env("CG_CLIF_JIT_ARGS", args);
336 }
337 spawn_and_wait(jit_cmd);
338
339 eprintln!("[JIT-lazy] {testname}");
340 let mut jit_cmd = self.rustc_command([
341 "-Zunstable-options",
342 "-Cllvm-args=mode=jit-lazy",
343 "-Cprefer-dynamic",
344 source,
345 "--cfg",
346 "jit",
347 ]);
348 if !args.is_empty() {
349 jit_cmd.env("CG_CLIF_JIT_ARGS", args);
350 }
351 spawn_and_wait(jit_cmd);
352 }
353 }
354 }
355 }
356
357 #[must_use]
358 fn rustc_command<I, S>(&self, args: I) -> Command
359 where
360 I: IntoIterator<Item = S>,
361 S: AsRef<OsStr>,
362 {
363 let mut cmd = Command::new(&self.target_compiler.rustc);
364 cmd.args(self.target_compiler.rustflags.split_whitespace());
365 cmd.arg("-L");
366 cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
367 cmd.arg("--out-dir");
368 cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
369 cmd.arg("-Cdebuginfo=2");
370 cmd.arg("--target");
371 cmd.arg(&self.target_compiler.triple);
372 cmd.arg("-Cpanic=abort");
373 cmd.args(args);
374 cmd
375 }
376
377 fn run_rustc<I, S>(&self, args: I)
378 where
379 I: IntoIterator<Item = S>,
380 S: AsRef<OsStr>,
381 {
382 spawn_and_wait(self.rustc_command(args));
383 }
384
385 fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
386 let mut full_cmd = vec![];
387
388 // Prepend the RUN_WRAPPER's
389 if !self.target_compiler.runner.is_empty() {
390 full_cmd.extend(self.target_compiler.runner.iter().cloned());
391 }
392
393 full_cmd.push(
394 BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
395 );
396
397 for arg in args {
398 full_cmd.push(arg.to_string());
399 }
400
401 let mut cmd_iter = full_cmd.into_iter();
402 let first = cmd_iter.next().unwrap();
403
404 let mut cmd = Command::new(first);
405 cmd.args(cmd_iter);
406
407 spawn_and_wait(cmd);
408 }
409 }