rust 与c 以及c 与rust 的互调用还是比较常见的需求,很多时候自己写可能比较费事,但是使用一些工具就比较方便了
cbindgen 是一个对于rust 代码生成c binding 的工具
参考使用
基于cbindgen 将rust 的代码生成对应的c 头文件,之后基于cmake 构建项目
- 项目结构
├── CMakeLists.txt
├── Cargo.lock
├── Cargo.toml
├── README.md
├── build.rs
├── main.c
└── src
├── app.rs
└── lib.rs
- 代码简单说明
app.rs 以及lib.rs 主要是关于rust 的,build.rs 是使用cbindgen 生成bindings,main.c 是使用生成的库文件,CMakeLists.txt 是基于
cmake 的c 应用构建
app.rs
#[repr(C)]
pub struct Foo {
a:i32,
b:i32,
c: *mut std::os::raw::c_char
}
#[no_mangle]
pub extern "C" fn addv2(a:i32,b:i32) -> i32 {
a + b
}
#[no_mangle]
pub extern "C" fn init_app(foo: Foo) -> bool {
if foo.c.is_null() {
return false
} else{
return true
}
}
lib.rs
pub mod app;
build.rs 标准的cargo 构建扩展
use cbindgen;
fn main() {
cbindgen::Builder::new()
.with_language(cbindgen::Language::C)
.with_crate(".")
.generate()
.expect("Unable to generate bindings")
.write_to_file("bindings.h");
}
main.c
#include <stdio.h>
#include "bindings.h"
int main(){
int result = addv2(13,33);
printf("Result: %d\n", result);
Foo foo = {
.a = 1,
.b = 2,
};
bool init_result = init_app(foo);
printf("init_result: %d\n", init_result);
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(mydemoapp)
add_executable(myapp main.c)
include_directories(${CMAKE_SOURCE_DIR})
target_link_libraries(myapp PRIVATE ${CMAKE_SOURCE_DIR}/target/release/libmylib.dylib)
构建
- 构建rust
cargo build --release
- 构建c应用
mkdir -p build
cd build
cmake ..
make
- 效果
运行
说明
cbindgen 是一个很不错的工具,可以方便c 与rust 的调用,同时对于生成的文件也方便其他语言进行互调用,比如python 的cffi 也可以方便调用
参考资料
https://github.com/mozilla/cbindgen
https://github.com/rongfengliang/cbindgen_cmake_learning