項目35:手動でFFIマッピングを書かずにbindgenを用いよう
この時 Rust と C のコードは整合する必要があるが、ツールチェーンではチェックできない
e.g.
code:lib.h
/* File lib.h */
typedef struct {
uint8_t byte;
uint32_t integer;
} FfiStruct;
int add(int x, int y);
uint32_t add32(uint32_t x, uint32_t y);
code:sh
$ bindgen \
# メモリ配置が対応するバインディングと一致しているかのテストを生成しない
--no-layout-tests \
# Rust にバインディングする関数名(正規表現)
--allowlist-function="add.*" \
# Rust にバインディングする型名
--allowlist-type=FfiStruct \
-o src/generated.rs \
lib.h
code:src/generated.rs
/* automatically generated by rust-bindgen 0.71.1 */
pub struct FfiStruct {
pub byte: u8,
pub integer: u32,
}
unsafe extern "C" {
pub fn add(x: ::std::os::raw::c_int, y: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
}
unsafe extern "C" {
pub fn add32(x: u32, y: u32) -> u32;
}
code:rs
include!("generated.rs");
bindgen の --allowlist-function や --allowlist-type などのオプションを用いると、C のライブラリを Rust で段階的に公開するアプローチが可能になる
e.g. xyzzy というライブラリの場合
xyzzy-sys クレート: bindgen が生成したコードだけを保持するクレート
このクレートの使用は必ず unsafe となる
xyzzy クレート: unsafe なコードを カプセル化 し、安全な Rust らしいアクセスを実現する そのため、「C++ と Rust のよりスムーズに連携させたい場合は、cxx クレートの使用を検討しよう」 それでも制限はあるが...
cxx では、Rust ↔︎ C++ の 双方の コードを自動生成するアプローチを取る