相信为nodejs写过 c++扩展的人,都有过nodejs版本升级之后c++需要重新编译的惨痛经历。nodejs v8.0之后node官方推出了N-API 大大的解决了这一问题。
N-API 是独立于v8引擎之外的模块。用来向c++扩展程序提供接口,从而达到了c++扩展程序和v8引擎的隔离。因此在当nodejs版本变化之后c++扩展程序无需重新编译也能运行。
下面我们来看如何利用N-API为nodejs写一个简单的扩展:
环境
首先已经确认你的环境已经可以编译c++程序。
例如 python , make , gcc 等等。
我们的例子只从nodejs方面讲起。nodejs版本为8.x 。
首先安装 node-gyp 用来编译我们的扩展程序
npm install -g node-gyp
编写扩展程序
- 创建文件建 hello
- 在hello目录下创建hello.cc
- 在hello.cc 中编写如下代码并保存。
// 首先要引用 node_api.h
#include <node_api.h>
// 定义native方法 SayHello 打印一个字符串"Hello"
napi_value SayHello(napi_env env, napi_callback_info info) {
printf("Hello\n");
return nullptr;
}
// 如果把hello.cc看做js文件,则Init 方法的作用就是初始化当前module。
// 但是Init方法不能修改module,只能修改module的exports。
// env :当前javascript的上下文文件
// exports : 即可看做当前文件的model.exports,初始化之前是一个空对象。
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_value fn;
// 将上面的SayHello 方法生成一个可供javascript调用的napi_value对象。
// 并且赋值给指针 fn。
// status 为是否生成成功的状态值 ,若成功则值为 napi_ok。
status = napi_create_function(env, nullptr, 0, SayHello, nullptr, &fn);
if (status != napi_ok) return nullptr;
// 将刚才生成的javascript 对象方法fn 添加到exports中,属性名为sayHello
// 翻译为javascript代码为:exports.sayHello = fn;
status = napi_set_named_property(env, exports, "sayHello", fn);
if (status != napi_ok) return nullptr;
// 后将exports 返回 完成module的初始化
return exports;
}
// 注册当前module
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
编译扩展程序
- 创建文件 binding.gyp
- 在binding.gyp 中写入如下描述并保存。
{
"targets": [
{
"target_name": "hello",
"sources": [ "./hello.cc" ]
}
]
}
- 运行 node-gyp rebuild 进行编译
调用刚才写好的扩展程序
- 创建app.js 并写入下面的代码。
var addon = require("../build/Release/hello");
addon.hello();
- 运行 node app.js 会输出如下信息。
Hello
(node:42630) Warning: N-API is an experimental feature and could change at any time.
注:N-API还在试验阶段api变动会比较大。所以会输出一个Warning。