As you select where to begin, you should be aware that N-API operates at two levels which we can think of as the “C level” and the “C++ level”.
The “C level” code is built entirely into Node itself and is very well documented on the Node documentation pages. If you need low-level access to the intricacies of Node, this is the tool for you.
Alternatively, there is the node-addon-api package which adds a C++ wrapper to the N-API code built into Node. This package makes working with N-API much easier as it implements a very nice object model and abstracts away much of the detailed coding that would otherwise be required, while retaining the N-API promise of ABI stability and forward compatibility.
This tutorial uses
N-API has been in public release and active development starting with Node 8.0.0. Since then, it’s undergone a number of refinements. This tutorial has been tested with Node 10.10.0 and is known to fail with older versions of Node. You can determine the version of Node you’re running with the command
npm install -g yo
On some systems, you may receive the error
Error: EACCES: permission denied, access. In that case, on Mac and Linux systems you need to run the commands with elevated privileges:
sudo npm install -g yo
nvmis an excellent way to banish permission issues.
Then enter these commands to generate a new project:
Here are the prompts you’ll see and some suggested responses:
package name: (object-wrap-demo)
Yeoman will display the generated
package.json file here.
Is this OK? (yes) yes
Yeoman will now build your “Hello World” add-on module.
At this point, you might try running
npm test to make sure everything is correctly installed:
At this point you have a completely functional N-API module project. The project files are structured according to N-API best practices. It should look like this:
Let’s take a look at the essential files.
This is a typical
package.json file as generated by Yeoman from the responses we entered earlier to the
yo napi-module command. There are a couple of entries of interest here.
There is also a
"gypfile": true entry which informs npm that your package requires a build using the capabilities of the
node-gyp package which is covered next.
One of the challenges of making C/C++ code available to Node is getting the code compiled, linked, and packaged for a variety of operating systems and architectures. Historically, this would require learning the intricacies of a variety of build tools across a number of operating systems. This is the specific issue GYP seeks to address.
Using GYP permits having a single configuration file that works across all platforms and architectures GYP supports. (It’s GYP, by the way, that requires Python).
node-gyp is a command line tool built in Node that orchestrates GYP to compile your C/C++ files to the correct destination. When npm sees the
"gypfile": true entry in your
package.json file, it automatically invokes its own internal copy of
node-gyp which looks for this
binding.gyp file which must be called
binding.gyp in order for node-gyp to locate it.
Here is the nub of our project where all the magic occurs. This is a sample C++ file that shows how to use the power of the
napi.h file included in the header file comes from
object_wrap_demo.cc file defines a C++ object called
The code also defines a
ObjectWrapDemo::GetClass static method returns a class definition that N-API uses in order know how to call the methods implemented by the C++ class.
ObjectWrapDemo class as declared by the
ObjectWrapDemo::GetClass static method.
The macro call at the bottom of the C++ file,
NODE_API_MODULE(addon, Init), specifies that the
Init function is to be called when the module is loaded.
const addon = require('../build/Release/object-wrap-demo-native');
The file defines a
ObjectWrapDemo object using the N-API binary and stores it internally as
greet method to call the same method in the C++ binary.
const ObjectWrapDemo = require("../lib/binding.js");
This code demonstrates how to use the
Note that as a side-effect of the
printf code in the C++ module, two text strings are written to stdout each time the
greet method is called.
This project provides a solid foundation on which you can create your own N-API modules. In addition, here are some things you might want to try:
test_binding.js to use the C++ binary module directly instead of through
binding.js. Step through the code in your debugger to see how things are different.
object_wrap_demo.cc, or create a new C++ module, to export functions instead of an object.