use std::fmt::Write; use std::path::PathBuf; use std::process::Command; use std::str::FromStr; use std::{env, fs}; const BENCHMARKS: &[&str] = &[ "src/ud/libud.c", // "src/wikisort/libwikisort.c", Error: undefined reference to rand_beebs "src/nbody/nbody.c", "src/edn/libedn.c", "src/st/libst.c", "src/aha-mont64/mont64.c", "src/matmult-int/matmult-int.c", "src/slre/libslre.c", "src/tarfind/tarfind.c", "src/sglib-combined/combined.c", "src/huffbench/libhuffbench.c", "src/nsichneu/libnsichneu.c", "src/minver/libminver.c", "src/statemate/libstatemate.c", "src/crc32/crc_32.c", "src/picojpeg/libpicojpeg.c", "src/cubic/basicmath_small.c", "src/md5sum/md5.c", "src/qrduino/qrtest.c", "src/nettle-aes/nettle-aes.c", "src/primecount/primecount.c", "src/nettle-sha256/nettle-sha256.c", ]; fn main() { println!("cargo:rerun-if-changed=build.rs"); let out_dir = env::var("OUT_DIR").unwrap(); Command::new("git") .args(&["clone", "https://github.com/embench/embench-iot"]) .current_dir(&out_dir) .spawn() .unwrap() .wait() .unwrap(); let embench_dir = PathBuf::from_str(&format!("{out_dir}/embench-iot")).unwrap(); let mut generated_code = String::new(); let mut benchmark_functions = vec![]; for &benchmark_file in BENCHMARKS { let path = embench_dir.join(benchmark_file); let dir = path.parent().unwrap(); let benchmark_name = dir.file_name().unwrap().to_string_lossy(); let (wrapper_path, function_name) = make_wrapper(&benchmark_name, &out_dir); cc::Build::new() .include(embench_dir.join("support")) .include(dir) .file(&path) .file(&wrapper_path) .define("CPU_MHZ", "2700") // FIXME: Use correct CPU frequency .compile(&format!("libembench_{benchmark_name}.a")); write!( generated_code, r#" unsafe extern "C" {{ fn {function_name}(); }}"# ) .unwrap(); benchmark_functions.push(function_name); } writeln!(generated_code, "#[allow(non_camel_case_types)] pub enum Benchmark {{").unwrap(); for benchmark_name in &benchmark_functions { writeln!(generated_code, " {benchmark_name},").unwrap(); } writeln!(generated_code, "}}").unwrap(); writeln!(generated_code, "pub unsafe fn run(benchmark: Benchmark) {{").unwrap(); writeln!(generated_code, "match benchmark {{").unwrap(); for benchmark_name in benchmark_functions { writeln!(generated_code, " Benchmark::{benchmark_name} => unsafe {{ {benchmark_name}() }},").unwrap(); } writeln!(generated_code, "}}").unwrap(); writeln!(generated_code, "}}").unwrap(); fs::write(&format!("{out_dir}/libembench-sys.rs"), generated_code).unwrap(); } fn make_wrapper(benchmark_name: &str, out_dir: &str) -> (PathBuf, String) { let benchmark_name = benchmark_name.replace("-", "_"); let function_name = format!("benchmark_{benchmark_name}"); let code = format!( r#" extern int benchmark(void); void {function_name}(void) {{ benchmark(); }} "# ); let path = PathBuf::from(out_dir).join(&format!("{benchmark_name}_wrapper.c")); fs::write(&path, code).unwrap(); (path, function_name) }