Java と Bazel

問題を報告 ソースを表示 ナイトリー · 8.0 · 7.4 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

このページには、Java プロジェクトで Bazel を使用する際に役立つリソースが記載されています。チュートリアル、ビルドルール、Bazel を使用した Java プロジェクトのビルドに固有の情報へのリンクが含まれています。

Bazel の使用

Java プロジェクトで Bazel を使用する際に役立つリソースは次のとおりです。

Bazel への移行

現在 Maven で Java プロジェクトをビルドしている場合は、移行ガイドの手順に沿って、Bazel で Maven プロジェクトのビルドを開始します。

Java のバージョン

構成フラグで設定される、関連する Java のバージョンは 2 つあります。

  • リポジトリ内のソースファイルのバージョン
  • コードの実行とテストに使用される Java ランタイムのバージョン

リポジトリ内のソースコードのバージョンを構成する

追加の構成を行わない場合、Bazel はリポジトリ内のすべての Java ソースファイルが単一の Java バージョンで記述されていることを前提とします。リポジトリ内のソースのバージョンを指定するには、.bazelrc ファイルに build --java_language_version={ver} を追加します。ここで、{ver}11 などです。Bazel リポジトリのオーナーは、Bazel とそのユーザーがソースコードの Java バージョン番号を参照できるように、このフラグを設定する必要があります。詳細については、Java 言語バージョン フラグをご覧ください。

コードの実行とテストに使用する JVM の構成

Bazel は、コンパイルに 1 つの JDK を使用し、コードの実行とテストに別の JVM を使用します。

デフォルトでは、Bazel はダウンロードした JDK を使用してコードをコンパイルし、ローカルマシンにインストールされている JVM を使用してコードを実行してテストします。Bazel は、JAVA_HOME またはパスを使用して JVM を検索します。

生成されたバイナリは、システム ライブラリにローカルにインストールされた JVM と互換性があります。つまり、生成されたバイナリはマシンにインストールされているものに依存します。

実行とテストに使用する JVM を構成するには、--java_runtime_version フラグを使用します。デフォルト値は local_jdk です。

密閉型テストとコンパイル

完全なコンパイルを作成するには、コマンドライン フラグ --java_runtime_version=remotejdk_11 を使用します。コードは、リモート リポジトリからダウンロードされた JVM 用にコンパイルされ、実行され、テストされます。詳細については、Java ランタイム バージョン フラグをご覧ください。

Java でのビルドツールのコンパイルと実行の構成

ツールのビルドと実行に使用される JDK と JVM の 2 つ目のペアがあります。これはビルドプロセスで使用されますが、ビルド結果には含まれません。この JDK と JVM は、--tool_java_language_version--tool_java_runtime_version を使用して制御されます。デフォルト値はそれぞれ 11remotejdk_11 です。

ローカルにインストールされた JDK を使用したコンパイル

Bazel はデフォルトでリモート JDK を使用してコンパイルします。これは、JDK の内部をオーバーライドするためです。ローカルにインストールされた JDK を使用するコンパイル ツールチェーンは構成されていますが、使用されません。

ローカルにインストールされた JDK を使用してコンパイルするには、ローカル JDK のコンパイル ツールチェーンを使用するように、追加のフラグ --extra_toolchains=@local_jdk//:all を使用します。ただし、任意のベンダーの JDK では動作しない場合があります。

詳細については、Java ツールチェーンの構成をご覧ください。

ベスト プラクティス

Bazel の一般的なベスト プラクティスに加えて、Java プロジェクトに固有のベスト プラクティスは次のとおりです。

ディレクトリ構造

Maven の標準ディレクトリ レイアウト(src/main/java の下にソース、src/test/java の下にテスト)を使用する。

BUILD ファイル

BUILD ファイルを作成する際のガイドラインは次のとおりです。

  • Java ソースを含むディレクトリごとに 1 つの BUILD ファイルを使用すると、ビルドのパフォーマンスが向上します。

  • すべての BUILD ファイルには、次のような 1 つの java_library ルールを含める必要があります。

    java_library(
        name = "directory-name",
        srcs = glob(["*.java"]),
        deps = [...],
    )
    
  • ライブラリの名前は、BUILD ファイルを含むディレクトリの名前にする必要があります。これにより、ライブラリのラベルが短くなります。つまり、"//package:package" ではなく "//package" を使用します。

  • ソースは、ディレクトリ内のすべての Java ファイルの非再帰 glob である必要があります。

  • テストは src/test の下の一致するディレクトリに配置し、このライブラリに依存する必要があります。

