How to call C/C++ code from Node.js

Node.js ❤ C/C++

Hello World

Let’s start by rewriting the following piece of JavaScript code into C++:

module.exports.hello = () => 'world';

binding.cpp

#include <napi.h>using namespace Napi;String Hello(const CallbackInfo& info) {
return String::New(info.Env(), "world");
}
void Init(Env env, Object exports, Object module) {
exports.Set("hello", Function::New(env, Hello));
}
NODE_API_MODULE(addon, Init)

binding.gyp

{
"targets": [
{
"target_name": "native",
"sources": [
"binding.cpp"
],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")"
],
"cflags!": ["-fno-exceptions"],
"cflags_cc!": ["-fno-exceptions"],
"defines": ["NAPI_CPP_EXCEPTIONS"]
}
]
}
{
"name": "app",
"version": "0.0.0",
"private": true,
"gypfile": true,
"dependencies": {
"node-addon-api": "^0.6.3"
}
}
$ node --napi-modules -e \
"console.log(require('./build/Release/native.node').hello())"
world

Using a native C/C++ library from Node.js

Now, let’s call some 3rd party library from under our native module (addon). I’d like to believe that you develop your Node.js apps inside Docker containers. As an example, let’s install Sodium crypto library and try to call its methods from our binding.cpp file. In node:8.4.0-alpine Docker container you can install it as follows:

apk add --no-cache make g++ python2 libsodium-dev
{
"targets": [
{
...
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")",
"/usr/include/sodium"
],
...
"libraries": ["/usr/lib/libsodium.so.18"],
...
}
]
}
#include <napi.h>
#include <sodium.h>
using namespace Napi;String Hash(const CallbackInfo& info) {
Env env = info.Env();
std::string password = info[0].As<String>().Utf8Value();
char hash[crypto_pwhash_STRBYTES];
crypto_pwhash_str(
hash,
password.c_str(),
password.size(),
crypto_pwhash_OPSLIMIT_INTERACTIVE,
crypto_pwhash_MEMLIMIT_INTERACTIVE);
return String::New(env, hash.c_str(), crypto_pwhash_STRBYTES);
}
void Init(Env env, Object exports, Object module) {
exports.Set("hash", Function::New(env, Hash));
}
NODE_API_MODULE(addon, Init)
$ node --napi-modules -e \
"console.log(require('bindings')('native').hash('Passw0rd'))"
$argon2i$v=19$m=32768,t=4,p=1$/N3vumg47o4EfbdB5FZ5xQ$utzaQCjEKmBTW1g1+50KUOgsRdUmRhNI1TfuxA8X9qU

Summary

Calling C/C++ code using modern N-API interface in combination with C++ wrappers (node-addon-api) is almost too easy to be true. I hope the code samples above demonstrate the point. Just try to avoid using old APIs and approaches, e.g. Nan, using C instead of C++, and you’ll be good :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Konstantin Tarkus

Konstantin Tarkus

Bringing the technical edge to early-stage companies with advice on software architecture, best practices, database design, web infrastructure, and DevOps.