Skip to content

Node.js native C modules

Graham Wakefield edited this page Jun 20, 2019 · 25 revisions

Writing Node.js modules in C/C++ ("native modules")

Overview:

  • make project folder as a git repo
  • as a Node.js module, it is defined for npm in a package.json file
  • write C++ code against the Node.js API
  • build it with node-gyp via definitions in a binding.gyp file
  • test it / wrap it with a index.js file

N-API, AKA Node.js C API, "napi" or "node_api.h"

The API reference docs are here -- but they are really a reference, and not a good place to learn from initially.

There is an official repository of examples here

Here's a quick tutorial on the napi API

Why use N-API?

There are several different APIs for developing native (i.e. C/C++) Node.js modules. Until recently, the recommended API was called nan, however this C++ API does not guarantee stability. But nowadays it is recommended instead to use the napi API, which does guarantee ABI stability. There is also a C++ wrapper of this API, with the confusingly-similar name of node-addon-api.

Starting a new module project:

Assuming a module called "addon":

mkdir addon
cd addon
git init
npm init
npm install --save bindings
npm install --save-dev node-gyp

Edit the package.json to add "gypfile": true

Create a binding.gyp file (the code below assumes module name is "addon"):

{
    "targets": [{
        "target_name": "addon",
        "sources": [ "addon.cpp" ],
        "defines": [],
        "cflags": ["-std=c++11", "-Wall", "-pedantic"],
        "include_dirs": [],
        "libraries": [],
        "dependencies": [],
        "conditions": [
            ['OS=="win"', {}],
            ['OS=="mac"', {}],
            ['OS=="linux"', {}],
        ],
    }]
}

A minimal addon.cpp:

#include <node_api.h> 
#include <assert.h>
#include <stdio.h> 
#include <stdlib.h>

napi_value Hello(napi_env env, const napi_callback_info info) {
    printf("hello\n");
    return nullptr;
}

napi_value Goodbye(napi_env env, const napi_callback_info info) {
    napi_value msg;
    napi_create_string_utf8(env, "ciao", NAPI_AUTO_LENGTH, &msg);
    return msg;
}

napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor export_properties[] = {
	{
		"Hello", nullptr, Hello,
		nullptr, nullptr, nullptr, napi_default, nullptr
	},
	{
		"Goodbye", nullptr, Goodbye,
		nullptr, nullptr, nullptr, napi_default, nullptr
	},
    };
    assert(napi_define_properties(env, exports, 
	sizeof(export_properties) / sizeof(export_properties[0]), export_properties) == napi_ok);
    return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

Binding.gyp

https://gyp.gsrc.io/docs/InputFormatReference.md

Clone this wiki locally