|
1 |
| -//! Build program to generate a program which runs all the testsuites. |
2 |
| -//! |
3 |
| -//! By generating a separate `#[test]` test for each file, we allow cargo test |
4 |
| -//! to automatically run the files in parallel. |
5 |
| -
|
6 |
| -use anyhow::Context; |
7 | 1 | use std::env;
|
8 |
| -use std::fmt::Write; |
9 |
| -use std::fs; |
10 |
| -use std::path::{Path, PathBuf}; |
| 2 | +use std::path::Path; |
11 | 3 | use std::process::Command;
|
12 | 4 |
|
13 |
| -fn main() -> anyhow::Result<()> { |
| 5 | +fn main() { |
14 | 6 | println!("cargo:rerun-if-changed=build.rs");
|
15 | 7 |
|
16 | 8 | set_commit_info_for_rustc();
|
17 |
| - |
18 |
| - let out_dir = PathBuf::from( |
19 |
| - env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"), |
20 |
| - ); |
21 |
| - let mut out = String::new(); |
22 |
| - |
23 |
| - for strategy in &["Cranelift", "Winch"] { |
24 |
| - writeln!(out, "#[cfg(test)]")?; |
25 |
| - writeln!(out, "#[allow(non_snake_case)]")?; |
26 |
| - if *strategy == "Winch" { |
27 |
| - // We only test Winch on x86_64, for now. |
28 |
| - writeln!(out, "{}", "#[cfg(all(target_arch = \"x86_64\"))]")?; |
29 |
| - } |
30 |
| - writeln!(out, "mod {} {{", strategy)?; |
31 |
| - |
32 |
| - with_test_module(&mut out, "misc", |out| { |
33 |
| - test_directory(out, "tests/misc_testsuite", strategy)?; |
34 |
| - test_directory_module(out, "tests/misc_testsuite/multi-memory", strategy)?; |
35 |
| - test_directory_module(out, "tests/misc_testsuite/simd", strategy)?; |
36 |
| - test_directory_module(out, "tests/misc_testsuite/tail-call", strategy)?; |
37 |
| - test_directory_module(out, "tests/misc_testsuite/threads", strategy)?; |
38 |
| - test_directory_module(out, "tests/misc_testsuite/memory64", strategy)?; |
39 |
| - test_directory_module(out, "tests/misc_testsuite/component-model", strategy)?; |
40 |
| - test_directory_module(out, "tests/misc_testsuite/function-references", strategy)?; |
41 |
| - test_directory_module(out, "tests/misc_testsuite/gc", strategy)?; |
42 |
| - // The testsuite of Winch is a subset of the official |
43 |
| - // WebAssembly test suite, until parity is reached. This |
44 |
| - // check is in place to prevent Cranelift from duplicating |
45 |
| - // tests. |
46 |
| - if *strategy == "Winch" { |
47 |
| - test_directory_module(out, "tests/misc_testsuite/winch", strategy)?; |
48 |
| - } |
49 |
| - Ok(()) |
50 |
| - })?; |
51 |
| - |
52 |
| - with_test_module(&mut out, "spec", |out| { |
53 |
| - let spec_tests = test_directory(out, "tests/spec_testsuite", strategy)?; |
54 |
| - // Skip running spec_testsuite tests if the submodule isn't checked |
55 |
| - // out. |
56 |
| - if spec_tests > 0 { |
57 |
| - test_directory_module(out, "tests/spec_testsuite/proposals/memory64", strategy)?; |
58 |
| - test_directory_module( |
59 |
| - out, |
60 |
| - "tests/spec_testsuite/proposals/function-references", |
61 |
| - strategy, |
62 |
| - )?; |
63 |
| - test_directory_module(out, "tests/spec_testsuite/proposals/gc", strategy)?; |
64 |
| - test_directory_module( |
65 |
| - out, |
66 |
| - "tests/spec_testsuite/proposals/multi-memory", |
67 |
| - strategy, |
68 |
| - )?; |
69 |
| - test_directory_module(out, "tests/spec_testsuite/proposals/threads", strategy)?; |
70 |
| - test_directory_module( |
71 |
| - out, |
72 |
| - "tests/spec_testsuite/proposals/relaxed-simd", |
73 |
| - strategy, |
74 |
| - )?; |
75 |
| - test_directory_module(out, "tests/spec_testsuite/proposals/tail-call", strategy)?; |
76 |
| - } else { |
77 |
| - println!( |
78 |
| - "cargo:warning=The spec testsuite is disabled. To enable, run `git submodule \ |
79 |
| - update --remote`." |
80 |
| - ); |
81 |
| - } |
82 |
| - Ok(()) |
83 |
| - })?; |
84 |
| - |
85 |
| - writeln!(out, "}}")?; |
86 |
| - } |
87 |
| - |
88 |
| - // Write out our auto-generated tests and opportunistically format them with |
89 |
| - // `rustfmt` if it's installed. |
90 |
| - let output = out_dir.join("wast_testsuite_tests.rs"); |
91 |
| - fs::write(&output, out)?; |
92 |
| - drop(Command::new("rustfmt").arg(&output).status()); |
93 |
| - Ok(()) |
94 |
| -} |
95 |
| - |
96 |
| -fn test_directory_module( |
97 |
| - out: &mut String, |
98 |
| - path: impl AsRef<Path>, |
99 |
| - strategy: &str, |
100 |
| -) -> anyhow::Result<usize> { |
101 |
| - let path = path.as_ref(); |
102 |
| - let testsuite = &extract_name(path); |
103 |
| - with_test_module(out, testsuite, |out| test_directory(out, path, strategy)) |
104 |
| -} |
105 |
| - |
106 |
| -fn test_directory( |
107 |
| - out: &mut String, |
108 |
| - path: impl AsRef<Path>, |
109 |
| - strategy: &str, |
110 |
| -) -> anyhow::Result<usize> { |
111 |
| - let path = path.as_ref(); |
112 |
| - let mut dir_entries: Vec<_> = path |
113 |
| - .read_dir() |
114 |
| - .context(format!("failed to read {:?}", path))? |
115 |
| - .map(|r| r.expect("reading testsuite directory entry")) |
116 |
| - .filter_map(|dir_entry| { |
117 |
| - let p = dir_entry.path(); |
118 |
| - let ext = p.extension()?; |
119 |
| - // Only look at wast files. |
120 |
| - if ext != "wast" { |
121 |
| - return None; |
122 |
| - } |
123 |
| - // Ignore files starting with `.`, which could be editor temporary files |
124 |
| - if p.file_stem()?.to_str()?.starts_with('.') { |
125 |
| - return None; |
126 |
| - } |
127 |
| - Some(p) |
128 |
| - }) |
129 |
| - .collect(); |
130 |
| - |
131 |
| - dir_entries.sort(); |
132 |
| - |
133 |
| - let testsuite = &extract_name(path); |
134 |
| - for entry in dir_entries.iter() { |
135 |
| - write_testsuite_tests(out, entry, testsuite, strategy, false)?; |
136 |
| - write_testsuite_tests(out, entry, testsuite, strategy, true)?; |
137 |
| - } |
138 |
| - |
139 |
| - Ok(dir_entries.len()) |
140 |
| -} |
141 |
| - |
142 |
| -/// Extract a valid Rust identifier from the stem of a path. |
143 |
| -fn extract_name(path: impl AsRef<Path>) -> String { |
144 |
| - path.as_ref() |
145 |
| - .file_stem() |
146 |
| - .expect("filename should have a stem") |
147 |
| - .to_str() |
148 |
| - .expect("filename should be representable as a string") |
149 |
| - .replace(['-', '/'], "_") |
150 |
| -} |
151 |
| - |
152 |
| -fn with_test_module<T>( |
153 |
| - out: &mut String, |
154 |
| - testsuite: &str, |
155 |
| - f: impl FnOnce(&mut String) -> anyhow::Result<T>, |
156 |
| -) -> anyhow::Result<T> { |
157 |
| - out.push_str("mod "); |
158 |
| - out.push_str(testsuite); |
159 |
| - out.push_str(" {\n"); |
160 |
| - |
161 |
| - let result = f(out)?; |
162 |
| - |
163 |
| - out.push_str("}\n"); |
164 |
| - Ok(result) |
165 |
| -} |
166 |
| - |
167 |
| -fn write_testsuite_tests( |
168 |
| - out: &mut String, |
169 |
| - path: impl AsRef<Path>, |
170 |
| - testsuite: &str, |
171 |
| - strategy: &str, |
172 |
| - pooling: bool, |
173 |
| -) -> anyhow::Result<()> { |
174 |
| - let path = path.as_ref(); |
175 |
| - let testname = extract_name(path); |
176 |
| - |
177 |
| - writeln!(out, "#[test]")?; |
178 |
| - // Ignore when using QEMU for running tests (limited memory). |
179 |
| - if ignore(testsuite, &testname, strategy) { |
180 |
| - writeln!(out, "#[ignore]")?; |
181 |
| - } else { |
182 |
| - writeln!(out, "#[cfg_attr(miri, ignore)]")?; |
183 |
| - } |
184 |
| - |
185 |
| - writeln!( |
186 |
| - out, |
187 |
| - "fn r#{}{}() {{", |
188 |
| - &testname, |
189 |
| - if pooling { "_pooling" } else { "" } |
190 |
| - )?; |
191 |
| - writeln!(out, " let _ = env_logger::try_init();")?; |
192 |
| - writeln!( |
193 |
| - out, |
194 |
| - " crate::wast::run_wast(r#\"{}\"#, crate::wast::Strategy::{}, {}).unwrap();", |
195 |
| - path.display(), |
196 |
| - strategy, |
197 |
| - pooling, |
198 |
| - )?; |
199 |
| - writeln!(out, "}}")?; |
200 |
| - writeln!(out)?; |
201 |
| - Ok(()) |
202 |
| -} |
203 |
| - |
204 |
| -/// Ignore tests that aren't supported yet. |
205 |
| -fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool { |
206 |
| - assert!(strategy == "Cranelift" || strategy == "Winch"); |
207 |
| - |
208 |
| - // Ignore some tests for when testing Winch. |
209 |
| - if strategy == "Winch" { |
210 |
| - if testsuite == "misc_testsuite" { |
211 |
| - let denylist = [ |
212 |
| - "externref_id_function", |
213 |
| - "int_to_float_splat", |
214 |
| - "issue6562", |
215 |
| - "many_table_gets_lead_to_gc", |
216 |
| - "mutable_externref_globals", |
217 |
| - "no_mixup_stack_maps", |
218 |
| - "no_panic", |
219 |
| - "simple_ref_is_null", |
220 |
| - "table_grow_with_funcref", |
221 |
| - ]; |
222 |
| - return denylist.contains(&testname); |
223 |
| - } |
224 |
| - if testsuite == "spec_testsuite" { |
225 |
| - let denylist = [ |
226 |
| - "br_table", |
227 |
| - "global", |
228 |
| - "table_fill", |
229 |
| - "table_get", |
230 |
| - "table_set", |
231 |
| - "table_grow", |
232 |
| - "table_size", |
233 |
| - "elem", |
234 |
| - "select", |
235 |
| - "unreached_invalid", |
236 |
| - "linking", |
237 |
| - ] |
238 |
| - .contains(&testname); |
239 |
| - |
240 |
| - let ref_types = testname.starts_with("ref_"); |
241 |
| - let simd = testname.starts_with("simd_"); |
242 |
| - |
243 |
| - return denylist || ref_types || simd; |
244 |
| - } |
245 |
| - |
246 |
| - if testsuite == "memory64" { |
247 |
| - return testname.starts_with("simd") || testname.starts_with("threads"); |
248 |
| - } |
249 |
| - |
250 |
| - if testsuite != "winch" { |
251 |
| - return true; |
252 |
| - } |
253 |
| - } |
254 |
| - |
255 |
| - // This is an empty file right now which the `wast` crate doesn't parse |
256 |
| - if testname.contains("memory_copy1") { |
257 |
| - return true; |
258 |
| - } |
259 |
| - |
260 |
| - if testsuite == "gc" { |
261 |
| - if [ |
262 |
| - "array_copy", |
263 |
| - "array_fill", |
264 |
| - "array_init_data", |
265 |
| - "array_init_elem", |
266 |
| - "array", |
267 |
| - "binary_gc", |
268 |
| - "binary", |
269 |
| - "br_on_cast_fail", |
270 |
| - "br_on_cast", |
271 |
| - "br_on_non_null", |
272 |
| - "br_on_null", |
273 |
| - "br_table", |
274 |
| - "call_ref", |
275 |
| - "data", |
276 |
| - "elem", |
277 |
| - "extern", |
278 |
| - "func", |
279 |
| - "global", |
280 |
| - "if", |
281 |
| - "linking", |
282 |
| - "local_get", |
283 |
| - "local_init", |
284 |
| - "ref_as_non_null", |
285 |
| - "ref_cast", |
286 |
| - "ref_eq", |
287 |
| - "ref_is_null", |
288 |
| - "ref_null", |
289 |
| - "ref_test", |
290 |
| - "ref", |
291 |
| - "return_call_indirect", |
292 |
| - "return_call_ref", |
293 |
| - "return_call", |
294 |
| - "select", |
295 |
| - "struct", |
296 |
| - "table_sub", |
297 |
| - "table", |
298 |
| - "type_canon", |
299 |
| - "type_equivalence", |
300 |
| - "type_rec", |
301 |
| - "type_subtyping", |
302 |
| - "unreached_invalid", |
303 |
| - "unreached_valid", |
304 |
| - ] |
305 |
| - .contains(&testname) |
306 |
| - { |
307 |
| - return true; |
308 |
| - } |
309 |
| - } |
310 |
| - |
311 |
| - match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() { |
312 |
| - "s390x" => { |
313 |
| - // TODO(#6530): These tests require tail calls, but s390x |
314 |
| - // doesn't support them yet. |
315 |
| - testsuite == "function_references" || testsuite == "tail_call" |
316 |
| - } |
317 |
| - |
318 |
| - _ => false, |
319 |
| - } |
320 | 9 | }
|
321 | 10 |
|
322 | 11 | fn set_commit_info_for_rustc() {
|
|
0 commit comments