electron-rebuild

ElectronでC++拡張モジュールを呼び出せるかやってみる。

electron/using-native-node-modules.md at master · electron/electron · GitHub

まず、npm init。

$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (app_)
version: (1.0.0)
description: electron-rebuild sample
entry point: (index.js) main.js
test command: start
git repository: -
keywords: -
author: B.G
license: (ISC) MIT
About to write to
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/package.json:

{
  "name": "app_",
  "version": "1.0.0",
  "description": "electron-rebuild sample",
  "main": "main.js",
  "scripts": {
    "test": "start"
  },
  "repository": {
    "type": "git",
    "url": "-"
  },
  "keywords": [
    "-"
  ],
  "author": "B.G",
  "license": "MIT"
}


Is this OK? (yes)
$

package.jsonを作成したら、
main.jsで、

デベロッパーツールを起動するようにしておく。
index.htmlは、

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>app_</title>
  </head>
  <body>
    <h1>ABCDE</h1>
    <button onclick="run()">Run</button>
    <script>
      document.write(process.versions.electron);
      function run(){
        var nativeExt = require('./build/Release/native_ext.node');
        var str = nativeExt.get_abc();
        alert(str);
      }
    </script>
  </body>
</html>

ネイティブ拡張を参照できるようにしておく。
package.jsonは、

{
  "name": "app_",
  "version": "1.0.0",
  "description": "electron-rebuild sample",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "repository": {
    "type": "git",
    "url": "-"
  },
  "keywords": [
    "-"
  ],
  "author": "B.G",
  "license": "MIT"
}

npm startで"electron ."を起動できるように。
electronをインストールする。

$ vi main.js
$ vi index.html
$ vi package.json
$ npm install electron

> electron@4.1.0 postinstall /home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/electron
> node install.js

Downloading tmp-4643-1-SHASUMS256.txt-4.1.0
[============================================>] 100.0% of 4.74 kB (4.74 kB/s)
npm notice created a lockfile as package-lock.json. You should commit this file.
+ electron@4.1.0
added 145 packages from 141 contributors and audited 201 packages in 81.199s
found 0 vulnerabilities



   ╭───────────────────────────────────────────────────────────────╮
   │                                                               │
   │       New minor version of npm available! 6.4.1 → 6.9.0       │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.9.0   │
   │               Run npm install -g npm to update!               │
   │                                                               │
   ╰───────────────────────────────────────────────────────────────╯

$

続いて、node-gypのインストール。

$ ls
index.html  main.js  node_modules  package-lock.json  package.json
$ npm install node-gyp
+ node-gyp@3.8.0
added 35 packages from 10 contributors and audited 384 packages in 4.585s
found 0 vulnerabilities

$

binding.gypはnode-gypのトピックで使ったものと同じものを使用した。
また、native_ext.ccでは、

get_abcの中でsleepで5秒休止するようにした。
node-gyp configureする。

[bg1@localhost app_]$ vi binding.gyp
[bg1@localhost app_]$ vi native_ext.cc
[bg1@localhost app_]$ ./node_modules/.bin/node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/bg1/.node-gyp/10.15.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/bg1/.node-gyp/10.15.0',
gyp info spawn args
'-Dnode_gyp_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp',
gyp info spawn args
'-Dnode_lib_file=/home/bg1/.node-gyp/10.15.0/<(target_arch)/node.lib',
gyp info spawn args
'-Dmodule_root_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok
$

node-gyp buildする。

$ ./node_modules/.bin/node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
に入ります
  CXX(target) Release/obj.target/native_ext/native_ext.o
