use regex::Regex; use std::{ env, fs::File, io::Write, path::Path, process::{Command, Stdio}, }; fn main() { const FILE: &str = "src/codegen/irrt/irrt.c"; /* * HACK: Sadly, clang doesn't let us emit generic LLVM bitcode. * Compiling for WASM32 and filtering the output with regex is the closest we can get. */ let flags: &[&str] = &[ "--target=wasm32", FILE, "-fno-discard-value-names", match env::var("PROFILE").as_deref() { Ok("debug") => "-O0", Ok("release") => "-O3", flavor => panic!("Unknown or missing build flavor {flavor:?}"), }, "-emit-llvm", "-S", "-Wall", "-Wextra", "-o", "-", ]; println!("cargo:rerun-if-changed={FILE}"); let out_dir = env::var("OUT_DIR").unwrap(); let out_path = Path::new(&out_dir); let output = Command::new("clang-irrt") .args(flags) .output() .map(|o| { assert!(o.status.success(), "{}", std::str::from_utf8(&o.stderr).unwrap()); o }) .unwrap(); // https://github.com/rust-lang/regex/issues/244 let output = std::str::from_utf8(&output.stdout).unwrap().replace("\r\n", "\n"); let mut filtered_output = String::with_capacity(output.len()); let regex_filter = Regex::new(r"(?ms:^define.*?\}$)|(?m:^declare.*?$)").unwrap(); for f in regex_filter.captures_iter(&output) { assert_eq!(f.len(), 1); filtered_output.push_str(&f[0]); filtered_output.push('\n'); } let filtered_output = Regex::new("(#\\d+)|(, *![0-9A-Za-z.]+)|(![0-9A-Za-z.]+)|(!\".*?\")") .unwrap() .replace_all(&filtered_output, ""); println!("cargo:rerun-if-env-changed=DEBUG_DUMP_IRRT"); if env::var("DEBUG_DUMP_IRRT").is_ok() { let mut file = File::create(out_path.join("irrt.ll")).unwrap(); file.write_all(output.as_bytes()).unwrap(); let mut file = File::create(out_path.join("irrt-filtered.ll")).unwrap(); file.write_all(filtered_output.as_bytes()).unwrap(); } let mut llvm_as = Command::new("llvm-as-irrt") .stdin(Stdio::piped()) .arg("-o") .arg(out_path.join("irrt.bc")) .spawn() .unwrap(); llvm_as.stdin.as_mut().unwrap().write_all(filtered_output.as_bytes()).unwrap(); assert!(llvm_as.wait().unwrap().success()); }