Skip to main content
bun:ffi实验性的,存在已知的 bug 和限制,不应在生产环境中依赖。从 Bun 与原生代码交互的最稳定方式是编写 Node-API 模块
使用内置的 bun:ffi 模块高效地从 JavaScript 调用原生库。它适用于任何支持 C ABI 的语言,包括 Zig、Rust、C/C++、C#、Nim 和 Kotlin。

dlopen 用法(bun:ffi

打印 sqlite3 的版本号:

性能

根据我们的基准测试bun:ffi 的速度大约是 Node.js 通过 Node-API 进行 FFI 的 2-6 倍。 Bun 生成并即时编译 C 绑定,高效地在 JavaScript 类型和原生类型之间转换值。为了编译 C,Bun 嵌入了 TinyCC,一个小型且快速的 C 编译器。

用法

Zig

add.zig
要编译:
terminal
将共享库的路径和要导入的符号映射传递给 dlopen

Rust

要编译:

C++

要编译:

FFI 类型

支持以下 FFIType 值。 buffer 参数必须是 TypedArrayDataView

字符串

JavaScript 字符串和类 C 字符串是不同的,这给使用字符串与原生库交互带来了复杂性。
JavaScript 字符串:
  • UTF16(每个字母 2 字节)或可能的 latin1,取决于 JavaScript 引擎和使用的是什么字符
  • length 单独存储
  • 不可变
C 字符串:
  • UTF8(每个字母 1 字节),通常
  • 不存储长度。相反,字符串以 null 结尾:其长度是第一个 \0 的索引
  • 可变
为了解决这个问题,bun:ffi 导出了 CString,它扩展了 JavaScript 内置的 String 以支持 null 结尾的字符串并添加了一些额外功能:
从 null 结尾的字符串指针转换为 JavaScript 字符串:
从具有已知长度的指针转换为 JavaScript 字符串:
new CString() 构造器会克隆 C 字符串,因此在 ptr 被释放后继续使用 myString 是安全的。
当用于 returns 时,FFIType.cstring 将指针强制转换为 JavaScript string。当用于 args 时,FFIType.cstringptr 相同。

函数指针

不支持异步函数
要从 JavaScript 调用函数指针,请使用 CFunction,例如配合您从已加载的 Node-API(napi)模块获得的指针。
要一次定义多个函数指针,请使用 linkSymbols

回调

使用 JSCallback 创建可传递给 C/FFI 函数的 JavaScript 回调函数,使原生代码可以回调您的 JavaScript 或 TypeScript。这对于异步代码非常有用。
当您完成 JSCallback 的使用后,调用 close() 以释放内存。

实验性线程安全回调

JSCallback 具有实验性的线程安全回调支持。如果您将回调函数传递到创建它的线程之外的其他线程,则需要此功能。通过可选的 threadsafe 参数启用它。 线程安全回调在从运行 JavaScript 代码的另一个线程(即 Worker)调用时效果最佳。未来的 Bun 版本将支持从任何线程调用它们,例如由 Bun 不知晓的原生库生成的新线程。
⚡️ 性能提示:为获得轻微的性能提升,直接传递 JSCallback.prototype.ptr 而不是 JSCallback 对象:

指针

Bun 将指针表示为 JavaScript 中的 number
64 位处理器支持多达 52 位的可寻址空间JavaScript 数值支持 53 位的可用空间,这留下了约 11 位的额外空间。为什么不用 BigInt BigInt 更慢。JavaScript 引擎单独分配 BigInt,因此它们不能放入常规的 JavaScript 值中。如果您将 BigInt 传递给函数,它会被转换为 numberWindows 注意:Windows API 类型 HANDLE 不表示虚拟地址,将其用于 ptr 不会按预期工作。请使用 u64 安全地表示 HANDLE 值。
TypedArray 转换为指针:
从指针转换为 ArrayBuffer
要读取指针中的数据,您有两种选择。对于长期存在的指针,使用 DataView
对于短期存在的指针,使用 read
read 函数的行为类似于 DataView,但通常更快,因为它不需要创建 DataViewArrayBuffer

内存管理

bun:ffi 不会为您管理内存。当您使用完内存后,必须自行释放。

从 JavaScript

要跟踪 TypedArray 何时不再从 JavaScript 使用,请使用 FinalizationRegistry

从 C、Rust、Zig 等

要跟踪 TypedArray 何时不再从 C 或 FFI 使用,请向 toArrayBuffertoBuffer 传递一个回调和可选上下文的指针。回调会在垃圾收集器释放底层 ArrayBuffer JavaScript 对象时稍后调用。 期望的签名与 JavaScriptCore 的 C API 相同:

内存安全

不要在 FFI 之外使用原始指针。未来的 Bun 版本可能会添加 CLI 标志来禁用 bun:ffi

指针对齐

如果 API 期望的指针大小不是 charu8,请确保 TypedArray 也是该大小。由于对齐原因,u64*[8]u8* 并不完全相同。

传递指针

在 FFI 函数期望指针的地方,传递同等大小的 TypedArray
自动生成的包装器会将 TypedArray 转换为指针。
如果您不想要自动转换,或者想要指向 TypedArray 内特定字节偏移量的指针,请直接获取 TypedArray 的指针:

读取指针