如何使用 cbindgen
-
以命令行工具的方式使用; -
以庫的方式在 build.rs 中使用;
命令行工具方式
cargo install --force cbindgen
cbindgen --config cbindgen.toml --crate my_rust_library --output my_header.h
my_header.h
就是生成的頭文件。
-
不是任意 Rust crate 均可以,而是已經作了暴露 C API 開發的庫才行。由於 cbindgen 會去掃描整個源代碼,把對接的接口抽出來; -
能夠經過 cbindgen.toml 這個配置文件,給 cbindgen 配置行爲參數,參數不少,後面有參考連接。
build.rs 方式
extern crate cbindgen;
use std::env;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::Builder::new()
.with_crate(crate_dir)
.generate()
.expect("Unable to generate bindings")
.write_to_file("bindings.h");
}
bindings.h
就是咱們要的 C 頭文件。
生成的結果看起來是什麼樣子?
// trebuchet.rs
#[repr(u8)]
enum Ammo {
Rock,
WaterBalloon,
Cow,
}
#[repr(C)]
struct Target {
latitude: f64,
longitude: f64,
}
// notice: #[repr(rust)]
struct Trebuchet { ... }
#[no_mangle]
unsafe extern "C" fn trebuchet_new() -> *mut Trebuchet { ... }
#[no_mangle]
unsafe extern "C" fn trebuchet_delete(treb: *mut Trebuchet) { ... }
#[no_mangle]
unsafe extern "C" fn trebuchet_fire(treb: *mut Trebuchet,
ammo: Ammo,
target: Target) { ... }
// trebuchet.h
#include <cstdint>
#include <cstdlib>
extern "C" {
enum class Ammo : uint8_t {
Rock = 0,
WaterBalloon = 1,
Cow = 2,
};
struct Trebuchet;
struct Target {
double latitude;
double longitude;
};
void trebuchet_delete(Trebuchet *treb);
void trebuchet_fire(Trebuchet *treb, Ammo ammo, Target target);
Trebuchet* trebuchet_new();
} // extern "C"
-
Ammo 有正確的大小和值; -
Target 包含全部字段和正確的佈局(字段順序); -
Trebuchet 被聲明爲一個 opaque 結構體; -
全部的函數有了對應的聲明。
補充
-
cbindgen 不但能夠生成 C 頭文件,還能夠生成 C++ 的,甚至還能夠生成 swift 能夠用的頭文件; -
cbindgen 不是一包到底的,對 C 的支持相對成熟,對 C++ 的差一些。適當的時候,仍是須要手動作不少事情的; -
cbindgen 對 Rust 的泛型,有必定的支持;
參考連接
-
說明文檔 -
cbindgen.toml -
announcing-cbindgen
本文分享自微信公衆號 - Rust語言中文社區(rust-china)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。html