#[cfg(feature = "jit")]
use copypatch::extract::{Stencil, compile_object, extract_stencil};
#[cfg(feature = "jit")]
use std::{
env, fs,
path::{Path, PathBuf},
};
#[cfg(feature = "jit")]
const SYMBOLS: &[&str] = &["weavy_stencil_hostcall", "weavy_stencil_done"];
fn main() {
#[cfg(feature = "jit")]
{
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
let generated = out.join("weavy_stencils.rs");
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
if native_copy_patch_target(&target_os, &target_arch) {
emit_native(&out, &generated);
} else {
emit_empty(&generated);
}
}
}
#[cfg(feature = "jit")]
fn emit_empty(generated: &Path) {
fs::write(
generated,
"pub const HOSTCALL: &[u8] = &[];\n\
pub const HOSTCALL_CONT: &[usize] = &[];\n\
pub const DONE: &[u8] = &[];\n",
)
.unwrap();
}
#[cfg(feature = "jit")]
fn native_copy_patch_target(target_os: &str, target_arch: &str) -> bool {
matches!(
(target_os, target_arch),
("macos", "aarch64") | ("linux", "x86_64")
)
}
#[cfg(feature = "jit")]
fn emit_native(out: &Path, generated: &Path) {
println!("cargo:rerun-if-changed=stencils/hostcall.rs");
println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET set by cargo");
let obj = out.join("weavy_stencils.o");
let src = Path::new("stencils/hostcall.rs");
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
assert!(
compile_object(&rustc, &[], src, &obj, &target, false),
"rustc failed to compile Weavy stencils"
);
let bytes = fs::read(&obj).unwrap();
let hostcall = extract_stencil(&bytes, SYMBOLS, "weavy_stencil_hostcall", "weavy_cont");
let done = extract_stencil(&bytes, SYMBOLS, "weavy_stencil_done", "weavy_cont");
let mut s = String::new();
s.push_str("// Generated by build.rs from stencils/hostcall.rs (rustc --emit=obj, call).\n");
emit(
&mut s,
"HOSTCALL",
"`weavy_stencil_hostcall`: call one consumer-provided intrinsic, continue.",
&hostcall,
);
emit_cont(&mut s, "HOSTCALL_CONT", "HOSTCALL", &hostcall);
emit(&mut s, "DONE", "`weavy_stencil_done`: a lone `ret`.", &done);
fs::write(generated, s).unwrap();
}
#[cfg(feature = "jit")]
fn emit(out: &mut String, name: &str, doc: &str, stencil: &Stencil) {
out.push_str(&format!(
"/// {doc}\npub const {name}: &[u8] = &{:?};\n",
stencil.bytes
));
}
#[cfg(feature = "jit")]
fn emit_cont(out: &mut String, name: &str, of: &str, stencil: &Stencil) {
out.push_str(&format!(
"/// Byte offsets within `{of}` of the continuation relocations to patch.\n\
pub const {name}: &[usize] = &{:?};\n",
stencil.cont_relocs
));
}