Node支持两种C++插件形式,一种是依赖V8引擎,一种是使用NAPI。本文主要讲如何利用NAPI开发插件。
为什么要开发插件?
可能的原因有:
- 效率上的考虑,因为C++通常会比较快 :)
- 安全上的考虑,相比于JS,C++反编译毕竟难一些。(JS也有很多加密、混淆工具,但是大概难以同时满足效率和安全)
开始
安装node/npm(略)
先去看看N-API的官方文档,N-API,讲得比较粗略,读完仍然一头雾水。
新建工作目录
安装依赖
1 2 3
| npm install node-gyp --save-dev npm install node-addon-api npm install -g --production windows-build-tools
|
bingding.gyp
新建文件bingding.gyp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "targets": [{ "target_name": "testaddon", "cflags!": [ "-fno-exceptions" ], "cflags_cc!": [ "-fno-exceptions" ], "sources": [ "functionexample.cpp" ], 'include_dirs': [ "<!@(node -p \"require('node-addon-api').include\")" ], 'libraries': [], 'dependencies': [ "<!(node -p \"require('node-addon-api').gyp\")" ], 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ] }] }
|
cflags 和 cflags_cc可以根据需要增删
functionexample.cpp
新建文件functionexample.h
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <napi.h>
namespace functionexample {
std::string hello(); Napi::String HelloWrapped(const Napi::CallbackInfo& info);
int add(int a, int b); Napi::Number AddWrapped(const Napi::CallbackInfo& info);
Napi::Object Init(Napi::Env env, Napi::Object exports); }
|
新建文件functionexample.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include "functionexample.h"
std::string functionexample::hello(){ return "Hello World"; }
int functionexample::add(int a, int b){ return a + b; }
Napi::String functionexample::HelloWrapped(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); Napi::String returnValue = Napi::String::New(env, functionexample::hello()); return returnValue; }
Napi::Number functionexample::AddWrapped(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber()) { Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); }
Napi::Number first = info[0].As<Napi::Number>(); Napi::Number second = info[1].As<Napi::Number>();
int returnValue = functionexample::add(first.Int32Value(), second.Int32Value()); return Napi::Number::New(env, returnValue); }
Napi::Object functionexample::Init(Napi::Env env, Napi::Object exports) { exports.Set("hello", Napi::Function::New(env, functionexample::HelloWrapped)); exports.Set("add", Napi::Function::New(env, functionexample::AddWrapped)); return exports; }
Napi::Object InitAll(Napi::Env env, Napi::Object exports) { return functionexample::Init(env,exports); }
NODE_API_MODULE(testaddon, InitAll)
|
编译
1
| node-gyp configure build
|
最后如果gyp info ok表示成功了。
如果遇到NODE_MODULE_VERSION xx 不匹配的问题,请下载electron-rebuild重新编译应该可以解决。
1 2
| npm install electron-rebuild --save ./node_modules/.bin/electron-rebuild
|
测试
新建 test.js
1 2
| const testAddon = require('./build/Release/testaddon.node'); console.log(testAddon.hello());
|
然后
1 2 3
| $ node test.js Hello World
|
参考
Beginners guide to writing NodeJS Addons