Skip to content

bun:ffi prend en charge de manière expérimentale la compilation et l'exécution de code C depuis JavaScript avec une faible surcharge.


Utilisation (cc dans bun:ffi)

Consultez l'article de blog d'introduction pour plus d'informations.

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("Quelle est la réponse à l'univers ?", hello());

Source C :

c
int hello() {
  return 42;
}

Lorsque vous exécutez hello.js, cela affichera :

sh
bun hello.js
Quelle est la réponse à l'univers ? 42

Sous le capot, cc utilise TinyCC pour compiler le code C puis le lier avec le runtime JavaScript, en convertissant efficacement les types sur place.

Types primitifs

Les mêmes valeurs FFIType que dans dlopen sont prises en charge dans cc.

FFITypeType CAlias
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

Chaînes, objets et types non primitifs

Pour faciliter le travail avec les chaînes, les objets et autres types non primitifs qui ne correspondent pas 1:1 aux types C, cc prend en charge N-API.

Pour passer ou recevoir des valeurs JavaScript sans conversions de type depuis une fonction C, vous pouvez utiliser napi_value.

Vous pouvez également passer un napi_env pour recevoir l'environnement N-API utilisé pour appeler la fonction JavaScript.

Retourner une chaîne C vers JavaScript

Par exemple, si vous avez une chaîne en C, vous pouvez la retourner vers JavaScript comme ceci :

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

Et en 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;
}

Vous pouvez également utiliser cela pour retourner d'autres types comme des objets et des tableaux :

c
#include <node/node_api.h>

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

Référence cc

library: string[]

Le tableau library est utilisé pour spécifier les bibliothèques qui doivent être liées avec le code C.

ts
type Library = string[];

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

symbols

L'objet symbols est utilisé pour spécifier les fonctions et variables qui doivent être exposées à JavaScript.

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

source

Le source est un chemin de fichier vers le code C qui doit être compilé et lié avec le runtime JavaScript.

ts
type Source = string | URL | BunFile;

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

flags: string | string[]

Le flags est un tableau optionnel de chaînes qui doit être passé au compilateur TinyCC.

ts
type Flags = string | string[];

Ce sont des indicateurs comme -I pour les répertoires d'inclusion et -D pour les définitions de préprocesseur.

define: Record<string, string>

Le define est un objet optionnel qui doit être passé au compilateur TinyCC.

ts
type Defines = Record<string, string>;

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

Ce sont des définitions de préprocesseur passées au compilateur TinyCC.

Bun édité par www.bunjs.com.cn