use std::{env, path::PathBuf};
use glob::glob;
use miette::IntoDiagnostic;
#[cfg(feature = "bindgen")]
use bindgen::callbacks::{DeriveInfo, TypeKind};
#[cfg(feature = "bindgen")]
use miette::WrapErr;
#[cfg(feature = "bindgen")]
#[derive(Debug)]
struct AddDeriveCallbacks;
#[cfg(feature = "bindgen")]
impl bindgen::callbacks::ParseCallbacks for AddDeriveCallbacks {
fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec<String> {
let mut ret = vec![];
match info.kind {
TypeKind::Struct | TypeKind::Enum if !["WasmConstInstruction"].contains(&info.name) => {
ret.push("ConstDefault".to_string());
}
_ => {}
}
match info.kind {
TypeKind::Struct if !["WasmConstInstruction"].contains(&info.name) => {
ret.push("TypedBuilder".to_string());
}
_ => {}
}
ret
}
}
#[cfg(feature = "bindgen")]
fn do_bindgen<I: IntoIterator>(headers: I, file: &str) -> miette::Result<PathBuf>
where
I::Item: Into<String>,
{
let out_path: PathBuf = PathBuf::from("./src");
let bindings = bindgen::Builder::default()
.headers(headers)
.clang_args(["-Wno-incompatible-pointer-types", "-Wno-pointer-sign"])
.clang_args([
"-D__bool_true_false_are_defined",
"-Dbool=_Bool",
"-Dfalse=0",
"-Dtrue=1",
])
.allowlist_item(format!(
"([wW]asm|[bB]uffer|[aA]rray|readFile|stringBuilder).*"
))
.use_core()
.derive_copy(true)
.derive_hash(true)
.generate_cstr(true)
.array_pointers_in_arguments(true)
.sort_semantically(true)
.merge_extern_blocks(true)
.layout_tests(false)
.wrap_static_fns(true)
.wrap_static_fns_path(out_path.join("out"))
.newtype_enum(".*")
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
.parse_callbacks(Box::new(AddDeriveCallbacks))
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.into_diagnostic()?;
bindings
.write_to_file(out_path.join(file))
.into_diagnostic()
.wrap_err("Failed to write bindgen result")?;
Ok(out_path.join(file))
}
fn build_static_library() -> miette::Result<()> {
let out_path: PathBuf = PathBuf::from("./src");
let manifest_path: PathBuf = env::var("CARGO_MANIFEST_DIR").into_diagnostic()?.into();
let mut cc = cc::Build::new();
let sources = glob("./w2c2/w2c2/*.c")
.into_diagnostic()?
.filter_map(Result::ok)
.filter(|x| {
if let Some(file) = x.file_stem()
&& let Some(file) = file.to_str()
{
if file.ends_with("test") {
return false;
}
if file == "main" {
return false;
}
}
true
});
let cc = cc
.define("__bool_true_false_are_defined", None)
.define("bool", "_Bool")
.define("false", "0")
.define("true", "1")
.files(sources)
.file(out_path.join("out.c"))
.includes([
manifest_path.canonicalize().into_diagnostic()?,
manifest_path
.join("./w2c2/w2c2")
.canonicalize()
.into_diagnostic()?,
]);
cc.try_compile("libw2c2").into_diagnostic()?;
Ok(())
}
fn main() -> miette::Result<()> {
#[cfg(feature = "bindgen")]
{
let headers = glob("./w2c2/w2c2/*.h")
.into_diagnostic()?
.filter_map(Result::ok)
.filter(|x| {
if let Some(file) = x.file_stem()
&& let Some(file) = file.to_str()
{
if file.ends_with("test") {
return false;
}
if file == "main" {
return false;
}
}
return true;
})
.map(|x| x.display().to_string());
let _out_path = do_bindgen(headers, "wrapper.rs")?;
}
let _ = build_static_library();
Ok(())
}