LoginSignup
1
1

More than 3 years have passed since last update.

失敗談:VScodeでワンクリックでElectronのNativeAddonをデバッグしたかった

Last updated at Posted at 2019-08-03

ネガティブインフォメーションも価値があるよね。

やりたかったこと

  • 環境はWindowsかMac、両方で開発。
  • IDEは問わない。
  • ボタンひとつ押すだけでElectronを作成->C++のコードをビルド->Electron立ち上げ->C++をデバッグ
  • C++のコードを必ずデバッグするようにすると時間がかかるので、その部分だけビルドしたり飛ばしたりしたい。
  • 自動で既に起動している特定のプロセスをアタッチ(デバッグ)したい。

出来たこと

  • Electronをビルド->Electronを立ち上げ
  • Electronを作成->C++をビルド->Electron立ち上げ。
  • IDEはCLionとVScodeである程度は出来た。
  • Process IDを指定すれば、Electron起動後にC++のコードをアタッチしてデバッグ可能。でもいちいちProcess IDを特定するのが面倒。

出来なかったこと

  • Electronは起動するとMainとRendererで別のプロセスが起動し、Renderer側にC++を実行させたのだが、複数のRendererが立ち上がっているので「どれか1つを特定して」アタッチさせる。

VSCodeでやってみたこと

以下のファイルをプロジェクトの直下において、適当にnpm installした。

package.json
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build:dev": "./node_modules/.bin/node-gyp rebuild --target=5.0.8 --arch=x64 --dist-url=https://electronjs.org/headers --debug"
  },
  "devDependencies": {
    "electron": "5.0.8",
    "electron-prebuilt": "^1.4.13",
    "electron-rebuild": "^1.8.5",
    "node-gyp": "5.0.0",
    "rebuild": "^0.1.2"
  },
  "dependencies": {}
}

test.cc
#include <node.h>
#include <v8.h>
#include <string.h>
#include <memory>

int data = 0;

void Method(const v8::FunctionCallbackInfo <v8::Value> &args) {
    v8::Isolate *isolate = args.GetIsolate();
    v8::HandleScope scope(isolate);
    std::string strings = "world" + std::to_string(data);
    args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, strings.c_str()));
}

void CountUp(const v8::FunctionCallbackInfo <v8::Value> &args) {
// このへんにブレークポイント設置。
    data = data + 1;
}

void init(v8::Local <v8::Object> exports) {
    NODE_SET_METHOD(exports, "hello", Method);
    NODE_SET_METHOD(exports, "countUp", CountUp);
}

NODE_MODULE(binding, init
);
index.html
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>test</title></head>
<body>
<div id='test'></div>
<button onclick="testFunc()">test button</button>
<button onclick="test2()">Count up</button>
<script>
    var remote = require('electron').remote;
    var testC = require('./build/Debug/testFunction');
    function test2(){
        testC.countUp();
    }
    function testFunc(){
        document.getElementById('test').innerText = "hello " + testC.hello();
    }
</script>
</body>
</html>
index.js
"use strict";
const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
let mainWindow;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({
      width: 800, height: 600, title: 'test',darkTheme:true,
      webPreferences: {
        nodeIntegration: true
  }
  });
  mainWindow.on('page-title-updated', (evt) => {
    evt.preventDefault();
  });
  mainWindow.webContents.openDevTools();
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

binding.gyp
{
  "targets": [
    {
      "target_name": "testFunction",
      "sources": [
        "test.cc"
      ]
    },
  ]
}

launch.json

実行環境はMac
VSCodeのビルドとかデバッグは、「.vscode/launch.json」に記述してます。
やってみた結果とかをコメントで書いてます。

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "electron start",
            "type": "node",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            "program": "${workspaceRoot}/index.js",
            // 実行前にpackage.jsonで指定したビルドを実行
            "preLaunchTask": "npm: build:dev",
            // Electronを指定
            "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
            // 子プロセスもアタッチしてみた(ただしlldbではなくnode.jsとして)
            "autoAttachChildProcesses":true,
            "runtimeArgs": [
                "--enable-logging",
                "--debug=5858",
                "--remote-debugging-port=9223",
            ],
            "args": [
                ".",
            ],
            "windows": {
                "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
            },
            "console": "internalConsole",
        },
      { 
          "name": "native addon",
          // lldbでアタッチ(Mac用)
          "type": "lldb",
          // 実行前にC++をビルド
          "preLaunchTask": "npm: build:dev",
          // attachに指定すると、以下の"program"が有効になる。
          "request": "attach",
          // ↓process name  Electron Helperだからこれでアタッチできるんじゃね?->1個に絞れと怒られた。
          // "program": "pgrep -n 'Electron Helper'",
          // ↓ダメ元でプログラムの位置を指定してみた->ダメだった。
          // "program": "/Applications/Visual Studio Code.app/Contents/MacOS/Electron",
          // "program": "${workspaceRoot}/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron",
          // "pid": 7669,
          // でも上記が上手く行かなかったので手動でprocess idを指定することに・・・
          "pid":"${command:pickMyProcess}",
          "expressions": "native",
      },
      {
        "name": "native addon custom (error)",
        // lldbでアタッチ(Mac用)
        "type": "lldb",
        // customに指定すると、lldbの細かい動作を指定できる。。
        "request": "custom",
        "preLaunchTask": "npm: build:dev",
        // 1つに絞れと怒られる。
        "targetCreateCommands":["process attach --name \"Electron Helper\""],
        // pgrepでprocess idを表示はできるが、結局何処に使えば・・・
        // pgrep 'Electron Helper'
        // shellで実行出来なくはない。でもその値をlldbに持っていけない
        // "targetCreateCommands":["platform shell pgrep 'Electron Helper'"],
        // process id一覧表示
        // "targetCreateCommands":["platform list"],
        // 配列で複数の内容を記述も可能。
        // "targetCreateCommands":["env ELECTRON_HELPER='Electron Helper'",
            // "attach --name 'Electron Helper'",
            // "platform shell pgrep 'Electron Helper'",
            // "attach ${command:pickProcess}",
            // "attach --name '${input:pickProgram}'"
        //],
        // target createでファイルでの指定はできるが、Electronは一度に複数のHelperを起動するので、その全てをどうやってか指定する必要がある。
        // "targetCreateCommands":["target create 'path'"],
        "expressions": "native",
      }
    ],
    // ちなみに、自分で作ったリストを表示させる方法もあるが、pidは起動ごとに変わるので意味はないかな。
    "inputs": [
      {
          "id": "pickData",
          "description": "select",
          "type": "pickString",
          "options": ["Electron Helper","Electron"],
          "default": "Electron Helper"
      }
  ]
  }


参考

https://github.com/vadimcn/vscode-lldb/blob/v1.2.3/MANUAL.md
https://electronjs.org/docs/development/debugging-instructions-macos
https://yokaze.github.io/2018/01/06/

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1