C贸mo crear plugins C / C ++ en el node

    Node.js es excelente por muchas razones, una de las cuales es la velocidad con la que puede crear aplicaciones significativas. Sin embargo, como todos sabemos, esto tiene el precio del rendimiento (en comparaci贸n con el c贸digo nativo). Para evitar esto, puede escribir su c贸digo para interactuar con un c贸digo m谩s r谩pido escrito en C o C ++. Todo lo que tenemos que hacer es informar a Node d贸nde encontrar este c贸digo y c贸mo interactuar con 茅l.

    Hay algunas formas de resolver este problema seg煤n el nivel de abstracci贸n que desee. Comenzaremos con la abstracci贸n m谩s baja, que es el node A帽adir.

    Complementos

    Un plugin funciona proporcionando el pegamento entre las bibliotecas Node y C / C ++. Para el desarrollador t铆pico de Node, esto puede ser un poco complicado, ya que tendr谩 que comenzar a escribir c贸digo C / C ++ para configurar la interfaz. Sin embargo, entre este art铆culo y la documentaci贸n de Node, deber铆a poder hacer funcionar algunas interfaces simples.

    Hay algunas cosas que debemos repasar antes de comenzar a crear plugins. En primer lugar, necesitamos saber c贸mo compilar (algo que los desarrolladores de Node felizmente olvidan) el c贸digo nativo. Esto se hace usando node-gyp. Luego, hablaremos brevemente sobre yaya, que ayuda a manejar diferentes versiones de API de node.

    node-gyp

    Hay muchos tipos diferentes de procesadores (x86, ARM, PowerPC, etc.) e incluso m谩s sistemas operativos con los que lidiar al compilar su c贸digo. Por suerte, node-gyp maneja todo esto por ti. Como se describe en su p谩gina de Github, node-gyp es una “herramienta de l铆nea de comandos multiplataforma escrita en Node.js para compilar m贸dulos complementarios nativos para Node.js”. Esencialmente, node-gyp es solo un envoltorio estafa, que est谩 hecho por el equipo de Chromium.

    El archivo README del proyecto tiene excelentes instrucciones sobre c贸mo instalar y usar el paquete, por lo que deber铆a leerlo para obtener m谩s detalles. En resumen, usar node-gyp debe hacer lo siguiente.

    Vaya al directorio de su proyecto:

    $ cd my_node_addon
    

    Genere los archivos de compilaci贸n adecuados utilizando el configure comando, que crear谩 un Makefile (en Unix), o vcxproj (en Windows):

    $ node-gyp configure
    

    Y finalmente, construye el proyecto:

    $ node-gyp build
    

    Esto generar谩 un /build directorio que contiene, entre otras cosas, el binario compilado.

    Incluso cuando se utilizan abstracciones superiores como ffi paquete, es bueno entender lo que est谩 sucediendo bajo el cap贸, as铆 que le recomiendo que se tome el tiempo para aprender los entresijos node-gyp.

    yaya

    nan (Native Abstractions for Node) es un m贸dulo que se pasa por alto f谩cilmente, pero le ahorrar谩 horas de frustraci贸n. Entre versiones de node v0.8, v0.10y v0.12, las versiones V8 utilizadas pasaron por algunos cambios importantes (adem谩s de cambios dentro del propio node), por lo que nan ayuda a ocultarle estos cambios y proporciona una interfaz agradable y coherente.

    Esta abstracci贸n nativa funciona proporcionando objetos / funciones C / C ++ en el #include <nan.h> archivo de cabecera.

    Para usarlo, instale el nan paquete:

    $ npm install --save nan
    

    Agregue estas l铆neas a su archivo binding.gyp:

    "include_dirs" : [ 
        "<!(node -e "require('nan')")"
    ]
    

    Y est谩s listo para usar m茅todos / funciones desde nan.h dentro de tus ganchos en lugar del original #include <node.h> c贸digo. Te recomiendo encarecidamente que uses nan. No tiene mucho sentido reinventar la rueda en este caso.

    Crear el plugin

    Antes de comenzar con su plugin, aseg煤rese de tomarse un tiempo para familiarizarse con las siguientes bibliotecas:

    • La biblioteca V8 JavaScript C ++, que se utiliza para interactuar realmente con JavaScript (como crear funciones, llamar a objetos, etc.).
      • NOTA: node.h es el archivo predeterminado sugerido, pero realmente nan.h deber铆a usarse en su lugar
    • libuv, una biblioteca de E / S as铆ncrona multiplataforma escrita en C. Esta biblioteca es 煤til cuando se realiza cualquier tipo de E / S (abrir un archivo, escribir en la red, configurar un temporizador, etc.) en sus bibliotecas nativas y necesita para hacerlo asincr贸nico.
    • Bibliotecas de nodes internos. Uno de los objetos m谩s importantes para comprender es node::ObjectWrap, del que derivan la mayor铆a de los objetos.

    A lo largo del resto de esta secci贸n, lo guiar茅 a trav茅s de un ejemplo real. En este caso, crearemos un enlace a C ++ <cmath> de la biblioteca pow funci贸n. Dado que casi siempre deber铆as usar nan, eso es lo que usar茅 a lo largo de los ejemplos.

    Para este ejemplo, en su proyecto de plugin debe tener al menos estos archivos presentes:

    • pow.cpp
    • binding.gyp
    • package.json

    El archivo C ++ no necesita ser nombrado pow.cpp, pero el nombre normalmente refleja que es un plugin o su funci贸n espec铆fica.

    // pow.cpp
    #include <cmath>
    #include <nan.h>
    
    void Pow(const Nan::FunctionCallbackInfo<v8::Value>& info) {
    
    	if (info.Length() < 2) {
    		Nan::ThrowTypeError("Wrong number of arguments");
    		return;
    	}
    
    	if (!info[0]->IsNumber() || !info[1]->IsNumber()) {
    		Nan::ThrowTypeError("Both arguments should be numbers");
    		return;
    	}
    
    	double arg0 = info[0]->NumberValue();
    	double arg1 = info[1]->NumberValue();
    	v8::Local<v8::Number> num = Nan::New(pow(arg0, arg1));
    
    	info.GetReturnValue().Set(num);
    }
    
    void Init(v8::Local<v8::Object> exports) {
    	exports->Set(Nan::New("pow").ToLocalChecked(),
    				 Nan::New<v8::FunctionTemplate>(Pow)->GetFunction());
    }
    
    NODE_MODULE(pow, Init)
    

    Tenga en cuenta que no hay punto y coma (;) al final de NODE_MODULE. Esto se hace intencionalmente ya que NODE_MODULE en realidad no es una funci贸n, es una macro.

    El c贸digo anterior puede parecer un poco abrumador al principio para aquellos que no han escrito C ++ en un tiempo (o nunca), pero en realidad no es demasiado dif铆cil de entender. los Pow La funci贸n es la carne del c贸digo donde verificamos el n煤mero de argumentos pasados, los tipos de argumentos, llamamos al nativo pow funci贸n y devolver el resultado a la aplicaci贸n Node. los info El objeto contiene todo lo que necesitamos saber sobre la llamada, incluidos los argumentos (y sus tipos) y un lugar para devolver el resultado.

    los Init la funci贸n principalmente solo asocia el Pow funcionar con el
    el nombre de “pow” y el NODE_MODULE macro en realidad maneja el registro del plugin con Node.

    los package.json El archivo no es muy diferente de un m贸dulo de node normal. Aunque no parece ser necesario, la mayor铆a de los m贸dulos adicionales tienen "gypfile": true establecido dentro de ellos, pero el proceso de compilaci贸n parece funcionar bien sin 茅l. Esto es lo que us茅 para este ejemplo:

    {
      "name": "addon-hook",
      "version": "0.0.0",
      "description": "Node.js Addon Example",
      "main": "index.js",
      "dependencies": {
        "nan": "^2.0.0"
      },
      "scripts": {
        "test": "node index.js"
      }
    }
    

    A continuaci贸n, este c贸digo debe integrarse en un archivo ‘pow.node’, que es el binario del plugin. Para hacer esto, necesitar谩 decir node-gyp qu茅 archivos necesita compilar y el nombre de archivo resultante del binario. Si bien hay muchas otras opciones / configuraciones que puede usar con node-gyp, para este ejemplo no necesitamos mucho. los binding.gyp El archivo puede ser tan simple como:

    {
    	"targets": [
    		{
    			"target_name": "pow",
    			"sources": [ "pow.cpp" ],
    			"include_dirs": [
    				"<!(node -e "require('nan')")"
    			]
    		}
    	]
    }
    

    Ahora, usando node-gyp, genera los archivos de construcci贸n del proyecto adecuados para la plataforma dada:

    $ node-gyp configure
    

    Y finalmente, construye el proyecto:

    $ node-gyp build
    

    Esto deber铆a resultar en una pow.node archivo que se crea, que residir谩 en el build/Release/ directorio. Para usar este gancho en el c贸digo de su aplicaci贸n, simplemente require en el pow.node archivo (sin la extensi贸n ‘.node’):

    var addon = require('./build/Release/pow');
    
    console.log(addon.pow(4, 2));		// Prints '16'
    

    Interfaz de funci贸n ajena de node

    Nota: Los ffi el paquete se conoc铆a anteriormente como node-ffi. Aseg煤rese de agregar el m谩s nuevo ffi nombre a sus dependencias para evitar mucha confusi贸n durante npm install 馃檪

    Si bien la funcionalidad Addon proporcionada por Node le brinda toda la flexibilidad que necesita, no todos los desarrolladores / proyectos la necesitar谩n. En muchos casos, una abstracci贸n como ffi funcionar谩 bien, y normalmente requiere muy poca o ninguna programaci贸n C / C ++.

    ffi solo carga bibliotecas din谩micas, lo que puede ser limitante para algunos, pero tambi茅n facilita la configuraci贸n de los ganchos.

    var ffi = require('ffi');
    
    var libm = ffi.Library('libm', {
    	'pow': [ 'double', [ 'double', 'double' ] ]
    });
    
    console.log(libm.pow(4, 2));	// 16
    

    El c贸digo anterior funciona especificando la biblioteca a cargar (libm), y espec铆ficamente qu茅 m茅todos cargar desde esa biblioteca (pow). los [ 'double', [ 'double', 'double' ] ] la l铆nea dice ffi cu谩l es el tipo de retorno y los par谩metros del m茅todo, que en este caso son dos double par谩metros y un double regres贸.

    Conclusi贸n

    Si bien puede parecer intimidante al principio, crear un plugin realmente no es tan malo despu茅s de haber tenido la oportunidad de trabajar con un peque帽o ejemplo como este por su cuenta. Cuando sea posible, sugerir铆a conectarse a una biblioteca din谩mica para facilitar la creaci贸n de la interfaz y la carga del c贸digo, aunque para muchos proyectos esto puede no ser posible o la mejor opci贸n.

    驴Hay ejemplos de bibliotecas para las que le gustar铆a ver enlaces? 隆H谩znoslo saber en los comentarios!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *