bun:ffi は、JavaScript から低オーバーヘッドで C をコンパイルして実行するための実験的サポートを備えています。
使用方法(bun:ffi 内の cc)
詳細については、紹介ブログ投稿 を参照してください。
JavaScript:
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 ソース:
int hello() {
return 42;
}hello.js を実行すると、以下が出力されます。
bun hello.js
What is the answer to the universe? 42内部では、cc は TinyCC を使用して C コードをコンパイルし、JavaScript ランタイムとリンクして、型をその場で効率的に変換します。
プリミティブ型
dlopen と同じ FFIType 値が cc でサポートされています。
FFIType | C 型 | エイリアス |
|---|---|---|
| cstring | char* | |
| function | (void*)(*)() | fn、callback |
| ptr | void* | pointer、void*、char* |
| i8 | int8_t | int8_t |
| i16 | int16_t | int16_t |
| i32 | int32_t | int32_t、int |
| i64 | int64_t | int64_t |
| i64_fast | int64_t | |
| u8 | uint8_t | uint8_t |
| u16 | uint16_t | uint16_t |
| u32 | uint32_t | uint32_t |
| u64 | uint64_t | uint64_t |
| u64_fast | uint64_t | |
| f32 | float | float |
| f64 | double | double |
| bool | bool | |
| char | char | |
| napi_env | napi_env | |
| napi_value | napi_value |
文字列、オブジェクト、および非プリミティブ型
C 型に 1:1 でマッピングされない文字列、オブジェクト、およびその他の非プリミティブ型をより簡単に操作できるように、cc は N-API をサポートしています。
C 関数から型変換なしで JavaScript 値を渡したり受け取ったりするには、napi_value を使用できます。
また、napi_env を渡して、JavaScript 関数を呼び出すために使用される N-API 環境を受け取ることもできます。
C 文字列を JavaScript に返す
たとえば、C に文字列がある場合、次のようにして JavaScript に返すことができます。
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 側:
#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;
}これを使用して、オブジェクトや配列などの他の型を返すこともできます。
#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 は、コンパイルされて JavaScript ランタイムとリンクされる C コードへのファイルパスです。
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 コンパイラーに渡されるプリプロセッサ定義です。