#ffi #bindings #c #string

nightly ffishim

ffishim_derive背后的库

3个版本

0.1.2 2020年7月1日
0.1.1 2020年6月30日
0.1.0 2020年6月30日

#1243 in 过程宏


用于 2 crate

MIT/Apache

58KB
1.5K SLoC

FFIShim

crates.io badge

许多常见的Rust类型(例如,像String)不能通过FFI传递,因为它们的内存布局与C ABI不匹配(String的末尾没有空字节)。这使得使用原生的Rust类型和从FFI调用该代码变得困难。

这个crate提供了一个shim,该shim将公开FFI兼容的数据结构和函数包装器,用于原生Rust类型和函数。

以下是一个使用原生String并从C调用它的Rust代码的快速示例

#[ffishim_function]
fn hello(s: String) -> String {
    format!("Hello, {}!", s)
}

您应该能够如下从C调用它

#include "ffishim/header.h"
extern result_t *ffi_hello(char *s);
int main() {
	char *ffi = malloc(sizeof(char) * 4);
	ffi[0] = "f";
	ffi[1] = "f";
	ffi[2] = "i";
	ffi[3] = "\0";

	result_t *res = ffi_hello(ffi)
	if (res->message != NULL) {
		printf("error: %s\n", res->message);
		free(res->message);
	} else {
		printf("%s\n", res->payload);
		free(res->payload);
	}
	free(res);
}

这将打印

Hello, ffi!

由于某些类型转换可能会失败,函数总是返回一个result_t类型,该类型包含指向错误消息的指针和有效负载。在出现错误的情况下,有效负载为空,消息包含错误字符串。

更多示例

您可以通过查看tests文件夹来找到更多关于shim行为的示例。测试的结构如下

  • src/lib.rs:要公开的Rust库
  • Cargo.toml:Rust库的清单
  • main.c:使用此Rust库的C代码
  • expected_output:包含运行C程序时预期的输出

每个测试crate都是一个利用ffishim库的独立应用程序。它们将说明如何设置库并使用它。

C ABI免责声明

这个crate目前不生成与C ABI兼容的绑定。这是因为它已被设计为与dustr一起使用,该工具在ffi shim之上生成Dart绑定。

由于Dart ffi支持仍处于alpha阶段,它还不能完全消费C ABI。例如,它不支持嵌套结构,并且结构不能按值传递给函数

TODO/限制

这个crate仍处于beta阶段。它还不适合用于生产。

错误

  • 从标量类型到libc类型的映射应该只引用libc类型或者都不引用
  • 在.so文件中不同crate之间可能会出现名称冲突:例如,如果有两个crate中存在名为Config的结构体,那么函数名free_config就会发生冲突。需要使用名称混淆

功能

  • from改为try_from?(无效的Rust字符串转换为CString的不安全操作)
  • 如果使用feature(ffishim)而不是ffi_前缀,则替换函数
  • 明确重新考虑对::anyhow::Error的依赖
  • chrono日期的类型行为

测试

  • 添加一个“完整”的测试/示例场景
  • 设计基准测试策略和框架
  • 添加枚举的测试

文档

  • 编写README.md介绍,说明这个crate的功能
  • 编写ffishim_derive文档,说明如何使用宏

依赖

~0.7–1.3MB
~28K SLoC