Skip to content

bun:ffi ha supporto sperimentale per compilare ed eseguire C da JavaScript con basso overhead.


Utilizzo (cc in bun:ffi)

Vedi il post del blog introduttivo per maggiori informazioni.

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("Qual è la risposta all'universo?", hello());

Sorgente C:

c
int hello() {
  return 42;
}

Quando esegui hello.js, stamperà:

sh
bun hello.js
Qual è la risposta all'universo? 42

Sotto il cofano, cc usa TinyCC per compilare il codice C e poi linkarlo con il runtime JavaScript, convertendo efficientemente i tipi in-place.

Tipi primitivi

Gli stessi valori FFIType in dlopen sono supportati in cc.

FFITypeTipo 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

Stringhe, oggetti e tipi non primitivi

Per rendere più facile lavorare con stringhe, oggetti e altri tipi non primitivi che non mappano 1:1 ai tipi C, cc supporta N-API.

Per passare o ricevere valori JavaScript senza alcuna conversione di tipo da una funzione C, puoi usare napi_value.

Puoi anche passare un napi_env per ricevere l'ambiente N-API usato per chiamare la funzione JavaScript.

Restituire una stringa C a JavaScript

Ad esempio, se hai una stringa in C, puoi restituirla a JavaScript in questo modo:

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

E 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;
}

Puoi anche usare questo per restituire altri tipi come oggetti e array:

c
#include <node/node_api.h>

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

Riferimento cc

library: string[]

L'array library è usato per specificare le librerie che dovrebbero essere linkate con il codice C.

ts
type Library = string[];

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

symbols

L'oggetto symbols è usato per specificare le funzioni e le variabili che dovrebbero essere esposte a JavaScript.

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

source

Il source è un percorso file al codice C che dovrebbe essere compilato e linkato con il runtime JavaScript.

ts
type Source = string | URL | BunFile;

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

flags: string | string[]

I flags sono un array opzionale di stringhe che dovrebbero essere passate al compilatore TinyCC.

ts
type Flags = string | string[];

Questi sono flag come -I per le directory di include e -D per le definizioni del preprocessore.

define: Record<string, string>

Il define è un oggetto opzionale che dovrebbe essere passato al compilatore TinyCC.

ts
type Defines = Record<string, string>;

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

Queste sono definizioni del preprocessore passate al compilatore TinyCC.

Bun a cura di www.bunjs.com.cn