Bazel 可以依賴其他專案的目標。這些其他專案的依附元件稱為外部依附元件。
工作區目錄中的 WORKSPACE
檔案 (或 WORKSPACE.bazel
檔案) 會告訴 Bazel 如何取得其他專案的來源。這些其他專案可包含一或多個 BUILD
檔案,且各自有各自的目標。主專案中的 BUILD
檔案可以使用 WORKSPACE
檔案中的名稱,依附這些外部目標。
舉例來說,假設系統中有兩個專案:
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
如果 project1
想要依附在 /home/user/project2/BUILD
中定義的目標 :foo
,可指定在 /home/user/project2
中找到名為 project2
的存放區。則 /home/user/project1/BUILD
中的目標可能會依附於 @project2//:foo
。
WORKSPACE
檔案可讓使用者依附來自檔案系統其他部分或從網路下載的目標。其使用的語法與 BUILD
檔案相同,但允許使用不同的一組規則,稱為「存放區規則」 (有時也稱為「工作區規則」)。Bazel 提供幾項內建存放區規則和一組嵌入式 Starlark 存放區規則。使用者也可以編寫自訂存放區規則,利用更複雜的行為。
支援的外部依附元件類型
您可以使用以下幾種基本類型的外部依附元件:
依賴其他 Bazel 專案
如果您想使用第二個 Bazel 專案的目標,可以使用 local_repository
、git_repository
或 http_archive
從本機檔案系統建立符號連結、參照 Git 存放區或下載 Git 存放區 (依序)。
舉例來說,假設您正在處理專案 my-project/
,且想要依附同事專案 coworkers-project/
中的目標。兩個專案都使用 Bazel,因此您可以將同事的專案新增為外部依附元件,然後使用同事在 BUILD 檔案中定義的任何目標。請將以下內容新增到 my_project/WORKSPACE
:
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
如果同事具有目標 //foo:bar
,專案就可以將其稱為 @coworkers_project//foo:bar
。外部專案名稱必須是有效的工作區名稱。
依賴非 Bazel 專案
加上 new_
前置字串的規則 (例如 new_local_repository
),可讓您從不使用 Bazel 的專案建立目標。
舉例來說,假設您正在處理專案 my-project/
,且想要依附同事的專案 coworkers-project/
。同事的專案使用 make
進行建構,但您想依附其中一個產生的 .so 檔案。如要這樣做,請在 my_project/WORKSPACE
中加入以下內容:
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file
會指定要重疊在現有專案的 BUILD
檔案,例如:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
接著,您可以從專案的 BUILD
檔案依附 @coworkers_project//:some-lib
。
視外部套件而定
Maven 構件和存放區
使用規則集 rules_jvm_external
從 Maven 存放區下載構件,並將其設為 Java 依附元件。
擷取依附元件
根據預設,系統會在 bazel build
期間視需要擷取外部依附元件。如要預先擷取一組特定目標所需的依附元件,請使用 bazel fetch
。如要無條件擷取所有外部依附元件,請使用 bazel sync
。由於擷取的存放區會儲存在輸出基礎中,因此每個工作區都會擷取。
遮蔽依附元件
建議您盡可能在專案中採用單一版本政策。這是針對您要編譯的依附元件,並最終納入最終二進位檔案的必要條件。但如果不是這種情況,則可能會產生陰影相依項目。請參考下列情境:
myproject/WORKSPACE
workspace(name = "myproject")
local_repository(
name = "A",
path = "../A",
)
local_repository(
name = "B",
path = "../B",
)
A/WORKSPACE
workspace(name = "A")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "...",
)
B/WORKSPACE
workspace(name = "B")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
依附元件 A
和 B
都依附於 testrunner
,但依附於不同的 testrunner
版本。這些測試執行器在 myproject
中不應有任何衝突,但由於名稱相同,因此會發生衝突。如要宣告兩個依附元件,請更新 myproject/WORKSPACE:
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner-v1",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "..."
)
http_archive(
name = "testrunner-v2",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
local_repository(
name = "A",
path = "../A",
repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
name = "B",
path = "../B",
repo_mapping = {"@testrunner" : "@testrunner-v2"}
)
這個機制也可以用來彙整鑽石。舉例來說,如果 A
和 B
有相同的依附元件,但以不同名稱呼叫,則這些依附元件可以在 myproject/WORKSPACE 中合併。
透過指令列覆寫存放區
如要透過指令列使用本機存放區覆寫已宣告的存放區,請使用 --override_repository
旗標。使用這個標記可變更外部存放區的內容,而不會變更原始碼。
舉例來說,如要將 @foo
覆寫為本機目錄 /path/to/local/foo
,請傳遞 --override_repository=foo=/path/to/local/foo
標記。
以下列舉幾個用途:
- 偵錯問題。舉例來說,您可以將
http_archive
存放區覆寫為本地目錄,以便更輕鬆地進行變更。 - 供應商。如果您所在環境無法發出網路呼叫,請覆寫以網路為基礎的存放區規則,改為指向本機目錄。
使用 Proxy
Bazel 會從 HTTPS_PROXY
和 HTTP_PROXY
環境變數中挑選 Proxy 位址,並利用這些位址下載 HTTP/HTTPS 檔案 (如有指定)。
支援 IPv6
在僅支援 IPv6 的機器上,Bazel 將能夠下載依附元件,且不會發生任何變更。不過,在雙重堆疊 IPv4/IPv6 機器上,Bazel 會遵循與 Java 相同的慣例:如果已啟用 IPv4,則會優先使用 IPv4。在某些情況下,例如 IPv4 網路無法解析/存取外部位址時,這可能會導致 Network unreachable
例外狀況和建構失敗。在這種情況下,您可以使用 java.net.preferIPv6Addresses=true
系統屬性覆寫 Bazel 的行為,以便優先使用 IPv6。詳細說明:
請使用
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
啟動選項,例如在.bazelrc
檔案中加入下列程式碼:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
如果您執行的 Java 建構目標也需要連上網際網路 (有時需要整合測試),請一併使用
--jvmopt=-Djava.net.preferIPv6Addresses=true
工具旗標,例如在.bazelrc
檔案中加入下列程式碼:build --jvmopt=-Djava.net.preferIPv6Addresses
如果您使用的是 rules_jvm_external,例如為了取得依附元件版本解析,請將
-Djava.net.preferIPv6Addresses=true
新增至COURSIER_OPTS
環境變數,為 Coursier 提供 JVM 選項
遞移依附元件
Bazel 只會讀取 WORKSPACE
檔案中列出的依附元件。如果您的專案 (A
) 依附於另一個專案 (B
),而該專案在其 WORKSPACE
檔案中列出了第三個專案 (C
),請將 B
和 C
同時新增至專案的 WORKSPACE
檔案。這項規定可能會使 WORKSPACE
檔案大小膨脹,但可避免某個程式庫在 1.0 版中加入 C
,而另一個程式庫在 2.0 版中加入 C
。
外部依附元件的快取
根據預設,Bazel 只會在外部依附元件的定義變更時重新下載。定義中參照的檔案 (例如修補程式或 BUILD
檔案) 也會由 bazel 納入考量。
如要強制重新下載,請使用 bazel sync
。
版面配置
外部依附元件會全部下載至輸出基地的 external
子目錄底下的目錄。如果是本機存放區,系統會在該處建立符號連結,而非建立新目錄。如要查看 external
目錄,請執行以下指令:
ls $(bazel info output_base)/external
請注意,執行 bazel clean
實際上並不會刪除外部目錄。如要移除所有外部構件,請使用 bazel clean --expunge
。
離線版本
有時您可能需要或希望以離線方式執行建構作業。對於簡單的用途 (例如搭乘飛機),使用 bazel fetch
或 bazel sync
預先擷取所需的存放區就足夠了;此外,使用 --nofetch
選項,在建構期間可停用擷取其他存放區的功能。
對於真正的離線建構作業,如果需要的檔案是由與 Bazel 不同的實體提供,Bazel 會支援 --distdir
選項。每當存放區規則要求 Bazel 透過 ctx.download
或 ctx.download_and_extract
擷取檔案,並提供所需檔案的雜湊總和時,Bazel 會先查看該選項指定的目錄,找出與提供的第一個網址的基礎名稱相符的檔案,如果雜湊相符,就會使用該本機副本。
Bazel 本身會使用這項技術,從發布構件啟動離線作業。方法是在內部 distdir_tar
中收集所有必要的外部依附元件。
不過,Bazel 允許在存放區規則中執行任意指令,而不會知道這些指令是否呼叫網路。因此,bazel 無法強制將建構作業完全離線。因此,如要測試建構作業是否可在離線狀態下正常運作,就必須封鎖網路,就像 bazel 在其引導測試中所做的那樣。
最佳做法
存放區規則
存放區規則通常應負責:
- 偵測系統設定並將其寫入檔案。
- 尋找系統上的其他位置資源。
- 從網址下載資源。
- 將 BUILD 檔案產生或符號連結到外部存放區目錄中。
盡量避免使用 repository_ctx.execute
。舉例來說,如果使用非 Bazel C++ 程式庫,且該程式庫使用 Make 進行建構,建議您使用 repository_ctx.download()
,然後編寫 BUILD 檔案進行建構,而不要執行 ctx.execute(["make"])
。
請優先使用 http_archive
而非 git_repository
和 new_git_repository
。原因如下:
- Git 存放區規則會依賴系統
git(1)
,而 HTTP 下載器則會建構至 Bazel,且沒有系統依附元件。 http_archive
支援將urls
清單做為鏡像,而git_repository
僅支援單一remote
。http_archive
可搭配存放區快取使用,但無法搭配git_repository
使用。詳情請參閱 #5116。
請勿使用 bind()
。請參閱「考慮移除 bind」,深入探討 bind 的問題和替代方案。