Bazel 模組

回報問題 查看來源 夜間 7.4 ,直接在 Google Cloud 控制台實際操作。 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel 模組是可擁有多個版本的 Bazel 專案,每個版本都會發布關於所依附其他模組的中繼資料。這是 類似其他依附元件管理系統中熟悉的概念 Maven 構件、npm 套件、Go 模組或 Cargo crate

模組的存放區根目錄中必須有 MODULE.bazel 檔案。此檔案是模組的資訊清單,會宣告模組的名稱、版本、直接依附元件清單和其他資訊。查看基本範例:

module(name = "my-module", version = "1.0")

bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")

請參閱 MODULE.bazel 檔案中可用的指令完整清單

為了執行模組解析,Bazel 會先讀取根模組的 MODULE.bazel 檔案,然後重複要求任何依附元件的 MODULE.bazel 檔案從 Bazel 登錄檔移除,直到該檔案為止 即可查看完整的依附元件圖表

根據預設,Bazel 會選取每個模組的一個版本來使用。Bazel 會用存放區代表每個模組,並諮詢該註冊資料庫 ,瞭解如何定義各個存放區。

版本格式

Bazel 擁有多元的生態系統,專案會使用各種版本管理方案。目前最受歡迎的是 SemVer,但也有知名專案使用其他配置,例如 Abseil (其版本是以日期為準,例如 20210324.2)。

因此,Bzlmod 採用較寬鬆的 SemVer 規格版本。 差異包括:

  • SemVer 闡述了「release」部分版本必須包含 3 個 區隔:MAJOR.MINOR.PATCH。在 Bazel 中,這項要求會放寬,因此 ,任意數量的區隔都可使用。
  • 在 SemVer 中,「release」中的每個區段部分只能由數字組成。 在 Bazel 中,這項限制已放寬,因此也允許使用英文字母,且比較語義會與「預發布」部分的「ID」相符。
  • 另外,還有大、小和修補程式版本的語意 沒有強制執行的指令不過,請參閱相容性等級,瞭解 並詳細說明我們如何表示回溯相容性

任何有效的 SemVer 版本都是有效的 Bazel 模組版本。此外,如果兩個 SemVer 版本 ab 以 Bazel 模組版本比較,則只有在兩者相同時,才能比較 a < b

選擇版本

請考慮鑽石依附元件問題,也就是版本化依附元件中的基石 管理空間假設您有依附元件圖:

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

應使用哪個版本的「D」?為解決這個問題,Bzlmod 使用 Go 模組系統中引進的最小版本選取 (MVS) 演算法。MVS 會假設模組的所有新版本皆可向下相容,因此會挑選任何依附元件 (在本例中為 D 1.1) 指定的最高版本。之所以稱為「最小」版本,是因為 D 1.1 是可滿足我們需求的早期版本,即使 D 1.2 或更新版本存在,我們也不會選取這些版本。使用 MVS 會建立 高保真可重現的版本選擇程序。

彎曲版本

如果有特定版本應避免使用,註冊資料庫可將特定版本宣告為「yanked」 (例如安全漏洞)。Bazel 在選取 模組的 Shaked 版本。如要修正這個錯誤,請升級至新版 避免變形語,或是使用 --allow_yanked_versions 旗標,明確允許該版本。

相容性等級

在 Go 中,MVS 對向下相容性的假設是有效的,因為它會將模組的向下相容版本視為獨立模組。目標 SemVer,這表示 A 1.xA 2.x 被視為不同的模組,且 與已解析的依附元件圖中存在。換句話說 在 Go 套件路徑中編碼主要版本,因此沒有任何 編譯時間或連結時間衝突

不過,Bazel 無法提供這類保證,因此需要「主要版本」編號才能偵測回溯不相容的版本。這個數字稱為相容性層級,由各模組版本在其 module() 指令中指定。有了這項資訊,Bazel 便可在發生錯誤時擲回錯誤 偵測是否有不同相容性等級的同一模組 都存在於已解析的依附元件圖中

覆寫

