会員事業部所属エンジニアの山下(@tomorrowkey)です。
去年はモバイルファースト室でバリバリとAndroidアプリを書いていたのですが、今年に入ってサーバーサイドもやってみたいと思い、最近はRubyを書いている日々です。
Rubyはあまりやったことがなかったのですが、REPLがあってとても助かります。Java 9でREPLが使えるようになるらしいですが、Androidは縁遠い話ですね。
さて、今回は来年ビルドツールとして脚光を浴びそうなBazelをご紹介したいと思います。
Bazelとは何か
Bazel http://bazel.io/
BazelはGoogleが社内で使用していたビルドツールをオープンソース版として開発をしているものです。2015年3月にAlpha版が公開されました。
Alpha版ではクライアントアプリケーションやiOSアプリのビルドなどがサポートされていて、最近Beta版が公開され、Androidアプリのビルドも可能になりました。
Beta版のサポート動作環境はUbuntuとOSXだけですが、将来Windowsもサポートする計画もあります。
実装のロードマップはここで参照することができます。
2016年5月以降のStable版ではAndroid Studioとの統合という計画もあります。現在AndroidアプリではGradleでのビルドが主流ですが、Bazelでのビルドもできるようになるので、いまのうちに味見しておきましょう。
Bazelの特徴
Bazelの特徴は以下のようなものがあります。
- Bazelは複数のプラットフォームをサポートします。
- 現在サポートしている動作環境はUbuntuとOSXです。
- サーバーアプリケーションや、クライアントアプリケーション、iOSやAndroidのアプリなどさまざまなソフトウェアのビルドスクリプトを記述できます。
- Bazel独自の言語(Pythonに似ています)を使用し、ビルドスクリプトの役割である、WORKSPACEファイルやBUILDファイルを記述します。
Gradleとの違い
ここまで聞くとAndroidアプリ開発者なら、Gradleとどう違うんだ?と思いますが、Bazelではこの問に対して以下のように回答しています。
Gradleより構造的に記述することができ、それによりビルドの並列化と同時に再現性も担保することが可能
また、BraintreeではJavaアプリケーションやライブラリのビルドをGradleからBazelに移行したというエントリを書いており、その中でBazelはGradleよりも高速であると記載しています。
https://www.braintreepayments.com/blog/migrating-from-gradle-to-bazel/
Androidアプリのビルドは非常に時間がかかるものなので、これだけでも興味が湧いてくるのではないでしょうか。
Bazelの構成
BazelでビルドするにはWORKSPACEとBUILDというファイルが必要になります。
WORKSPACEファイル
Bazelを使用したビルドはworkspaceという場所で行われます。
workspaceの場所はどこでも大丈夫ですが、必ずWORKSPACEファイルを配置する必要があります。
WORKSPACEファイルが配置された場所がworkspaceのトップディレクトリとなります。
WORKSPACEファイルはライブラリ外部参照の依存関係を記述します。もし、依存関係がない場合は空ファイルになります。
WORKSPACEはPythonに似た独自の言語を使用して記述します。
workspaceには複数のプロジェクトを含むことができます。
BUILDファイル
BUILDファイルにはソースコードの配置やプロジェクトの依存関係、ライブラリの依存などを記述します。
Androidアプリのビルド
概念の説明ではよくわからないと思うので、具体的なAndroidアプリプロジェクトを例にBazelを使ったビルドをやってみましょう。
Bazelのインストール
ここを読みながらインストールします。 Androidが開発できる環境であればスクリプトを実行するだけで終わると思います。
今回はv0.1.0を使用します。
$ bazel version Build label: 0.1.0 Build target: bazel-out/local_darwin-fastbuild/bin/src/main/java/bazel-main_deploy.jar Build time: Tue Sep 8 23:14:50 2015 (1441754090) Build timestamp: 1441754090 Build timestamp as int: 1441754090
プロジェクト構成
サンプルプロジェクトはここにあります。 https://github.com/tomorrowkey/HelloBazel
プロジェクトの構成は以下のようになります。
. ├── BUILD ├── HelloBazel │ ├── app │ │ ├── build.gradle │ │ ├── libs │ │ ├── proguard-rules.pro │ │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── jp │ │ │ └── tomorrowkey │ │ │ └── android │ │ │ └── hellobazel │ │ │ └── MainActivity.java │ │ └── res │ │ ├── drawable │ │ ├── layout │ │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── values │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp │ │ └── dimens.xml │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── local.properties │ └── settings.gradle └── WORKSPACE
このプロジェクトはGradleとBazelを共存させるように作られています。
一般的なAndroidStudioのプロジェクト構成をベースに作っており、親ディレクトリにWORKSPACEファイルとBUILDファイルが存在するのが特徴です。
WORKSPACEの定義
前述の通り、WORKSPACEにはビルドに必要なフレームワークやライブラリの参照を定義します。
今回はAndroid SDKの定義と、Mavenで配布されているcommons-langを使用します。
android_sdk_repository( name="androidsdk", path="/usr/local/opt/android-sdk", api_level = 23, build_tools_version="23.0.1" ) maven_jar(name = "commons-lang", artifact = "org.apache.commons:commons-lang3:3.4")
pathにAndroid SDKの配置パスを指定します。api_level
やbuild_tools_version
はビルドするアプリによって適宜変更してください。
Mavenで公開されているライブラリの定義はmaven_jar
ルールを使用します。
BUILDファイルの作成
BUILDファイルにはソースコードやリソースがどこに配置されているか、どのライブラリを参照するのかを定義します。
android_binary ( name = "android", srcs = glob(["HelloBazel/app/src/main/java/**/*.java"]), custom_package = "jp.tomorrowkey.android.hellobazel", manifest = "HelloBazel/app/src/main/AndroidManifest.xml", resource_files = glob(["HelloBazel/app/src/main/res/**"]), deps = ["//external:android/appcompat_v4", "//external:android/appcompat_v7", "commons-lang"], ) java_library( name="commons-lang", exports = [ "@commons-lang//jar", ], )
android_binary
はAndroidアプリをビルドするためのキーワードで、Bazelではこれをルールと呼びます。
Android向けのルールは他にAndroidライブラリを定義するandroid_library
があります。
各属性に名前やファイル名を指定します。globはワイルドカードを使ってファイルの配列を取得する関数です。
nameはandroidとしていますが、これはビルドやアプリインストールする際に使われる名前なので、何でも構いません。
他の属性は名前からだいたいの想像がつくのではないでしょうか。
どのようなルールや属性などが使えるかはBuild Encyclopediaに定義されています。
java_library
にcommons-langを定義し、android_binary
のdepsにnameを指定します。
BUILDファイルの場所について
BUILDファイルはworkspace直下ではなく、プロジェクトに配置するのが一般的だと思われるのですが、モジュール内に配置するとGradleが生成するbuildディレクトリと名前が衝突してしまうためworkspace直下にBUILDファイルを配置しています。
AndroidStudioサポートする際はこの問題をどうするのか気になりますね。
ビルド
WORKSPACEファイルがあるディレクトリで以下のコマンドを実行することでビルドできます。
bazel build :android
android
はさきほどBUILDファイルに指定した名前です。:
の前に何も書かれていませんが、BUILDファイルがカレントディレクトリ以外にある場合に、BUILDファイルが配置してあるディレクトリまでのパスを指定します。
例えば以下のようなディレクトリ構成だった場合
. ├── app │ ├─── BUILD │ ├─── hoge │ └─── fuga └── WORKSPACE
このようなコマンドでビルドできるようになります。
bazel build app:android
インストール
Bazelにはアプリをインストールするためのコマンドも用意されており、以下のコマンドでインストールすることができます。
bazel mobile-install :android
ただし、環境によってはインストールしたアプリがクラッシュすることがあり、adbコマンドでインストールすることによって問題を回避することができる場合があります。
adb install ./bazel-bin/android_signed.apk
今回解説しなかったこと
例えばQueryを使えば、ビルドコマンド実行時に参照するライブラリを差し替えることができたり、Macroを使えばBUILDファイルで使える関数を増やすことなどができます。
今回説明したもの以外にもいくつかのルールや関数が公開されており、Build Encyclopediaに使用できるルールや関数が一覧できます。一部はv0.1.0には含まれておらず、次バージョンのv0.1.1に含まれるものもあるので注意してください。
おわりに
Android開発ではAndroid Studio移行と同時にGradleが使われてきましたが、Gradleは遅いという意見を多く聞きます。Bazelを使うことによって少しでもビルド時間が短くなればよいですね。Stable版がリリースされるまで半年ほどありますが、すこしずつ触って慣れておきましょう。
クックパッドでは最新のオープンソースプロジェクトやツールに敏感なモバイルアプリエンジニアを募集しています。