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:
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:
int hello() {
return 42;
}Wenn Sie hello.js ausführen, wird Folgendes ausgegeben:
bun hello.js
Was ist die Antwort auf das Universum? 42Unter 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.
FFIType | C Typ | Aliase |
|---|---|---|
| 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 |
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:
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:
#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:
#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.
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.
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.
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.
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.
type Defines = Record<string, string>;
cc({
source: "hello.c",
define: {
NDEBUG: "1",
},
});Dies sind Präprozessor-Definitionen, die an den TinyCC-Compiler übergeben werden.