non vorrei lavorare

2020年度からの小学校プログラミング教育の必修化を親として迎えるブロガーの書く、子供との日常

N-APIはホントにV8以外のJavaScriptエンジンでもリビルドなしでネイティブモジュールが動くのか

qiita.com

この記事はNode.js Advent Calendar 2018の16日目の記事です。 また、ここ数年チャレンジしている@kjunichiのパーソナルアドベントカレンダーの16日目の記事も兼ねてます。

まえがき

Node.jsとは直接関係ないが、V8をPostgreSQLで動かせるplv8にWindows対応のプルリク投げた前科がある。

github.com

このプルリクは残念がらマージに至らなかったが、作者の方が、対応して現在、少し頑張れば、Windowsでも 新しいplv8がビルドできるハズ。

v8以外のエンジンのnode.jsに切り替えられるバージョン管理ツールの導入

とりあえず、macOS mojaveで試す。

node.jsではnvmがメジャーなバージョン管理ツールですが、chakracoreなnode.jsを試すには、以下のnvsが 便利です。

github.com

READMEに従って以下のように入れた。

export NVS_HOME="$HOME/.nvs"
git clone https://github.com/jasongin/nvs "$NVS_HOME"
. "$NVS_HOME/nvs.sh" install

chakracoreを入れる

nvsコマンドで対話的にchakracoreを入れられる。

nvs ls

とする事で、現在インストールされているnode.jsの一覧と選択されているnode.jsが表示される。

  node/10.14.2/x64 (Dubnium)
  node/10.13.0/x64 (Dubnium)
  node/10.12.0/x64
  node/10.7.0/x64
 >chakracore/10.13.0/x64 (Dubnium)

node-gypを入れる

N-APIに限らず、node.jsでネイティブモジュールを作る際に必要なnode-gypを入れる。

npm install -g node-gyp

N-APIを使ったモジュールを作る

以下のリポジトリをクローンしてN-APIのモジュールを用意。

github.com

git clone https://github.com/schahriar/n-api-article.git
cd n-api-article/Getting_Started

以下のコマンドでモジュールをビルドする。

node-gyp configure build

最後に以下のように表示されればモジュールのビルドに成功している。

  CC(target) Release/obj.target/module/src/module.o
  SOLINK_MODULE(target) Release/module.node
gyp info ok 

動かす

念の為、ここでどのnode.jsを使っているかを確認する。

node -p -e process.versions
{ http_parser: '2.8.0',
  node: '10.13.0',
  chakracore: '1.11.1.0',
  uv: '1.23.2',
  zlib: '1.2.11',
  ares: '1.14.0',
  modules: '64',
  nghttp2: '1.34.0',
  napi: '3',
  openssl: '1.1.0i',
  icu: '62.1',
  unicode: '11.0',
  cldr: '33.1',
  tz: '2018e' }

と、chakracoreの文字列が入っているので、v8エンジンでは無い事が確認できた。

それでは、実行してみる。

node module.js 



JSエンジンを変更して実行してみる

今度はJSエンジンをv8に変更して実行。

nvsコマンドで通常のnode.jsを入れて、

nvs ls
>node/10.14.2/x64 (Dubnium)
  node/10.13.0/x64 (Dubnium)
  node/10.12.0/x64
  node/10.7.0/x64
  chakracore/10.13.0/x64 (Dubnium)

だめ押しで、

node -p -e process.versions
{ http_parser: '2.8.0',
  node: '10.14.2',
  v8: '6.8.275.32-node.45',
  uv: '1.23.2',
  zlib: '1.2.11',
  ares: '1.15.0',
  modules: '64',
  nghttp2: '1.34.0',
  napi: '3',
  openssl: '1.1.0j',
  icu: '62.1',
  unicode: '11.0',
  cldr: '33.1',
  tz: '2018e' }
node module.js
8 times 2 equals 16

動いた!

Windows10でもやってみた

Windowsでnodeのネイティブモジュールをビルドできるようにするのに手っ取り早いのは

npm install --global --production windows-build-tools --vs2017

としてwindows-build-toolsを入れてしまうのがお手軽。

Rustを入れた時、構成変更して、C++周りのツールやらライブラリを入れる必要があったが、 対応できるので、Node.js以外の処理系でC/C++のMSの処理系が必要なら、これで入れてしまうのが楽。

Windowsではnvsを常用しているものの、chakracoreをこれまで入れた事なかったw。

前述のmacOS同様にchakracoreなnode.jsnvsで入れて、 node-gypを入れる。

トラブル発生!

以下のように、node-gypでモジュールをビルドしたら、

node-gyp configure build

以下のように、リンクでエラーが発生。

LINK : fatal error LNK1181: 入力ファイル 'chakracore.lib' を開けません。 [C:\Users\kjunichi\Documents\work\nod
ejs\n-api-ar
ticle\Getting_Started\build\module.vcxproj]

WindowsではMSVCでは共有ライブラリを利用する際に、ビルド時にリンカーに.libファイルを参照させる必要がある。 このエラーは、この.libファイルが見つからないというエラー。

対応方法

%homepath%\.node-gyp配下にchakracore版のnode.jsの.libファイルをコピーする。

コピー元の.libファイルは%homepath%\AppData\Local\nvs\chakracore\配下にある。 この記事を書いた際は

%homepath%\AppData\Local\nvs\chakracore\10.13.0\x64\sdk\Release

に配置されていた。

コピー先の詳細なパスは後述のmodule.vcxprojのAdditionalDependenciesセクションのnode.libのパスの指定に従い、 そこにコピーする。

buildフォルダのmodule.vcxprojファイルのchakracore.libの指定個所を先ほどコピーしたするパスで指定する。

複数箇所あるので、検索して該当個所を書き換える。

変更前

<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\Users\kjunichi\.node-gyp\10.13.0\x64\node.lib&quot;;chakracore.lib</AdditionalDependencies>

変更後

<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\Users\kjunichi\.node-gyp\10.13.0\x64\node.lib&quot;;&quot;C:\Users\kjunichi\.node-gyp\10.13.0\x64\chakracore.lib&quot;</AdditionalDependencies>

configureをつけずに

node-gyp build
  module.vcxproj -> C:\Users\kjunichi\Documents\work\nodejs\n-api-article\Getting_Started\build\Release\\modu
  le.node
gyp info ok

あとは、macOSの時同様、JSのエンジンを切り替えてもリビルドなしで、動かせた。

まとめ

N-APIの謳い文句通りにリビルドなしで、v8エンジンでもMSのchakracoreエンジンでもネイティブモジュールが 動くとこが確認できた。

本命?のWindowsでは.libファイルの扱いがnvs側の考慮不足なのか、node-gyp側なのかとにかく上手く扱われていないので、 node-gyp一発で作業ができないことが分かった。

あと、

myakura.hatenablog.com

に書いてあるような状況なので、chakracoreの未来は暗いのかも。。

Rustで実装されているRapidusがN-APIに対応する事に期待。

関連記事

10年前の記事

4年前の記事

3年前の記事

2年前の記事

1年前の記事