高度な Java ビルド用の新しいルールを作成する

: 新しいルールの作成は、高度なビルドとテストのシナリオを対象としています。Bazel の使用を開始する際には必要ありません。

次のモジュール、構成フラグメント、プロバイダは、Java プロジェクトのビルド時に Bazel の機能を拡張するのに役立ちます。

Java ツールチェーンの構成

Bazel では、2 種類の Java ツールチェーンを使用します。 - 実行: Java バイナリの実行とテストに使用され、--java_runtime_version フラグで制御されます。 - コンパイル: Java ソースのコンパイルに使用され、--java_language_version フラグで制御されます。

追加の実行ツールチェーンの構成

実行ツールチェーンは、ローカルまたはリポジトリにある JVM で、バージョン、オペレーティング システム、CPU アーキテクチャに関する追加情報があります。

Java 実行ツールチェーンは、WORKSPACE ファイルの local_java_repository ルールまたは remote_java_repository ルールを使用して追加できます。ルールを追加すると、フラグを使用して JVM を使用できるようになります。同じオペレーティング システムと CPU アーキテクチャの定義が複数指定されている場合は、最初の定義が使用されます。

ローカル JVM の構成例:

load("@bazel_tools//tools/jdk:local_java_repository.bzl", "local_java_repository")

local_java_repository(
  name = "additionaljdk",          # Can be used with --java_runtime_version=additionaljdk, --java_runtime_version=11 or --java_runtime_version=additionaljdk_11
  version = 11,                    # Optional, if not set it is autodetected
  java_home = "/usr/lib/jdk-15/",  # Path to directory containing bin/java
)

リモート JVM の構成例:

load("@bazel_tools//tools/jdk:remote_java_repository.bzl", "remote_java_repository")

remote_java_repository(
  name = "openjdk_canary_linux_arm",
  prefix = "openjdk_canary", # Can be used with --java_runtime_version=openjdk_canary_11
  version = "11",            # or --java_runtime_version=11
  target_compatible_with = [ # Specifies constraints this JVM is compatible with
    "@platforms//cpu:arm",
    "@platforms//os:linux",
  ],
  urls = ...,               # Other parameters are from http_repository rule.
  sha256 = ...,
  strip_prefix = ...
)

追加のコンパイル ツールチェーンの構成

コンパイル ツールチェーンは、JDK と、Bazel がコンパイル中に使用する複数のツールで構成されています。これらのツールは、Error Prone、厳格な Java 依存関係、ヘッダーのコンパイル、Android デシュガーリング、カバレッジ計測、IDE 用の genclass 処理などの追加機能を提供します。

JavaBuilder は、コンパイルを実行し、前述の機能を提供する Bazel バンドルのツールです。実際のコンパイルは、JDK の内部コンパイラを使用して実行されます。コンパイルに使用される JDK は、ツールチェーンの java_runtime 属性で指定します。

Bazel は、一部の JDK 内部をオーバーライドします。JDK バージョンが 9 より大きい場合、java.compiler モジュールと jdk.compiler モジュールは JDK のフラグ --patch_module を使用してパッチが適用されます。JDK バージョン 8 の場合、Java コンパイラは -Xbootclasspath フラグを使用してパッチが適用されます。

VanillaJavaBuilder は JavaBuilder の 2 番目の実装で、JDK の内部コンパイラを変更せず、追加機能もありません。VanillaJavaBuilder は、組み込みの toolchain では使用されません。

Bazel は、コンパイル中に JavaBuilder に加えて、他のいくつかのツールも使用します。

ijar ツールは jar ファイルを処理して、呼び出しシグネチャ以外のすべてを削除します。生成された JAR はヘッダー JAR と呼ばれます。これらは、関数の本体が変更された場合にのみダウンストリームの依存関係を再コンパイルすることで、コンパイルの増分性を向上させるために使用されます。

singlejar ツールは、複数の jar ファイルを 1 つにまとめます。

genclass ツールは、Java コンパイルの出力を後処理し、アノテーション プロセッサによって生成されたソースのクラスファイルのみを含む jar を生成します。