In file included from ../native_ext.cc:2:
/home/bg1/.node-gyp/10.15.0/include/node/node.h:570:43: 警告: cast
between incompatible function types from ‘void
(*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void
(*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’}
[-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/home/bg1/.node-gyp/10.15.0/include/node/node.h:604:3: 備考: in
expansion of macro ‘NODE_MODULE_X’
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../native_ext.cc:28:1: 備考: in expansion of macro ‘NODE_MODULE’
 NODE_MODULE(native_ext, init);
 ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/native_ext.node
  COPY Release/native_ext.node
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
から出ます
gyp info ok
$

ビルドすると、

$ ls
binding.gyp  build  index.html  main.js  native_ext.cc  node_modules
package-lock.json  package.json
$ cd build/
$ cd Release/
$ ls
native_ext.node  obj.target
$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/Release
$

build/Releaseの下にnative_ext.nodeができる。
npm startすると、

起動時
起動時

このように表示される。
右の開発ツールでConsoleのタブをクリック。

Console
Console

いまのところは問題なさそうだが、"Run"ボタンを押すと、

エラー
エラー

エラーが発生。
実は、ElectronのNODE_MODULEとNode.jsのNODE_MODULEのバージョンには違いがあり、それが原因でネイティブモジュールを呼び出せない。
そこで、electron-rebuildを使って、"ElectronのヘッダでNode.jsをリビルドする"という作業を行う。
(ここ、よくわからないとおもうが、次のようにすればうまくいくと思えばいい・・・。)
まず、electron-rebuildをインストール。

$ ls
binding.gyp  build  index.html  main.js  native_ext.cc  node_modules
package-lock.json  package.json
$ npm install --save-dev electron-rebuild
+ electron-rebuild@1.8.4
added 75 packages from 53 contributors and audited 679 packages in 9.573s
found 0 vulnerabilities

$

ビルド時にしか使わないので、"--save-dev"でインストール。
npmの--save, --save-dev, --save-optionalの違い - how to code something

electron-rebuildコマンドを実行し、configureとbuild。

$ ./node_modules/.bin/electron-rebuild
✔ Rebuild Complete
$ ./node_modules/.bin/node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/bg1/.node-gyp/10.15.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/bg1/.node-gyp/10.15.0',
gyp info spawn args
'-Dnode_gyp_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp',
gyp info spawn args
'-Dnode_lib_file=/home/bg1/.node-gyp/10.15.0/<(target_arch)/node.lib',
gyp info spawn args
'-Dmodule_root_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok
$ ./node_modules/.bin/node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
に入ります
  CXX(target) Release/obj.target/native_ext/native_ext.o
In file included from ../native_ext.cc:2:
/home/bg1/.node-gyp/10.15.0/include/node/node.h:570:43: 警告: cast
between incompatible function types from ‘void
(*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void
(*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’}
[-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/home/bg1/.node-gyp/10.15.0/include/node/node.h:604:3: 備考: in
expansion of macro ‘NODE_MODULE_X’
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../native_ext.cc:28:1: 備考: in expansion of macro ‘NODE_MODULE’
 NODE_MODULE(native_ext, init);
 ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/native_ext.node
  COPY Release/native_ext.node
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
から出ます
gyp info ok
$

そうすると、

$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ cd bin
$ ls
linux-x64-69
$ cd linux-x64-69/
$ ls
app_.node
$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/src/app_/bin/linux-x64-69
$

bin/linux-x64-69の下にapp_.nodeができる。これがリビルドされたモジュールなのでこれを参照するようにする。

このように書き換えたら、npm startしてみる。

$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ vi index.html
$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ npm start

> app_@1.0.0 start /home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
> electron .

で起動し、

起動時
起動時

このようになるので、Runボタンを押す。

エラーが出ず、へこんだままになる。
エラーが出ず、へこんだままになる。

今度は、エラーが出ず、へこんだままになるので、5秒待つ。
5秒経つと、

alertで&quot;ABC&quot;が表示される。
alertで"ABC"が表示される。

alertで"ABC"が表示される。
このように、Electronからネイティブ拡張を使う場合は、electron-rebuildが必要になる。

Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_ at master · bg1bgst333/Sample · GitHub