Node.js Addon编译调试教程(一次成功版)

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
node-gyp configure --nodedir=D:\\nodejs && node-gyp build --debug

binding.gyp配置

{
  # 构建目标集合
  "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
        }
      },
      # 预定义宏,禁用NAPIC++异常处理和node-addon-api废弃的API
      "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS", "NODE_ADDON_API_DISABLE_DEPRECATED"]
    }
  ]
}

vscode debug配置

// 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配置

"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

  • 下载地址:https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/

示例代码

  • index.js
const Add = require('./build/Debug/add.node');

Add(1,2, result => {
    console.log('1 + 2 =',result)
})
  • ./src/main.cpp
#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
#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
#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__
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值