この記事では,先日オープンソースとして公開された Buck と xctool の詳細を紹介する。いずれも Facebook 社内で,AndroidとiOSのネイティブアプリケーション開発用に使用されていたビルドツールだ。
Buck
Facebookは先頃,同社がAndroidネイティブアプリケーション開発に使用しているビルドツールの Buck をオープンソースとした。Buckは Google Blaze にヒントを得て開発されたツールで,複雑で数の多いAndroidライブラリを管理して,ビルド時間を短縮するものだ。Buckを導入後,Facebookでは4つのAndroidネイティブアプリを,単一のコードツリーとビルドツールを使って開発完了している。導入以前に比べると,開発はシンプルで合理化され,エラーも少なくなった。当初38あったライブラリは,最終的には4つのアプリケーションで共有される500ほどのモジュールになった。また,Antベースだった最初のシステムをBuckに置き換えた結果,コード全体に対する初期ビルド時間は3分40秒から1分30秒に短縮されている。
BuckはJavaで記述されている。構築ルールは当初Pythonで定義されていたが,ルール評価高速化のためにJythonに変更された。現在はAndroid Javaコードの開発用だが,Androildとは無関係の純粋なJavaコードを開発可能にするためのプロセスが進行中だ。Pythonやその他の開発用に拡張される可能性もある。
FacebookのAndroidコードは,独立したサブツリーを持ったツリーによる 有方向巡回グラフ(directed acyclic graph) を構成している。サブツリーそれぞれに関連するビルドルールの並列実行を可能にすることで,ビルド時間の短縮を達成しているのだ。ルールを記述したビルドファイルがAndroidモジュールごとにひとつずつあり,これがコードツリー全体に展開されている。ビルドファイルが実行されるのはモジュール内に変更ファイルが存在する場合のみであると同時に,各ビルドは並列実行が可能である。並列機能を有効にして8スレッドを利用した場合,ユニットテスト時間が20分から4分まで短縮された,とBuckの開発者であるMichael Bolin氏は述べている。氏は DevCon New York 2013のセッション で,このビルドシステムについて解説している。
Buckは複数バージョンのファイルを扱うことができる,と 氏は,Google+のスレッドで説明している。
Androidアプリを構築する上で難しい問題としてもうひとつ,R.javaファイルの生成があります。詳細はここでは述べませんが,Rという名称の同じクラスに依存性を持つ,複数のAndroidアプリを開発しているとしましょう。普通のJavaクラスなら,それを1度だけコンパイルして,他のいくつかのJavaクラスがそれを参照すれば済む話です。ところがAndroidでは,コンパイルの必要なRのバージョンは,コンパイルされたJavaコードが最終的に含まれるAndroidアプリに依存性を持っているのです。ビルドするAndroidアプリごとに違うバージョンのJavaコードをコンパイルするのでは非効率になるので,Buckではいくつかの巧妙なトリック(コンパイル時には,実行時とは違うR.javaファイルを生成する)を採用しています。
近い将来には,ファイル編集を監視するデーモンが追加されて,ファイルが更新されたら即座にビルドを開始するようになる予定だ。
BuckはMac OSとLinux上で動作する。Windowsへの移植 も検討中である。
Gerrit の開発者であるShawn Pearce氏は,Mavenの代替として Buckを使用するという提案 の中で,何よりもその速度について言及している。
buck: clean: 0.452s, full 1m21.083s [*], no-op: 7.145s,
maven: clean: 4.596s, full 2m53.776s, no-op: 59.108s,[*] fullのビルド時間には依存ファイルすべてのダウンロードを含むため,リモートサーバのパフォーマンスによって変化する可能性がある。
氏は同時に,Buckの欠点もいくつか指摘している。
- Windowsがサポートされない
- Maven Central がネイティブでサポートされない (マクロで追加)
- ネイティブGWT,Prolog, WARがサポートされない (マクロで追加)
- Buckの立ち上げ時にAntが必要
xctool
xctool はFacebookが最近オープンソースにしたもうひとつのビルドツールで,iOSアプリケーションの開発に使用される。xcodebuild の代替として,以下のような機能を備えている。
- Xcode.appと同じテストを実行可能
- ビルド出力とテスト結果はJSONとして取り込まれるため,出力の解析が不要
- エラー発生時のみメッセージを出力する。xcodebuildのように,すべてのソースファイルに対してメッセージを出力しない
Facebookがxcodebuildとは別のツールを構築した理由を知るため,我々はxctoolのコミッタである Fred Potter 氏に,彼らのツールの持つ優位性について質問した。
xctool最大のメリットは,ユニットテストの構築と実行を,Xcode.appがGUIで行っているのと同じ方法で,コマンドラインから可能なことです。iOS用に継続的インテグレーションシステムを構築しているのであれば,これは特に重要です。開発者がローカルマシンで実行しているのと同じテストを自動化環境で実行したくても,xcodebuildでは,Xcode.appと同じ方法でビルドやテストを行うことはできません。Xcode4でAppleは,ユニットテストを完全にXcodeに統合しました - 'Build' や 'Run' と合わせて,'Test' というアクションが新たに追加されたのです。Xcodeのスキーマ内で,ユニットテストの有効と無効を選択することが可能になりました。iOSシミュレータに依存するテスト (いわゆるアプリケーションテスト) を記述すれば,Xcodeが自動的にシミュレータをローンチしてそれを実行してくれます。これは大きな進歩だったのですが,Appleがこれらをxcodebuildには追加しなかったため,自動ビルドやテストはますます難しくなってしまいました。
もうひとつの大きな問題は,ビルドとテストの失敗を通知する方法です。xcodebuildではコンパイラのコマンド,コンパイルエラーと警告,OCUnitの出力などを含んだ巨大なテキストデータが出力されます。ビルドに失敗したコンポーネントや失敗したユニットテストを自動的に判断するためには,私たちやiOSコミュニティの他の人たちがやってきたように,正規表現を駆使したパーサを記述しなければなりません。これでも役にはたちますが,かなり面倒です。xctoolではxcodebuildとOCUnitテストランナを応用して,ビルドやテストの結果をJSONオブジェクトの構造化ストリームとして出力します。このためどのような形式であっても,ビルド結果やテスト結果を簡単に表示することができます。例えば私たちは,処理結果をカラー出力で見栄えよく表示できるレポータを作りました (https://fpotter_public.s3.amazonaws.com/xctool-uicatalog.gif)。これを使ってテスト結果をJUnit XML形式で出力して,ユーザの多いJenkinsビルドシステムできれいに表示させている人もいます。
実を言うとxctoolは当初,私たちが使っている継続的インテグレーションシステムのために開発されました。ところが多くの社内開発者たちが,それをローカルマシンで使用するようになったのです。テスト実行のコマンドラインワークフローが必要ならば,便利なツールです。