Java 和 Bazel

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

本頁面含有可協助您搭配 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 是用來建構和執行工具 使用,但不包含在建構結果中。該 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 最佳做法以外,你還可以參閱下文 最佳做法。

目錄結構

偏好 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"

  • 來源必須是非遞迴的 glob, 目錄中所有 Java 檔案

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

為進階 Java 版本建立新規則

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

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

設定 Java 工具鍊

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

設定其他執行工具鍊

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

Java 執行工具鍊可以使用 local_java_repositoryWORKSPACE 檔案中的 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 所編寫的用於編譯的 JDK 是由 java_runtime 指定 屬性。

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 規則新增至 WORKSPACE 檔案或使用 --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:無其他功能,支援 供應商。
  • 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