//! This file will run at build time to autogenerate the Emscripten tests //! It will compile the files indicated in TESTS, to:executable and .wasm //! - Compile using cc and get the output from it (expected output) //! - Compile using emcc and get the .wasm from it (wasm) //! - Generate the test that will compare the output of running the .wasm file //! with wasmer with the expected output use std::fs; use std::path::PathBuf; use std::process::Command; static BANNER: &str = "// Rust test file autogenerated with cargo build (build/emtests.rs). // Please do NOT modify it by hand, as it will be reseted on next build.\n"; const TESTS: [&str; 2] = [ "emtests/puts.c", "emtests/printf.c" ]; pub fn compile(file: &str) -> String { let mut output_path = PathBuf::from(file); output_path.set_extension("out"); let output_str = output_path.to_str().unwrap(); // Compile to .out Command::new("cc") .arg(file) .arg("-o") .arg(output_str) .output() .expect("failed to execute process"); // Get the result of .out let output = Command::new(output_str) .arg(output_str) .output() .expect("failed to execute process"); // Remove executable fs::remove_file(output_str).unwrap(); let mut output_path = PathBuf::from(file); output_path.set_extension("js"); let output_str = output_path.to_str().unwrap(); // Compile to wasm let _wasm_compilation = Command::new("emcc") .arg(file) .arg("-s").arg("WASM=1") .arg("-o") .arg(output_str) .output() .expect("failed to execute process"); // panic!("{:?}", wasm_compilation); // if output.stderr { // panic!("{}", output.stderr); // } // Remove js file fs::remove_file(output_str).unwrap(); let mut output_path = PathBuf::from(file); output_path.set_extension("output"); let module_name = output_path.file_stem().unwrap().to_str().unwrap().to_owned(); let output_str = output_path.to_str().unwrap(); // Write the output to file fs::write(output_str, output.stdout).expect("Unable to write file"); let rust_test_filepath = format!( concat!(env!("CARGO_MANIFEST_DIR"), "/src/emtests/{}.rs"), module_name.as_str() ); let contents = format!("#[test] fn test_{module_name}() {{ assert_emscripten_output!(\"../../emtests/{module_name}.wasm\", \"{module_name}\", vec![], \"../../emtests/{module_name}.output\"); }} ", module_name=module_name); fs::write(&rust_test_filepath, contents.as_bytes()).unwrap(); module_name // panic!("OUTPUT: {:?}", output); } pub fn build() { let rust_test_modpath = concat!(env!("CARGO_MANIFEST_DIR"), "/src/emtests/mod.rs"); let mut modules: Vec = Vec::new(); // modules.reserve_exact(TESTS.len()); for test in TESTS.iter() { let moudle_name = compile(test); modules.push(format!("mod {};", moudle_name)); } modules.insert(0, BANNER.to_string()); modules.insert(1, "// The _common module is not autogenerated, as it provides common macros for the emtests\n#[macro_use]\nmod _common;".to_string()); // We add an empty line modules.push("".to_string()); let modfile: String = modules.join("\n"); let source = fs::read(&rust_test_modpath).unwrap(); // We only modify the mod file if has changed if source != modfile.as_bytes() { fs::write(&rust_test_modpath, modfile.as_bytes()).unwrap(); } }