Skip to content

TUTORIAL 01 Creating a native module by using CMake.js and NAN

AlanLi edited this page Nov 23, 2020 · 8 revisions

Introduction

Let's take a classical example of a native Node.js addon and turn it into a CMake.js based module. Every native addon developer knows NAN. It's an excellent C++ template library that provides a consistent API across Node.js versions for making native modules. By writing your module using NAN interfaces, it compiles with all supported versions even if there are breaking API changes across them (and there are).

In the repository of NAN there is an example code for a native C++ addon that calculates PI asynchronously. This example uses node-gyp as its build system. Now, let's take the C++ source and create a CMake.js based module on it.

Package and Dependencies

First, you need an empty directory. Put a package.json in it and give the module a nice name.

{
  "name": "cmake-js-tut-01-module",
  "version": "1.0.0",
  "description": "Native module calculating estimate of PI"
}

Install NAN and CMake.js:

npm install nan --save
npm install cmake-js --save

Note: Because CMake.js doesn't come bundled with Node.js distributions like node-gyp, the global cmake-js command won't be available when a consumer installs your cmake-js-tut-01-module. So, you have to add it as a dependency to make sure it will be available for compiling during installation.

C++ Source

Make a src/ directory and put all *.cc and *.h files from the NAN addon example module in it. The goal of the next step will be to compile those as a shared library with the .node extension which will then be requireable from the JavaScript side.

CMakeLists.txt

The following shows a minimal CMakeLists.txt file capable of building node addons. Put it into your project's root folder. It is the CMake project file (like a makefile or VisualStudio sln) and with it you have the full potential of CMake including all its commands working an all major platforms at your disposal.

cmake_minimum_required(VERSION 2.8)

# Name of the project (will be the name of the plugin)
project(addon)

# Build a shared library named after the project from the files in `src/`
file(GLOB SOURCE_FILES "src/*.cc" "src/*.h")
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})

# Gives our library file a .node extension without any "lib" prefix
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")

# Essential include files to build a node addon,
# You should add this line in every CMake.js based project
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_JS_INC})

# Essential library files to link to a node addon
# You should add this line in every CMake.js based project
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

Include paths to node, v8 and NAN headers, as well as the linked library file location in Windows are handled by CMake.js.

To test if it compiles, you can install cmake-js as a global command and invoke the build or rebuild command (they will invoke configure if needed).

npm install -g cmake-js
cmake-js build

You can use the --debug switch for compiling in debug mode. Also, try --help for more details about how to use cmake-js.

The generated project files reside in the build/ directory exactly like when compiling with node-gyp. The actual plugin file (projectnamehere.node) went into the build/Release (or build/Debug) directory.

Finishing package.json

The final thing is to modify package.json so that the cmake-js compile command is invoked once your module gets installed by npm.

{
  ...
  "scripts": {
    "install": "cmake-js compile"
  }
}

Referencing the Compiled Plugin

Now, you can either require the compiled plugin's binaray file directly (not recommended):

// projectnamehere.node plugin file without the extension:
var myModule = require("./build/Release/projectnamehere");
module.exports = myModule; // Just reexport it

Or use the bindings module for this purpose:

npm install --save bindings
var myModule = require("bindings")("addon");
module.exports = myModule; // Just reexport it

Example Code

It's done. You have made your first CMake.js based module. Here is the code:

git clone https://github.com/unbornchikken/cmake-js-tut-01-module.git

You can also install it via npm:

npm install git+https://github.com/unbornchikken/cmake-js-tut-01-module.git

There's also an example application that uses it:

git clone https://github.com/unbornchikken/cmake-js-tut-01-test.git
npm install
node app