Bun

C 编译器

bun:ffi 具有实验性支持,可以使用低开销从 JavaScript 编译和运行 C 代码。

用法 (cc 在 bun:ffi 中)

有关更多信息,请参阅介绍性博客文章

JavaScript

hello.js
import { cc } from "bun:ffi";
import source from "./hello.c" with { type: "file" };

const {
  symbols: { hello },
} = cc({
  source,
  symbols: {
    hello: {
      args: [],
      returns: "int",
    },
  },
});

console.log("What is the answer to the universe?", hello());

C 源代码

hello.c
int hello() {
  return 42;
}

当您运行 hello.js 时,它将打印

bun hello.js
What is the answer to the universe? 42

在底层,cc 使用 TinyCC 编译 C 代码,然后将其与 JavaScript 运行时链接,从而高效地就地转换类型。

原始类型

dlopen 中的相同 FFIType 值在 cc 中也受支持。

FFITypeC 类型别名
cstringchar*
function(void*)(*)()fn, callback
ptrvoid*pointer, void*, char*
i8int8_tint8_t
i16int16_tint16_t
i32int32_tint32_t, int
i64int64_tint64_t
i64_fastint64_t
u8uint8_tuint8_t
u16uint16_tuint16_t
u32uint32_tuint32_t
u64uint64_tuint64_t
u64_fastuint64_t
f32floatfloat
f64doubledouble
boolbool
charchar
napi_envnapi_env
napi_valuenapi_value

字符串、对象和非原始类型

为了更轻松地处理字符串、对象和其他不与 C 类型 1:1 映射的非原始类型,cc 支持 N-API。

要传递或接收 JavaScript 值,而无需从 C 函数进行任何类型转换,您可以使用 napi_value

您还可以传递 napi_env 以接收用于调用 JavaScript 函数的 N-API 环境。

将 C 字符串返回到 JavaScript

例如,如果您在 C 中有一个字符串,您可以像这样将其返回到 JavaScript

hello.js
import { cc } from "bun:ffi";
import source from "./hello.c" with { type: "file" };

const {
  symbols: { hello },
} = cc({
  source,
  symbols: {
    hello: {
      args: ["napi_env"],
      returns: "napi_value",
    },
  },
});

const result = hello();

在 C 中

hello.c
#include <node/node_api.h>

napi_value hello(napi_env env) {
  napi_value result;
  napi_create_string_utf8(env, "Hello, Napi!", NAPI_AUTO_LENGTH, &result);
  return result;
}

您也可以使用它来返回其他类型,例如对象和数组

hello.c
#include <node/node_api.h>

napi_value hello(napi_env env) {
  napi_value result;
  napi_create_object(env, &result);
  return result;
}

cc 参考

library: string[]

library 数组用于指定应与 C 代码链接的库。

type Library = string[];

cc({
  source: "hello.c",
  library: ["sqlite3"],
});

symbols

symbols 对象用于指定应向 JavaScript 公开的函数和变量。

type Symbols = {
  [key: string]: {
    args: FFIType[];
    returns: FFIType;
  };
};

source

source 是 C 代码的文件路径,该文件路径应与 JavaScript 运行时编译和链接。

type Source = string | URL | BunFile;

cc({
  source: "hello.c",
  symbols: {
    hello: {
      args: [],
      returns: "int",
    },
  },
});

flags: string | string[]

flags 是一个可选的字符串数组,应传递给 TinyCC 编译器。

type Flags = string | string[];

这些是诸如 -I (用于包含目录)和 -D (用于预处理器定义)之类的标志。

define: Record<string, string>

define 是一个可选对象,应传递给 TinyCC 编译器。

type Defines = Record<string, string>;

cc({
  source: "hello.c",
  define: {
    "NDEBUG": "1",
  },
});

这些是传递给 TinyCC 编译器的预处理器定义。