模組擴充功能

回報問題 查看來源 夜間 7.2 7.1 7.0 6.5 6.4

模組擴充功能可讓使用者讀取輸入資料,藉此擴充模組系統 從依附元件圖的模組中學習,並執行必要的邏輯來解決 最後是呼叫存放區規則來建立存放區。這些擴充功能 具備類似存放區規則的功能,可執行檔案 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.installmaven.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.installmaven.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_depuse_repo
  • 模組擴充功能產生的存放區,可以查看 代管擴充功能的模組,並「加上」該擴充功能產生的所有其他存放區。 相同的模組擴充功能 (使用存放區規則呼叫中指定的名稱,例如 這類名稱)。
    • 這可能會造成衝突。如果模組存放區可以查看 名稱為 foo,擴充功能會產生包含 指定的名稱為 foo,則套用至該擴充功能產生的所有存放區 foo 是指前者。

最佳做法

本節說明編寫擴充功能,確保其遵循最佳做法 易於使用、維護方便,並適合隨時間變化。

將各項副檔名放入個別檔案中

當副檔名位於不同檔案時,即可允許系統載入其中一個擴充功能 其他擴充功能產生的存放區即使您不使用 建議您分別存放至個別檔案,以備不時之需 這是因為擴充功能 ID 是以檔案為基礎,因此將 新增至另一個檔案,稍後會變更您的公用 API 對使用者而言並不相容。

指定作業系統和架構

如果您的擴充功能必須使用作業系統或架構類型, 請務必使用 os_dependent,在擴充功能定義中指定此屬性 和 arch_dependent 布林屬性這可確保 Bazel 能辨識 或是有任何變動時,必須重新評估。

只有根模組應直接影響存放區名稱

請記住,當擴充功能建立存放區時,其會建立在 擴充功能的命名空間也就是說,如果 模組均使用相同的擴充功能,最終建立 名稱。這通常會顯示為模組擴充功能的 tag_class,且具有 name 引數。name

舉例來說,假設根模組 A 依附於 B 模組。兩個模組 依附於 mylang 模組。如果同時呼叫 AB mylang.toolchain(name="foo"),兩者都會嘗試建立一個名為 mylang 模組中的 foo,就會發生錯誤。

如要避免這種情況,您可以移除直接設定存放區名稱的功能。 或僅允許根模組執行此動作您可以允許根模組 因為這一切都沒有依賴,所以 另一個模組產生衝突的名稱