模組擴充功能可讓使用者讀取輸入資料,藉此擴充模組系統 從依附元件圖的模組中學習,並執行必要的邏輯來解決 最後是呼叫存放區規則來建立存放區。這些擴充功能 具備類似存放區規則的功能,可執行檔案 I/O 傳送網路要求等除了其他要素,Bazel 也能用來 與其他套件管理系統互動,同時尊重 透過 Bazel 模組建構的依附元件圖表。
您可以在 .bzl
檔案中定義模組擴充功能,就像存放區規則一樣。這些是
未直接叫用;而每個模組都會指定名為「標記」的資料片段
以便讀取擴充功能Bazel 會執行模組解析作業,再評估
。這個擴充功能可讀取整個
依附關係圖
擴充功能使用情形
擴充功能是由 Bazel 模組代管。如何在
請先在代管擴充功能的模組中新增 bazel_dep
,然後
呼叫 use_extension
內建函式
再納入範圍請參考以下例子:
MODULE.bazel
檔案以使用「maven」您可以使用
rules_jvm_external
模組:
bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
這會將 use_extension
傳回的值繫結至變數,
使用者才能使用 dot-syntax 指定擴充功能的標記。標籤必須緊跟著
標記類別中指定的對應標記類別定義的結構定義,
擴充功能定義:舉例來說,指定
maven.install
和 maven.artifact
標記:
maven.install(artifacts = ["org.junit:junit:4.13.2"])
maven.artifact(group = "com.google.guava",
artifact = "guava",
version = "27.0-jre",
exclusions = ["com.google.j2objc:j2objc-annotations"])
使用 use_repo
指令導入存放區
會將延伸至目前模組的範圍內
use_repo(maven, "maven")
由擴充功能產生的重新產生的是其 API 的一部分。在這個範例中,
「maven」模組擴充功能會承諾產生名為 maven
的存放區。使用
宣告,擴充功能會正確解析標籤,例如
@maven//:org_junit_junit
:指向「maven」產生的存放區
。
擴充功能定義
您可以採用類似存放區規則的方式定義模組擴充功能,方法是使用
module_extension
函式。不過
存放區規則有很多屬性
tag_class
,每個變數都有多種
屬性。標記類別會定義這項擴充功能所用標記的結構定義。適用對象
例如「maven」上方的副檔名可以定義如下:
# @rules_jvm_external//:extensions.bzl
_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
maven = module_extension(
implementation = _maven_impl,
tag_classes = {"install": _install, "artifact": _artifact},
)
這些宣告顯示 maven.install
和 maven.artifact
標記可
指定的屬性。
模組擴充功能的實作函式與存放區相似
但會取得 module_ctx
物件
,可使用擴充功能和所有相關標記存取所有模組。
接著,實作函式會呼叫存放區規則來產生存放區。
# @rules_jvm_external//:extensions.bzl
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") # a repo rule
def _maven_impl(ctx):
# This is a fake implementation for demonstration purposes only
# collect artifacts from across the dependency graph
artifacts = []
for mod in ctx.modules:
for install in mod.tags.install:
artifacts += install.artifacts
artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]
# call out to the coursier CLI tool to resolve dependencies
output = ctx.execute(["coursier", "resolve", artifacts])
repo_attrs = _process_coursier_output(output)
# call repo rules to generate repos
for attrs in repo_attrs:
http_file(**attrs)
_generate_hub_repo(name = "maven", repo_attrs)
擴充功能身分
模組擴充功能可透過名稱和顯示的 .bzl
檔案來識別
呼叫 use_extension
在以下範例中,擴充功能 maven
是以 .bzl
檔案 @rules_jvm_external//:extension.bzl
識別
名稱 maven
:
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
從其他 .bzl
檔案重新匯出擴充功能會取得新的識別資訊
如果兩種版本的擴充功能都用於遞移模組圖表中
那將另行評估,且只會看到與廣告素材相關的
與該身分相關的資訊
身為擴充功能的作者,請確保使用者只會將您的
從單一 .bzl
檔案匯入模組擴充功能
存放區名稱和瀏覽權限
擴充功能產生的回覆會採用 module_repo_canonical_name+extension_name+repo_name
形式的標準名稱。請注意,標準名稱
格式並非您應依賴的 API,格式隨時可能變更。
這個命名政策代表每個擴充功能都有自己的「存放區命名空間」;二
不同的擴充功能可以定義名稱相同的存放區,而不會有風險
的任何衝突。這也代表 repository_ctx.name
會回報標準名稱
,這與存放區規則中指定的名稱「不同」
呼叫。
將模組擴充功能產生的存放區納入考量 幾項存放區瀏覽權限規則
- Bazel 模組存放區可查看所有
MODULE.bazel
檔案導入的存放區 透過bazel_dep
和use_repo
。 - 模組擴充功能產生的存放區,可以查看
代管擴充功能的模組,並「加上」該擴充功能產生的所有其他存放區。
相同的模組擴充功能 (使用存放區規則呼叫中指定的名稱,例如
這類名稱)。
- 這可能會造成衝突。如果模組存放區可以查看
名稱為
foo
,擴充功能會產生包含 指定的名稱為foo
,則套用至該擴充功能產生的所有存放區foo
是指前者。
- 這可能會造成衝突。如果模組存放區可以查看
名稱為
最佳做法
本節說明編寫擴充功能,確保其遵循最佳做法 易於使用、維護方便,並適合隨時間變化。
將各項副檔名放入個別檔案中
當副檔名位於不同檔案時,即可允許系統載入一個擴充功能 其他擴充功能產生的存放區即使您不使用 建議您分別存放至個別檔案,以備不時之需 這是因為擴充功能 ID 是以檔案為基礎,因此將 新增至另一個檔案,稍後會變更您的公用 API 對使用者而言並不相容。
指定可重現性
如果擴充功能一律為相同的輸入定義相同的存放區
(擴充功能標記、所讀取的檔案等) 以及不必依賴
任何未保護的下載內容
檢查碼,考慮傳回
extension_metadata
至
reproducible = True
。這可讓 Bazel 在寫入到
檔案。
指定作業系統和架構
如果您的擴充功能必須使用作業系統或架構類型,
請務必使用 os_dependent
,在擴充功能定義中指定此屬性
和 arch_dependent
布林屬性這可確保 Bazel 能辨識
或是有任何變動時,必須重新評估。
這種依賴機制與主機不同,因此較難維護 這個擴充功能的 Lockfile 項目 標示可重現的擴充功能。
只有根模組應直接影響存放區名稱
請記住,當擴充功能建立存放區時,其會建立在
擴充功能的命名空間也就是說,如果
模組均使用相同的擴充功能,最終建立
名稱。這通常會顯示為模組擴充功能的 tag_class
,且具有 name
引數。name
舉例來說,假設根模組 A
依附於 B
模組。兩個模組
依附於 mylang
模組。如果同時呼叫 A
和 B
mylang.toolchain(name="foo")
,兩者都會嘗試建立一個名為
mylang
模組中的 foo
,就會發生錯誤。
如要避免這種情況,您可以移除直接設定存放區名稱的功能。 或僅允許根模組執行此動作您可以允許根模組 因為這一切都沒有依賴,所以 另一個模組產生衝突的名稱