標籤是目標的 ID。一般標籤的完整標準形式如下:
@@myrepo//my/app/main:app_binary
標籤的第一部分是存放區名稱 @@myrepo
。雙重 @
語法表示這是工作區中唯一的標準存放區名稱。標籤如果含有標準的 repo 名稱,無論出現在何種情境中,都能明確識別目標。
通常正規的 repo 名稱會是類似 @@rules_java++toolchains+local_jdk
的神秘字串。更常見的是標記具有明顯的存放區名稱,如下所示:
@myrepo//my/app/main:app_binary
唯一的差異在於,Repo 名稱的前置字串為 @
而非兩個。這指的是具有明顯名稱 myrepo
的存放區,根據此標籤出現的結構定義可能有所不同。
在一般情況下,如果標籤參照的是使用該標籤的相同存放區,則可以省略存放區名稱部分。因此,在 @@myrepo
中,第一個標籤通常會寫成
//my/app/main:app_binary
標籤的第二部分是未限定的套件名稱 my/app/main
,也就是相對於存放區根目錄的套件路徑。存放區名稱和未加修飾符的套件名稱會組成完整的套件名稱 @@myrepo//my/app/main
。如果標籤是指稱套件中使用的同一個套件,則可以省略套件名稱 (以及半形冒號)。因此,在 @@myrepo//my/app/main
中,這個標籤可以使用下列任一方式編寫:
app_binary
:app_binary
為遵循慣例,系統會在檔案中忽略冒號,但依規則保留該冒號,但不具其他顯著性。
標籤中冒號後的部分 (app_binary
) 是未限定的目標名稱。如果與套件路徑的最後一個元件相符,則可省略該元件和冒號。因此,這兩個標籤相等:
//my/app/lib
//my/app/lib:lib
套件子目錄中檔案目標的名稱,是相對於套件根目錄 (包含 BUILD
檔案的目錄) 的檔案路徑。因此,這個檔案位於存放區的 my/app/main/testdata
子目錄中:
//my/app/main:testdata/input.txt
//my/app
和 @@some_repo//my/app
這類字串有兩種含義,取決於使用時的情況:當 Bazel 預期標籤時,分別代表 //my/app:app
和 @@some_repo//my/app:app
。不過,當 Bazel 預期套件 (例如在 package_group
規格中) 時,就會參照包含該標籤的套件。
BUILD
檔案常見的錯誤是使用 //my/app
參照套件,或參照套件中的「所有」目標,但這並非實際情況。請注意,它等同於 //my/app:app
,因此會命名目前存放區 my/app
套件中的 app
目標。
不過,建議您在 package_group
或 .bzl
檔案的規格中使用 //my/app
來參照套件,因為該套件會明確說明套件名稱為絕對路徑,且位於工作區的頂層目錄中。
相對標籤無法用於參照其他套件中的目標;在這種情況下,必須一律指定存放區 ID 和套件名稱。舉例來說,如果來源樹狀結構同時包含 my/app
套件和 my/app/testdata
套件 (這兩個目錄都有各自的 BUILD
檔案),後者套件會包含名為 testdepot.zip
的檔案。以下是兩種在 //my/app:BUILD
中參照此檔案的方式 (一個錯誤,一個正確):
錯誤:testdata
是不同的套件,因此您無法使用相對路徑
testdata/testdepot.zip
正確:參照 testdata
及其完整路徑
//my/app/testdata:testdepot.zip
以 @@//
開頭的標籤是主要存放區的參照項目,即使來自外部存放區,仍可正常運作。因此,如果從外部存放區參照 @@//a/b/c
,就會與 //a/b/c
不同。前者會參照主要存放區,後者則尋找外部存放區本身中的 //a/b/c
。在主要存放區中撰寫參照主要存放區中目標的規則時,這一點尤其重要,且會從外部存放區使用。
如要瞭解如何參照目標的不同方式,請參閱目標模式。
標籤的語彙規格
標籤語法不建議使用對殼層具有特殊意義的中繼字元。這有助於避免不慎引用的問題,並可更輕鬆地建構用於操控標籤的工具和指令碼,例如 Bazel 查詢語言。
以下是允許的目標名稱詳細資料。
目標名稱:package-name:target-name
target-name
是套件中的目標名稱。規則名稱是 BUILD
檔案中規則宣告內 name
屬性的值;檔案名稱則是相對於包含 BUILD
檔案的目錄的路徑名稱。
目標名稱必須完全由 a
到 z
、A
到 Z
、0
到 9
的字元組成,並加上標點符號 !%-@^_"#$&'()*-+,;<=>?[]{|}~/.
。
檔案名稱必須是標準格式的相對路徑名稱,也就是說,檔案名稱的開頭或結尾不得為斜線 (例如 /foo
和 foo/
遭到禁止),也不得使用多個連續斜線做為路徑分隔符 (例如 foo//bar
)。同樣地,系統不允許較高層級的參照 (..
) 和目前的目錄參照 (./
)。
錯誤:請勿使用 ..
參照其他套件中的檔案
正確:使用 //package-name:filename
雖然在檔案目標名稱中使用 /
很常見,但請避免在規則名稱中使用 /
。尤其是使用簡寫形式的標籤時,可能會讓讀者感到困惑。標籤 //foo/bar/wiz
一律是 //foo/bar/wiz:wiz
的簡寫,即使沒有這樣的套件 foo/bar/wiz
也一樣;即使目標存在,也不會參照 //foo:bar/wiz
。
不過,在某些情況下使用斜線會比較方便,甚至有時是必要的。舉例來說,某些規則的名稱必須與主要來源檔案相符,而該檔案可能位於套件的子目錄中。
套件名稱://package-name:target-name
套件的名稱是指包含 BUILD
檔案的目錄名稱,相對於包含的存放區頂層目錄。例如:my/app
。
在技術層面,Bazel 會強制執行以下事項:
- 套件名稱中允許使用的字元為小寫字母
a
到z
、大寫字母A
到Z
、數字0
到9
、字元! \"#$%&'()*+,-.;<=>?@[]^_`{|}
(是的,其中有空格字元!),當然還有正斜線/
(因為這是目錄分隔符)。 - 套件名稱開頭或結尾不得為正斜線字元
/
。 - 套件名稱不得包含子字串
//
。這不合理,對應的目錄路徑會是什麼? - 套件名稱不得包含子字串
/./
或/../
或/.../
等。這項規定是為了避免在路徑字串中使用點字元時,邏輯套件名稱和實際目錄名稱之間產生混淆,因為點字元有其語意意義。
實際上:
- 如果語言的目錄結構對其模組系統具有重要意義 (例如 Java),請務必選擇在該語言中有效的識別項做為目錄名稱。例如,請勿以開頭為數字,並避免使用特殊字元,尤其是底線和連字號。
- 雖然 Bazel 支援工作區根目錄套件 (例如
//:foo
) 中的目標,但最好還是讓該套件保持空白,讓所有有意義的套件都有描述性名稱。
規則
規則會指定輸入和輸出之間的關係,以及建構輸出的步驟。規則可以是許多不同類型 (有時稱為規則類別) 之一,可產生編譯的執行檔和程式庫、測試執行檔和其他支援的輸出內容,如建構百科全書所述。
BUILD
檔案會叫用規則來宣告目標。
在以下範例中,我們會看到使用 cc_binary
規則宣告目標 my_app
。
cc_binary(
name = "my_app",
srcs = ["my_app.cc"],
deps = [
"//absl/base",
"//absl/strings",
],
)
每個規則叫用都有 name
屬性 (必須是有效的目標名稱),可在 BUILD
檔案的套件中宣告目標。
每項規則都有一組屬性;適用於特定規則的屬性,以及每項屬性的意義和語義,都是規則類型的函式;請參閱Build Encyclopedia,瞭解規則和相應屬性的清單。每個屬性都有名稱和類型屬性可有的常見類型包括整數、標籤、標籤清單、字串、字串清單、輸出標籤、輸出標籤清單。並非每個規則都需要指定所有屬性。因此,屬性會形成字典,從鍵 (名稱) 到選用型別值。
許多規則中存在的 srcs
屬性屬於「標籤清單」類型;其值 (如果有的話) 則是標籤清單,每個標籤都是此規則輸入的目標名稱。
在某些情況下,規則類型的名稱會有所不同,但更有趣的是規則產生的檔案名稱,這也是 genrules 的情況。詳情請參閱「一般規則:genrule」。
在其他情況下,名稱很重要:舉例來說,對 *_binary
和 *_test
規則而言,規則名稱會決定建構作業產生的執行檔名稱。
這個以目標為基礎的有向非循環圖稱為「目標圖」或「建構依附元件圖」,也是 Bazel 查詢工具 運作的網域。
目標 | BUILD 檔案 |