use std::{env::current_dir, fs::create_dir_all, process::Command};
use bindgen::callbacks::ParseCallbacks;
#[derive(Debug)]
struct XedBindgenParseCallbacks {
xed_install_include_dir: String,
cargo_callbacks: bindgen::CargoCallbacks,
}
impl ParseCallbacks for XedBindgenParseCallbacks {
fn will_parse_macro(&self, name: &str) -> bindgen::callbacks::MacroParsingBehavior {
self.cargo_callbacks.will_parse_macro(name)
}
fn generated_name_override(
&self,
item_info: bindgen::callbacks::ItemInfo<'_>,
) -> Option<String> {
self.cargo_callbacks.generated_name_override(item_info)
}
fn generated_link_name_override(
&self,
item_info: bindgen::callbacks::ItemInfo<'_>,
) -> Option<String> {
self.cargo_callbacks.generated_link_name_override(item_info)
}
fn int_macro(&self, name: &str, value: i64) -> Option<bindgen::callbacks::IntKind> {
self.cargo_callbacks.int_macro(name, value)
}
fn str_macro(&self, name: &str, value: &[u8]) {
self.cargo_callbacks.str_macro(name, value)
}
fn func_macro(&self, name: &str, value: &[&[u8]]) {
self.cargo_callbacks.func_macro(name, value)
}
fn enum_variant_behavior(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
variant_value: bindgen::callbacks::EnumVariantValue,
) -> Option<bindgen::callbacks::EnumVariantCustomBehavior> {
self.cargo_callbacks
.enum_variant_behavior(enum_name, original_variant_name, variant_value)
}
fn enum_variant_name(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
variant_value: bindgen::callbacks::EnumVariantValue,
) -> Option<String> {
self.cargo_callbacks
.enum_variant_name(enum_name, original_variant_name, variant_value)
}
fn item_name(&self, original_item_name: &str) -> Option<String> {
self.cargo_callbacks.item_name(original_item_name)
}
fn header_file(&self, filename: &str) {
self.cargo_callbacks.header_file(filename)
}
fn include_file(&self, filename: &str) {
if filename.starts_with(self.xed_install_include_dir.as_str()) {
return;
}
self.cargo_callbacks.include_file(filename)
}
fn read_env_var(&self, key: &str) {
self.cargo_callbacks.read_env_var(key)
}
fn blocklisted_type_implements_trait(
&self,
name: &str,
derive_trait: bindgen::callbacks::DeriveTrait,
) -> Option<bindgen::callbacks::ImplementsTrait> {
self.cargo_callbacks
.blocklisted_type_implements_trait(name, derive_trait)
}
fn add_derives(&self, info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> {
self.cargo_callbacks.add_derives(info)
}
fn process_comment(&self, comment: &str) -> Option<String> {
self.cargo_callbacks.process_comment(comment)
}
fn field_visibility(
&self,
info: bindgen::callbacks::FieldInfo<'_>,
) -> Option<bindgen::FieldVisibilityKind> {
self.cargo_callbacks.field_visibility(info)
}
fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
self.cargo_callbacks.wrap_as_variadic_fn(name)
}
}
fn main() {
let cwd_path = current_dir().unwrap();
let cwd = cwd_path.to_str().unwrap();
let out_dir = std::env::var("OUT_DIR").unwrap();
let xed_build_dir = format!("{}/xed", out_dir);
let xed_install_dir = format!("{}/xed_install", out_dir);
let num_jobs_str = std::env::var("NUM_JOBS").unwrap_or_else(|_| "1".to_string());
let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
println!("cargo:rerun-if-changed-env=OUT_DIR");
println!("cargo:rerun-if-changed-env=PROFILE");
println!("cargo:rerun-if-changed={}/xed", cwd);
println!("cargo:rerun-if-changed={}/mbuild", cwd);
create_dir_all(xed_build_dir.as_str()).unwrap();
let mut cmd = Command::new(format!("{}/xed/mfile.py", cwd));
cmd.arg("-j")
.arg(num_jobs_str.as_str())
.arg("--static")
.arg(format!("--install-dir={}", xed_install_dir))
.env("PYTHONDONTWRITEBYTECODE", "1")
.current_dir(xed_build_dir.as_str());
if profile == "release" {
cmd.arg("--opt=3");
} else {
cmd.arg("--opt=0");
}
cmd.arg("install");
let exit_code = cmd.spawn().unwrap().wait().unwrap();
assert!(exit_code.success());
println!("cargo:rustc-link-search=native={}/lib", xed_install_dir);
println!("cargo:rustc-link-lib=static=xed");
let xed_include_dir = format!("{}/include", xed_install_dir);
let wrapped_static_fns_file_path = format!("{}/xed_wrapped_static_fns.c", out_dir);
let bindings = bindgen::Builder::default()
.wrap_static_fns(true)
.wrap_static_fns_path(wrapped_static_fns_file_path.as_str())
.clang_arg(format!("-I{}", xed_include_dir))
.clang_arg("-DXED_ENCODER")
.clang_arg("-DXED_DECODER")
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
.use_core()
.header("xed.h")
.parse_callbacks(Box::new(XedBindgenParseCallbacks {
xed_install_include_dir: xed_include_dir.clone(),
cargo_callbacks: bindgen::CargoCallbacks::new(),
}))
.generate()
.unwrap();
bindings
.write_to_file(format!("{}/xed.rs", out_dir))
.unwrap();
cc::Build::new()
.file(wrapped_static_fns_file_path.as_str())
.flag("-DXED_ENCODER")
.flag("-DXED_DECODER")
.flag_if_supported("-Wno-duplicate-decl-specifier")
.include(xed_include_dir.as_str())
.include(cwd)
.compile("xed_wrapped_static_fns");
}