Bzlmod 是新外部依附元件系統的代號 可在 Bazel 5.0 中導入該領域說明瞭 無法漸進式修正的舊系統請參閱 原始設計文件的問題陳述部分 ,掌握更多詳細資訊。
在 Bazel 5.0 中,Bzlmod 預設為不開啟。旗幟
請指定 --experimental_enable_bzlmod
,下列項目才能取得
效果。顧名思義,這項功能目前為實驗功能。
在正式推出功能前,API 和行為可能會有所變動。
如要將專案遷移至 Bzlmod,請按照 Bzlmod 遷移指南的說明操作。 您也可以在 examples 存放區中找到 Bzlmod 的用法範例。
Bazel 模組
舊版 WORKSPACE
外部依附元件系統的中心位置是
存放區 (或「存放區」),透過存放區規則 (或存放區規則) 建立的。
存放區仍是新系統的重要概念,模組是
依附元件的核心單位
基本上,「模組」就是可以有多個版本的 Bazel 專案。每個模組 ,其中會發布依附的其他模組相關中繼資料。這是 類似於其他依附元件管理系統中的熟悉概念:Maven Artifact、npm 套件、Cargo crate、Go 模組等
模組會直接使用 name
和 version
組合指定依附元件。
而不是 WORKSPACE
中的特定網址。然後查詢依附元件
Bazel 註冊資料庫;根據預設
Bazel Central Registry。在工作區中
會轉換成存放區
MODULE.bazel
每個模組版本都有一個 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
檔案應位於工作區目錄的根目錄
(位於 WORKSPACE
檔案旁)。與 WORKSPACE
檔案不同的是,您不需要
指定遞移依附元件;而是只要指定
「direct」依附元件和依附元件的 MODULE.bazel
檔案
,自動找出遞移依附元件。
MODULE.bazel
檔案和 BUILD
檔案十分相似,因為不支援所有
控制流程的形式也會禁止 load
陳述式。指令
支援的 MODULE.bazel
檔案如下:
module
,用於指定中繼資料 包括目前模組的名稱和版本等等;bazel_dep
,用於指定直接造訪 其他 Bazel 模組的依附元件- 覆寫,只有根模組可以使用 做為依附元件的模組) 來自訂 特定直接或遞移依附元件:
- 與模組擴充功能相關的指令:
版本格式
Bazel 的生態系統五花八門,而專案會使用不同的版本管理架構。
目前為止最受歡迎的是 SemVer
也經常使用不同配置來知名的專案
Abseil,
版本都是以日期表示,例如 20210324.2
)。
因此,Bzlmod 採用較寬鬆的 SemVer 規格版本。 差異包括:
- SemVer 闡述了「release」部分版本必須包含 3 個
區隔:
MAJOR.MINOR.PATCH
。在 Bazel 中,這項要求會放寬,因此 ,任意數量的區隔都可使用。 - 在 SemVer 中,「release」中的每個區段部分只能由數字組成。 在 Bazel 中,這會導致字母和比較 語意符合「ID」「預先發布版」部分。
- 另外,還有大、小和修補程式版本的語意 沒有強制執行的指令(但請參閱相容性等級,瞭解 以及有關回溯相容性的詳細說明)。
任何有效的 SemVer 版本都是有效的 Bazel 模組版本。此外,兩個
如果 SemVer 版本 a
和 b
處於相同訴訟保留,就會比較 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.2 以上版本,也不會選取還有一項額外福利 選擇「高保真」且「可重現」。
版本解析作業是在電腦本機執行,而非註冊資料庫。
相容性等級
請注意,MVS 對於回溯相容性的假設是可行的,因為 只是將回溯不相容的模組視為個別模組。 就 SemVer 而言,1.x 和 A 2.x 被視為不同模組 且可以存在於已解析的依附元件圖表中。這就是為什麼 主要版本已經過編碼,主要版本 Go,確保編譯時間或連結時間不會發生衝突。
在 Bazel 中,我們沒有這類保證。因此,我們需要一個方式
版本」數字,以便偵測回溯不相容的版本。這個號碼
稱為相容性等級,由
其 module()
指令。掌握這些資訊後
當我們偵測到同一個模組的版本不同且相容性時
所對應的依附元件圖表
存放區名稱
在 Bazel 中,每個外部依附元件都有存放區名稱。有時相同
依附元件可以透過不同的存放區名稱使用 (例如:
@io_bazel_skylib
和 @bazel_skylib
平均值
Bazel skylib) 或
存放區名稱可用於不同專案中的不同依附元件。
在 Bzlmod 中,存放區可由 Bazel 模組產生 模組擴充功能。為解決存放區名稱衝突 我們採用了存放區對應 建立新系統的機制以下提供兩個重要概念:
標準存放區名稱:各個存放區的全域不重複存放區名稱 Cloud Storage 也提供目錄同步處理功能這會是存放區所在的目錄名稱。
其建構方式如下 (警告:標準名稱格式為 而非應仰賴的 API,且隨時可能變更):- 適用於 Bazel 模組存放區:
module_name~version
(範例:@bazel_skylib~1.0.3
) - 適用於模組擴充功能存放區:
module_name~version~extension_name~repo_name
(範例:@rules_cc~0.0.1~cc_configure~local_config_cc
)
- 適用於 Bazel 模組存放區:
「Apparent repository name」:要在
BUILD
和 存放區中的.bzl
檔案相同的依附元件可能有不同的明顯 多個不同存放區中的不同名稱
判定方式如下:
每個存放區都有直接依附元件的存放區對應字典
從顯目存放區名稱到標準存放區名稱的對應。
建構容器時,我們會使用存放區對應來解析存放區名稱
標籤。請注意,標準存放區名稱沒有衝突,
藉由剖析 MODULE.bazel
,即可找出明顯的存放區名稱使用情況
因此,您可以輕鬆及早發現衝突並加以解決
和其他依附元件
嚴格依附元件
新的依附元件規格格式可讓我們執行更嚴格的檢查。於 具體來說,我們現在強制讓模組只能使用從其建立的存放區 直接依附元件這有助於避免意外和難以偵錯的故障情形 當遞移依附關係圖中的某個項目變更時。
嚴格依附元件的實作 存放區對應。基本上 每個存放區的存放區對應都包含其所有直接依附元件, 其他存放區不會顯示每個存放區可見的依附元件 判斷方式如下:
- Bazel 模組存放區可查看所有在
MODULE.bazel
檔案中導入的存放區 透過bazel_dep
和use_repo
。 - 模組擴充功能存放區,能查看模組中所有可用的依附元件 提供擴充功能,以及由同一模組產生的所有其他存放區 。
登錄檔
Bzlmod 透過 Bazel 要求其資訊來探索依附元件 註冊資料庫。Bazel 註冊資料庫只是 Bazel 模組的資料庫,只有 是一種索引註冊資料庫, 本機目錄或靜態 HTTP 伺服器 (遵循特定格式)。在 未來,我們打算新增單一模組註冊資料庫支援功能, 含有專案原始碼和記錄的 Git 存放區。
索引註冊資料庫
索引註冊資料庫是本機目錄或含有
包括模組清單的首頁、維護人員、
每個版本的 MODULE.bazel
檔案,以及如何擷取各個版本的原始碼
版本。值得注意的是,「不需要」提供來源封存。
索引註冊資料庫必須採用以下格式:
/bazel_registry.json
:包含登錄檔中繼資料的 JSON 檔案,例如:mirrors
,指定用於來源封存的鏡像清單。module_base_path
,指定含有source.json
檔案中的local_repository
類型。
/modules
:包含子目錄中每個模組的子目錄 註冊資料庫/modules/$MODULE
:包含每個版本的子目錄的目錄 詳細內容,以及下列檔案:metadata.json
:包含模組相關資訊的 JSON 檔案。 包含下列欄位:homepage
:專案的首頁網址。maintainers
:JSON 物件清單,每個物件都對應至 登錄檔中模組維護人員的資訊。 請注意,此指示不一定等於文件的作者 專案。versions
:可顯示此模組的所有版本 這個登錄檔yanked_versions
:此模組的「yanked」版本的清單。這個 目前免人工管理,但日後就會 略過或產生錯誤
/modules/$MODULE/$VERSION
:包含下列檔案的目錄:MODULE.bazel
:此模組版本的MODULE.bazel
檔案。source.json
:JSON 檔案,內含如何擷取 請務必提供此模組版本的原始碼- 預設類型為「封存」包含下列欄位:
url
:來源封存網址。integrity
: 子資源完整性 檢查碼的總和檢查碼strip_prefix
:擷取 原始碼封存檔patches
:字串清單,每個字串都為修補檔案命名 並套用至擷取的封存檔您可以在/modules/$MODULE/$VERSION/patches
目錄。patch_strip
:與 Unix 修補程式的--strip
引數相同。
- 您可以改為將類型變更為使用以下欄位的本機路徑:
type
:local_path
path
:存放區的本機路徑,計算方式如下:- 如果路徑是絕對路徑,則會依原樣使用。
- 如果路徑是相對路徑,且
module_base_path
是絕對路徑, 路徑已解析為<module_base_path>/<path>
- 如果路徑和
module_base_path
都是相對路徑,則路徑為 解析為<registry_path>/<module_base_path>/<path>
。 註冊資料庫必須由本機託管,並由--registry=file://<registry_path>
使用。 否則 Bazel 會擲回錯誤。
- 預設類型為「封存」包含下列欄位:
patches/
:包含修補檔案的選用目錄,只有在source.json
具有「封存」時才使用類型。
Bazel Central Registry
Bazel Central Registry (BCR) 是位於
bcr.bazel.build.其內容
由 GitHub 存放區支援
bazelbuild/bazel-central-registry
。
BCR 由 Bazel 社群維護。歡迎捐款者 提取要求詳情請見 Bazel Central Registry 政策和程序。
除了遵循一般索引註冊資料庫的格式之外,BCR 也規定
每個模組版本都有一個 presubmit.yml
檔案
(/modules/$MODULE/$VERSION/presubmit.yml
)。這個檔案指出一些
建構和測試目標,用於對此次評估的有效性
模組版本,並由 BCR 的 CI 管道使用,以確保互通性
繫結至 BCR 的各個模組間
選取登錄檔
可重複的 Bazel 標記 --registry
可用來指定
向其要求模組的註冊資料庫,因此您可以設定專案
安裝自第三方或內部註冊資料庫早期的註冊資料庫
優先順序。為了方便起見,您可以在--registry
.bazelrc
檔案。
模組擴充功能
模組擴充功能可讓您讀取輸入資料,藉此擴充模組系統
從依附元件圖的模組中學習,並執行必要的邏輯來解決
最後是呼叫存放區規則來建立存放區。兩者相似
用於今天的 WORKSPACE
巨集,但更適用於
模組和遞移依附元件
模組擴充功能是在 .bzl
檔案中定義,就像存放區規則或
WORKSPACE
巨集。不會直接叫用;而每個單元
指定名為「標記」的資料,讓擴充功能讀取。接著是
版本解析完畢後,就會執行模組擴充功能。系統已執行每項擴充功能
模組解析後一次 (直到任何版本實際發生之前)。
在整個依附元件圖表中,讀取屬於該物件的所有標記。
[ A 1.1 ]
[ * maven.dep(X 2.1) ]
[ * maven.pom(...) ]
/ \
bazel_dep / \ bazel_dep
/ \
[ B 1.2 ] [ C 1.0 ]
[ * maven.dep(X 1.2) ] [ * maven.dep(X 2.1) ]
[ * maven.dep(Y 1.3) ] [ * cargo.dep(P 1.1) ]
\ /
bazel_dep \ / bazel_dep
\ /
[ D 1.4 ]
[ * maven.dep(Z 1.4) ]
[ * cargo.dep(Q 1.1) ]
在上方的依附元件圖表範例中,A 1.1
和 B 1.2
等是 Bazel 模組。
您可將每個項目視為 MODULE.bazel
檔案。每個模組皆可指定
模組擴充功能的標記;這裡有些是針對「maven」擴充功能指定
有些則指定為「cargo」此依附元件圖完成之後 (適用於
舉例來說,假設 B 1.2
其實在 D 1.3
有bazel_dep
,但升級為
D 1.4
,因為 C
),擴充功能「maven」該函式可讀取所有
maven.*
標記,使用該資訊決定要建立哪些存放區。
與「cargo」相當類似。
擴充功能使用情形
擴充功能是由 Bazel 模組自行代管,因此如要在
您必須先在該模組中新增 bazel_dep
,然後呼叫
內建 use_extension
來納入範圍請參考以下範例
使用假想「maven」的 MODULE.bazel
檔案您可以使用
rules_jvm_external
模組:
bazel_dep(name = "rules_jvm_external", version = "1.0")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
讓擴充功能進入涵蓋範圍後,
並指定其標記請注意,標記必須遵循
對應的標記類別 (請參閱擴充功能定義)
)。以下範例是指定一些 maven.dep
和 maven.pom
標記。
maven.dep(coord="org.junit:junit:3.0")
maven.dep(coord="com.google.guava:guava:1.2")
maven.pom(pom_xml="//:pom.xml")
如果擴充功能產生了要在模組中使用的存放區,請使用
要宣告的 use_repo
指令
具體做法是指示 Kubernetes 建立並維護
一或多個代表這些 Pod 的物件以便滿足嚴格的 deps 條件,避免使用本機存放區名稱
衝突。
use_repo(
maven,
"org_junit_junit",
guava="com_google_guava_guava",
)
擴充功能產生的存放區屬於其 API 的一部分,因此您所在的標記
但請注意,「maven」就能產生
名為「org_junit_junit」和「com_google_guava_guava」的存放區。取代為
use_repo
,您可以視需要在模組範圍內重新命名,例如:
「guava」此處。
擴充功能定義
模組擴充功能的定義方式與存放區規則類似,
module_extension
函式。
兩者都有實作函式雖然存放區規則有許多
模組擴充功能有許多屬性
tag_class
,每個
屬性的數量標記類別會定義此項目所用標記的結構定義
。延續上述假設,假設「maven」副檔名:
# @rules_jvm_external//:extensions.bzl
maven_dep = tag_class(attrs = {"coord": attr.string()})
maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
maven = module_extension(
implementation=_maven_impl,
tag_classes={"dep": maven_dep, "pom": maven_pom},
)
這些宣告會明確指出 maven.dep
和 maven.pom
標記可以
並透過上述定義的屬性結構定義進行指定。
實作函式與 WORKSPACE
巨集類似,差別在於
取得 module_ctx
物件
依附元件圖表和所有相關標記的存取權。實作方式
函式應呼叫存放區規則來產生存放區:
# @rules_jvm_external//:extensions.bzl
load("//:repo_rules.bzl", "maven_single_jar")
def _maven_impl(ctx):
coords = []
for mod in ctx.modules:
coords += [dep.coord for dep in mod.tags.dep]
output = ctx.execute(["coursier", "resolve", coords]) # hypothetical call
repo_attrs = process_coursier(output)
[maven_single_jar(**attrs) for attrs in repo_attrs]
在上例中,我們逐一介紹依附元件圖表中的所有模組
(ctx.modules
),每個表格都是
包含 tags
欄位的 bazel_module
物件
會顯示模組中的所有 maven.*
標記。然後叫用 CLI 公用程式
與 Maven 聯絡並執行解決方案。最後,使用
使用假設 maven_single_jar
建立多個存放區的結果
儲存空間規則