Skip to content

bun:ffi bietet experimentelle Unterstützung zum Kompilieren und Ausführen von C aus JavaScript mit geringem Overhead.


Verwendung (cc in bun:ffi)

Weitere Informationen finden Sie im Einführungs-Blogbeitrag.

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("Was ist die Antwort auf das Universum?", hello());

C-Quellcode:

c
int hello() {
  return 42;
}

Wenn Sie hello.js ausführen, wird Folgendes ausgegeben:

sh
bun hello.js
Was ist die Antwort auf das Universum? 42

Unter der Haube verwendet cc TinyCC, um den C-Code zu kompilieren und dann mit der JavaScript-Runtime zu verknüpfen, wobei Typen effizient an Ort und Stelle konvertiert werden.

Primitive Typen

Die gleichen FFIType-Werte wie in dlopen werden in cc unterstützt.

FFITypeC TypAliase
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

Strings, Objekte und nicht-primitive Typen

Um die Arbeit mit Strings, Objekten und anderen nicht-primitiven Typen, die nicht 1:1 auf C-Typen abgebildet werden können, zu erleichtern, unterstützt cc N-API.

Um JavaScript-Werte ohne Typkonvertierungen von einer C-Funktion zu übergeben oder zu empfangen, können Sie napi_value verwenden.

Sie können auch ein napi_env übergeben, um die N-API-Umgebung zu erhalten, die zum Aufrufen der JavaScript-Funktion verwendet wird.

Rückgabe eines C-Strings an JavaScript

Wenn Sie beispielsweise einen String in C haben, können Sie ihn wie folgt an JavaScript zurückgeben:

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();

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

Sie können dies auch verwenden, um andere Typen wie Objekte und Arrays zurückzugeben:

c
#include <node/node_api.h>

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

cc Referenz

library: string[]

Das library-Array wird verwendet, um die Bibliotheken anzugeben, die mit dem C-Code verknüpft werden sollen.

ts
type Library = string[];

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

symbols

Das symbols-Objekt wird verwendet, um die Funktionen und Variablen anzugeben, die für JavaScript verfügbar gemacht werden sollen.

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

source

Die source ist ein Dateipfad zum C-Code, der kompiliert und mit der JavaScript-Runtime verknüpft werden soll.

ts
type Source = string | URL | BunFile;

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

flags: string | string[]

Die flags ist ein optionales Array von Strings, die an den TinyCC-Compiler übergeben werden sollen.

ts
type Flags = string | string[];

Dies sind Flags wie -I für Include-Verzeichnisse und -D für Präprozessor-Definitionen.

define: Record<string, string>

Das define ist ein optionales Objekt, das an den TinyCC-Compiler übergeben werden soll.

ts
type Defines = Record<string, string>;

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

Dies sind Präprozessor-Definitionen, die an den TinyCC-Compiler übergeben werden.

Bun von www.bunjs.com.cn bearbeitet