外部依附元件總覽

回報問題 查看原始碼 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel 支援外部依附元件,也就是在建構作業中使用的來源檔案 (文字和二進位檔),但這些檔案並非來自您的工作區。舉例來說,這些規則集可能會託管在 GitHub 存放區、Maven 構件或本機電腦上 (不在目前工作區內)。

在 Bazel 6.0 中,有兩種方法可透過 Bazel 管理外部依附元件:傳統的以存放區為重點的 WORKSPACE 系統,以及較新的以模組為重點的 MODULE.bazel 系統 (代碼名稱為 Bzlmod,並透過標記 --enable_bzlmod 啟用)。這兩個系統可同時使用,但 Bzlmod 會在未來的 Bazel 版本中取代 WORKSPACE 系統,請參閱 Bzlmod 遷移指南瞭解如何遷移。

本文將說明 Bazel 中外部依附元件管理的相關概念,接著依序深入探討這兩個系統。

概念

存放區

目錄樹狀結構,根目錄含有邊界標記檔案,內含可用於 Bazel 建構作業的原始碼檔案。通常會縮寫為 repo

Repo 邊界標記檔案可以是 MODULE.bazel (表示此 repo 代表 Bazel 模組)、REPO.bazel (請參閱下文),或在舊版情境中為 WORKSPACEWORKSPACE.bazel。任何 repo 邊界標記檔案都會標示 repo 的邊界;多個此類檔案可在目錄中共存。

主要存放區

目前執行 Bazel 指令的存放區。

主存放區的根目錄也稱為工作區根目錄

工作區

所有 Bazel 指令在同一個主要存放區執行時共用的環境。包含主要存放區和所有已定義的外部存放區。

請注意,過去「存放區」和「工作區」的概念經常會混淆;「工作區」一詞經常用來指主要存放區,有時甚至會用作「存放區」的同義詞。

標準存放區名稱

存放區可供存取的正規名稱。在工作區的背景資訊中,每個存放區都有一個標準名稱。在標準名稱為 canonical_name 的存放區中,可以使用標籤 @@canonical_name//pac/kage:target 來處理目標 (請注意雙 @)。

主存放區的正式名稱一律為空白字串。

明顯的存放區名稱

在特定其他存放區的情況下,可用來尋址存放區的名稱。這可以視為儲存庫的「別名」:具有標準名稱 michael 的儲存庫在 alice 儲存庫的上下文中可能會使用顯式名稱 mike,但在 bob 儲存庫的上下文中可能會使用顯式名稱 mickey。在這種情況下,michael 內的目標可由 alice 情境中的標籤 @mike//pac/kage: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 子目錄中,以正規名稱找到該存放區。

您可以執行下列指令,查看名稱為 canonical_name 的標準化名稱的存放區內容:

ls $(bazel info output_base)/external/ canonical_name 

REPO.bazel 檔案

REPO.bazel 檔案用於標示組成存放區的目錄樹狀結構的頂層邊界。這個檔案不必包含任何內容,即可做為存放區邊界檔案;不過,您也可以使用這個檔案,為存放區內的所有建構目標指定一些通用屬性。

REPO.bazel 檔案的語法與 BUILD 檔案類似,但不支援 load 陳述式,且僅提供單一函式 repo()repo() 會採用與 BUILD 檔案中的 package() 函式相同的引數;package() 會為套件內的所有建構目標指定通用屬性,repo() 也會為存放區內的所有建構目標執行相同的操作。

舉例來說,您可以透過以下 REPO.bazel 檔案,為存放區中的所有目標指定通用授權:

repo(
    default_package_metadata = ["//:my_license"],
)

使用 Bzlmod 管理外部依附元件

新的外部依附元件子系統 Bzlmod 無法直接與 repo 定義搭配使用。而是從模組建構依附元件圖表,在圖表上執行擴充功能,並據此定義 repos。

Bazel 模組是可以擁有多個版本的 Bazel 專案,每個版本都會發布關於所依附其他模組的中繼資料。模組必須在其存放區根目錄中,WORKSPACE 檔案旁邊,有 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")

模組只需列出其直接依附元件,Bzlmod 會在 Bazel 登錄項目中查詢這些依附元件,預設為 Bazel 中央登錄項目。登錄會提供相依性的 MODULE.bazel 檔案,讓 Bazel 在執行版本解析前,先探索整個傳遞式相依性圖表。

在版本解析完成後,Bazel 會為每個模組選取一個版本,然後再次諮詢註冊中心,瞭解如何為每個模組定義一個存放區 (在大多數情況下,使用 http_archive)。

模組也可以指定稱為「標記」的自訂資料片段,這些標記會在模組解析後由模組擴充功能使用,用於定義其他存放區。這些擴充功能的功能類似於 repo 規則,可執行檔案 I/O 和傳送網路要求等動作。除了其他功能外,這些模組還可讓 Bazel 與其他套件管理系統互動,同時遵循 Bazel 模組建立的依附元件圖。

使用 WORKSPACE 定義 repos

過去,您可以透過在 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 系統中,根據預設,Repo 的正式名稱也是所有其他 Repo 的顯示名稱。

請參閱 WORKSPACE 檔案中可用的函式完整清單

WORKSPACE 系統的缺點

WORKSPACE 系統推出以來,使用者回報了許多困擾,包括:

  • Bazel 不會評估任何依附元件的 WORKSPACE 檔案,因此除了直接依附元件外,所有傳遞依附元件都必須在主存放區的 WORKSPACE 檔案中定義。
  • 為解決這個問題,專案採用了「deps.bzl」模式,其中定義的巨集會依序定義多個存放區,並要求使用者在 WORKSPACE 檔案中呼叫這個巨集。
    • 這會產生一些問題:巨集無法 load 其他 .bzl 檔案,因此這些專案必須在這個「deps」巨集中定義其傳遞依附元件,或是透過讓使用者呼叫多個分層「deps」巨集來解決這個問題。
    • Bazel 會依序評估 WORKSPACE 檔案。此外,依附元件會使用 http_archive 和網址指定,不含任何版本資訊。也就是說,在鑽石依附元件情況下,沒有可靠的方法可執行版本解析 (A 依附 BCBC 都依附不同版本的 D)。

由於 WORKSPACE 有缺點,Bzlmod 將在日後的 Bazel 版本中取代舊版 WORKSPACE 系統。請參閱 Bzlmod 遷移指南,瞭解如何遷移至 Bzlmod。