Bzlmod 遷移指南

回報問題 查看原始碼 夜間 7.2 7.1 7.0 6.5 6.4

由於 WORKSPACE,Bzlmod 會 在日後的 Bazel 版本中,取代舊版 WORKSPACE 系統這份指南 將專案遷移至 Bzlmod 並捨棄 WORKSPACE 以擷取外部 依附元件

WORKSPACE 與 Bzlmod

Bazel 的 WORKSPACE 與 Bzlmod 提供了語法不同的類似功能。這個 本節說明如何從特定 WORKSPACE 功能遷移至 Bzlmod。

定義 Bazel 工作區的根

WORKSPACE 檔案會標示 Bazel 專案的來源根目錄 (此責任) 在 Bazel 6.3 以上版本中,已由 MODULE.bazel 取代。使用 Bazel 版本 6.3 之前的 WORKSPACEWORKSPACE.bazel 檔案,在 至於工作區根層級,您可以使用下列註解:

  • 工作區

    # This file marks the root of the Bazel workspace.
    # See MODULE.bazel for external dependencies setup.
    

指定工作區的存放區名稱

  • 工作區

    使用 workspace 函式 為工作區指定存放區名稱。這使 以「@<workspace name>//foo:bar」的形式參照工作區的「//foo:bar」。如未指定,您的預設存放區名稱 工作區為「__main__」。

    ## WORKSPACE
    workspace(name = "com_foo_bar")
    
  • Bzlmod

    建議您在含有 不含 @<repo name>//foo:bar 語法。不過,如果您需要使用舊版語法 ,您可以使用由 module 函式做為存放區 名稱。如果模組名稱與所需存放區名稱不同, 可以使用 repo_name 屬性的 module 函式用來覆寫 存放區名稱

    ## MODULE.bazel
    module(
        name = "bar",
        repo_name = "com_foo_bar",
    )
    

以 Bazel 模組擷取外部依附元件

如果您的依附元件是 Bazel 專案,應該就能以 Bazel 模組,前提是該模組也採用 Bzlmod。

  • 工作區

    使用 WORKSPACE 時,通常會使用 http_archivegit_repository 存放區規則 下載 Bazel 專案的來源

    ## WORKSPACE
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    
    http_archive(
        name = "bazel_skylib",
        urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz"],
        sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa",
    )
    load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
    bazel_skylib_workspace()
    
    http_archive(
        name = "rules_java",
        urls = ["https://github.com/bazelbuild/rules_java/releases/download/6.1.1/rules_java-6.1.1.tar.gz"],
        sha256 = "76402a50ae6859d50bd7aed8c1b8ef09dae5c1035bb3ca7d276f7f3ce659818a",
    )
    load("@rules_java//java:repositories.bzl", "rules_java_dependencies", "rules_java_toolchains")
    rules_java_dependencies()
    rules_java_toolchains()
    

    如您所見,使用者經常需要 依附元件巨集中的依附元件。假設 bazel_skylibrules_java 依附於 platoform,也就是 platform 的確切版本 依附元件是由巨集的順序決定。

  • Bzlmod

    使用 Bzlmod (前提是您的依附元件可在 Bazel Central 中提供) 登錄檔或自訂 Bazel 註冊資料庫bazel_dep 指令。

    ## MODULE.bazel
    bazel_dep(name = "bazel_skylib", version = "1.4.2")
    bazel_dep(name = "rules_java", version = "6.1.1")
    

    Bzlmod 會使用 MVS 演算法。因此,最大值 系統會自動選取 platform 的必要版本。

將依附元件覆寫為 Bazel 模組

由於是根模組,您可以覆寫不同位置的 Bazel 模組依附元件 管理基礎架構

詳情請參閱「覆寫」一節 可能不準確或不適當

您可以在 例子 Cloud Storage 也提供目錄同步處理功能

使用模組擴充功能擷取外部依附元件

