相信為nodejs寫過 c++擴展的人,都有過nodejs版本升級之后c++需要重新編譯的慘痛經(jīng)歷。nodejs v8.0之后node官方推出了N-API 大大的解決了這一問題。
N-API 是獨立于v8引擎之外的模塊。用來向c++擴展程序提供接口,從而達到了c++擴展程序和v8引擎的隔離。因此在當nodejs版本變化之后c++擴展程序無需重新編譯也能運行。
下面我們來看如何利用N-API為nodejs寫一個簡單的擴展:
環(huán)境
首先已經(jīng)確認你的環(huán)境已經(jīng)可以編譯c++程序。
例如 python , make , gcc 等等。
我們的例子只從nodejs方面講起。nodejs版本為8.x 。
首先安裝 node-gyp 用來編譯我們的擴展程序
npm install -g node-gyp
編寫擴展程序
- 創(chuàng)建文件建 hello
- 在hello目錄下創(chuàng)建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調(diào)用的napi_value對象。
// 并且賦值給指針 fn。
// status 為是否生成成功的狀態(tài)值 ,若成功則值為 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)
編譯擴展程序
- 創(chuàng)建文件 binding.gyp
- 在binding.gyp 中寫入如下描述并保存。
{
"targets": [
{
"target_name": "hello",
"sources": [ "./hello.cc" ]
}
]
}
- 運行 node-gyp rebuild 進行編譯
調(diào)用剛才寫好的擴展程序
- 創(chuàng)建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。