Rust bindgen: Generate Rust Bindings for C Header Files
2025年8月26日Elecmonkey
This article was translated by AI and has not been manually reviewed.
Basic Usage
Command-Line Usage
First, install the bindgen executable:
cargo install bindgen-cli
Then run binding generation:
bindgen input.h -o bindings.rs
Here, input.h is your C header file, and bindings.rs is the generated Rust binding. If you need to pass include directories or macro definitions, add -- followed by the corresponding clang arguments, such as -I, after the command.
Library Usage (build.rs)
Add bindgen to [build-dependencies] in Cargo.toml, then use it in build.rs:
use std::env;
use std::path::PathBuf;
use bindgen;
fn main() {
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("无法生成绑定");
bindings.write_to_file(PathBuf::from(env!("OUT_DIR")).join("bindings.rs"))
.expect("无法写入绑定文件");
}
In Rust code, include the generated bindings with include!(concat!(env!("OUT_DIR"), "/bindings.rs"));.
Clang/Libclang Dependency
bindgen depends on libclang (Clang 9.0+).
- Windows: Use
winget install LLVM.LLVM, and setLIBCLANG_PATHto the bin path of the LLVM installation directory - Linux (Debian/Ubuntu):
apt install libclang-dev - macOS: Install llvm with Homebrew
Complex C Type Support
Structs and Unions
- Structs: Directly translated into Rust structs with
#[repr(C)] - Unions: If all fields are Copy, native union is generated; otherwise, an
__BindgenUnionFieldwrapper is generated
Enum Handling
// 生成新类型加关联常量
.newtype_enum("MyEnum")
// 生成真正的 Rust enum(注意越界风险)
.rustified_enum("MyEnum")
// 位标志枚举
.bitfield_enum("MyFlags")
Function Pointers
Function pointer types in C are converted to Option<extern "C" fn(...)>, supporting null pointer cases.
Bitfield Handling
Rust does not natively support bitfields in C structs, so bindgen generates accessor methods:
// C: struct { unsigned a:1; unsigned b:1; unsigned c:2; };
let mut bf = unsafe { create_bitfield() };
bf.set_a(1);
println!("a={}", bf.a());
bf.set_b(1);
bf.set_c(3);
Automatically Generating Bindings at Build Time
Dynamically generate bindings in build.rs:
use std::env;
use std::path::PathBuf;
use bindgen;
fn main() {
let header = "wrapper.h";
let bindings = bindgen::Builder::default()
.header(header)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// 可选:指定 clang 参数
//.clang_args(&["-I/path/to/include"])
// 可选:只生成需要的符号
//.allowlist_function("foo_.*")
//.allowlist_type("MyStruct")
.generate()
.expect("无法生成绑定");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs");
bindings.write_to_file(out_path).expect("写入绑定文件失败");
// 链接 C 库
println!("cargo:rustc-link-search=native=/path/to/lib");
println!("cargo:rustc-link-lib=mylib");
}
FFI Safety
unsafe Usage
Put external functions and pointer operations inside unsafe { } blocks:
unsafe {
let result = c_function(ptr);
}
Signature Correctness
Rust cannot verify FFI function signatures at compile time, so you must use the correct C types, such as aliases from libc like c_int and c_char.
Memory and Ownership
Clearly handle memory ownership and lifetimes when working with pointers:
// 字符串转换示例
use std::ffi::{CString, CStr};
let c_string = CString::new("Hello").unwrap();
let ptr = c_string.as_ptr();
// 调用 C 函数...
Null Pointer Checks
Pointers are handled as Option<fn> returns, forcing callers to check for null pointers.
Error Handling
Wrap error representations from C functions into common Rust error-handling enums: Result or Option.