Skip to content

bun:ffi は、JavaScript から低オーバーヘッドで C をコンパイルして実行するための実験的サポートを備えています。


使用方法(bun:ffi 内の cc)

詳細については、紹介ブログ投稿 を参照してください。

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("What is the answer to the universe?", hello());

C ソース:

c
int hello() {
  return 42;
}

hello.js を実行すると、以下が出力されます。

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

内部では、ccTinyCC を使用して C コードをコンパイルし、JavaScript ランタイムとリンクして、型をその場で効率的に変換します。

プリミティブ型

dlopen と同じ FFIType 値が cc でサポートされています。

FFITypeC 型エイリアス
cstringchar*
function(void*)(*)()fncallback
ptrvoid*pointervoid*char*
i8int8_tint8_t
i16int16_tint16_t
i32int32_tint32_tint
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 をサポートしています。

C 関数から型変換なしで JavaScript 値を渡したり受け取ったりするには、napi_value を使用できます。

また、napi_env を渡して、JavaScript 関数を呼び出すために使用される N-API 環境を受け取ることもできます。

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 は、コンパイルされて JavaScript ランタイムとリンクされる C コードへのファイルパスです。

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 by www.bunjs.com.cn 編集