diff --git a/.gitignore b/.gitignore index b5312504..7a158cb3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,10 @@ target # .NET build output (from the C# binding demo) **/bin/ **/obj/ +# …but NOT Rust's src/bin/ crate-binary sources (e.g. the pure-bindgen tool), +# which the broad **/bin/ rule above would otherwise swallow. +!**/src/bin/ +!**/src/bin/** # RustRover # JetBrains specific template is maintained in a separate JetBrains.gitignore that can diff --git a/crates/ffi/src/bin/pure-bindgen.rs b/crates/ffi/src/bin/pure-bindgen.rs new file mode 100644 index 00000000..d78b2cb0 --- /dev/null +++ b/crates/ffi/src/bin/pure-bindgen.rs @@ -0,0 +1,68 @@ +//! Regenerate the committed language bindings from the `pure-ffi` C ABI. +//! +//! ```sh +//! cargo run -p pure-ffi --features bindgen --bin pure-bindgen +//! ``` +//! +//! Emits, relative to the crate root: +//! * `include/pure_study.h` — C header (cbindgen), for +//! C consumers and csbindgen/P-Invoke. +//! * `bindings/csharp/PureStudyNative.g.cs` — C# P/Invoke shim (csbindgen). +//! +//! Kotlin/Android binds the same header via JNA (see `bindings/kotlin/`); its +//! wrapper is hand-written rather than generated, so it is not produced here. +//! +//! This is a developer tool, kept out of the cdylib so a plain build / +//! cross-compile never pulls host-only generators. + +use std::path::Path; + +fn main() { + let crate_dir = env!("CARGO_MANIFEST_DIR"); + generate_c_header(crate_dir); + generate_csharp(crate_dir); + println!("bindings regenerated."); +} + +fn generate_c_header(crate_dir: &str) { + let out = Path::new(crate_dir).join("include/pure_study.h"); + std::fs::create_dir_all(out.parent().unwrap()).expect("create include/"); + + let config = cbindgen::Config { + language: cbindgen::Language::C, + pragma_once: true, + cpp_compat: true, // wrap in extern "C" when compiled as C++ + documentation: true, + documentation_style: cbindgen::DocumentationStyle::C99, + header: Some( + "/* pure-study C ABI — GENERATED by `cargo run -p pure-ffi \ + --features bindgen`. Do not edit by hand. */" + .to_string(), + ), + usize_is_size_t: true, + ..Default::default() + }; + + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_config(config) + .generate() + .expect("cbindgen: generate C header") + .write_to_file(&out); + println!("wrote {}", out.display()); +} + +fn generate_csharp(crate_dir: &str) { + let out = Path::new(crate_dir).join("bindings/csharp/PureStudyNative.g.cs"); + std::fs::create_dir_all(out.parent().unwrap()).expect("create bindings/csharp/"); + + csbindgen::Builder::default() + .input_extern_file(Path::new(crate_dir).join("src/lib.rs")) + .csharp_class_name("PureStudyNative") + .csharp_dll_name("pure_ffi") + .csharp_namespace("PureStudy.Native") + .csharp_class_accessibility("public") + .generate_csharp_file(&out) + .expect("csbindgen: generate C# bindings"); + println!("wrote {}", out.display()); +}