vscode 调试 NodeJS c++ 扩展

笔者最近在使用c++和N-API来开发NodeJS扩展。绝大部分情况下,笔者可以通过简单的std::coutprintf来调试NodeJS扩展,但是打印日志的方式来调试比较费力、耗时。
image
笔者想配置vscode来调试NodeJS的C++扩展。下面主要展示了mac环境下的配置过程,对于windows和linux的情况配置也是类似的。
首先来看一个简单的扩展案例,项目目录如下:
2018-10-18 at 13 22
binding.gyp需要开发者通过npm install -g node-gyp安装node-gyp,对应的内容如下:

{
    "targets":[
        {
            "target_name" : "hello",
            "sources" : [ "hello.cc" ]
        }
    ]
}

表示构建的源码是hello.cc,构建的目标是hello,对应的会生成hello.node。

hello.cc的内容如下:

#include <node.h>
#include <v8.h>
using namespace v8;

void Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
}

void init(Handle<Object> exports){
  NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(hello, init)

构建方式如下:

node-gyp configure
node-gyp build

上面简单描述了一个c++扩展的的案例,执行完毕后,会在在./build/Release/下生成hello.node,可以通过如下方式进行调用:

let addon = require('./build/Release/hello')
console.log(addon.hello())

配置npm任务

在当前项目的package.json的scripts部分加入如下内容:

"scripts": {
   "start": "node index.js",
   "build:dev": "node-gyp -j 8 build --debug",
   "build": "node-gyp -j 8 build",
   "rebuild:dev": "node-gyp -j 8 rebuild --debug",
   "rebuild": "node-gyp -j 8 rebuild",
   "clean": "node-gyp clean"
}

-j x取决于你的机器的情况,一般来说x数值越大越好,但是也要取决于你的cpu的支持情况。build:dev任务会在当前目录下的build/Debug下生成用于调试版本的node扩展,build任务会在当前目录下的build/Release下生成正式版的node扩展。

配置vscode

笔者使用lldb来调试node扩展。首先安装vscode的lldb扩展,推荐 https://github.com/vadimcn/vscode-lldb
cmd+shift+p 打开command bar,输入open launch.json,按照如下形式进行修改:

{
  "version": "0.2.0",
  "configurations": [{
     "type": "lldb",
     "request": "launch",
     "name": "Launch Program",
     "preLaunchTask": "npm: build:dev",
     "program": "/absolute/path/to/node",
     "args": [
        "/absolute/path/to/your/hello.js"
     ]
  }]
}

这段配置的意思首先执行preLaunchTask生成用于debug的node扩展,然后执行lldb任务,用lldb来调试nodejs,注意到args为一个js文件,这个js文件负责引用node扩展并调用扩展提供的能力。

测试

配置完成之后,可以来试试调试node扩展:
2018-10-18 at 13 40
后面的调试就是常规操作了,这里不再赘述。