non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

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年前の記事