JacocoRunner ツールは、計測対象のファイルに対して Jacoco を実行し、結果を LCOV 形式で出力します。

TestRunner ツールは、制御された環境で JUnit 4 テストを実行します。

コンパイルを再構成するには、BUILD ファイルに default_java_toolchain マクロを追加し、WORKSPACE ファイルに register_toolchains ルールを追加するか、--extra_toolchains フラグを使用して登録します。

ツールチェーンは、source_version 属性が --java_language_version フラグで指定された値と一致する場合にのみ使用されます。

ツールチェーンの構成例:

load(
  "@bazel_tools//tools/jdk:default_java_toolchain.bzl",
  "default_java_toolchain", "DEFAULT_TOOLCHAIN_CONFIGURATION", "BASE_JDK9_JVM_OPTS", "DEFAULT_JAVACOPTS"
)

default_java_toolchain(
  name = "repository_default_toolchain",
  configuration = DEFAULT_TOOLCHAIN_CONFIGURATION,        # One of predefined configurations
                                                          # Other parameters are from java_toolchain rule:
  java_runtime = "@bazel_tools//tools/jdk:remote_jdk11", # JDK to use for compilation and toolchain's tools execution
  jvm_opts = BASE_JDK9_JVM_OPTS + ["--enable_preview"],   # Additional JDK options
  javacopts = DEFAULT_JAVACOPTS + ["--enable_preview"],   # Additional javac options
  source_version = "9",
)

これは、--extra_toolchains=//:repository_default_toolchain_definition を使用するか、ワークスペースに register_toolchains("//:repository_default_toolchain_definition") を追加することで使用できます。

事前定義された構成:

  • DEFAULT_TOOLCHAIN_CONFIGURATION: すべての機能、JDK バージョン 9 以降をサポート
  • VANILLA_TOOLCHAIN_CONFIGURATION: 追加機能なし。任意のベンダーの JDK をサポートします。
  • PREBUILT_TOOLCHAIN_CONFIGURATION: デフォルトと同じですが、事前ビルドされたツール(ijarsinglejar)のみを使用します。
  • NONPREBUILT_TOOLCHAIN_CONFIGURATION: デフォルトと同じですが、すべてのツールがソースからビルドされます(これは、libc が異なるオペレーティング システムで役立つ場合があります)。

JVM と Java コンパイラ フラグの構成

JVM フラグと javac フラグは、フラグまたは default_java_toolchain 属性で構成できます。

関連するフラグは --jvmopt--host_jvmopt--javacopt--host_javacopt です。

関連する default_java_toolchain 属性は、javacoptsjvm_optsjavabuilder_jvm_optsturbine_jvm_opts です。

パッケージ固有の Java コンパイラ フラグの構成

default_java_toolchainpackage_configuration 属性を使用して、特定のソースファイルに異なる Java コンパイラ フラグを構成できます。以下の例を参照してください。

load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")

# This is a convenience macro that inherits values from Bazel's default java_toolchain
default_java_toolchain(
    name = "toolchain",
    package_configuration = [
        ":error_prone",
    ],
    visibility = ["//visibility:public"],
)

# This associates a set of javac flags with a set of packages
java_package_configuration(
    name = "error_prone",
    javacopts = [
        "-Xep:MissingOverride:ERROR",
    ],
    packages = ["error_prone_packages"],
)

# This is a regular package_group, which is used to specify a set of packages to apply flags to
package_group(
    name = "error_prone_packages",
    packages = [
        "//foo/...",
        "-//foo/bar/...", # this is an exclusion
    ],
)

1 つのリポジトリに複数のバージョンの Java ソースコードがある

Bazel は、ビルド内で単一バージョンの Java ソースのコンパイルのみをサポートしています。つまり、Java テストまたはアプリケーションをビルドするときに、すべての依存関係が同じ Java バージョンに対してビルドされます。

ただし、別のフラグを使用して個別のビルドを実行できます。

さまざまなフラグの使用を容易にするため、特定のバージョンのフラグセットを .bazelrc 構成でグループ化できます。

build:java8 --java_language_version=8
build:java8 --java_runtime_version=local_jdk_8
build:java11 --java_language_version=11
build:java11 --java_runtime_version=remotejdk_11

これらの構成は、--config フラグ(bazel test --config=java11 //:java11_test など)で使用できます。