ぼちぼち日記

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

node-0.7.x の新機能: GYPによる Node.js のビルド

ちょうど先ほど Node.js の新しい unstable ブランチである 0.7.0 がリリースされました。(パチパチ)
年末からの hash collision 問題や、 core dump など安定性を脅かす問題も 0.6.x である程度片付いたので、これからは新機能開発・改良に重点を移していくのではないかと思われます。

この新しい node-0.7.0 変更点の一つとして、Node.js のビルドが WAF から GYP に変わったことが挙げられます。

WAFを止める

Node.js から WAF をなくすことは以前からの Ryan Dahl の念願で、インタビューでは
http://bostinno.com/2011/01/31/node-js-interview-4-questions-with-creator-ryan-dahl/

BostInno: Is there anything you wish you had done differently with node?

Dahl: Yes – many things. For example, I wish I had not used the CommonJS module system. It’s far too complex and wildly different from how the browser works. I wish I had not used the WAF build system, it works - it’s okay, but it introduces more WTFs than necessary. I can perhaps dig out from under WAF at some point but it would be a monumental undertaking.

BostInno: (振り返って)nodeで(今と)違ってたことをやっていればよかったと思うことは?

Dahl: はい – いっぱいあります. 例えば CommonJS のモジュールシステムを使わなければよかった。ブラウザが動作するより複雑過ぎて、しかも大きく異なっているから。 WAF ビルドシステムも使わなければよかった。確かに動いているよ、でも必要以上に厄介な事が起きている。ある程度 WAFの下でいろんなごちゃごちゃを整理できるかもしれないが、それはとてつもない大事業になっちゃうだろう。

のように Node.js にWAFを使ったことを非常に後悔してると嘆いています。(Node学園祭の2次会で本人と直接話をした時も「WAFは絶対にやめる GYP にする。」と言いきってました。)

実は以前(11月中旬)より github の master 上では既に GYP でビルドするようになっていましたが、0.6.x のリリースの毎に WAFビルドに置き換えていました。
WAF からGYPに変えた時のコミットとその時のツィートがこちら。

https://github.com/joyent/node/commit/14b04b06b4a7f31b3b489abba5e1467678f0f6be
本人の喜びようが伝わります。

なぜGYP?

WAF の代わりに一時は独自のビルド方式も検討したようですが、最終的に GYP を選びました。その理由として MLでこう述べています。

Node.js の GYPビルドのやり方

実際に GYP によるビルドを試してみます。 (Ubuntu11.10 Linux の場合です。)まずは configure です。

> ./configure
{ 'target_defaults': { 'cflags': [],
                       'defines': [],
                       'include_dirs': [],
                       'libraries': ['-lz']},
  'variables': { 'host_arch': 'ia32',
                 'node_debug': 'false',
                 'node_install_npm': 'true',
                 'node_prefix': '',
                 'node_shared_cares': 'false',
                 'node_shared_v8': 'false',
                 'node_use_dtrace': 'false',
                 'node_use_isolates': 'true',
                 'node_use_openssl': 'true',
                 'node_use_system_openssl': 'false',
                 'target_arch': 'ia32',
                 'v8_use_snapshot': 'true'}}
creating  ./config.gypi

configure を実行すると config.gypi に GYPの設定ファイル(JSON形式)とビルドを行う out/ ディレクトリ(とビルドに必要なファイル)が作成されます。(実際には tools/gyp_node -f make が呼ばれて各種設定ファイルの読み込み・生成が始まります。)
次に make を行うと、out/Release 以下でビルドが始まります。(defaultの BUILDTYPE は Release です。)

> make
make -C out BUILDTYPE=Release
make[1]: Entering directory `/home/ohtsu/tmp/node-v0.7.0/out'
  CC(target) /home/ohtsu/tmp/node-v0.7.0/out/Release/obj.target/http_parser/deps/http_parser/http_parser.o
(以下コンパイルが続く)
  LINK(target) /home/ohtsu/tmp/node-v0.7.0/out/Release/node
  LINK(target) /home/ohtsu/tmp/node-v0.7.0/out/Release/node: Finished
make[1]: Leaving directory `/home/ohtsu/tmp/node-v0.7.0/out'
ln -fs out/Release/node node
>

と、out/Release/node にビルドされた node のバイナリーが生成されます。
デバッグビルドをしたい場合は、

> make BUILDTYPE=Debug

にします。その場合の出力先は out/Debug/node_g になります。(いずれもソースツリーとルートディレクトリにシンボリックリンクされます。)
理由はわかりませんが、WAFの時よりもビルドに時間がかかっているような感じですね。(ざっと1.5倍ぐらいかも)
上の出力をみれば気が付きますが、コンパイル・リンクのフラグとかが見えないです。なししているのか結構不安じゃないかと。
そんな場合、 V=1 フラグを付けて make しましょう。

> make V=1
make -C out BUILDTYPE=Release
make[1]: Entering directory `/home/ohtsu/tmp/node-v0.7.0/out'
  cc '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DL_ENDIAN' '-DOPENSSLDIR="ssl"' '-DENGINESDIR="ssl/lib/engines"' '-DOPENSSL_THREADS' '-DPURIFY' '-D_REENTRANT' '-DTERMIO' '-DNDEBUG' -I../deps/openssl -I../deps/openssl/openssl -I../deps/openssl/openssl/crypto -I../deps/openssl/openssl/crypto/asn1 -I../deps/openssl/openssl/crypto/evp -I../deps/openssl/openssl/include -I../deps/openssl/config/piii -Wall -pthread -m32 -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections  -MMD -MF /home/ohtsu/tmp/node-v0.7.0/out/Release/.deps//home/ohtsu/tmp/node-v0.7.0/out/Release/obj.target/openssl/deps/openssl/openssl/engines/e_ubsec.o.d.raw  -c -o /home/ohtsu/tmp/node-v0.7.0/out/Release/obj.target/openssl/deps/openssl/openssl/engines/e_ubsec.o ../deps/openssl/openssl/engines/e_ubsec.c

と見慣れたビルド出力が現れました。

以上で node-0.7.x の新機能 GYP による Node.jsビルドのご紹介をしました。 node-v.0.7.x では本体のビルドだけではなくC/C++アドオンの作成も GYP による作成になります。(node-waf はしばらくメンテナンスのためだけに残ります。) 本当はそこまで書きたかったのですが、思わず説明が長くなってしまったので本日はここまでにしておきます。