imgui-rs/xtask/src/bindgen.rs
2021-03-12 18:12:56 -08:00

146 lines
4.7 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::flags::Bindgen;
use anyhow::{anyhow, Context, Result};
use std::path::{Path, PathBuf};
impl Bindgen {
pub fn run(self) -> Result<()> {
let root = crate::project_root();
let bindings = self
.cimgui_path
.map(PathBuf::from)
.unwrap_or_else(|| root.join("imgui-sys/third-party"));
let output = self
.output_path
.map(PathBuf::from)
.unwrap_or_else(|| root.join("imgui-sys/src"));
let wasm_name = self
.wasm_import_name
.or_else(|| std::env::var("IMGUI_RS_WASM_IMPORT_NAME").ok())
.unwrap_or_else(|| "imgui-sys-v0".to_string());
let types = get_types(&bindings.join("structs_and_enums.json"))?;
let funcs = get_definitions(&bindings.join("definitions.json"))?;
let header = bindings.join("cimgui.h");
generate_binding_file(&header, &output.join("bindings.rs"), &types, &funcs, None)?;
generate_binding_file(
&header,
&output.join("wasm_bindings.rs"),
&types,
&funcs,
Some(&wasm_name),
)?;
Ok(())
}
}
fn get_types(structs_and_enums: &Path) -> Result<Vec<String>> {
let types_txt = std::fs::read_to_string(structs_and_enums)?;
let types_val = types_txt
.parse::<smoljson::ValOwn>()
.map_err(|e| anyhow!("Failed to parse {}: {:?}", structs_and_enums.display(), e))?;
let mut types: Vec<String> = types_val["enums"]
.as_object()
.ok_or_else(|| anyhow!("No `enums` in bindings file"))?
.keys()
.map(|k| format!("^{}", k))
.collect();
types.extend(
types_val["structs"]
.as_object()
.ok_or_else(|| anyhow!("No `structs` in bindings file"))?
.keys()
.map(|k| format!("^{}", k)),
);
Ok(types)
}
fn get_definitions(definitions: &Path) -> Result<Vec<String>> {
fn bad_arg_type(s: &str) -> bool {
s == "va_list" || s.starts_with("__")
}
let defs_txt = std::fs::read_to_string(definitions)?;
let defs_val = defs_txt
.parse::<smoljson::ValOwn>()
.map_err(|e| anyhow!("Failed to parse {}: {:?}", definitions.display(), e))?;
let definitions = defs_val
.into_object()
.ok_or_else(|| anyhow!("bad json data in defs file"))?;
let mut keep_defs = vec![];
for (name, def) in definitions {
let defs = def
.into_array()
.ok_or_else(|| anyhow!("def {} not an array", &name))?;
keep_defs.reserve(defs.len());
for func in defs {
let args = func["argsT"].as_array().unwrap();
if !args
.iter()
.any(|a| a["type"].as_str().map_or(false, bad_arg_type))
{
let name = func["ov_cimguiname"]
.as_str()
.ok_or_else(|| anyhow!("ov_cimguiname wasnt string..."))?;
keep_defs.push(format!("^{}", name));
}
}
}
Ok(keep_defs)
}
fn generate_binding_file(
header: &Path,
output: &Path,
types: &[String],
funcs: &[String],
wasm_import_mod: Option<&str>,
) -> Result<()> {
let mut cmd = std::process::Command::new("bindgen");
let a = &[
"--size_t-is-usize",
"--no-prepend-enum-name",
"--no-doc-comments",
// Layout tests aren't portable (they hardcode type sizes), and for
// our case they just serve to sanity check rustc's implementation of
// `#[repr(C)]`. If we bind directly to C++ ever, we should reconsider this.
"--no-layout-tests",
"--with-derive-default",
"--with-derive-partialeq",
"--with-derive-eq",
"--with-derive-hash",
"--impl-debug",
"--use-core",
];
cmd.args(a);
cmd.args(&["--blacklist-type", "__darwin_size_t"]);
cmd.args(&["--raw-line", "#![allow(nonstandard_style, clippy::all)]"]);
cmd.arg("--output").arg(output);
cmd.args(&["--ctypes-prefix", "cty"]);
if let Some(name) = wasm_import_mod {
cmd.args(&["--wasm-import-module-name", &name]);
}
for t in types {
cmd.args(&["--whitelist-type", t]);
}
for f in funcs {
cmd.args(&["--whitelist-function", f]);
}
cmd.arg(header);
cmd.args(&["--", "-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1"]);
eprintln!("Executing bindgen [output = {}]", output.display());
let status = cmd.status().context("Failed to exacute bindgen")?;
if !status.success() {
anyhow!(
"Failed to execute bindgen: {}, see output for details",
status
);
}
eprintln!("Success [output = {}]", output.display());
Ok(())
}