Skip to main content

nodejs/
aot.rs

1//! Ahead-of-time compilation (`node --build`).
2//!
3//! Precompiles the script to fusevm bytecode, warms the on-disk cache
4//! (`cache.rs`) so subsequent runs skip lex/parse/lower, and — via fusevm's `aot`
5//! feature (a native-object emitter linked against the node-js `staticlib`) —
6//! emits a standalone native executable that carries the node-js builtin dispatch
7//! and the fusevm AOT runtime. The report below is explicit user-requested
8//! output.
9
10/// Precompile `file` to a standalone native executable next to the source, and
11/// warm the bytecode cache. Returns a one-line report of what was built.
12pub fn build(file: &str) -> Result<String, String> {
13    let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
14    let prog = crate::compile(&src)?;
15    let (nfns, nops) = (prog.functions.len(), prog.main.ops.len());
16    crate::cache::store(&src, &prog)?;
17    // `--build` warms the shard for later runs, so it must reach disk here
18    // rather than at the end of an ordinary run.
19    crate::cache::flush();
20
21    // Emit the native object + link a standalone executable. The output path is
22    // the source stem (`foo.js` -> `foo`).
23    let stem = std::path::Path::new(file)
24        .file_stem()
25        .map(|s| s.to_string_lossy().into_owned())
26        .unwrap_or_else(|| "a.out".into());
27    let out = std::path::Path::new(file)
28        .parent()
29        .unwrap_or_else(|| std::path::Path::new("."))
30        .join(&stem);
31    crate::aot_native::emit_executable(&prog, &out)?;
32
33    Ok(format!(
34        "built {file}: {nops} top-level ops, {nfns} functions -> {} (+ ~/.node-js/scripts.rkyv)",
35        out.display()
36    ))
37}