從 Maven 遷移至 Bazel

回報問題 查看來源

本頁面說明如何從 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:

  1. 建立 WORKSPACE 檔案
  2. 建立一個 BUILD 檔案
  3. 建立更多 BUILD 檔案
  4. 使用 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 檔案

現在您已定義工作區,並列出外部依附元件 (如適用),您需要建立 BUILD 檔案來說明專案的建構方式。有別於 Maven 有一個 pom.xml 檔案,Bazel 可以使用許多BUILD檔案來建構專案。這些檔案指定多個建構目標,這可讓 Bazel 產生漸進式建構作業。

分階段新增 BUILD 檔案。請先在專案的根目錄新增一個 BUILD 檔案,然後使用 Bazel 執行初始建構作業。接著,您可以透過更精細的目標新增更多 BUILD 檔案,藉此修正建構內容。

  1. 在與 WORKSPACE 檔案相同的目錄中建立文字檔案,並將其命名為 BUILD

  2. 在這個 BUILD 檔案中,使用適當的規則建立一個目標,藉此建構專案。以下提供幾項訣竅:

    • 使用適當的規則:

      • 如要建構包含單一 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:為目標設定有意義的名稱。在上述範例中,目標稱為「一切」。
      • srcs:使用 Gboard 列出專案中的所有 .java 檔案。
      • resources:使用閃爍功能列出專案中的所有資源。
      • deps:您必須判斷專案需要的外部依附元件。舉例來說,如果您使用 generate_workspace 工具產生外部依附元件清單,java_library 的依附元件就是 generated_java_libraries 巨集中列出的程式庫。
    • 請參閱 Guava 專案遷移作業的這個頂層 BUILD 檔案範例

  3. 現在,專案根目錄已有 BUILD 檔案,請建構專案以確保能正常運作。在指令列的工作區目錄中,使用 bazel build //:everything 以 Bazel 建構專案。

    已成功使用 Bazel 成功建構專案。您必須新增更多 BUILD 檔案,以允許漸進式建構專案。

Guava 專案範例:開頭為一個 BUILD 檔案

將 Guava 專案遷移至 Bazel 時,一開始會使用一個 BUILD 檔案建構完整的專案。以下是這個工作區目錄中的初始 BUILD 檔案內容:

java_library(
    name = "everything",
    srcs = glob([
        "guava/src/**/*.java",
        "futures/failureaccess/src/**/*.java",
    ]),
    javacopts = ["-XepDisableAllChecks"],
    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 只會使用一個 BUILD file。您仍應考慮將更多包含精細目標的 BUILD 檔案,拆分為較小的區塊。

有多個目標的 BUILD 檔案會提高建構精細程度,進而允許:

  • 漸進式專案版本
  • 增加建構作業的平行執行功能
  • 讓日後使用者更容易維護這個版本
  • 控管套件之間的目標瀏覽權限,避免問題,例如含有實作詳細資料外洩到公用 API 的程式庫。

新增更多 BUILD 檔案的訣竅:

  • 首先,您可以將 BUILD 檔案新增至每個 Java 套件。從依附元件最少的 Java 套件開始,並逐步處理具有最多依附元件的套件。
  • 當您新增 BUILD 檔案並指定目標時,請將這些新目標新增至依附於目標的 deps 區段。請注意,glob() 函式不會跨套件邊界,因此,隨著 glob() 比對的檔案數量增加,比對出的檔案會縮減。
  • 每次將 BUILD 檔案新增至 main 目錄時,請務必新增 BUILD 檔案至對應的 test 目錄。
  • 請謹慎限制套件之間的瀏覽權限。
  • 為了簡化 BUILD 檔案設定的疑難排解錯誤,請確保在您新增每個建構檔案時,專案會持續使用 Bazel 進行建構。執行 bazel build //...,確保所有目標仍然處於建構狀態。

4. 使用 Bazel 建構

在新增 BUILD 檔案以驗證建構作業的設定時,您已使用 Bazel 進行建構。

您可以在想要的精細程度有 BUILD 檔案時,使用 Bazel 產生所有建構作業。