2011-03-05

新しいビルドシステム、ニンジャ

Chromium Notes: Ninja, a new build system

ChromeをWindowsから移植し始めたとき、我々はSconsを使ってChromeをビルドしようとした。Sconsは、正しく動作して、使い方も簡単であった。しかし、開発を始めてすぐに、Sconsはとても遅いということに気がついた。ソースを実際にビルドし始めるまでに、40秒もかかるのだ。Sconsが全面的に悪いというわけでもない。Chromeのビルドは、たったひとつの実行ファイルのために、WebKitも含めて、30000ものファイルがあるのだ。

結局、私はLinuxビルドのために、単にMakefileを使うことにした。これは、我々のビルドシステムが、メタビルドシステム、すなわち、WindowsやMac用のビルドファイルを生成するビルドシステムだったから可能だったのだ。開発を進めるほどに、私はどんどんビルドのパフォーマンスが気になって仕方がなかった。Windowsビルドで、たったひとつのファイルを変更しただけなのに、リンクするのに8分もかかったことがある。これは、私のプロダクティビティとモラルの為に害悪である。

ビルドのパフォーマンスというものは、様々なファクターが影響する。ビルドシステムは、何をすべきなのかを計算しなければならない。コンパイラーがファイルをコンパイルするのにも時間がかかる。リンカーがリンクするのにも時間がかかる。これらの要素は改良できる、逆順に。Google社員によって書かれたgoldリンカーは、素晴らしく速い。コンパイル時間は、高速なコンパイラー(最近の私のclangにおける活動を参照のこと)と、より良い並列化(私はかなりの時間を、同僚にdistccを布教するのに費やしている)によって、短縮できる。ビルドシステムそのものも改良可能だ。

これらの改良と、注意深く、再帰しないように生成されたmakefileによって、インクリメンタルなビルドは、10秒から20秒程度に抑えることができた。私は特に、Linuxにおけるビルドシステムを開発したことを誇りに思っている。というのも、最初の移植では、開発は進まなかっただろうと思うからだ。他の開発者が使いたいと思うようにならなければ、Chromeの開発は進まない。例えば、多くの(いや全員か?)Chromeエクステンション開発チームは、開発環境にLinuxを使っている。何故といって、デバッガーの質は悪いものの、その他の要素がはるかに優れているからだ。このため、私はGitのサポート要員でもあるのだ。Gitはよりプロダクティブで、Linuxでは爆速である。

しかし、まだ私は、実際のコンパイルが始まるのに20秒かかるということに、満足していない。ディスクキャッシュが効いている状態ならば、そんなに時間がかかるはずはないと思うのだ。

我々のmakefileは、様々な賢いハックを多用している。多くのアイディアは、Linuxカーネルのビルドシステムからパクッてきた。makeが自分ではやってくれないことをやらせるのだ。例えば、ある出力におけるコンパイルフラグが変わった場合、出力ファイルはリビルドしなければならない。これは、すべてのmakefileを、存在しない入力に依存させることによって実現できる。つまり、ルールは常に一致するのだ。その後、ほんとうにリビルドが必要かどうか独自に判断すればよい。また、以前のビルドに使われたコマンドラインも保存しておく必要がある。このような、本来Makeの想定していない使い方こそが、Makeがそれほど早くない原因なのだろう。

我々のビルドをMakeに移植する際に、私は多くのことを学んだ。中には、意外なこともあった。たとえば、これを試してみるといい。

touch foo.c
echo 'foo: foo.c' > Makefile
strace -estat make

GNU makeは、ビルドルールの一環として、RCSとSCCSメタデータを読み込みに行くではないか!(これは大昔のバージョン管理システムで使われていたものである。この挙動は、Makeお-rフラグで変更できる)

これらをすべて踏まえ、週末を使えば、私はとても単純なビルドシステムを作れると考えた。Makeによく似ているが、機能がほとんどないものだ。なぜ単にMakeや他のビルドシステムを改良しないのか。それは、私はこれを娯楽としてやっているからだ。他のものを娯楽でやるつもりはない。さて、私はMakeにはない機能をいくつか実装した。例えば、ビルドコマンドを並行して実行しているときに、すべてのビルドコマンドの出力をバッファーしておくことによって、エラーの出力は、他の出力を妨げることなく、失敗したコマンドの完全なコマンドラインと関連付けることができる。そしてプロファイルの結果、Chromeのビルドを1秒で開始させることができた。

これを他のツール(特にgold)や高速なコンピューターと組み合わせれば、ひとつのファイルを変更したことによるChromeのインクリメンタルビルドを、6秒で終えることができる。私はこの開発の結果であるビルドシステムをオープンソースにする許可を得た。私はこれに、ニンジャ(Ninja)という名前をつけた。これは素早いからだ。githubから入手できる、また、より詳しいことは、マニュアルを読んでほしい

この人の他の記事も面白い。例えば、Clangにおける開発だ。

Chromium Notes: Clang work

No comments: