Node.js Addon编译调试教程(一次成功版)
环境配置
nodejs headers和lib下载
- headers下载地址:https://nodejs.org/download/release/v18.18.0/node-v18.18.0-headers.tar.gz
- lib下载地址:https://nodejs.org/download/release/v18.18.0/win-x64/node.lib
- 以上路径修改版本号下载对应的即可
- 解压node-v18.18.0-headers.tar.gz(include目录),放在nodejs安装目录,例如:C:/Program Files/nodejs
- 在nodejs安装目录新建两个文件夹 Debug 和 Release,拷贝node.lib到这两个目录
- include/node目录的common.gypi拷贝到nodejs安装目录
- 如果上述文件无法放在nodejs安装目录,也可以单独放一个文件夹,但是编译的时候指定nodedir
shell
node-gyp configure --nodedir=D:\\nodejs && node-gyp build --debug
binding.gyp配置
js
{
# 构建目标集合
"targets": [
{
# 模块最终生成的二进制文件名
"target_name": "add",
# 要编译的源文件
"sources": [
"./src/main.cpp",
"./src/DemoAsyncWorker.cpp"
],
# 头文件包含目录,!是执行shell命令取输出值,@是在列表中展开输出的每一项
"include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
# 外部依赖项
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
# 以下是编译器选项,启用node-addon-api的集成C++和JavaScript的异常处理
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"xcode_settings": {
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
"CLANG_CXX_LIBRARY": "libc++",
"MACOSX_DEPLOYMENT_TARGET": "10.7"
},
"msvs_settings": {
"VCCLCompilerTool": {
"ExceptionHandling": 1
}
},
# 预定义宏,禁用NAPI的C++异常处理和node-addon-api废弃的API
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS", "NODE_ADDON_API_DISABLE_DEPRECATED"]
}
]
}
vscode debug配置
js
// launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "JS Debug Build",
"console": "integratedTerminal",
"program": "${workspaceFolder}/index.js", // 测试js
"preLaunchTask": "npm: build:debug"
},
{
"name": "Windows Attach",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}" // 启动的时候选择一个进程进行debug
}
]
}
// task.json
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build:release",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
python3
安装python3,并配置环境变量 PYTHON = python3安装目录
示例: C:\Programs\Python\Python311\python.exe
package.json配置
js
"scripts": {
"build:debug": "node-gyp configure && node-gyp build --debug",
"build:release": "node-gyp configure && node-gyp build",
"clean": "node-gyp clean"
},
"devDependencies": {
"node-gyp": "^9.3.1" // 支持 python3,不要用 3.8.0 这个不支持pyton3
},
MSBuild 和 VC++工具集140/141
示例代码
- index.js
js
const Add = require('./build/Debug/add.node');
Add(1,2, result => {
console.log('1 + 2 =',result)
})
- ./src/main.cpp
c++
#include "./DemoAyncWorker.h"
using namespace Napi;
static Value _asyncDemo(const CallbackInfo& info) {
Env env = info.Env();
if (info.Length() != 3)
{
Error::New(env, "arguments.length !== 3").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[2].IsFunction())
{
Error::New(env, "typeof arguments[2] !== 'function'").ThrowAsJavaScriptException();
return env.Undefined();
}
Function cb = info[2].As<Function>(); // Napi::Value -> Napi::Function
DemoAsyncWorker *worker = new DemoAsyncWorker(cb);
worker->Queue();
return env.Undefined();
}
Object init(Env env, Object exports) {
Object global = env.Global();
Object console = global.Get("console").As<Object>();
Function log = console.Get("log").As<Function>();
log.Call(console, { String::New(env, "[C++] Call console.log()") });
Function module = Function::New(env, _asyncDemo);
return module;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, init)
- ./src/DemoAyncWorker.cpp
c++
#include "./DemoAyncWorker.h"
#include <thread>
#include <chrono>
using namespace Napi;
// 构造函数中把JS回调传给基类构造函数
DemoAsyncWorker::DemoAsyncWorker(Function& callback): AsyncWorker(callback) {}
// 析构函数啥也不干
DemoAsyncWorker::~DemoAsyncWorker() {}
// 子线程中等待1秒
void DemoAsyncWorker::Execute() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 打断点
}
// 异步操作完成,执行JS回调,传入'callback.'字符串,JS中将接收到这个字符串
void DemoAsyncWorker::OnOK() {
Callback().Call({ String::New(Env(), "callback.") }); // 打断点
}
- ./src/DemoAyncWorker.h
c++
#ifndef __DEMO_ASYNC_WORKER_H__
#define __DEMO_ASYNC_WORKER_H__
// 包含node-addon-api的头文件
#include <napi.h>
// 要实现异步必须继承Napi::AsyncWorker类,该类的内部会调用NAPI开启子线程
class DemoAsyncWorker : public Napi::AsyncWorker {
public:
// 构造函数传入JS的回调函数
DemoAsyncWorker(Napi::Function&);
// 析构函数
~DemoAsyncWorker();
// 子线程下执行异步操作
void Execute();
// 异步操作执行完成的回调
void OnOK();
};
#endif // ! __DEMO_ASYNC_WORKER_H__