MODULE.bazel 檔案中指定覆寫值,即可變更 Bazel 模組解析的行為。只有根模組的覆寫值會生效 (如果模組 做為依附元件,系統會忽略其覆寫值

每個覆寫值都是由特定模組名稱指定,影響了該模組的所有 依附元件圖表中列出各個版本雖然只有根模組的覆寫值會生效,但這些值可用於根模組未直接依附的間接依附元件。

單一版本覆寫

single_version_override 用途:

  • 使用 version 屬性,即可將依附元件固定在特定 版本,不受 Deployment 中要求的依附元件版本 依附關係圖
  • 透過 registry 屬性,您可以強制這個依附元件來自 而非一般的註冊資料庫 選取流程
  • 您可以使用 patch* 屬性,指定要套用至下載模組的一系列修補程式。

這些屬性為選用屬性,可以混合搭配。

多重版本覆寫

multiple_version_override 您可以指定多個版本,讓同一模組的多個版本共存 已解析的依附關係圖

您可以指定明確的模組可用版本清單, 全都列在依附元件圖中,才能解決 (必須存在) 一些遞移依附元件,視每個允許的版本而定。更新後 ,但 Bazel 升級時,系統只會保留允許的模組版本 其他版本的模組 (例如相同的 Pod 版本) 至最接近的可用版本 相容性等級。沒有其他具備相同相容性的版本 Bazel 會擲回錯誤

舉例來說,如果在解析前,依附元件圖表中存在 1.11.31.51.72.0 版本,且主要版本為相容性層級:

  • 允許 1.31.72.0 的多版本覆寫值會導致 1.1 升級至 1.31.5 升級至 1.7,其他版本則保持不變。
  • 如果覆寫 1.52.0 的多重版本覆寫方法會導致錯誤, 1.7 沒有具備相同相容性等級的版本,無法升級至該版本。
  • 允許 1.92.0 的多版本覆寫會導致錯誤,因為在解析前,依附元件圖中並未出現 1.9

此外,使用者也可以使用 registry 覆寫登錄檔。 屬性,與單一版本覆寫機制類似。

非登錄覆寫值

非登錄檔覆寫會將模組從版本解析中完全移除。Bazel 未向註冊資料庫要求這 MODULE.bazel 檔案,而是向 存放區本身

Bazel 支援下列非登錄檔覆寫:

定義不代表 Bazel 模組的 repos

透過 bazel_dep,您可以定義代表其他 Bazel 模組的存放區。 有時候,您需要定義「不」代表 Bazel 的存放區 module;例如,內含要當做資料讀取的純 JSON 檔案。

在這種情況下,您可以使用 use_repo_rule 指令,直接定義存放區 叫用存放區規則這個存放區只會顯示其定義的模組。

實際上,實作時會使用與 module 相同的機制實作 擴充功能,可讓您定義包含更多 靈活彈性

存放區名稱和嚴格依附元件

備份 Deployment 的存放區 apparent name 模組直接依附於其模組名稱,除非 bazel_deprepo_name 屬性 指令。請注意,這表示模組只能找出 依附元件這有助於防止因 遞移依附元件

備份 Deployment 的標準名稱 模組為 module_name+version (例如 bazel_skylib+1.0.3) 或 module_name+ (例如 bazel_features+),視是否有 整個依附元件圖表中,模組有多種版本 (請參閱 multiple_version_override)。 請注意,標準名稱格式不是您應依附於 隨時可能變動。相較於硬式編碼為正規名稱 請使用支援的方法,直接從 Bazel 取得該檔案: * 如果是 BUILD 和 .bzl 檔案中,請使用 Label 執行個體上的 Label.repo_name 透過存放區的明顯名稱提供的標籤字串所建構,例如 Label("@bazel_skylib").repo_name。* 查詢執行檔時,請使用 $(rlocationpath ...)@bazel_tools//tools/{bash,cpp,java}/runfiles 中的其中一個執行檔程式庫,或是在 @rules_foo//foo/runfiles 中查詢規則集 rules_foo。* 透過 IDE 或語言伺服器等外部工具與 Bazel 互動時,請使用 bazel mod dump_repo_mapping 指令,針對特定的存放區集合取得從明顯名稱到標準名稱的對應項目。

模組擴充功能也可以將其他存放區引入模組的可見範圍。