pub fn build(file: &str) -> Result<String, String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
let prog = crate::compile(&src)?;
let (nfns, nops) = (prog.functions.len(), prog.main.ops.len());
crate::cache::store(&src, &prog)?;
crate::cache::flush();
let stem = std::path::Path::new(file)
.file_stem()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_else(|| "a.out".into());
let out = std::path::Path::new(file)
.parent()
.unwrap_or_else(|| std::path::Path::new("."))
.join(&stem);
crate::aot_native::emit_executable(&prog, &out)?;
Ok(format!(
"built {file}: {nops} top-level ops, {nfns} functions -> {} (+ ~/.node-js/scripts.rkyv)",
out.display()
))
}