Skip to content

bun:ffi имеет экспериментальную поддержку компиляции и запуска C из JavaScript с низкими накладными расходами.


Использование (cc в bun:ffi)

Дополнительную информацию см. в вводном сообщении в блоге.

JavaScript:

ts
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("Каков ответ на вселенную?", hello());

Исходный код C:

c
int hello() {
  return 42;
}

Когда вы запустите hello.js, он напечатает:

sh
bun hello.js
Каков ответ на вселенную? 42

Под капотом cc использует TinyCC для компиляции кода C и затем связывает его со средой выполнения JavaScript, эффективно преобразуя типы на месте.

Примитивные типы

Те же значения FFIType, что и в dlopen, поддерживаются в cc.

FFITypeТип CПсевдонимы
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

Строки, объекты и непримитивные типы

Чтобы упростить работу со строками, объектами и другими непримитивными типами, которые не отображаются 1:1 на типы C, cc поддерживает N-API.

Для передачи или получения значений JavaScript без каких-либо преобразований типов из функции C вы можете использовать napi_value.

Вы также можете передать napi_env для получения окружения N-API, используемого для вызова функции JavaScript.

Возврат строки C в JavaScript

Например, если у вас есть строка в C, вы можете вернуть её в JavaScript следующим образом:

ts
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:

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;
}

Вы также можете использовать это для возврата других типов, таких как объекты и массивы:

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.

ts
type Library = string[];

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

symbols

Объект symbols используется для указания функций и переменных, которые должны быть предоставлены JavaScript.

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

source

source — это путь к файлу с кодом C, который должен быть скомпилирован и связан со средой выполнения JavaScript.

ts
type Source = string | URL | BunFile;

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

flags: string | string[]

flags — это необязательный массив строк, которые должны быть переданы компилятору TinyCC.

ts
type Flags = string | string[];

Это флаги, такие как -I для каталогов включения и -D для определений препроцессора.

define: Record<string, string>

define — это необязательный объект, которое должно быть передано компилятору TinyCC.

ts
type Defines = Record<string, string>;

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

Это определения препроцессора, передаваемые компилятору TinyCC.

Bun от www.bunjs.com.cn