Monday, December 2, 2019

create and use native c++ modules in nodejs

In nodeJs, we can also use c/c++ compiled code. nodeJs is very fast on the server-side because of using JavaScript libraries though we can improve NodeJs productivity by using c++ code.

if you want to get more performance you can use c++ modules with nodejs.

We can use c++ modules by using any method/api/module for building native Addons which is given bellow

-> nan: 
    if you want something mature and very backward-compatible, you can make C++-based abstraction between NodeJs and direct V8 APIs.

-> napi / N-API: 
    if you are comfortable working in C and dealing with possible lower-level concerns, you can make C-based API stability across different node versions as well as JavaScript engines.

-> node-addon-api: 
    if you want something forwards-looking in C++,  you can make header only C++ wrapper classes, which simplify the use of the C based N-API.

Here, we will make a simple demo by using nan method/api/module for building native Addons of c++ in nodejs and use it.

The directory structure of our demo will be like as bellow :
├── build
├── node_modules
├── binding.gyp
├── package.json
├── package-lock.json
├── main.js
└── main.cpp

For create, new demo make a new directory and run following command
npm init
fill required information by asking npm init command

now check package.json file.

Install nan and node-gyp modue
npm install nan node-gyp --save
Update your package.json file like as bellow

package.json
{
  "name": "node-c++-demo",
  "version": "1.0.0",
  "dependencies": {
    "nan": "^2.14.0",
    "node-gyp": "^6.0.1"
  },
  "scripts": {
    "compile": "node-gyp rebuild",
    "start": "node main.js"
  },
  "gypfile": true
}
Here, we need to add/edit in a script only the following code in package.json file

"scripts": {
    "compile": "node-gyp rebuild",
    "start": "node main.js"
  },
  "gypfile": true

  here,
  "compile": “node-gyp rebuild”  is for C++ code compilation,
  "start": "node main.js" is for our main nodejs executable script file

 bindings.gyp (create and add this file beside package.json)
  {
  "targets": [
    {
      "include_dirs": [
        "<!(node -e \"require('nan')\")"
      ],
      "target_name": "addon",
      "sources": [ "main.cpp" ]
    }
  ]
}
bindings.gyp is used for configuration for node-gyp. here you can add all c++ file in sources in array like as "sources": [ "main.cpp", "helper.cpp" ].

main.cpp (create and add this file)
#include <nan.h>

using namespace std;
using namespace v8;

NAN_METHOD(WelcomeMessage) {
    Nan::HandleScope scope;
    String::Utf8Value cmd(info[0]);
    string s = "welcome " + string(*cmd);
    info.GetReturnValue().Set(Nan::New<String>(s.c_str()).ToLocalChecked());
}

NAN_METHOD(IsPrime) {
    if (!info[0]->IsNumber()) {
        Nan::ThrowTypeError("argument must be a number!");
        return;
    }
 
    int number = (int) info[0]->NumberValue();
 
    if (number < 2) {
        info.GetReturnValue().Set(Nan::False());
        return;
    }
 
    for (int i = 2; i < number; i++) {
        if (number % i == 0) {
            info.GetReturnValue().Set(Nan::False());
            return;
        }
    }
 
    info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(passArray) {
    Nan::HandleScope scope;
    vector<string> result;
    Handle<Value> val;
    Local<Array> arr = Nan::New<Array>();

    if (info[0]->IsArray()) {
      Handle<Array> jsArray = Handle<Array>::Cast(info[0]);
      for (unsigned int i = 0; i < jsArray->Length(); i++) {
        val = jsArray->Get(i);
        result.push_back(string(*String::Utf8Value(val)));
        Nan::Set(arr, i, val);
      }
    }
    info.GetReturnValue().Set(arr);
}

NAN_MODULE_INIT(Initialize) {
    NAN_EXPORT(target, IsPrime);
    NAN_EXPORT(target, WelcomeMessage);
    NAN_EXPORT(target, passArray);
}

NODE_MODULE(addon, Initialize);
Here we have added main.cpp file which is developed in c++ and it will be used in nodejs routing API file like as main.js

we have added three methods in main.cpp which is listed bellow
1)WelcomeMessage
2)IsPrime
3)passArray
You can make any methods like as given this.

main.js (create and add this file)
/*
* native c++ Demo
*/

/*
*Include c++ addon in nodejs routing file
*/
const {IsPrime, WelcomeMessage, passArray} = require('./build/Release/addon');

/*
*Use WelcomeMessage method of c++ addon in nodejs routing file
*/
let name = "laxman";
console.log(`Welcome message from c++... : ${WelcomeMessage(name)}`);

/*
*Use IsPrime method of c++ addon in nodejs routing file
*/
const number = 85418749;
console.log(`Checking whether ${number} is prime number check from c++... : ${IsPrime(number)}`);

/*
*Use passArray method of c++ addon in nodejs routing file
*/
let myArray = ["red","green", "blue"];
console.log(`Pass array to passArray method in c++ ... : ${passArray(myArray)}`);

main.js file is the which will be executed by nodejs. you can make any other file or also put this code in any routing api of nodejs

const {IsPrime, WelcomeMessage, passArray} = require('./build/Release/addon'); : This line is used to include/require accedd c++ functions.
In main.cpp we have made three modules so for access these we have required these all modules and use it.

For compile c++ code
npm run compile
By using this command you can compile a cpp file. it will start node-gyp and compile your C++ sources as configured in bindings.gyp file.

If everything went properly, you can see similar output like as bellow:
> node-native-addons-example@1.0.0 compile <Your project directory path>
> node-gyp rebuild

make: Entering directory <Your project directory path>
  CXX(target) Release/obj.target/addon/main.o
  SOLINK_MODULE(target) Release/obj.target/addon.node
  COPY Release/addon.node
make: Leaving directory <Your project directory path>/build

if you get this type of successful output, you can see "build" directory in which all compiled c++ code will be available.

Make sure /build/Release/addon.node file will be present after code compiled.

Now, after all these processes you can run node file like as bellow
node main.js

Our put :
Welcome message from c++... : welcome laxman
Checking whether 85418749 is prime number check from c++... : false
Pass array to passArray method in c++ ... : red,green,blue

From this demo, it's too easy to use c++ native Addons in nodejs.

No comments:

Post a Comment