Bazel 支援外部依附元件和來源檔案 (文字和二進位檔),這些檔案用於建構作業,但並非來自工作區。例如,可以是 GitHub 存放區中代管的規則集、Maven 構件,或本機電腦上目前工作區外的目錄。
本文將先概略介紹這個系統,再詳細說明部分概念。
系統總覽
Bazel 的外部依附元件系統以 Bazel 模組為基礎運作,每個模組都是有版本的 Bazel 專案,以及存放區 (或存放區),也就是包含來源檔案的目錄樹狀結構。
Bazel 會從根模組開始,也就是您正在處理的專案。與所有模組一樣,這個模組的目錄根層級也需要有 MODULE.bazel
檔案,宣告基本中繼資料和直接依附元件。以下是基本範例:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.1.1")
bazel_dep(name = "platforms", version = "0.0.11")
接著,Bazel 會在 Bazel 登錄檔 (預設為 Bazel Central Registry) 中,查閱所有傳輸依附元件模組。登錄檔會提供依附元件的 MODULE.bazel
檔案,讓 Bazel 能夠在執行版本解析作業前,探索整個遞移依附元件圖表。
版本解析後 (為每個模組選取一個版本),Bazel 會再次查詢登錄檔,瞭解如何為每個模組定義存放區,也就是如何擷取每個依附元件模組的來源。大多數時候,這些只是從網際網路下載並解壓縮的封存檔。
模組也可以指定稱為「標記」的自訂資料片段,這些資料片段會在模組解析後由模組擴充功能使用,以定義其他存放區。這些擴充功能可執行檔案 I/O 和傳送網路要求等動作。除了其他功能外,這些模組還可讓 Bazel 與其他套件管理系統互動,同時遵循由 Bazel 模組建構的依附元件圖表。
這三種存放區 (主要存放區,也就是您正在使用的來源樹狀結構;代表遞移依附元件模組的存放區;以及由模組擴充功能建立的存放區) 會共同組成工作區。系統會視需要擷取外部存放區 (非主要存放區),例如在 BUILD 檔案中由標籤 (如 @repo//pkg:target
) 參照時。
優點
Bazel 的外部依附元件系統提供許多優點。
自動依存性解決方法
- 確定性版本解析:Bazel 採用確定性 MVS 版本解析演算法,可減少衝突並解決菱形依附元件問題。
- 簡化依附元件管理:
MODULE.bazel
只會宣告直接依附元件,而遞移依附元件會自動解析,讓您更清楚瞭解專案的依附元件。 - 嚴格的依附元件瀏覽權限: 只會顯示直接依附元件,確保正確性和可預測性。
生態系統整合
- Bazel Central Registry:集中式存放區,可做為 Bazel 模組,用於探索及管理常見依附元件。
- 採用非 Bazel 專案:當非 Bazel 專案 (通常是 C++ 程式庫) 適用於 Bazel 並在 BCR 中提供時,可簡化整個社群的整合作業,並消除重複作業和自訂 BUILD 檔案的衝突。
- 與語言專屬套件管理工具整合:規則集可簡化與外部套件管理工具的整合,適用於非 Bazel 依附元件,包括:
- Maven 的 rules_jvm_external,
- rules_python (適用於 PyPi)
- bazel-gazelle 適用於 Go 模組,
- Cargo 的 rules_rust。
進階功能
- 模組擴充功能:
use_repo_rule
和模組擴充功能可彈性使用自訂存放區規則和解析邏輯,導入任何非 Bazel 依附元件。 bazel mod
指令:這個子指令提供強大的方式來檢查外部依附元件。您確切知道外部依附元件的定義方式和來源。- 供應商模式:預先擷取離線建構所需的確切外部依附元件。
- 鎖定檔案:鎖定檔案可提高建構重現性,並加快依附元件解析速度。
- (即將推出) BCR 來源認證: 確保依附元件的來源經過驗證,進而提升供應鏈安全性。
概念
本節將進一步說明與外部依附元件相關的概念。
Module
Bazel 專案可以有多個版本,每個版本都可以依附於其他模組。
在 Bazel 本機工作區中,模組是以存放區表示。
詳情請參閱「Bazel 模組」。
存放區
目錄樹狀結構,根目錄中含有邊界標記檔案,內含可用於 Bazel 建構作業的來源檔案。通常會簡稱為「repo」。
存放區界線標記檔案可以是 MODULE.bazel
(表示這個存放區代表 Bazel 模組)、REPO.bazel
(請參閱下文),或在舊版環境中為 WORKSPACE
或 WORKSPACE.bazel
。任何存放區界線標記檔案都會標示存放區的界線;多個這類檔案可以共存在一個目錄中。
主要存放區
目前 Bazel 指令執行的存放區。
主要存放區的根目錄也稱為「工作區根目錄」。
工作區
所有 Bazel 指令都會在同一個主要存放區中執行,並共用環境。其中包含主要存放區和所有已定義的外部存放區集。
請注意,從歷史來看,「存放區」和「工作區」的概念一直混淆不清;「工作區」一詞通常是指主要存放區,有時甚至用做「存放區」的同義詞。
正規存放區名稱
存放區一律可透過這個名稱存取。在工作區的脈絡中,每個存放區都有單一標準名稱。如果存放區中的目標標準名稱為 canonical_name
,則可透過標籤 @@canonical_name//package:target
(請注意雙 @
) 進行定址。
主要存放區的正式名稱一律為空字串。
存放區名稱
存放區在特定其他存放區環境中可定址的名稱。這可以視為 repo 的「暱稱」:正規名稱為 michael
的 repo 在 repo alice
的環境中可能具有顯而易見的名稱 mike
,但在 repo bob
的環境中可能具有顯而易見的名稱 mickey
。在這種情況下,michael
內的目標可在 alice
的環境中,透過標籤 @mike//package:target
進行定址 (請注意單一 @
)。
反過來說,這可以視為「存放區對應」:每個存放區都會維護從「顯而易見的存放區名稱」到「標準存放區名稱」的對應。
存放區規則
存放區定義的結構,會告知 Bazel 如何具體化存放區。舉例來說,可以是「從特定網址下載並解壓縮 zip 封存檔」、「擷取特定 Maven 構件並設為 java_import
目標」,或只是「符號連結本機目錄」。每個存放區都是透過呼叫存放區規則並提供適當數量的引數定義。
如要進一步瞭解如何編寫自己的存放區規則,請參閱存放區規則。
目前最常見的存放區規則是 http_archive
,可從網址下載並解壓縮封存檔,以及 local_repository
,可符號連結已是 Bazel 存放區的本機目錄。
擷取存放區
透過執行相關聯的存放區規則,在本地磁碟上提供存放區的動作。工作區中定義的存放區必須先擷取,才能在本機磁碟上使用。
通常 Bazel 只會在需要存放區中的項目,且尚未擷取存放區時,才會擷取存放區。如果先前已擷取存放區,只有在定義變更時,Bazel 才會重新擷取。
fetch
指令可用於啟動存放區、目標或所有必要存放區的預先擷取作業,以執行任何建構作業。這項功能可透過 --nofetch
選項啟用離線建構。
--fetch
選項用於管理網路存取權。預設值為 true。
不過,如果設為 false (--nofetch
),指令會使用依附元件的任何快取版本,如果沒有快取版本,指令就會失敗。
如要進一步瞭解如何控管擷取作業,請參閱擷取選項。
目錄版面配置
擷取完成後,您可以在輸出基準的 external
子目錄中,找到以正式名稱命名的存放區。
您可以執行下列指令,查看具有標準名稱 canonical_name
的存放區內容:
ls $(bazel info output_base)/external/ canonical_name
REPO.bazel 檔案
REPO.bazel
檔案用於標記構成存放區的目錄樹最上層邊界。這個檔案不需要包含任何內容,即可做為存放區界線檔案;不過,這個檔案也可以用來指定存放區內所有建構目標的某些常見屬性。
REPO.bazel
檔案的語法與 BUILD
檔案類似,但系統不支援 load
陳述式。repo()
函式會採用與 BUILD
檔案中 package()
函式相同的引數;而 package()
會指定套件內所有建構目標的通用屬性,repo()
則會指定存放區內所有建構目標的通用屬性。
舉例來說,您可以透過下列 REPO.bazel
檔案,為存放區中的所有目標指定通用授權:
repo(
default_package_metadata = ["//:my_license"],
)
舊版 WORKSPACE 系統
在舊版 Bazel (9.0 之前) 中,外部依附元件是透過在 WORKSPACE
(或 WORKSPACE.bazel
) 檔案中定義存放區來導入。這個檔案的語法與 BUILD
檔案類似,但採用的是存放區規則,而非建構規則。
以下程式碼片段是 WORKSPACE
檔案中使用 http_archive
存放區規則的範例:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "foo",
urls = ["https://example.com/foo.zip"],
sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)
程式碼片段會定義正規名稱為 foo
的存放區。在 WORKSPACE
系統中,根據預設,存放區的正式名稱也是所有其他存放區的顯示名稱。
如要查看 WORKSPACE
檔案中可用的函式完整清單,請參閱這篇文章。
WORKSPACE
系統的缺點
WORKSPACE
系統推出後,使用者回報了許多痛點,包括:
- Bazel 不會評估任何依附元件的
WORKSPACE
檔案,因此除了直接依附元件外,所有遞移依附元件都必須在主要存放區的WORKSPACE
檔案中定義。 - 為解決這個問題,專案採用了「deps.bzl」模式,其中定義了巨集,而巨集又定義了多個存放區,並要求使用者在
WORKSPACE
檔案中呼叫這個巨集。- 這會產生自己的問題:巨集無法
load
其他.bzl
檔案,因此這些專案必須在這個「deps」巨集中定義其遞移依附元件,或讓使用者呼叫多個分層「deps」巨集,以解決這個問題。 - Bazel 會依序評估
WORKSPACE
檔案。此外,依附元件是使用含網址的http_archive
指定,不含任何版本資訊。也就是說,如果出現菱形依附元件 (A
依附於B
和C
;B
和C
都依附於不同版本的D
),就無法可靠地執行版本解析。
- 這會產生自己的問題:巨集無法
由於 WORKSPACE 有缺點,因此在 Bazel 6 到 9 之間,新的模組式系統 (代號為「Bzlmod」) 逐步取代了舊版 WORKSPACE 系統。請參閱 Bzlmod 遷移指南,瞭解如何遷移至 Bzlmod。