¿Es posible escribir una extensión node.js en C (no en C ++)?

Una búsqueda rápida en Google produce al menos un tutorial para escribir un “Hola mundo” de C ++ para node.js, pero no está claro si es posible escribir una extensión de este tipo utilizando solo C. Suponiendo que sea posible, ¿a qué desafíos y limitaciones me enfrentaría?

Si lo desea, puede escribir partes de su extensión en C, pero necesitará al menos un poco de código C ++ para unir su código C con Nodo.

Como habrá visto en su HelloWorld, las extensiones se basan en los encabezados v8.h y node.h , que tienen todas las clases que Node espera. Sin ellos, no podrá crear correctamente el objeto JS para exportarlo a Node.

Dicho esto, puede escribir fácilmente un pequeño conjunto de funciones C ++ que simplemente llaman funciones C, y envolver algún tipo de estructura C.

Encontré esto en Hacker News:

https://github.com/wesolows/v8plus

v8 +: Nodo addon C ++ al límite C

Esta capa ofrece una forma de escribir al menos complementos de Nodo simples en C sin todos los errores de C ++ que de otro modo se esperaría que usaran. Ese pegote todavía existe, pero no tienes que escribirlo. Más importante aún, puede escribir su módulo en un entorno de progtwigción sano, evitando la semántica de C ++ confusa y propensa a errores.

Ahora tenemos al menos 3 buenas opciones:

node-ffi: Node.js Interfaz de función externa
Complemento para cargar y llamar a bibliotecas dinámicas usando JavaScript puro. Puede utilizarse para crear enlaces a bibliotecas nativas sin escribir ningún código C
https://github.com/node-ffi/node-ffi

SWIG: Envoltorio simplificado y generador de interfaz
(genera envoltorios para muchos idiomas, lo que resuelve muchos problemas a la vez)
http://www.swig.org/

emscripten
Comstack C y C ++ en JavaScript altamente optimizable que se ejecuta incluso en la web a una velocidad casi nativa, sin complementos.
http://kripken.github.io/emscripten-site/

Debe declarar la función C individual en su código C ++ usando la syntax externa “C”

Ejemplo:

 #define BUILDING_NODE_EXTENSION #include  extern "C" void f(int i, char c, float x); using namespace v8; 

Si tiene varias funciones de C, puede agruparse mediante llaves:

 extern "C" { void f(int i, char c, float x); int g(char* s, char const* s2); double sqrtOfSumOfSquares(double a, double b); } 

luego llame a la función desde la función C ++:

 Handle MyFunction(const Arguments& args) { HandleScope scope; f(7, 'x', 3.14); // <--- return scope.Close(String::New("Hello")); } Handle CreateFunction(const Arguments& args) { HandleScope scope; Local tpl = FunctionTemplate::New(MyFunction); Local fn = tpl->GetFunction(); fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous return scope.Close(fn); } void Init(Handle target) { target->Set(String::NewSymbol("createFunction"), FunctionTemplate::New(CreateFunction)->GetFunction()); } NODE_MODULE(addon, Init) 

Nota: Usar código de muestra de Nodejs Addons

El código que interactúa directamente con node.js debe escribirse en C ++.

Podría escribir envoltorios extern "C" usando tipos opacos para todo lo que necesite desde node.hy v8.h , pero probablemente sea más fácil usar C ++ en su lugar (que, por supuesto, puede llamar al código C).

Si su módulo utiliza libuv, puede vincularlo al nodo ejecutable. Exporta las funciones libuv como lo hace una biblioteca compartida.

Luego puede usar node-ffi para interactuar con él (no se necesita conocimiento de C ++ aquí).

Así es como lo hice en Windows, usando MSVS:

  • Crear una nueva solución DLL en MSVS
  • Descargue el libuv y copie los archivos de inclusión y lib en el MSVS
  • Descargue el archivo node.lib y póngalo en la carpeta lib de MSVS
  • Compile la siguiente fuente de ejemplo que agrega un temporizador al ciclo de eventos principal

testlib.c:

 #include  #include  #include "uv.h" void (*p_callback)(int number, char *text); void timer_cb1 (uv_timer_t* timer, int status) { printf("libuv timer here\n", status); p_callback(123, "it worked!"); } void set_timer (int interval, void *pfunction) { uv_loop_t *loop; uv_timer_t *timer1; printf("set_timer called. interval=%d callback=%p\n", interval, pfunction); p_callback = pfunction; printf("uv_version_string = %s\n", uv_version_string()); loop = uv_default_loop(); if (loop == 0) { puts("could not get the reference to the default loop"); return; } puts("got the default loop. now allocating the timer struct"); timer1 = (uv_timer_t *) malloc(sizeof(uv_timer_t)); if (timer1 == 0) { puts("malloc failed"); return; } puts("initializing timer"); uv_timer_init(loop, timer1); puts("starting timer"); uv_timer_start(timer1, (uv_timer_cb) &timer_cb1, interval, interval); puts("timer created. returning"); } 

utilizar el testlib.def:

 EXPORTS set_timer 

Y recuerda enlazar al nodo.lib

  • Mueva la dll creada a la carpeta de prueba y ejecute estos comandos allí:

npm install ffi (actualmente se requieren las herramientas de construcción. consulte las instrucciones)

node test-lib.js

test-lib.js está aquí:

 var ffi = require('ffi'); var testlib = ffi.Library('testlib', { 'set_timer': [ 'void', [ 'int', 'pointer' ] ] }); var callback = ffi.Callback('void', ['int', 'string'], function(number, text) { console.log("javascript callback here!!! number=" + number + " text=" + text); } ); console.log('registering the callback...'); testlib.set_timer(500, callback); console.log('done') 

Use su imaginación. Tenemos redes, hilos de trabajo y otras opciones dentro de libuv …