use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
const WASM3_SOURCE: &str = "wasm3/source";
const SHIM_SOURCE: &str = "shim";
const ALLOWLIST_FUNCTION: &str = "(wasm3x_|[A-Z]|m3_).*";
const ALLOWLIST_TYPE: &str = "(?:I|c_)?[Mm]3.*";
const PRIMITIVES: &[&str] = &[
"f64", "f32", "u64", "i64", "u32", "i32", "u16", "i16", "u8", "i8",
];
fn main() {
ensure_sources_present();
generate_bindings();
compile_wasm3();
println!("cargo:rerun-if-changed={WASM3_SOURCE}");
println!("cargo:rerun-if-changed={SHIM_SOURCE}");
println!("cargo:rerun-if-changed=build.rs");
}
fn ensure_sources_present() {
if !PathBuf::from(format!("{WASM3_SOURCE}/wasm3.h")).exists() {
panic!(
"Wasm3 sources not found at `{WASM3_SOURCE}`. The Wasm3 C library is a \
git submodule; fetch it with:\n\n \
git submodule update --init crates/wasm3x-sys/wasm3\n"
);
}
}
fn generate_bindings() {
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR is set by Cargo"));
let mut builder = bindgen::builder()
.header(format!("{WASM3_SOURCE}/wasm3.h"))
.header(format!("{SHIM_SOURCE}/wasm3x_shim.h"))
.clang_arg(format!("-I{WASM3_SOURCE}"))
.clang_arg("-Dd_m3LogOutput=0")
.clang_arg(format!("-Dd_m3Use32BitSlots={}", slot_bits_define()))
.clang_arg(wasi_clang_define())
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
.allowlist_function(ALLOWLIST_FUNCTION)
.allowlist_type(ALLOWLIST_TYPE)
.allowlist_var(ALLOWLIST_TYPE)
.layout_tests(false)
.generate_comments(false)
.derive_debug(false);
for primitive in PRIMITIVES {
builder = builder.blocklist_type(primitive);
}
builder
.generate()
.expect("failed to generate Wasm3 bindings")
.write_to_file(out_dir.join("bindings.rs"))
.expect("failed to write Wasm3 bindings");
}
fn compile_wasm3() {
let mut build = cc::Build::new();
for entry in std::fs::read_dir(WASM3_SOURCE)
.unwrap_or_else(|err| panic!("failed to read `{WASM3_SOURCE}`: {err}"))
{
let path = entry.expect("failed to read directory entry").path();
if path.extension().and_then(OsStr::to_str) != Some("c") {
continue;
}
if path.file_name().and_then(OsStr::to_str) == Some("m3_api_uvwasi.c") {
continue;
}
build.file(path);
}
build.file(format!("{SHIM_SOURCE}/wasm3x_shim.c"));
build
.include(WASM3_SOURCE)
.define("d_m3LogOutput", Some("0"))
.define("d_m3Use32BitSlots", Some(slot_bits_define()))
.warnings(false)
.extra_warnings(false);
if cfg!(feature = "wasi") {
build.define("d_m3HasWASI", None);
}
build.compile("wasm3");
}
fn slot_bits_define() -> &'static str {
"0"
}
fn wasi_clang_define() -> &'static str {
if cfg!(feature = "wasi") {
"-Dd_m3HasWASI"
} else {
"-DWASM3_SYS_NO_WASI"
}
}