如果依附元件並非 Bazel 專案,或尚未在任何 Bazel 中使用 註冊資料庫,就能使用模組擴充功能加以引入。

  • 工作區

    使用 http_file下載檔案 存放區規則

    ## WORKSPACE
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
    
    http_file(
        name = "data_file",
        url = "http://example.com/file",
        sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    )
    
  • Bzlmod

    使用 Bzlmod 時,您必須將定義移到 .bzl 檔案, 可讓您在 遷移週期。

    ## repositories.bzl
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
    def my_data_dependency():
        http_file(
            name = "data_file",
            url = "http://example.com/file",
            sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        )
    

    實作模組擴充功能,載入依附元件巨集。您可以定義 這個巨集位於巨集的同一個 .bzl 檔案中,但是為了與 建議您建立另一個 .bzl 檔案。

    ## extensions.bzl
    load("//:repositories.bzl", "my_data_dependency")
    def _non_module_dependencies_impl(_ctx):
        my_data_dependency()
    
    non_module_dependencies = module_extension(
        implementation = _non_module_dependencies_impl,
    )
    

    如要讓根專案查看存放區,請宣告 模組擴充功能和 MODULE.bazel 檔案中存放區的用法。

    ## MODULE.bazel
    non_module_dependencies = use_extension("//:extensions.bzl", "non_module_dependencies")
    use_repo(non_module_dependencies, "data_file")
    

使用模組擴充功能解決衝突的外部依附元件

專案可提供根據 呼叫其呼叫端但如果 是否會造成衝突?

假設專案 foo 提供下列巨集,將 version 做為 引數。

## repositories.bzl in foo {:#repositories.bzl-foo}
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
def data_deps(version = "1.0"):
    http_file(
        name = "data_file",
        url = "http://example.com/file-%s" % version,
        # Omitting the "sha256" attribute for simplicity
    )
  • 工作區

    使用 WORKSPACE 時,您可以從 @foo 載入巨集並指定版本 所需的資料依附元件假設您還有另一個依附元件 @bar 這也取決於 @foo,但需要其他版本的資料 依附元件

    ## WORKSPACE
    
    # Introduce @foo and @bar.
    ...
    
    load("@foo//:repositories.bzl", "data_deps")
    data_deps(version = "2.0")
    
    load("@bar//:repositories.bzl", "bar_deps")
    bar_deps() # -> which calls data_deps(version = "3.0")
    

    在此情況下,使用者必須謹慎調整 WORKSPACE 檔案取得所需版本。這是最艱鉅的任務之一 使用 WORKSPACE 模型,因為這個方法無法提供有效的方式 解析依附元件

  • Bzlmod

    透過 Bzlmod,專案 foo 的作者可以使用模組擴充功能來解決問題 衝突。舉例來說,假設一律選取 所有 Bazel 模組的資料依附元件最低版本需求。

    ## extensions.bzl in foo
    load("//:repositories.bzl", "data_deps")
    
    data = tag_class(attrs={"version": attr.string()})
    
    def _data_deps_extension_impl(module_ctx):
        # Select the maximal required version in the dependency graph.
        version = "1.0"
        for mod in module_ctx.modules:
            for data in mod.tags.data:
                version = max(version, data.version)
        data_deps(version)
    
    data_deps_extension = module_extension(
        implementation = _data_deps_extension_impl,
        tag_classes = {"data": data},
    )
    
    ## MODULE.bazel in bar
    bazel_dep(name = "foo", version = "1.0")
    
    foo_data_deps = use_extension("@foo//:extensions.bzl", "data_deps_extension")
    foo_data_deps.data(version = "3.0")
    use_repo(foo_data_deps, "data_file")
    
    ## MODULE.bazel in root module
    bazel_dep(name = "foo", version = "1.0")
    bazel_dep(name = "bar", version = "1.0")
    
    foo_data_deps = use_extension("@foo//:extensions.bzl", "data_deps_extension")
    foo_data_deps.data(version = "2.0")
    use_repo(foo_data_deps, "data_file")
    

    在此情況下,根模組需要資料版本 2.0, 依附元件 bar 需要 3.0foo 中的模組擴充功能可正確 解決這項衝突,並自動為資料選取「3.0」版本 依附元件

