cbindgen rust 代码生成c binding 的工具

发布时间 2023-12-13 17:04:00作者: 荣锋亮

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