OS:Windows 10/1903
Welcome~ N-API & CMake.js
目前NodeJS的LTS(长期支持)版本是10.16.x,在文档中该版本的N-API稳定性已经达到了Stability: 2 - Stable的程度,使用N-API已经可以逐步摆脱先锋实验性质,考虑基于此构建复杂项目了。
以往构建C++ Addon时惯用的构建工具是node-gyp,这一项目脱胎于Google的构建配置工具gyp(Generate your project)。由于谷歌已经在全面投入新的构建工具链,gyp也已如明日黄花。更搞笑的是,受到上游项目gyp的限制,node-gyp目前为止仍然不支持Python 3。这个从2013年开始提的issue,直到2019年7月才放出了实验性的支持py3更新。与此同时,CMake.js也在快速发展,其使用更加成熟的CMake进行配置,这一方案的潜力无需多言。
依赖环境
在Windows下编译项目依赖于MSVC编译器,直接安装一个VisualStudio 2019 Community就好了,同时会附带配置好MSBuild等环境。
安装CMake.js:
npm install -g cmake-js
cmake-js install
# 以下是安装后的输出
info TOOL Using Visual Studio 16 2019 generator.
info DIST Downloading distribution files.
http DIST - https://nodejs.org/dist/v10.16.3/SHASUMS256.txt
http DIST - https://nodejs.org/dist/v10.16.3/win-x64/node.lib
http DIST - https://nodejs.org/dist/v10.16.3/node-v10.16.3-headers.tar.gz
另外还需要安装CMake,安装过程中记得选择添加环境变量的选项。到此为止,编译C++ Addon的环境已经准备好了。
小试牛刀
使用的代码同这篇文章 ,具体引入的node_api.h实际上是不在引用库中的,编译时cmake-js会负责链接正确的头文件。这一点实际上非常不方便,因为开发过程中调用的N-API函数就没有对应的补全和检查了。
使用的CMakeLists.txt文件如下:
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/*.c" "src/*.h")
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})
# 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})
最后运行cmake-js build
,即可生成一个addon.node模块。
在JS中,可以使用binding这个模块来方便的引入自己编写的.node模块:
let my_mod = require('bindings')('addon');
console.log(my_mod.hello());
Bonus
使用纯C风格的原生N-API有诸多不便之处,因此我们可以使用基于N-API的封装:node-addon-api。只需要这样:仔细阅读这里,把该修改的加上。然后可以从node_modules里面翻到这个项目下附带的头文件,拷出来供开发的时候引用。使用C++封装之后的hello会变得非常简单:
#include <napi.h>
Napi::String Method(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
return Napi::String::New(env, "world");
}
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, Method));
return exports;
}
NODE_API_MODULE(addon, Init)