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 中央登錄檔。登錄會提供相依性的 MODULE.bazel
檔案,讓 Bazel 在執行版本解析前,先找出整個傳遞式相依性圖表。
在版本解析完成後,系統會為每個模組選取一個版本,Bazel 會再次參考註冊中心,瞭解如何為每個模組定義一個存放區,也就是如何擷取每個依附元件模組的原始碼。大多數情況下,這些只是從網際網路下載並擷取的封存資料。
模組也可以指定稱為「標記」的自訂資料片段,這些標記會在模組解析後由模組擴充功能使用,用於定義其他存放區。這些擴充功能可執行檔案 I/O 和傳送網路要求等動作。除了其他功能外,這些模組還可讓 Bazel 與其他套件管理系統互動,同時遵循由 Bazel 模組建構的依附元件圖表。
三種類型的 repo 包括主要 repo (即您正在使用的來源樹狀結構)、代表傳遞依附元件模組的 repo,以及由模組擴充功能建立的 repo,這些 repo 共同組成 工作區。系統會視需要擷取外部存放區 (非主要存放區),例如當 BUILD 檔案中的標籤 (例如 @repo//pkg:target
) 參照外部存放區時。
優點
Bazel 的外部相依性系統提供多種優點。
自動依存性解決方法
- 確定性版本解析:Bazel 採用確定性 MVS 版本解析演算法,盡可能減少衝突並解決菱形依附元件問題。
- 簡化依附元件管理:
MODULE.bazel
只會宣告直接依附元件,而間接依附元件會自動解析,讓您更清楚瞭解專案的依附元件。 - 嚴格依附元件瀏覽權限:只顯示直接依附元件,確保正確性和可預測性。
生態系統整合
- Bazel 中央註冊表:集中式存放區,用於探索及管理常見的依附元件,做為 Bazel 模組。
- 採用非 Bazel 專案:當非 Bazel 專案 (通常是 C++ 程式庫) 為 Bazel 所用,並在 BCR 中提供時,可為整個社群簡化整合作業,並消除重複的作業和自訂 BUILD 檔案的衝突。
- 與語言專屬套件管理工具整合:Rulesets 可簡化與非 Bazel 依附元件的外部套件管理工具整合,包括:
- 針對 Maven,請使用 rules_jvm_external
- 適用於 PyPi 的 rules_python,
- bazel-gazelle (適用於 Go 模組)
- 使用 Cargo 的 rules_rust。
進階功能
- 模組擴充功能:
use_repo_rule
和模組擴充功能可讓您靈活運用自訂存放區規則和解析邏輯,引入任何非 Bazel 依附元件。 bazel mod
指令:這個子指令提供強大的檢查外部依附元件的方法。您會確切瞭解外部相依性的定義方式和來源。- 供應商模式:預先擷取所需的確切外部相依項目,以利離線建構。
- Lockfile:鎖定檔案可改善建構可重現性,並加快依附元件解析速度。
- (即將推出) BCR 來源認證:確保依附元件的來源已經過驗證,強化供應鏈安全性。
概念
本節將進一步說明與外部依附元件相關的概念。
模組
可擁有多個版本的 Bazel 專案,每個版本都可能會依附其他模組。
在本機 Bazel 工作區中,模組會以存放區表示。
詳情請參閱「Bazel 模組」。
存放區
根目錄中含有邊界標記檔案的目錄樹狀結構,其中包含可用於 Bazel 建構的原始碼檔案。通常會縮寫為 repo。
Repo 邊界標記檔案可以是 MODULE.bazel
(表示此 repo 代表 Bazel 模組)、REPO.bazel
(請參閱下文),或在舊版情境中為 WORKSPACE
或 WORKSPACE.bazel
。任何 repo 邊界標記檔案都會標示 repo 的邊界;多個此類檔案可在目錄中共存。
主要存放區
目前執行 Bazel 指令的存放區。
主存放區的根目錄也稱為工作區根目錄。
工作區
在同一個主要存放區執行的所有 Bazel 指令共用的環境。包含主要存放區和所有已定義的外部存放區。
請注意,過去「存放區」和「工作區」的概念經常會混淆;「工作區」一詞經常用來指主要存放區,有時甚至會用來指「存放區」。
標準存放區名稱
存放區可供存取的正規名稱。在工作區的背景資訊中,每個存放區都有一個標準名稱。在標準名稱為 canonical_name
的存放區中,可以使用標籤 @@canonical_name//package:target
來處理目標 (請注意雙 @
)。
主存放區的正式名稱一律為空白字串。
明顯的存放區名稱
在特定其他存放區的情況下,可用來尋址存放區的名稱。這可以視為是儲存庫的「別名」:具有標準名稱 michael
的儲存庫在 alice
儲存庫的內容中可能會使用顯式名稱 mike
,但在 bob
儲存庫的內容中可能會使用顯式名稱 mickey
。在這種情況下,michael
內的目標可由 alice
情境中的標籤 @mike//package:target
處理 (請注意單一 @
)。
反過來說,這可以視為存放區對應:每個存放區都會維護從「明顯的存放區名稱」到「正式的存放區名稱」的對應關係。
存放區規則
存放區定義的結構定義,可告知 Bazel 如何具現存放區。舉例來說,您可以使用「從特定網址下載並解壓縮 ZIP 封存檔」,或「擷取特定 Maven 成果物,並將其用作 java_import
目標」,或是簡單地使用「建立本機目錄的符號連結」。每個 repo 都是透過呼叫 repo 規則,並使用適當數量的引數來定義。
如要進一步瞭解如何編寫自訂存放區規則,請參閱「存放區規則」。
目前最常見的存放區規則是 http_archive
,可從網址下載並解壓縮封存檔,以及 local_repository
,可建立已是 Bazel 存放區的本機目錄符號連結。
擷取存放區
透過執行相關聯的 repo 規則,在本機磁碟上提供 repo 的動作。在擷取之前,工作區中定義的 repo 無法在本機磁碟上使用。
通常,Bazel 只會在需要存放區的內容,且尚未擷取存放區時,才擷取存放區。如果先前已擷取存放區,Bazel 只會在定義變更時重新擷取。
fetch
指令可用於為執行任何建構作業的存放區、目標或所有必要存放區,啟動預先擷取作業。這項功能可使用 --nofetch
選項啟用離線建構作業。
--fetch
選項可用於管理網路存取權。其預設值為 true。不過,如果設為 false (--nofetch
),指令會使用依附元件的任何快取版本,如果沒有任何版本,指令就會失敗。
如要進一步瞭解如何控制擷取作業,請參閱「擷取選項」。
目錄版面配置
擷取後,您可以在輸出基地的 external
子目錄中,找到以正規名稱命名的 repo。
您可以執行下列指令,查看名稱為 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
) 檔案中定義 repos 而導入。這個檔案的語法與 BUILD
檔案相似,採用 repo 規則而非建構規則。
以下程式碼片段是使用 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 有缺點,新的模組式系統 (代號為「Bzlmod」) 已在 Bazel 6 到 9 之間逐步取代舊版 WORKSPACE 系統。請參閱 Bzlmod 遷移指南,瞭解如何遷移至 Bzlmod。