標籤是目標的 ID。完整標準格式中的典型標籤如下所示:
@@myrepo//my/app/main:app_binary
標籤的第一個部分是存放區名稱 @@myrepo
。雙 @
語法代表這是「標準」存放區名稱,在工作區中是不重複的名稱。含標準存放區名稱的標籤,不論目標內容為何,都能明確識別目標。
標準存放區名稱通常會是類似 @@rules_java~7.1.0~toolchains~local_jdk
的弧形字串。更常見的情況是附有「apparent」存放區名稱的標籤,如下所示:
@myrepo//my/app/main:app_binary
唯一的差別在於存放區名稱的前置字串是 @
,而不是兩個。此項目參照了明顯名稱為 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 Query Language) 的工具和指令碼。
允許指定名稱的確切詳細資料如下。
目標名稱 - 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) 至關重要,請務必選擇該語言中有效 ID 的目錄名稱。例如,請勿以開頭的數字開頭,並避免使用特殊字元,尤其是底線和連字號。
- 雖然 Bazel 支援工作區根套件 (例如
//:foo
) 中的目標,但最好將該套件留空,讓所有有意義的套件都有描述性的名稱。
規則
規則會指定輸入和輸出之間的關係,以及建構輸出的步驟。規則可以是多種不同種類 (有時稱為「規則類別」),會產生已編譯的執行檔和程式庫、測試執行檔,以及「建構信封」中所述的其他支援的輸出內容。
BUILD
檔案會透過叫用規則來宣告「目標」。
在以下範例中,我們會看到使用 cc_binary
規則的目標 my_app
宣告。
cc_binary(
name = "my_app",
srcs = ["my_app.cc"],
deps = [
"//absl/base",
"//absl/strings",
],
)
每個規則叫用都包含一個 name
屬性 (必須是有效的目標名稱),用於宣告 BUILD
檔案套件中的目標。
每項規則都有一組「屬性」;適用特定規則的屬性,以及每個屬性的重要程度和語意是規則種類的功能。如需規則及對應屬性的清單,請參閱建構百科全書。每個屬性都有名稱和類型屬性可以有幾種常見類型,包括整數、標籤、標籤清單、字串、字串清單、輸出標籤、輸出標籤清單。您不需要為每個規則指定所有屬性。因此,屬性形成了字典,從索引鍵 (名稱) 到選用的輸入值。
許多規則中存在的 srcs
屬性具有類型「標籤清單」類型;其值 (如有) 是標籤清單,每個值都是此規則輸入內容的目標名稱。
在某些情況下,規則種類的名稱有些是任意,而更有趣的是規則產生的檔案名稱,這是真正的 Genrules。詳情請參閱一般規則:genrule。
在其他情況下,名稱也有重要意義:以 *_binary
和 *_test
規則為例,規則名稱決定建構產生的執行檔名稱。
這個與目標上方的有向非循環圖稱為「目標圖」或「建構依附元件圖表」,也是 Bazel 查詢工具運作的網域。
目標 | BUILD 檔案 |