整合第三方套件管理工具

延續上一節的內容,因為模組擴充功能可讓您收集 ,執行自訂邏輯來解決問題 找出外部存放區的依附元件和呼叫存放區規則 可讓規則作者輕鬆強化將 特定語言的套件管理工具

詳情請參閱「模組擴充功能」頁面 如何使用模組擴充功能

以下是已採用 Bzlmod 擷取依附元件的規則集清單 不同的套件管理工具:

如要整合虛擬套件管理員,請參閱這個最精簡的範例 例子 Cloud Storage 也提供目錄同步處理功能

偵測主機上的工具鍊

當 Bazel 建構規則需要偵測主機上可用的工具鍊時 就會使用存放區規則來檢查主體機器 工具鍊資訊做為外部存放區使用

  • 工作區

    以下列存放區規則偵測殼層工具鍊。

    ## local_config_sh.bzl
    def _sh_config_rule_impl(repository_ctx):
        sh_path = get_sh_path_from_env("SH_BIN_PATH")
    
        if not sh_path:
            sh_path = detect_sh_from_path()
    
        if not sh_path:
            sh_path = "/shell/binary/not/found"
    
        repository_ctx.file("BUILD", """
    load("@bazel_tools//tools/sh:sh_toolchain.bzl", "sh_toolchain")
    sh_toolchain(
        name = "local_sh",
        path = "{sh_path}",
        visibility = ["//visibility:public"],
    )
    toolchain(
        name = "local_sh_toolchain",
        toolchain = ":local_sh",
        toolchain_type = "@bazel_tools//tools/sh:toolchain_type",
    )
    """.format(sh_path = sh_path))
    
    sh_config_rule = repository_rule(
        environ = ["SH_BIN_PATH"],
        local = True,
        implementation = _sh_config_rule_impl,
    )
    

    您可以在 WORKSPACE 中載入存放區規則。

    ## WORKSPACE
    load("//:local_config_sh.bzl", "sh_config_rule")
    sh_config_rule(name = "local_config_sh")
    
  • Bzlmod

    透過 Bzlmod,您可以使用模組擴充功能來導入相同的存放區。 這類似於上次介紹 @data_file 存放區的情況 專區。

    ## local_config_sh_extension.bzl
    load("//:local_config_sh.bzl", "sh_config_rule")
    
    sh_config_extension = module_extension(
        implementation = lambda ctx: sh_config_rule(name = "local_config_sh"),
    )
    

    然後在 MODULE.bazel 檔案中使用擴充功能。

    ## MODULE.bazel
    sh_config_ext = use_extension("//:local_config_sh_extension.bzl", "sh_config_extension")
    use_repo(sh_config_ext, "local_config_sh")
    

註冊工具鍊和執行平台

按照上一節的說明,介紹存放區代管工具鍊後 資訊 (例如:local_config_sh) 時,建議您註冊 工具鍊。

  • 工作區

    使用 WORKSPACE 時,您可以透過以下方式註冊工具鍊。

    1. 您可以在 .bzl 檔案中註冊工具鍊,並在 WORKSPACE 檔案。

      ## local_config_sh.bzl
      def sh_configure():
          sh_config_rule(name = "local_config_sh")
          native.register_toolchains("@local_config_sh//:local_sh_toolchain")
      
      ## WORKSPACE
      load("//:local_config_sh.bzl", "sh_configure")
      sh_configure()
      
    2. 您也可以直接在 WORKSPACE 檔案中註冊工具鍊。

      ## WORKSPACE
      load("//:local_config_sh.bzl", "sh_config_rule")
      sh_config_rule(name = "local_config_sh")
      register_toolchains("@local_config_sh//:local_sh_toolchain")
      
  • Bzlmod

    採用 Bzlmod 的 register_toolchainsregister_execution_platforms 只有 MODULE.bazel 檔案提供 API。你無法撥打電話 模組擴充功能中的 native.register_toolchains

    ## MODULE.bazel
    sh_config_ext = use_extension("//:local_config_sh_extension.bzl", "sh_config_extension")
    use_repo(sh_config_ext, "local_config_sh")
    register_toolchains("@local_config_sh//:local_sh_toolchain")
    

