存放區規則

回報問題 查看來源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

本頁說明如何建立存放區規則,並提供範例以瞭解詳情。

外部存放區是只能在 WORKSPACE 檔案中使用的規則,可在 Bazel 的載入階段啟用非密封作業。每個外部存放區規則都會建立自己的工作區,並擁有自己的 BUILD 檔案和構件。這些檔案可用於依附第三方程式庫 (例如 Maven 封裝的程式庫),也能產生主機專屬的 BUILD 檔案,供 Bazel 執行。

建立存放區規則

.bzl 檔案中,使用 repository_rule 函式建立新的存放區規則,並將其儲存在全域變數中。

自訂存放區規則的使用方式與原生存放區規則相同。這個屬性具有強制性的 name 屬性,且建構檔案中的每個目標都可以參照為 @<name>//package:target,其中 <name>name 屬性的值。

當您明確建構規則,或規則是建構作業的依附元件時,系統就會載入規則。在這種情況下,Bazel 會執行 implementation 函式。這個函式說明如何建立存放區、存放區內容和 BUILD 檔案。

屬性

屬性是規則引數,會以字典形式傳遞至 attrs 規則引數。 定義存放區規則時,系統會列出屬性和屬性類型。以下範例會將 urlsha256 屬性定義為字串:

local_repository = repository_rule(
    implementation=_impl,
    local=True,
    attrs={
        "url": attr.string(mandatory=True)
        "sha256": attr.string(mandatory=True)
    }
)

如要在實作函式中存取屬性,請使用 repository_ctx.attr.<attribute_name>

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

所有 repository_rule 都會隱含定義屬性 (就像建構規則一樣)。這兩個隱含屬性分別是 name (與建構規則相同) 和 repo_mapping。存放區規則的名稱可透過 repository_ctx.name 存取。repo_mapping 的意義與原生存放區規則 local_repositorynew_local_repository 相同。

如果屬性名稱開頭為 _,則為私有屬性,使用者無法設定。

實作函式

每個存放區規則都需要 implementation 函式。其中包含規則的實際邏輯,且嚴格在載入階段執行。

這個函式只有一個輸入參數,也就是 repository_ctx。函式會傳回 None,表示規則可根據指定參數重現,或是傳回含有該規則參數組合的字典,將規則轉換為可重現的規則,產生相同的存放區。舉例來說,如果規則追蹤的是 Git 存放區,這表示系統會傳回特定提交 ID,而不是原本指定的浮動分支。

輸入參數 repository_ctx 可用於存取屬性值,以及非密封函式 (尋找二進位檔、執行二進位檔、在存放區中建立檔案,或從網際網路下載檔案)。如需更多背景資訊,請參閱程式庫。範例:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

導入函式何時執行?

當 Bazel 需要該存放區的目標時,就會執行存放區的實作函式,例如另一個存放區中的目標依附於該目標,或是在指令列中提及該目標時。接著,實作函式應會在檔案系統中建立存放區。這稱為「擷取」存放區。

與一般目標不同,如果發生會導致存放區不同的變更,系統不一定會重新擷取存放區。這是因為 Bazel 無法偵測變更,或每次建構時會造成過多負擔 (例如從網路擷取的項目)。因此,只有在下列情況下,系統才會重新擷取存放區:

  • 傳遞至 WORKSPACE 檔案中存放區聲明的參數。
  • 包含存放區實作內容的 Starlark 程式碼。
  • 傳遞至 repository_ctxgetenv() 方法或以 repository_ruleenviron 屬性宣告的任何環境變數值。您可以使用 --repo_env 旗標,在指令列中硬式連線這些環境變數的值。
  • 傳遞至 read()execute() 和類似方法的任何檔案內容 (以標籤參照,例如 //mypkg:label.txt,但不是 mypkg/label.txt)repository_ctx
  • 執行 bazel sync 時。

repository_rule 有兩個參數可控制何時重新擷取存放區:

  • 如果設定 configure 旗標,只有在將 --configure 參數傳遞至 bazel sync 時,系統才會重新擷取存放區 (如果屬性未設定,這項指令不會導致重新擷取)
  • 如果設定了 local 標記,除了上述情況外,當 Bazel 伺服器重新啟動,或任何影響存放區宣告的檔案變更時 (例如 WORKSPACE 檔案或載入的檔案),系統也會重新擷取存放區,無論變更是否導致存放區宣告或程式碼變更。

    在這些情況下,系統不會重新擷取非本機存放區。這是因為系統會假設這些存放區會與網路通訊,或有其他高昂的費用。

重新啟動實作函式

如果實作函式要求的依附元件遺失,系統可以在擷取存放區時重新啟動實作函式。在這種情況下,實作函式的執行作業會停止,系統會解決缺少的依附元件,並在解決依附元件後重新執行函式。為避免不必要的重新啟動 (這很耗費資源,因為可能需要重複網路存取),系統會預先擷取標籤引數,前提是所有標籤引數都能解析為現有檔案。請注意,從僅在函式執行期間建構的字串或標籤解析路徑,可能仍會導致重新啟動。

強制重新擷取外部存放區

有時,外部存放區可能會過時,但其定義或依附元件並未變更。舉例來說,存放區擷取來源時可能會追蹤第三方存放區的特定分支,而該分支上提供新的提交內容。在這種情況下,您可以呼叫 bazel sync,要求 bazel 無條件重新擷取所有外部存放區。

此外,部分規則會檢查本機,如果本機升級,這些規則可能會過時。您可以在這裡要求 bazel 只重新擷取定義設有 repository_rule configure 屬性的外部存放區,請使用 bazel sync --configure

範例

  • C++ 自動設定的工具鍊:使用存放區規則自動建立 Bazel 的 C++ 設定檔,方法是尋找本機 C++ 編譯器、環境和 C++ 編譯器支援的標記。

  • Go 存放區會使用多個 repository_rule 定義使用 Go 規則所需的依附元件清單。

  • rules_jvm_external 預設會建立名為 @maven 的外部存放區,為遞移相依樹狀結構中的每個 Maven 構件產生建構目標。