從 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 建構

以下範例是從 Maven 遷移至 Bazel 的 Guava 專案。使用的 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:使用 globbing 列出專案中的所有 .java 檔案。
      • resources:使用 globbing 列出專案中的所有資源。
      • 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",
    ]),
    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 檔案的訣竅:

  • 首先,為每個 Java 套件新增 BUILD 檔案。從依附元件最少的 Java 套件著手,逐步處理包含最多依附元件的套件。
  • 加入 BUILD 檔案並指定目標時,請將這些新目標新增至依附目標的 deps 區段。請注意,glob() 函式不會跨套件邊界,因此隨著套件數量增加,glob() 比對相符的檔案就會縮減。
  • 每次將 BUILD 檔案新增至 main 目錄時,請務必新增 BUILD 檔案至對應的 test 目錄。
  • 請小心限制套件之間的瀏覽權限。
  • 如要簡化 BUILD 檔案設定中的疑難排解錯誤,請確保在新增每個建構檔案時,專案仍繼續使用 Bazel 進行建構。執行 bazel build //...,確保所有目標仍然建構。

4. 使用 Bazel 進行建構

您已在新增 BUILD 檔案時透過 Bazel 建構檔案,藉此驗證建構作業的設定。

取得想要的精細程度 BUILD 檔案後,即可使用 Bazel 產生所有建構作業。