BunFFI(外函数接口) BunFFI

此技能用于通过 Bun 的 FFI 功能从 JavaScript 调用本地 C/C++ 库。关键词包括:Bun FFI、外函数接口、调用C库、原生代码集成、JavaScript、C/C++、跨语言调用、dlopen、共享库、性能优化。

后端开发 0 次安装 0 次浏览 更新于 3/8/2026

名称: Bun FFI 描述: 当用户询问关于 “bun:ffi”、“外函数接口”、“从 Bun 调用 C”、“原生库”、“dlopen”、“共享库”、“调用原生代码” 或与 Bun 集成 C/C++ 库时使用此技能。 版本: 1.0.0

Bun FFI

Bun 的 FFI 允许从 JavaScript 调用原生 C/C++ 库。

快速开始

import { dlopen, suffix, FFIType } from "bun:ffi";

// 加载库
const lib = dlopen(`libc.${suffix}`, {
  printf: {
    args: [FFIType.cstring],
    returns: FFIType.int,
  },
});

// 调用函数
lib.symbols.printf("Hello from C!
");

加载库

平台特定路径

import { dlopen, suffix } from "bun:ffi";

// suffix 是: "dylib" (macOS), "so" (Linux), "dll" (Windows)

// 系统库
const libc = dlopen(`libc.${suffix}`, { ... });

// 自定义库
const myLib = dlopen(`./libmylib.${suffix}`, { ... });

// 绝对路径
const sqlite = dlopen("/usr/lib/libsqlite3.so", { ... });

跨平台加载

function getLibPath(name: string): string {
  const platform = process.platform;
  const paths = {
    darwin: `/usr/local/lib/lib${name}.dylib`,
    linux: `/usr/lib/lib${name}.so`,
    win32: `C:\\Windows\\System32\\${name}.dll`,
  };
  return paths[platform] || paths.linux;
}

const lib = dlopen(getLibPath("mylib"), { ... });

FFI 类型

import { FFIType } from "bun:ffi";

const types = {
  // 整数
  i8: FFIType.i8,        // int8_t
  i16: FFIType.i16,      // int16_t
  i32: FFIType.i32,      // int32_t / int
  i64: FFIType.i64,      // int64_t / long long

  // 无符号整数
  u8: FFIType.u8,        // uint8_t
  u16: FFIType.u16,      // uint16_t
  u32: FFIType.u32,      // uint32_t
  u64: FFIType.u64,      // uint64_t

  // 浮点数
  f32: FFIType.f32,      // float
  f64: FFIType.f64,      // double

  // 指针
  ptr: FFIType.ptr,      // void*
  cstring: FFIType.cstring, // const char*

  // 其他
  bool: FFIType.bool,    // bool
  void: FFIType.void,    // void
};

函数定义

import { dlopen, FFIType, ptr, CString } from "bun:ffi";

const lib = dlopen("./libmath.so", {
  // 简单函数
  add: {
    args: [FFIType.i32, FFIType.i32],
    returns: FFIType.i32,
  },

  // 字符串函数
  greet: {
    args: [FFIType.cstring],
    returns: FFIType.cstring,
  },

  // 指针函数
  allocate: {
    args: [FFIType.u64],
    returns: FFIType.ptr,
  },

  // 空函数
  log_message: {
    args: [FFIType.cstring],
    returns: FFIType.void,
  },

  // 无参数
  get_version: {
    args: [],
    returns: FFIType.cstring,
  },
});

// 调用函数
const sum = lib.symbols.add(1, 2); // 3
const message = lib.symbols.greet(ptr(Buffer.from("World\0")));

处理字符串

import { dlopen, FFIType, ptr, CString } from "bun:ffi";

// 传递字符串到 C
const str = Buffer.from("Hello\0"); // 必须为空终止
lib.symbols.print_string(ptr(str));

// 从 C 接收字符串
const result = lib.symbols.get_string();
const jsString = new CString(result); // 转换为 JS 字符串
console.log(jsString.toString());

处理指针

import { dlopen, FFIType, ptr, toArrayBuffer } from "bun:ffi";

const lib = dlopen("./libdata.so", {
  create_buffer: {
    args: [FFIType.u64],
    returns: FFIType.ptr,
  },
  fill_buffer: {
    args: [FFIType.ptr, FFIType.u8, FFIType.u64],
    returns: FFIType.void,
  },
  free_buffer: {
    args: [FFIType.ptr],
    returns: FFIType.void,
  },
});

// 分配缓冲区
const size = 1024;
const bufPtr = lib.symbols.create_buffer(size);

// 填充缓冲区
lib.symbols.fill_buffer(bufPtr, 0xff, size);

// 以 ArrayBuffer 读取缓冲区
const arrayBuffer = toArrayBuffer(bufPtr, 0, size);
const view = new Uint8Array(arrayBuffer);
console.log(view); // [255, 255, 255, ...]

// 释放缓冲区
lib.symbols.free_buffer(bufPtr);

结构体

import { dlopen, FFIType, ptr } from "bun:ffi";

// C 结构体:
// struct Point { int32_t x; int32_t y; };

const lib = dlopen("./libgeom.so", {
  create_point: {
    args: [FFIType.i32, FFIType.i32],
    returns: FFIType.ptr, // 返回 Point*
  },
  get_distance: {
    args: [FFIType.ptr, FFIType.ptr],
    returns: FFIType.f64,
  },
});

// 手动创建结构体
const point = new ArrayBuffer(8); // 2 x int32
const view = new DataView(point);
view.setInt32(0, 10, true); // x = 10
view.setInt32(4, 20, true); // y = 20

// 传递到 C
lib.symbols.get_distance(ptr(point), ptr(point));

回调

import { dlopen, FFIType, callback } from "bun:ffi";

const lib = dlopen("./libsort.so", {
  sort_array: {
    args: [FFIType.ptr, FFIType.u64, FFIType.ptr], // 回调
    returns: FFIType.void,
  },
});

// 创建回调
const compareCallback = callback(
  {
    args: [FFIType.ptr, FFIType.ptr],
    returns: FFIType.i32,
  },
  (a, b) => {
    const aVal = new DataView(toArrayBuffer(a, 0, 4)).getInt32(0, true);
    const bVal = new DataView(toArrayBuffer(b, 0, 4)).getInt32(0, true);
    return aVal - bVal;
  }
);

// 使用回调
lib.symbols.sort_array(arrayPtr, length, compareCallback.ptr);

// 完成后关闭回调
compareCallback.close();

示例: SQLite

import { dlopen, FFIType, ptr, CString } from "bun:ffi";

const sqlite = dlopen("libsqlite3.dylib", {
  sqlite3_open: {
    args: [FFIType.cstring, FFIType.ptr],
    returns: FFIType.i32,
  },
  sqlite3_exec: {
    args: [FFIType.ptr, FFIType.cstring, FFIType.ptr, FFIType.ptr, FFIType.ptr],
    returns: FFIType.i32,
  },
  sqlite3_close: {
    args: [FFIType.ptr],
    returns: FFIType.i32,
  },
});

// 打开数据库
const dbPtrArray = new BigInt64Array(1);
const dbPath = Buffer.from("test.db\0");
sqlite.symbols.sqlite3_open(ptr(dbPath), ptr(dbPtrArray));
const db = dbPtrArray[0];

// 执行查询
const sql = Buffer.from("CREATE TABLE test (id INTEGER);\0");
sqlite.symbols.sqlite3_exec(db, ptr(sql), null, null, null);

// 关闭
sqlite.symbols.sqlite3_close(db);

内存管理

// 手动分配
const buffer = new ArrayBuffer(1024);
const pointer = ptr(buffer);

// 缓冲区在 ArrayBuffer 存在期间保持有效
// JavaScript GC 将清理 ArrayBuffer

// 对于 C 分配的内存,调用 C 的 free 函数
lib.symbols.free(cPointer);

线程安全

// FFI 调用是同步的并阻塞主线程
// 对于长时间运行的操作,使用 Web Workers:

// worker.ts
import { dlopen } from "bun:ffi";
const lib = dlopen(...);

self.onmessage = (e) => {
  const result = lib.symbols.expensive_operation(e.data);
  self.postMessage(result);
};

常见错误

错误 原因 修复
Library not found 路径错误 检查库路径
Symbol not found 函数名错误 检查函数导出
Type mismatch FFI 类型错误 精确匹配 C 类型
Segmentation fault 内存错误 检查指针有效性

何时加载参考文献

加载 references/type-mappings.md 当:

  • 复杂类型转换
  • 结构体布局
  • 联合类型

加载 references/performance.md 当:

  • 优化 FFI 调用
  • 批量操作
  • 内存池化