導入本機存放區

您需要將依附元件導入為本機存放區時 依附元件的本機版本,或是想將 做為外部存放區

  • 工作區

    使用 WORKSPACE 時,這項作業是由兩個原生存放區規則來完成 local_repositorynew_local_repository

    ## WORKSPACE
    local_repository(
        name = "rules_java",
        path = "/Users/bazel_user/workspace/rules_java",
    )
    
  • Bzlmod

    採用 Bzlmod 設計 local_path_override 到 使用本機路徑覆寫模組。

    ## MODULE.bazel
    bazel_dep(name = "rules_java")
    local_path_override(
        module_name = "rules_java",
        path = "/Users/bazel_user/workspace/rules_java",
    )
    

    您也能導入包含模組擴充功能的本機存放區。 但是,您無法在模組擴充功能中呼叫 native.local_repository。 正在持續努力解決所有原生存放區規則的星號 (勾選 #18285 代表進度)。 然後您可以在模組中呼叫對應的星線 local_repository 。實作自訂版本的 local_repository 存放區規則 (如果這是您遇到的阻礙問題)。

繫結目標

WORKSPACE 中的 bind 規則已淘汰, Bzlmod 不支援範本。它在 YAML 檔案中為目標命名 特殊的 //external 套件。系統會遷移所有相關使用者。

舉例來說

## WORKSPACE
bind(
    name = "openssl",
    actual = "@my-ssl//src:openssl-lib",
)

這可讓其他目標依附於 //external:openssl。您可以遷移 應採取的因應措施:

  • //external:openssl 的所有用法取代為 @my-ssl//src:openssl-lib

  • 或使用 alias 建構規則

    • 在套件中定義下列目標 (例如 //third_party)

      ## third_party/BUILD
      alias(
          name = "openssl,
          actual = "@my-ssl//src:openssl-lib",
      )
      
    • //external:openssl 的所有用法取代為 //third_party:openssl-lib

遷移

本節提供 Bzlmod 遷移作業的實用資訊和指引 上傳資料集之後,您可以運用 AutoML 自動完成部分資料準備工作

瞭解 WORKSPACE 中的依附元件

遷移的第一步是瞭解您有哪些依附元件。這項服務 可能難以識別 WORKSPACE 檔案,因為遞移依附元件通常會透過 *_deps 載入 巨集。

使用工作區解析的檔案檢查外部依附元件

幸運的是 --experimental_repository_resolved_file 可以幫助他們達成目標這個標記基本上會產生一個「鎖定檔案」佔所有已擷取外部 套用至最後一個 Bazel 指令的依附元件詳情請參閱這篇網誌文章 文章

使用方法有兩種:

  1. 擷取建構特定目標所需的外部依附元件資訊。

    bazel clean --expunge
    bazel build --nobuild --experimental_repository_resolved_file=resolved.bzl //foo:bar
    
  2. 擷取 WORKSPACE 檔案中定義的所有外部依附元件的資訊。

    bazel clean --expunge
    bazel sync --experimental_repository_resolved_file=resolved.bzl
    

    透過 bazel sync 指令,您可以擷取 WORKSPACE 檔案,包括:

    • bind 個用量
    • register_toolchainsregister_execution_platforms 個用量

    不過,如果您的專案是跨平台,則 bazel 同步處理作業可能會在特定 因為某些存放區規則只能在支援的裝置上 平台。

執行指令後,您應該會發現 resolved.bzl 檔案中的依附元件。

使用 bazel query 檢查外部依附元件

您可能也會知道 bazel query 可用於檢查存放區規則

bazel query --output=build //external:<repo name>

雖然 bazel 查詢比以前更方便也快速,但 外部依附元件版本 所以務必要謹慎使用查詢及檢查外部 將以 Bzlmod 的依附元件來說, 子指令

內建預設依附元件

檢查 --experimental_repository_resolved_file 產生的檔案之後 您會找出許多未在 WORKSPACE 中定義的依附元件。 這是因為 Bazel 實際上會為使用者的 WORKSPACE 新增前置字串和後置字串 檔案內容插入一些預設依附性,這類依附元件通常 原生規則 (例如 @bazel_tools@platforms@remote_java_tools)。取代為 Bzlmod,這些依附元件是透過內建模組導入 bazel_tools,這是其他各方的預設依附元件 Bazel 模組。

逐步遷移的混合模式

Bzlmod 和 WORKSPACE 可同時運作,以便遷移依附元件 從 WORKSPACE 檔案指向 Bzlmod 為逐步程序。

WORKSPACE.bzlmod

在遷移期間,Bazel 使用者可能需要 未啟用 Bzlmod。實作 WORKSPACE.bzlmod 支援, 讓處理程序更加順暢

WORKSPACE.bzlmod 的語法與 WORKSPACE 相同。啟用 Bzlmod 時 如果工作區根目錄中也有 WORKSPACE.bzlmod 檔案:

  • WORKSPACE.bzlmod 將生效,系統會忽略 WORKSPACE 的內容。
  • 沒有任何前置字串或後置字串 已新增至 WORKSPACE.bzlmod 檔案。

使用 WORKSPACE.bzlmod 檔案可協助您簡化遷移作業,原因如下:

  • Bzlmod 停用後,就會改回從 原始的 WORKSPACE 檔案
  • 啟用 Bzlmod 時,您可以更妥善地追蹤剩下哪些依附元件 使用 WORKSPACE.bzlmod 遷移。

存放區瀏覽權限

Bzlmod 可以控制來自指定資源的其他存放區 查看存放區名稱與嚴格存放區 deps

以下摘要說明不同類型的存放區瀏覽權限 容器也需一併考量

從主要存放區 來自 Bazel 模組存放區 來自模組擴充功能存放區 來自 WORKSPACE 存放區
主要存放區 顯示 如果根模組為直接依附元件 如果根模組是代管模組擴充功能的模組直接依附元件 顯示
Bazel 模組存放區 直接依附元件 直接依附元件 代管模組擴充功能的模組直接依附元件 直接模組的依附元件
模組擴充功能存放區 直接依附元件 直接依附元件 代管模組擴充功能的模組直接依附元件 + 由相同模組擴充功能產生的所有存放區 直接模組的依附元件
Workspace 重寫 所有可見項目 隱藏 隱藏 所有可見項目

遷移程序

典型的 Bzlmod 遷移程序如下:

  1. 瞭解 WORKSPACE 中的依附元件。
  2. 在專案根目錄中新增空白的 MODULE.bazel 檔案。
  3. 新增空白的 WORKSPACE.bzlmod 檔案,以覆寫 WORKSPACE 檔案內容。
  4. 在啟用 Bzlmod 的情況下建構目標,並檢查哪個存放區
  5. 檢查已解析依附元件中缺少存放區的定義 檔案。
  6. 透過模組將缺少的依附元件導入為 Bazel 模組 也可以將其保留在 WORKSPACE.bzlmod 中,以便稍後遷移。
  7. 請返回第 4 項,然後重複執行,直到所有依附元件都可用為止。

遷移工具

我們提供互動式 Bzlmod 遷移輔助指令碼, 即可開始使用

這個指令碼會執行下列作業:

  • 產生並剖析 WORKSPACE 解析的檔案。
  • 以使用者可理解的方式列印已解析檔案中的存放區資訊。
  • 執行 bazel 建構指令、偵測辨識出的錯誤訊息,以及建議 讓您以不同方式進行遷移
  • 檢查 BCR 中是否已有依附元件。
  • 將依附元件新增至 MODULE.bazel 檔案。
  • 透過模組擴充功能新增依附元件。
  • 將依附元件新增至 WORKSPACE.bzlmod 檔案。

如要使用,請確認您的應用程式已安裝最新的 Bazel 版本,並執行 以下指令:

git clone https://github.com/bazelbuild/bazel-central-registry.git
cd <your workspace root>
<BCR repo root>/tools/migrate_to_bzlmod.py -t <your build targets>

發布 Bazel 模組

如果您的 Bazel 專案是其他專案的依附元件 Bazel Central Registry 中所含的專案。

如要在 BCR 中查看專案,您必須將來源封存網址設為 專案。建立來源封存檔時,請注意下列事項:

  • 確認封存檔指向特定版本。

    BCR 只接受版本化來源封存檔,因為 Bzlmod 必須 在依附元件解析期間比較版本。

  • 確保封存網址穩定。

    Bazel 會根據雜湊值驗證封存的內容,因此您應 確認下載檔案的總和檢查碼一律不會變更。如果網址為 ,請在發布頁面中建立並上傳版本封存檔。 GitHub 不保證一定能針對以下項目產生的來源封存檔總和檢查碼: 需求量。簡單來說,網址形式為 將「https://github.com/<org>/<repo>/releases/download/...」視為穩定版 而 https://github.com/<org>/<repo>/archive/... 則不是。檢查 GitHub 封存總和檢查碼 服務中斷 瞭解背景資訊。

  • 確認來源樹狀結構符合原始存放區的版面配置。

    如果存放區相當龐大,而您打算建立發布版本 清除不必要的來源,縮減檔案大小,請 確定移除的來源樹狀結構是原始來源樹狀結構的子集。這個 方便使用者將模組覆寫為非發布 版本:archive_overridegit_override

  • 在可測試常用項目的子目錄中納入測試模組 API 整合

    測試模組是具有專屬 WORKSPACE 和 MODULE.bazel 的 Bazel 專案 檔案位於來源封存檔的子目錄中,會根據 實際發布的模組其中應包含範例或 整合測試,涵蓋最常見的 API。確認 測試模組瞭解設定方式。

準備好來源封存網址後,請追蹤 BCR 貢獻內容 指南,即可透過 GitHub 將模組提交至 BCR 提取要求。

強烈建議設定發布到 BCR GitHub 應用程式,適用於 ,將模組提交至 BCR。

最佳做法

本節將說明幾項您應遵循的最佳做法。 管理外部依附元件

將目標分割成不同套件,避免擷取不必要的依附元件。

勾選 #12835,開發位置 系統將強制擷取測試依附元件,藉此進行建構 不需要這些類別的物件這並非 Bzlmod 具體, 遵循上述做法,您就能更輕鬆地正確指定開發依附元件。

指定開發依附元件

您可以將 dev_dependency 屬性設為 true bazel_dep和 我們會使用 use_extension 指令 但不會套用至相依專案根模組可以使用 --ignore_dev_dependency 標記來驗證目標 仍會在沒有開發人員依附元件的情況下建構

社群遷移進度

您可以檢查 Bazel Central Registry 來找出 看看依附元件是否已存在你也可以隨時加入這個行列 GitHub 討論,前往 或發布導致遷移作業阻礙遷移作業的依附元件。

回報問題

請查看 Bazel GitHub 問題清單,確認已知的 Bzlmod 以負載平衡機制分配流量 即可降低應用程式發生效能問題的風險歡迎您提出新的問題或提出新功能要求,以利解除封鎖