Skip to content

CMake.js

CMake.js is good build tool alternative to node-gyp. CMake.js is based on the CMake tool which must be installed.

Pros

  • Uses the CMake tool which is widely-adopted in the open source community.
  • Ideal for existing C/C++ libraries already based on CMake.

Cons

  • Not widely adopted in the Node community.

Installation

CMake.js requires that CMake is already installed. Installers are available on the CMake website.

macOS developers may find it more convenient to install CMake using Homebrew. With Homebrew installed, CMake can be installed using a brew install cmake command.

You can verify your CMake installation with the command:

cmake --version

As a Node native module developer, you may find it convenient to install CMake.js as a global command line tool:

npm install cmake-js -g

You can verify your CMake.js installation with the command:

cmake-js --version

package.json

Your package.json file needs to have a couple of entires for your native module to work with CMake.js.

Since your native module needs to be compiled using CMake.js on installation, the scripts property of your package.json file needs an install entry to make this happen:

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

It is unlikely that the users of your native module will have CMake.js installed as a global command line tool. Therefore, your project needs to declare a development dependency on CMake.js. This can be accomplished by entering this command:

npm install cmake-js --save-dev

An alternative is to manually add the development dependency to your package.json file:

  "devDependencies": {
    "cmake-js": "^6.0.0"
  }

Here is a complete package.json file:

package.json

{
  "name": "build-node-addon-api-with-cmake",
  "version": "0.0.0",
  "description": "Build Node-API native addon with CMake and node-addon-api C++ wrapper.",
  "main": "hello.js",
  "private": true,
  "dependencies": {
    "bindings": "~1.5.0",
    "node-addon-api": "^8.1.0"
  },
  "scripts": {
    "install": "cmake-js compile",
    "test": "node hello.js"
  }
}

CMakeLists.txt

Native module built on CMake.js have a CMakeLists.txt that describe how the module is to be built. The file serves the same purpose as the binding.gyp for projects tht use node-gyp.

In addition to the entries required for any CMake build, additional entries are required when building native modules.

CMake.js

Here are the lines required for all native modules built using CMake.js:

project (napi-cmake-build-example)
include_directories(${CMAKE_JS_INC})
file(GLOB SOURCE_FILES "hello.cc")
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

NAPI_VERSION

When building a native module based on Node-API, it is important to declare the minimum Node-API version against which your module is designed to work. For CMake.js, this is accomplished by adding a line like this to the CMakeLists.txt file:

# define NAPI_VERSION
add_definitions(-DNAPI_VERSION=3)

In the absence of other requirements, Node-API version 3 is a good choice as this is the Node-API version active when Node-API left experimental status.

node-addon-api

Additional configuration values are required for Node-API modules based on node-addon-api.

node-addon-api requires C++11. These configuration lines at the top of the CMakeLists.txt file specify this requirement:

cmake_minimum_required(VERSION 3.9)
cmake_policy(SET CMP0042 NEW)
set (CMAKE_CXX_STANDARD 11)

Modules based on node-addon-api include additional header files that are not part of Node itself. These lines instruct CMake.js where to find these files:

# Include Node-API wrappers
execute_process(COMMAND node -p "require('node-addon-api').include"
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        OUTPUT_VARIABLE NODE_ADDON_API_DIR
        )
string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR})

Here is a complete CMakeLists.txt file for an Node-API native module built on node-addon-api:

CMakeLists.txt

cmake_minimum_required(VERSION 3.9)
cmake_policy(SET CMP0042 NEW)
set (CMAKE_CXX_STANDARD 11)

project (build-node-addon-api-with-cmake)
include_directories(${CMAKE_JS_INC})
file(GLOB SOURCE_FILES "hello.cc")
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

# Include Node-API wrappers
execute_process(COMMAND node -p "require('node-addon-api').include"
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        OUTPUT_VARIABLE NODE_ADDON_API_DIR
        )
string(REGEX REPLACE "[\r\n\"]" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})

target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR})

# define NAPI_VERSION
add_definitions(-DNAPI_VERSION=3)

Resources

The CMake.js project home page.

The CMake project home page.

CMake documentation.

A couple of working examples.