本頁面說明如何建立存放區規則,並提供詳細資料範例。
外部存放區是只能在 WORKSPACE
檔案中使用的規則,可在 Bazel 載入階段啟用非密封作業。每個外部存放區規則都會建立專屬的工作區,並包含專屬的 BUILD
檔案和構件。這些程式庫可用於依附第三方程式庫 (例如 Maven 封裝程式庫),也可產生專門執行 Bazel 主機的專用 BUILD
檔案。
建立存放區規則
在 .bzl
檔案中,使用 repository_rule 函式建立新的存放區規則,並將其儲存在全域變數中。
自訂存放區規則的使用方式與原生存放區規則相同。這類變數具有必要的 name
屬性,而建構檔案中顯示的每個目標都可以稱為 @<name>//package:target
,其中 <name>
是 name
屬性的值。
您明確建構規則,或規則是建構作業的依附元件時,系統就會載入規則。在這種情況下,Bazel 會執行 implementation
函式。這個函式說明如何建立存放區、其內容和 BUILD
檔案。
屬性
屬性是規則引數,會以字典的形式傳遞至 attrs
規則引數。定義存放區規則時,系統會列出屬性及其類型。以下範例將 url
和 sha256
屬性定義為字串:
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_repository
和 new_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_rule
的environ
屬性宣告的任何環境變數值。這些環境變數的值可在指令列上搭配--action_env
標記使用 (但此旗標會使建構作業的每個動作失效)。 - 任何檔案的內容,會傳遞至標籤所參照的
repository_ctx
的read()
、execute()
和類似方法 (例如//mypkg:label.txt
,但不是mypkg/label.txt
) - 執行
bazel sync
時。
repository_rule
有兩個參數可控制重新擷取存放區的時間:
- 如果已設定
configure
標記,系統只會在--configure
參數傳遞至bazel sync
時,重新擷取存放區 (如果未設定屬性,這項指令就不會導致重新擷取) 如果設定
local
標記,除了上述情況外,當 Bazel 伺服器重新啟動,或任何影響儲存庫宣告變更的檔案 (例如WORKSPACE
檔案或其載入的檔案) 發生變更時,也會重新擷取儲存庫,無論變更是否導致儲存庫宣告或其程式碼變更。在這種情況下,系統不會重新擷取非本機存放區。這是因為系統會假設這些存放區與網路通訊,或者可能須支付較高費用。
重新啟動實作函式
如果所要求的依附元件缺少,則在擷取存放區時,實作函式可以重新啟動。在這種情況下,實作函式會停止執行、已解析缺少的依附元件,並在依附元件解析後重新執行該函式。為避免不必要的重啟作業 (這項作業成本高昂,因為可能需要重複存取網路),系統會預先擷取標籤引數,前提是所有標籤引數都能解析為現有檔案。請注意,解析僅在函式執行期間建構的字串或標籤路徑,仍可能會導致重新啟動。
強制重新擷取外部存放區
有時,外部存放區可能會在定義或依附元件未變更的情況下過時。舉例來說,存放區擷取來源可能會追蹤第三方存放區的特定分支,而該分支會提供新的修訂版本。在這種情況下,您可以呼叫 bazel sync
,要求 bazel 以無條件重新擷取所有外部存放區。
此外,部分規則會檢查本機電腦,如果本機電腦已升級,這些規則可能會過時。在這裡,您可以要求 bazel 只重新擷取 repository_rule
定義設有 configure
屬性的外部存放區,並使用 bazel sync --configure
。
範例
C++ 自動設定工具鍊:它會使用存放區規則來尋找本機 C++ 編譯器、環境和 C++ 編譯器支援的標記,藉此自動為 Bazel 建立 C++ 設定檔。
Go 存放區使用多個
repository_rule
來定義使用 Go 規則所需的依附元件清單。rules_jvm_external 預設會建立名為
@maven
的外部存放區,為傳遞依附元件樹狀結構中的每個 Maven 構件產生建構目標。