Java 和 Bazel

回報問題 查看來源 夜間 7.3 7.2 7.1 7.0 6.5

本頁面含有可協助您搭配 Java 專案使用 Bazel 的資源。這項服務 教學課程、建構規則,以及有關建構的其他資訊 使用 Bazel 建立 Java 專案

使用 Bazel

下列資源可協助您在 Java 專案中使用 Bazel:

遷移至 Bazel

如果您目前使用 Maven 建構 Java 專案,請按照遷移指南中的步驟,開始使用 Bazel 建構 Maven 專案:

Java 版本

有兩個相關的 Java 版本都使用設定標記:

  • 存放區中來源檔案的版本
  • 想要用來執行程式碼及測試 該資料來源

設定存放區中的原始碼版本

如未額外設定,Bazel 會假設 存放區是以單一 Java 版本編寫。如何指定 將 build --java_language_version={ver} 新增至存放區的來源 .bazelrc 檔案,其中 {ver}11。Bazel 存放區擁有者應設定這個標記,讓 Bazel 及其使用者能夠參照原始碼的 Java 版本號碼。詳情請參閱「Java 語言版本標記」。

設定用於執行及測試程式碼的 JVM

Bazel 會使用一個 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,用於建構及執行工具,這些工具會用於建構程序,但不會用於建構結果。使用 --tool_java_language_version--tool_java_runtime_version 控管 JDK 和 JVM。預設值為 11remotejdk_11。 。

使用本機安裝的 JDK 進行編譯

根據預設,Bazel 會使用遠端 JDK 進行編譯,因為它會覆寫 JDK 的內部元件。使用本機安裝 JDK 的編譯工具鏈已設定,但未使用。

如要使用在本機安裝的 JDK 進行編譯,則使用編譯工具鍊 如果是本機 JDK,請使用其他標記 --extra_toolchains=@local_jdk//:all 但請注意,這個做法可能不適用於任意供應商的 JDK。

詳情請參閱 設定 Java 工具鍊

最佳做法

除了一般 Bazel 最佳做法以外,你還可以參閱下文 最佳做法。

目錄結構

偏好 Maven 的標準目錄版面配置 (src/main/java 下的來源、測試 低於 src/test/java)。

BUILD 檔案

建立 BUILD 檔案時,請遵守下列規範:

  • 每個包含 Java 來源的資料夾都使用一個 BUILD 檔案,這樣可改善建構效能。

  • 每個 BUILD 檔案都應包含一個 java_library 規則,如下所示:

    java_library(
        name = "directory-name",
        srcs = glob(["*.java"]),
        deps = [...],
    )
    
  • 程式庫的名稱應為包含 BUILD 檔案。如此一來,程式庫的標籤就會變短 "//package" 取代 "//package:package"

  • 來源應為目錄中所有 Java 檔案的非遞迴 glob

  • 測試應位於 src/test 下的相符目錄,並以此為基礎 資源庫。

為進階 Java 版本建立新規則

注意:建立新規則適用於進階建構和測試情境。您自己 不必使用這個電子郵件地址。

以下模組、設定片段和供應器將能助您一臂之力 在建構 Java 時擴充 Bazel 的功能 專案:

設定 Java 工具鏈

Bazel 使用兩種類型的 Java 工具鍊: - 用來執行及測試 Java 二進位檔的執行, --java_runtime_version 標記 - 編譯,用來編譯 Java 來源,以 --java_language_version 標記

設定其他執行工具鍊

執行工具鍊是 JVM,可以是本機或存放區中的 有關其版本、作業系統和 CPU 的其他資訊 這個架構的簡短總覽

Java 執行工具鍊可使用 local_java_repository 或 模組擴充功能中的 remote_java_repository 存放區規則。新增規則後,即可使用標記提供 JVM。當同一營運業務有多個定義時 並採用第一個架構

本機 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 使用的多項工具 且提供其他功能,例如: 容易取得、嚴謹的 Java 依附元件、標頭編譯、Android 脫糖、 涵蓋範圍檢測和 IDE 的基因類別處理。

JavaBuilder 是 Bazel 封裝工具,可執行編譯作業 上述功能實際編譯作業會由 JDK 使用內部編譯器執行。工具鏈的 java_runtime 屬性會指定用於編譯的 JDK。

Bazel 會覆寫部分 JDK 內部。若是 JDK 版本 >9、 已使用 JDK 標記來修補 java.compilerjdk.compiler 模組 --patch_module。如果是 JDK 8 版,Java 編譯器是以 -Xbootclasspath 標記。

VanillaJavaBuilder 是 JavaBuilder 的第二個實作項目,不會修改 JDK 的內部編譯器,也沒有任何額外功能。任何內建都沒有使用 VanillaJavaBuilder 工具鍊。

除了 JavaBuilder 之外,Bazel 會在編譯時使用幾項其他工具。

ijar 工具會處理 jar 檔案,移除呼叫以外的所有內容 簽章。產生的 jar 則稱為標頭 jar。這類模型能用來 並只在 函式的主體變更

singlejar 工具會將多個 jar 檔案合併為單一檔案。

genclass 工具會對 Java 編譯的輸出內容進行後續處理,然後產生 jar 只包含以下來源所產生來源的類別檔案: 註解處理工具

JacocoRunner 工具會在檢測過的檔案上執行 Jacoco,並以 LCOV 格式輸出結果。

TestRunner 工具會在受控管的環境中執行 JUnit 4 測試。

如要重新設定編譯作業,請將 default_java_toolchain 巨集新增至 建立 BUILD 檔案,然後將 register_toolchains 規則新增至 MODULE.bazel 檔案或使用 --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 編譯器標記

您可以使用旗標 或 default_java_toolchain 屬性。

相關標記為 --jvmopt--host_jvmopt--javacopt--host_javacopt

相關的 default_java_toolchain 屬性為 javacoptsjvm_optsjavabuilder_jvm_optsturbine_jvm_opts

套件專用的 Java 編譯器旗標設定

您可以為特定來源設定不同的 Java 編譯器標記 使用 default_java_toolchainpackage_configuration 屬性的檔案。 請參考以下範例。

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
    ],
)

單一存放區中有多種版本的 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