Bun

C 編譯器

bun:ffi 實驗性地支援從 JavaScript 編譯和執行 C 語言,且具有低開銷。

用法 (bun:ffi 中的 cc)

請參閱介紹部落格文章以取得更多資訊。

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 編譯器的前處理器定義。