结合 cc 以及bindgen 实现rust 调用c 语言
主要是一个学习,结合cc 以及bindgen 工具实现rust 访问c 语言,基于cargo 的build.rs 实现方便的编译(包含了c库编译以及方法ffi 生成)
项目结构
├── Cargo.lock
├── Cargo.toml
├── README.md
├── build.rs
├── num.c
├── num.h
├── src
│ ├── bindings.rs
│ └── main.rs
└── wrapper.h
简单说明: num.c 以及num.h 是一个简单的c 功能实现,wrapper.h 是一个包装,方便通过bindgen 实现ffi 签名
build.rs 利用cargo 的build 能力,实现c 编译以及ffi 签名,main.rs 实现方法调用
代码说明
- num.c& num.h
// num.h
#ifndef NUM_H
#define NUM_H
void print_num(int num);
#endif
// num.c
#include <stdio.h>
#include "num.h"
void print_num(int num) {
printf("num is mydemo from dalong %d",num);
}
- wrapper.h
#include "num.h"
- build.rs
use std::path::PathBuf;
fn main() {
// build c library
cc::Build::new()
.file("num.c")
.compile("num");
// build rust bindings
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(".");
bindings
.write_to_file(out_path.join("src/bindings.rs"))
.expect("Couldn't write bindings!");
}
- main.rs
mod bindings;
use bindings::print_num;
fn main() {
print!("call c ");
unsafe {
print_num(333);
}
}
构建&效果
- 构建
cargo build --release
- 运行效果
说明
对于需要rust 集成clang 访问的,利用bindgen 是一个很不错的选择,帮助我们生成了不少方法代码
参考资料
https://dev.to/xphoniex/how-to-call-c-code-from-rust-56do
https://crates.io/crates/cc
https://github.com/rust-lang/cc-rs
https://github.com/rongfengliang/rust-clang-learning
https://github.com/rust-lang/rust-bindgen
https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code
https://rust-lang.github.io/rust-bindgen/