#bindings #ffi #c #proc-macro

ffishim_derive

生成FFI兼容存根的过程宏

3个版本

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

#99 in #c

MIT/Apache

67KB
1.5K SLoC

FFIShim

crates.io badge

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

此crate提供了一个垫片,将公开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类型,该类型包含一个指向错误消息的指针和一个有效负载。在发生错误的情况下,有效负载为nil,而消息包含错误字符串。

更多示例

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

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

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

C ABI免责声明

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

由于dart ffi支持目前处于alpha阶段,因此它还不能完全消耗C ABI。例如,它不支持嵌套结构,并且结构不能按值传递给函数

待办/限制

此crate仍处于beta阶段。目前不适合用于生产环境。

错误

  • 标量类型到libc类型的转换应该只引用libc类型或都不引用
  • 在.so文件中,crate之间会出现名称冲突:例如,如果2个crate中存在Config结构体,则函数名称free_config需要名称混淆

特性

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

测试

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

文档

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

依赖

~0.8–1.4MB
~30K SLoC