Rust FFI工具库Diplomat的使用:简化跨语言接口生成与安全互操作
Rust FFI工具库Diplomat的使用:简化跨语言接口生成与安全互操作
介绍
Diplomat是一个实验性的Rust工具,用于生成FFI定义,允许许多其他语言调用Rust代码。使用Diplomat,您可以简单地定义要通过FFI公开的Rust API,并自动获得高级的C、C++和JavaScript绑定!
Diplomat支持从Rust生成以下语言的绑定:
- C
- C++
- Dart
- JavaScript/TypeScript
- Kotlin (使用JNA)
- Python (使用nanobind)
安装
首先,安装用于生成绑定的CLI工具:
$ cargo install diplomat-tool
然后,将Diplomat宏和运行时作为依赖项添加到您的项目中:
diplomat = "0.10.0"
diplomat-runtime = "0.10.0"
完整示例
以下是一个完整的Diplomat使用示例,展示如何创建一个Rust库并通过FFI暴露给其他语言:
- 首先创建一个Rust库项目:
$ cargo new --lib my_ffi_lib
$ cd my_ffi_lib
- 编辑
Cargo.toml
添加依赖:
[package]
name = "my_ffi_lib"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
diplomat = "0.10.0"
diplomat-runtime = "0.10.0"
- 创建
src/lib.rs
内容:
use diplomat_core::ffi::*;
#[diplomat::bridge]
mod ffi {
pub struct Person {
pub name: String,
pub age: u32,
}
impl Person {
/// 创建一个新Person
pub fn new(name: &str, age: u32) -> Person {
Person {
name: name.to_string(),
age,
}
}
/// 获取用户信息
pub fn get_info(&self) -> String {
format!("{} is {} years old", self.name, self.age)
}
/// 让用户年龄增长一岁
pub fn have_birthday(&mut self) {
self.age += 1;
}
}
}
- 生成FFI绑定:
$ diplomat-tool generate c --out-dir ./c_b bindings
$ diplomat-tool generate cpp --out-dir ./cpp_bindings
$ diplomat-tool generate js --out-dir ./js_bindings
- 构建项目:
$ cargo build --release
现在您可以在目标语言中使用生成的绑定来调用Rust代码。例如在C++中:
#include "my_ffi_lib.hpp"
#include <iostream>
int main() {
auto person = my_ffi_lib::Person::new_("Alice", 30);
std::cout << person.get_info() << std::endl; // 输出: Alice is 30 years old
person.have_birthday();
std::cout << person.get_info() << std::endl; // 输出: Alice is 31 years old
return 0;
}
或者在JavaScript中:
const { Person } = require('./js_bindings/my_ffi_lib');
let person = Person.new("Bob", 25);
console.log(person.getInfo()); // 输出: Bob is 25 years old
person.haveBirthday();
console.log(person.getInfo()); // 输出: Bob is 26 years old
注意事项
对于wasm32-unknown-unknown
目标的JavaScript绑定,Diplomat假设您正在C规范ABI上构建WebAssembly。在最新的Rust版本中,这不是默认设置,因此您有两个选项:
- 使用nightly Rust构建并启用
-Zwasm-c-abi=spec
标志 - 配置JS后端使用传统绑定。WASM ABI有一个配置选项
1 回复
Rust FFI工具库Diplomat:简化跨语言接口生成与安全互操作
完整示例Demo
下面是一个完整的Rust项目示例,展示如何使用Diplomat创建跨语言接口:
1. 创建Rust库项目
cargo new --lib my_diplomat_demo
cd my_diplomat_demo
2. 修改Cargo.toml
[package]
name = "my_diplomat_demo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
diplomat = "0.4"
3. 实现Rust库代码
// src/lib.rs
use diplomat::ffi;
#[diplomat::bridge]
mod ffi {
/// 表示一个数学计算器
pub struct Calculator {
value: f64,
}
impl Calculator {
/// 创建新的计算器实例
pub fn new(initial_value: f64) -> Calculator {
Calculator { value: initial_value }
}
/// 获取当前值
pub fn get_value(&self) -> f64 {
self.value
}
/// 加法运算
pub fn add(&mut self, operand: f64) -> Result<(), CalculatorError> {
self.value = self.value
.checked_add(operand)
.ok_or(CalculatorError::Overflow)?;
Ok(())
}
/// 乘法运算
pub fn multiply(&mut self, operand: f64) -> Result<(), CalculatorError> {
self.value = self.value
.checked_mul(operand)
.ok_or(CalculatorError::Overflow)?;
Ok(())
}
}
/// 计算器错误类型
#[derive(Debug)]
pub enum CalculatorError {
Overflow,
DivisionByZero,
}
}
4. 添加绑定生成工具
// src/bin/generate_bindings.rs
use std::path::PathBuf;
fn main() {
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
diplomat::run(
diplomat::Config {
out_dir: &out_dir,
target_languages: &[diplomat::TargetLanguage::C],
..Default::default()
},
&["src/lib.rs"],
).unwrap();
}
5. 构建项目并生成绑定
cargo build
6. 生成的C头文件示例
// calculator.h
#include <stdint.h>
#include <stddef.h>
typedef struct Calculator Calculator;
typedef enum CalculatorError {
CalculatorError_Overflow,
CalculatorError_DivisionByZero,
} CalculatorError;
Calculator* Calculator_new(double initial_value);
double Calculator_get_value(const Calculator* self);
CalculatorError Calculator_add(Calculator* self, double operand);
CalculatorError Calculator_multiply(Calculator* self, double operand);
void Calculator_destroy(Calculator* self);
7. C语言使用示例
// main.c
#include "calculator.h"
#include <stdio.h>
int main() {
// 创建计算器实例
Calculator* calc = Calculator_new(10.0);
// 进行加法运算
CalculatorError err = Calculator_add(calc, 5.0);
if (err != 0) {
printf("Addition error: %d\n", err);
return 1;
}
// 进行乘法运算
err = Calculator_multiply(calc, 3.0);
if (err != 0) {
printf("Multiplication error: %d\n", err);
return 1;
}
// 获取结果
double result = Calculator_get_value(calc);
printf("Final result: %f\n", result);
// 清理资源
Calculator_destroy(calc);
return 0;
}
8. 编译和运行C程序
gcc main.c -L./target/debug -lmy_diplomat_demo -o calculator_demo
./calculator_demo
这个完整示例展示了:
- 如何定义Rust结构体和方法
- 如何处理错误并跨语言传递
- 如何生成C语言绑定
- 如何在C语言中使用生成的绑定
- 内存管理的最佳实践
通过这个示例,您可以清楚地看到Diplomat如何简化Rust与其他语言的互操作过程。