このページでは、前提条件とインストール手順など、Maven から Bazel に移行する方法について説明します。Maven と Bazel の違いについて説明し、Guava プロジェクトを使用した移行例を示します。
ビルドツールから Bazel に移行する場合は、開発チーム、CI システム、その他の関連システムを完全に移行するまで、両方のビルドツールを並行して実行することをおすすめします。Maven と Bazel は同じリポジトリで実行できます。
始める前に
- Bazel がまだインストールされていない場合は、インストールします。
- Bazel を初めて使用する場合は、移行を開始する前に、Bazel の概要: Java のビルドのチュートリアルをご覧ください。このチュートリアルでは、Bazel のコンセプト、構造、ラベル構文について説明します。
Maven と Bazel の違い
- Maven はトップレベルの
pom.xml
ファイルを使用します。Bazel は、複数のビルドファイルと、BUILD
ファイルごとに複数のターゲットをサポートしているため、Maven よりも増分のビルドが可能です。 - Maven は、デプロイ プロセスのステップを管理します。Bazel はデプロイを自動化しません。
- Bazel を使用すると、言語間の依存関係を表現できます。
- プロジェクトに新しいセクションを追加するときに、Bazel での新しい
BUILD
ファイルの追加が必要になることがあります。新しい Java パッケージごとにBUILD
ファイルを追加することをおすすめします。
Maven から Bazel に移行する
以下の手順では、プロジェクトを Bazel に移行する方法について説明します。
以下の例では、Guava プロジェクトを Maven から Bazel に移行しています。使用されている Guava プロジェクトはリリース v31.1
です。Guava を使用した例では、移行の各ステップについては説明しませんが、移行用に手動で生成または追加されたファイルとコンテンツを示します。
$ git clone https://github.com/google/guava.git && cd guava
$ git checkout v31.1
1. WORKSPACE ファイルを作成する
プロジェクトのルートに WORKSPACE
という名前のファイルを作成します。プロジェクトに外部依存関係がない場合は、ワークスペース ファイルを空にできます。
プロジェクトがプロジェクトのディレクトリにないファイルやパッケージに依存している場合は、ワークスペース ファイルにこれらの外部依存関係を指定します。ワークスペース ファイルの外部依存関係のリストを自動化するには、rules_jvm_external
を使用します。このルールセットの使用方法については、README をご覧ください。
Guava プロジェクトの例: 外部依存関係
rules_jvm_external
ルールセットを使用すると、Guava プロジェクトの外部依存関係を一覧表示できます。
次のスニペットを WORKSPACE
ファイルに追加します。
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_JVM_EXTERNAL_TAG = "4.3"
RULES_JVM_EXTERNAL_SHA = "6274687f6fc5783b589f56a2f1ed60de3ce1f99bc4e8f9edef3de43bdf7c6e74"
http_archive(
name = "rules_jvm_external",
sha256 = RULES_JVM_EXTERNAL_SHA,
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"com.google.code.findbugs:jsr305:3.0.2",
"com.google.errorprone:error_prone_annotations:2.11.0",
"com.google.j2objc:j2objc-annotations:1.3",
"org.codehaus.mojo:animal-sniffer-annotations:1.20",
"org.checkerframework:checker-qual:3.12.0",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)
2. BUILD ファイルを 1 つ作成する
ワークスペースを定義し、外部依存関係(該当する場合)をリストアップしたら、BUILD
ファイルを作成して、プロジェクトのビルド方法を記述する必要があります。1 つの pom.xml
ファイルを使用する Maven とは異なり、Bazel では多くの BUILD
ファイルを使用してプロジェクトをビルドできます。これらのファイルにより、複数のビルド ターゲットが指定され、Bazel が増分ビルドを生成できるようになります。
BUILD
ファイルをステージ単位で追加します。まず、プロジェクトのルートに BUILD
ファイルを 1 つ追加し、そのファイルを使用して Bazel で初期ビルドを行います。次に、ターゲットを絞り込んだ BUILD
ファイルを追加して、ビルドを絞り込みます。
WORKSPACE
ファイルと同じディレクトリにテキスト ファイルを作成し、BUILD
という名前を付けます。この
BUILD
ファイルで、適切なルールを使用して、プロジェクトをビルドするためのターゲットを 1 つ作成します。次のヒントを参考にしてください。適切なルールを使用します。
単一の Maven モジュールでプロジェクトをビルドするには、次のように
java_library
ルールを使用します。java_library( name = "everything", srcs = glob(["src/main/java/**/*.java"]), resources = glob(["src/main/resources/**"]), deps = ["//:all-external-targets"], )
複数の Maven モジュールを含むプロジェクトをビルドするには、次のように
java_library
ルールを使用します。java_library( name = "everything", srcs = glob([ "Module1/src/main/java/**/*.java", "Module2/src/main/java/**/*.java", ... ]), resources = glob([ "Module1/src/main/resources/**", "Module2/src/main/resources/**", ... ]), deps = ["//:all-external-targets"], )
バイナリをビルドするには、
java_binary
ルールを使用します。java_binary( name = "everything", srcs = glob(["src/main/java/**/*.java"]), resources = glob(["src/main/resources/**"]), deps = ["//:all-external-targets"], main_class = "com.example.Main" )
属性を指定します。
name
: ターゲットにわかりやすい名前を付けます。上記の例では、ターゲットは「Everything」と呼ばれています。srcs
: グロビングを使用して、プロジェクト内のすべての .java ファイルを一覧表示します。resources
: グロビングを使用して、プロジェクト内のすべてのリソースを一覧表示します。deps
: プロジェクトに必要な外部依存関係を特定する必要があります。たとえば、generate_workspace
ツールを使用して外部依存関係のリストを生成した場合、java_library
の依存関係は、generated_java_libraries
マクロにリストされるライブラリです。
Guava プロジェクトの移行に関するトップレベルの BUILD ファイルの以下の例をご覧ください。
これで、プロジェクトのルートに
BUILD
ファイルが作成されました。プロジェクトをビルドして、動作することを確認します。コマンドラインで、ワークスペース ディレクトリからbazel build //:everything
を使用し、Bazel を使用してプロジェクトをビルドします。これで、プロジェクトが Bazel で正常にビルドされました。プロジェクトの増分ビルドを許可するには、
BUILD
ファイルをさらに追加する必要があります。
Guava プロジェクトの例: 1 つの BUILD ファイルから始める
Guava プロジェクトを Bazel に移行する場合、最初に 1 つの BUILD
ファイルを使用してプロジェクト全体をビルドします。ワークスペース ディレクトリにあるこの最初の BUILD
ファイルの内容は次のとおりです。
java_library(
name = "everything",
srcs = glob([
"guava/src/**/*.java",
"futures/failureaccess/src/**/*.java",
]),
deps = [
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_j2objc_j2objc_annotations",
"@maven//:org_checkerframework_checker_qual",
"@maven//:org_codehaus_mojo_animal_sniffer_annotations",
],
)
3. 追加の BUILD ファイルを作成する(省略可)
最初のビルドが完了した後に見たように、Bazel は 1 つの BUILD file
だけを使用します。ターゲットをきめ細かく指定する BUILD
ファイルをさらに追加して、ビルドを小さなチャンクに分割することを検討してください。
複数のターゲットを持つ複数の BUILD
ファイルを使用すると、ビルドの粒度が高まり、以下が可能になります。
- プロジェクトの増分ビルドの増加
- ビルドの並列実行の増加、
- 将来のユーザー向けにビルドの保守性が向上する。
- パッケージ間のターゲットの可視性の制御により、実装の詳細を含むライブラリが公開 API に漏洩するなどの問題を防止できます。
BUILD
ファイルをさらに追加するためのヒント:
- まず、各 Java パッケージに
BUILD
ファイルを追加します。依存関係が最も少ない Java パッケージから開始し、依存関係が最も多いパッケージまで処理します。 BUILD
ファイルを追加してターゲットを指定するときに、これらの新しいターゲットを、それらに依存するターゲットのdeps
セクションに追加します。glob()
関数はパッケージの境界を越えないため、パッケージの数が増えると、glob()
によって一致するファイルが縮小されます。BUILD
ファイルをmain
ディレクトリに追加する場合は、必ず、対応するtest
ディレクトリにBUILD
ファイルを追加してください。- パッケージ間の公開設定を適切に制限してください。
BUILD
ファイルの設定で発生するエラーのトラブルシューティングを簡素化するために、各ビルドファイルを追加する際に、プロジェクトのビルドが Bazel で続行されるようにしてください。bazel build //...
を実行して、すべてのターゲットがビルドされていることを確認します。
4. Bazel を使用したビルド
これまで Bazel を使用して、BUILD
ファイルを追加してビルドの設定を検証してきました。
目的の粒度で BUILD
ファイルがある場合は、Bazel を使用してすべてのビルドを生成できます。