ぼちぼち日記

おそらくプロトコルネタを書いていることが多いんじゃないかと思います。

gyp による Addon 向けネイティブモジュールの作成

ちょうど今朝 node-v0.7.6 がリリースされました。

このリリースではアドオン周りを TooTallNate さんがいくつか修正を行い、なんとか今後の Node.js のネイティブモジュール形が見えてきましたので、その辺の紹介をします。

現状わかっている範囲でネイティブモジュールの状況についてまとめると、

  • node-v0.7以降では node-waf が廃止されてネイティブモジュールの作成は gyp ベースで行われます。
  • gyp ベースになると Linux では make, Mac では xcode, Windows では Visual Studio を使ってネイティブモジュールの作成ができるようになります。
  • gyp によるネイティブモジュールの作成ツールは、ソース同梱の tools/gyp_addon (pythonスクリプト) かTooTallNate製の node-gyp モジュールを使う。(他にもあるかもしれませんが知りません。)
  • 0.7.6 から npm に node-gyp が含まれるようになりました。
  • 予定としては今後 npm はバイナリーインストールに対応し、利用者が自前でコンパイルせずにモジュールを利用する感じになりそう。(まだ本当にどうなるかわかりませんが。)

となります。今回ソース同梱の hello-world サンプルを使って gyp によるネイティブモジュールの作成の仕方について簡単に紹介します。

アドオンのサンプルは、 Node.js のソース中 test/addon/hello-world/ にあります。( ry の最後のお土産)
中身は、

  • test/addon/hello-world/binding.cc (モジュールのソース)
  • test/addon/hello-world/binding.gypi (モジュール向けの gyp ファイル)
  • test/addon/hello-world/test.js (モジュールを読みこみ出力する JSファイル)

です。
(注意)
2週間ほど前にビルドのパスが変わった(./out → ./build) のですが test.js 中の記述が変わっていないので、test.js 中の

var binding = require('./out/Release/binding');

var binding = require('./build/Release/binding');

に変えてください。(修正PR出しているので次のリリースでは直されていると思います。https://github.com/joyent/node/pull/2929 )

tools/gyp_addon によるネイティブモジュールの作成方法

  1. test/addon/hello-world/ ディレクトリに移動します。
  2. tools/gyp_addon コマンドを起動 (Windows の場合は python コマンドの引数にこのファイルを加えてください。)
  3. build ディレクトリが作成されていることを確認して、移動します。
  4. Linux の場合は Makefile が作成されているので make, Windows の場合は Visual Studio ファイルが作成されているので開いてビルドしてください。(コマンドラインで直接ビルドできる方法もあるかもしれませんが知りません。)
  5. ビルドが終わるとビルドタイプ名(デフォルトは Release) のディレクトリ以下に binding.node バイナリが作成されます。
  6. (注意で書いたパスを変更し) test.js を node で起動すれば、ネイティブモジュールの hello-world が出力されます。

下記、Linuxの場合の出力例です。

unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> ../../../tools/gyp_addon
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> ls
binding.cc  binding.gyp  build  test.js
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> cd build/
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world/build> make
  CXX(target) Release/obj.target/binding/binding.o
  SOLINK_MODULE(target) Release/obj.target/binding.node
  SOLINK_MODULE(target) Release/obj.target/binding.node: Finished
  COPY Release/binding.node
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world/build> cd ..
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> node ./test.js
binding.hello() = world

node-gyp によるネイティブモジュールの作成方法

  1. npm install -g node-gyp で node-gyp をインストールします。(0.7.6 で npm に同梱されたので npm のインストールで一緒に入るかもしれませんが、まっさらな環境での試験はまだやってません。Node.js のソース一式がダウンロードされますのでディスク容量などにご注意下さい。)
  2. node-waf の使い方と同じように、configure/build でネイティブモジュールのバイナリーが作成されます。(これは Linux/Windows一緒)
    1. node-gyp configure
    2. node-gyp build

Linuxの出力例は、以下の通りです。

unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> node-gyp configure
info it worked if it ends with ok
spawn python [ '/home/ohtsu/.node-gyp/0.7.6/tools/gyp_addon',
  'binding.gyp',
  '-I/var/tmp/node-v0.7.6/test/addons/hello-world/build/config.gypi',
  '-f',
  'make' ]
info done ok
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> node-gyp build
info it worked if it ends with ok
spawn make [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory `/var/tmp/node-v0.7.6/test/addons/hello-world/build'
  CXX(target) Release/obj.target/binding/binding.o
  SOLINK_MODULE(target) Release/obj.target/binding.node
  SOLINK_MODULE(target) Release/obj.target/binding.node: Finished
  COPY Release/binding.node
make: Leaving directory `/var/tmp/node-v0.7.6/test/addons/hello-world/build'
info done ok
unixjp:/var/tmp/node-v0.7.6/test/addons/hello-world> node ./test.js
binding.hello() = world

これで念願の Unix/Windows 両OSで、ほぼ同様の手順でアドオンの作成ができるようになりました。
次時間があれば gyp ファイルの書き方や node-gyp コマンドの使い方など紹介していきます。