1use crate::compiler::Program;
18use crate::host::{self, FuncDef, TryDef};
19use fusevm::VM;
20use std::path::{Path, PathBuf};
21use std::sync::Arc;
22
23const PROG_IMAGE_TAG: &str = "\u{1}node-js-prog-image:";
25
26#[derive(serde::Serialize, serde::Deserialize)]
27struct ProgImage {
28 functions: Vec<FuncDef>,
29 tries: Vec<TryDef>,
30}
31
32pub fn emit_executable(prog: &Program, out: &Path) -> Result<(), String> {
34 let obj = std::env::temp_dir().join("node_js_aot.o");
35 emit_object(prog, &obj)?;
36
37 let main_c = std::env::temp_dir().join("node_js_aot_main.c");
38 std::fs::write(
39 &main_c,
40 "extern long fusevm_aot_run_embedded(void);\n\
41 int main(void) { return (int)fusevm_aot_run_embedded(); }\n",
42 )
43 .map_err(|e| e.to_string())?;
44
45 let lib = staticlib_path()?;
46 let mut cmd = std::process::Command::new("cc");
47 cmd.arg(&main_c).arg(&obj).arg(&lib).arg("-o").arg(out);
48 if cfg!(target_os = "macos") {
49 cmd.args([
50 "-framework",
58 "CoreFoundation",
59 "-framework",
60 "Security",
61 "-liconv",
62 "-lc++",
63 ]);
64 } else {
65 cmd.args(["-lpthread", "-ldl", "-lm", "-lrt"]);
66 }
67 let status = cmd.status().map_err(|e| format!("cc: {e}"))?;
68 if !status.success() {
69 return Err(format!("link failed (cc exit {:?})", status.code()));
70 }
71 Ok(())
72}
73
74fn emit_object(prog: &Program, obj: &Path) -> Result<(), String> {
76 let mut chunk = prog.main.clone();
77 let image = ProgImage {
78 functions: prog.functions.iter().map(|(_, f)| f.clone()).collect(),
79 tries: prog.tries.clone(),
80 };
81 let json = serde_json::to_string(&image).map_err(|e| e.to_string())?;
82 chunk.names.push(format!("{PROG_IMAGE_TAG}{json}"));
83 fusevm::aot::compile_object(&chunk, obj).map_err(|e| format!("node-js --build: {e}"))
84}
85
86fn staticlib_path() -> Result<PathBuf, String> {
89 if let Ok(p) = std::env::var("NODE_JS_STATICLIB") {
90 return Ok(PathBuf::from(p));
91 }
92 let exe = std::env::current_exe().map_err(|e| e.to_string())?;
93 let lib = exe.parent().ok_or("no exe dir")?.join("libnodejs.a");
94 if lib.exists() {
95 Ok(lib)
96 } else {
97 Err(format!(
98 "libnodejs.a not found next to {}; build the staticlib or set NODE_JS_STATICLIB",
99 exe.display()
100 ))
101 }
102}
103
104#[no_mangle]
112pub unsafe extern "C" fn fusevm_aot_register_builtins(vm: *mut VM) {
113 let vm = unsafe { &mut *vm };
114 crate::builtins::install(vm);
115 vm.set_numeric_hook(Arc::new(crate::builtins::numeric_hook));
116 let images: Vec<ProgImage> = vm
117 .chunk
118 .names
119 .iter()
120 .filter_map(|n| n.strip_prefix(PROG_IMAGE_TAG))
121 .filter_map(|j| serde_json::from_str(j).ok())
122 .collect();
123 host::with_host(|h| {
124 for img in images {
125 h.load_program(img.functions, img.tries);
126 }
127 });
128}