use std::{
env,
path::{Path, PathBuf},
};
fn flag(feature: &str) -> &'static str {
let var = format!("CARGO_FEATURE_{}", feature.to_uppercase().replace('-', "_"));
if env::var_os(var).is_some() { "1" } else { "0" }
}
fn wamr_target() -> Option<&'static str> {
match env::var("CARGO_CFG_TARGET_ARCH").ok()?.as_str() {
"x86_64" => Some("X86_64"),
"x86" => Some("X86_32"),
"aarch64" => Some("AARCH64"),
"arm" => Some("ARM"),
"riscv64" => Some("RISCV64"),
"riscv32" => Some("RISCV32"),
_ => None,
}
}
fn wamr_platform() -> Option<&'static str> {
match env::var("CARGO_CFG_TARGET_OS").ok()?.as_str() {
"macos" => Some("darwin"),
"linux" => Some("linux"),
"windows" => Some("windows"),
"android" => Some("android"),
"freebsd" => Some("freebsd"),
_ => None,
}
}
fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let wamr_root = manifest_dir.join("wasm-micro-runtime");
assert!(
wamr_root.join("CMakeLists.txt").exists(),
"WAMR sources not found at {}.\n\
Initialize the git submodule first:\n \
git submodule update --init --recursive",
wamr_root.display(),
);
build_wamr(&wamr_root);
generate_bindings(&wamr_root);
println!("cargo:rerun-if-changed=wrapper.h");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=wasm-micro-runtime/CMakeLists.txt");
for var in [
"WAMR_BUILD_PLATFORM",
"WAMR_BUILD_TARGET",
"WAMR_SHARED_PLATFORM_CONFIG",
] {
println!("cargo:rerun-if-env-changed={var}");
}
}
fn build_wamr(wamr_root: &Path) {
let mut cfg = cmake::Config::new(wamr_root);
cfg.define("WAMR_BUILD_INTERP", "1")
.define("WAMR_BUILD_FAST_INTERP", "1")
.define("WAMR_BUILD_AOT", "0")
.define("WAMR_BUILD_JIT", "0")
.define("WAMR_BUILD_FAST_JIT", "0");
cfg.define("WAMR_BUILD_BULK_MEMORY", flag("bulk-memory"))
.define("WAMR_BUILD_REF_TYPES", flag("reference-types"))
.define("WAMR_BUILD_TAIL_CALL", flag("tail-call"))
.define("WAMR_BUILD_GC", flag("gc"))
.define("WAMR_BUILD_SHARED_MEMORY", flag("shared-memory"))
.define("WAMR_BUILD_EXTENDED_CONST_EXPR", flag("extended-const"));
let simd = flag("simd");
cfg.define("WAMR_BUILD_SIMD", simd)
.define("WAMR_BUILD_LIB_SIMDE", simd);
cfg.define(
"WAMR_BUILD_CUSTOM_NAME_SECTION",
flag("custom-name-section"),
)
.define(
"WAMR_BUILD_LOAD_CUSTOM_SECTION",
flag("load-custom-section"),
)
.define("WAMR_BUILD_DUMP_CALL_STACK", flag("dump-call-stack"))
.define("WAMR_BUILD_MULTI_MODULE", flag("multi-module"))
.define("WAMR_BUILD_THREAD_MGR", flag("thread-mgr"))
.define("WAMR_BUILD_PERF_PROFILING", flag("perf-profiling"));
cfg.define("WAMR_BUILD_LIBC_BUILTIN", flag("libc-builtin"))
.define("WAMR_BUILD_LIBC_WASI", flag("libc-wasi"));
let disable_hw_bound_check = if flag("hw-bound-check") == "1" {
"0"
} else {
"1"
};
cfg.define("WAMR_DISABLE_HW_BOUND_CHECK", disable_hw_bound_check);
if let Ok(platform) = env::var("WAMR_BUILD_PLATFORM") {
cfg.define("WAMR_BUILD_PLATFORM", platform);
} else if let Some(platform) = wamr_platform() {
cfg.define("WAMR_BUILD_PLATFORM", platform);
}
if let Ok(target) = env::var("WAMR_BUILD_TARGET") {
cfg.define("WAMR_BUILD_TARGET", target);
} else if let Some(target) = wamr_target() {
cfg.define("WAMR_BUILD_TARGET", target);
}
let dst = cfg.build_target("vmlib").build();
println!("cargo:rustc-link-search=native={}/build", dst.display());
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static=iwasm");
link_system_libs();
}
fn link_system_libs() {
let os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
match os.as_str() {
"linux" | "android" | "freebsd" => {
println!("cargo:rustc-link-lib=dylib=m");
println!("cargo:rustc-link-lib=dylib=dl");
println!("cargo:rustc-link-lib=dylib=pthread");
}
"windows" => {
println!("cargo:rustc-link-lib=dylib=ntdll");
println!("cargo:rustc-link-lib=dylib=ws2_32");
}
_ => {}
}
}
fn generate_bindings(wamr_root: &Path) {
let include_dir = wamr_root.join("core/iwasm/include");
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_arg(format!("-I{}", include_dir.display()))
.use_core()
.ctypes_prefix("::core::ffi")
.generate_comments(false)
.derive_default(true)
.derive_debug(true)
.allowlist_function("wasm_.*")
.allowlist_type("wasm_.*")
.allowlist_type("NativeSymbol")
.allowlist_type("RuntimeInitArgs")
.allowlist_type("RunningMode")
.allowlist_type("mem_alloc_type_t")
.allowlist_type("package_type_t")
.allowlist_var("WASM_.*")
.prepend_enum_name(false)
.generate()
.expect("failed to generate WAMR bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("failed to write bindings.rs");
}