目錄
包裹
package(default_deprecation, default_package_metadata, default_testonly, default_visibility, features)
這個函式會宣告套件中每個規則都適用的中繼資料。在套件 (BUILD 檔案) 中最多只能使用一次。
針對會宣告整個存放區中每個規則所套用的中繼資料的對應項目,請在存放區根目錄的 REPO.bazel 檔案中使用 repo() 函式。repo() 函式使用的引數與 package() 完全相同。
請在檔案頂端的所有 load() 陳述式之後,也就是任何規則之前,呼叫 package() 函式。
引數
| 屬性 | 說明 |
|---|---|
default_applicable_licenses |
|
default_visibility |
標籤清單;預設為 這個套件中頂層規則目標和符號巨集的預設可見度,也就是未在符號巨集中宣告的目標和符號巨集。如果目標或巨集指定 如要進一步瞭解這項屬性的語法,請參閱 可見度的說明文件。套件的預設瀏覽權限不適用於 exports_files,該檔案預設為公開。 |
default_deprecation |
字串;預設為 為此套件中的所有規則設定預設
|
default_package_metadata |
標籤清單;預設為 設定中繼資料目標的預設清單,套用至套件中的所有其他目標。這些通常是與 OSS 套件和授權聲明相關的目標。如需範例,請參閱 rules_license。 |
default_testonly |
布林值;預設值為 為本套件中的所有規則設定預設
在 |
features |
清單字串;預設為 設定會影響此 BUILD 檔案語意學的各種標記。 這項功能主要供建構系統工作人員使用,用於標記需要特殊處理的套件。除非建構系統的相關人員明確要求,否則請勿使用此選項。 |
範例
以下宣告會宣告這個套件中的規則僅對套件群組//foo:target 的成員可見。規則中的個別顯示設定聲明 (如有) 會覆寫此規格。package(default_visibility = ["//foo:target"])
package_group
package_group(name, packages, includes)
這個函式會定義一組套件,並將標籤與該組套件建立關聯。標籤可在 visibility 屬性中參照。
套件群組主要用於控管瀏覽權限。公開顯示的目標可從來源樹狀結構中的每個套件參照。私人可見的目標只能在其自身套件 (而非子套件) 中參照。在這些極端情況之間,目標可能會允許存取其自身套件,以及一或多個套件群組所描述的任何套件。如需瀏覽權限系統的詳細說明,請參閱 visibility 屬性。
如果特定套件符合 packages 屬性,或是已包含在 includes 屬性中提及的其他套件群組中,系統就會將該套件視為群組成員。
包裝組群在技術上是目標,但並非由規則建立,本身也不具備任何瀏覽權限保護機制。
引數
| 屬性 | 說明 |
|---|---|
name |
名稱;必填 這個目標的專屬名稱。 |
packages |
字串清單;預設為 零或多個套件規格的清單。 每個套件規格字串可以採用下列任一形式:
此外,前兩種套件規格也可以在開頭加上 套件群組包含至少符合其中一個正面規格,且不符合任何負面規格的任何套件。舉例來說,值 除了公開瀏覽權限之外,您無法直接指定目前存放區以外的套件。 如果缺少這項屬性,就等同於將其設為空白清單,也等同於將其設為只包含 注意:在 Bazel 6.0 之前,規格 注意:在 Bazel 6.0 之前,如果這個屬性以 |
includes |
標籤清單;預設為 這個套件組合中包含的其他套件組合。 這個屬性中的標籤必須參照其他套件群組。系統會將參照的套件群組中的套件視為此套件群組的一部分。這項屬性是傳遞性的,如果套件群組 與否定套件規格搭配使用時,請注意,每個群組的套件組合會先獨立計算,然後再將結果聯集。也就是說,一個群組中的否定規格不會影響另一個群組中的規格。 |
範例
以下 package_group 宣告會指定名為「tropical」的套件群組,其中包含熱帶水果。
package_group(
name = "tropical",
packages = [
"//fruits/mango",
"//fruits/orange",
"//fruits/papaya/...",
],
)
以下宣告會指定虛構應用程式的套件群組:
package_group(
name = "fooapp",
includes = [
":controller",
":model",
":view",
],
)
package_group(
name = "model",
packages = ["//fooapp/database"],
)
package_group(
name = "view",
packages = [
"//fooapp/swingui",
"//fooapp/webui",
],
)
package_group(
name = "controller",
packages = ["//fooapp/algorithm"],
)
exports_files
exports_files([label, ...], visibility, licenses)
exports_files() 會指定屬於這個套件且匯出至其他套件的檔案清單。
套件的 BUILD 檔案只能直接參照屬於其他套件的來源檔案,前提是這些來源檔案必須使用 exports_files() 陳述式明確匯出。進一步瞭解檔案的瀏覽權限。
由於這是舊版行為,因此在標記 --incompatible_no_implicit_file_export 翻轉之前,系統會以預設可見度匯出規則中提及的輸入檔案。不過,您不應依賴這種行為,也應積極避免使用這種行為。
引數
引數是目前套件中的檔案名稱清單。您也可以指定可見度宣告;在這種情況下,檔案會對指定的目標顯示。如果未指定可見度,則所有套件都能看到這些檔案,即使在 package 函式中指定了套件的預設可見度也一樣。您也可以指定授權。
範例
以下範例會匯出 golden.txt,這是 test_data 套件中的文字檔案,方便其他套件使用,例如在測試的 data 屬性中。
# from //test_data/BUILD exports_files(["golden.txt"])
glob
glob(include, exclude=[], exclude_directories=1, allow_empty=True)
Glob 是輔助函式,可找出符合特定路徑模式的所有檔案,並傳回新的可變更且已排序的路徑清單。Glob 只會搜尋自身套件中的檔案,且只會搜尋來源檔案 (而非產生的檔案或其他目標)。
如果檔案的套件相對於路徑與任何 include 模式相符,且不符合任何 exclude 模式,結果就會包含來源檔案的標籤。
include 和 exclude 清單包含相對於目前套件的路徑模式。每個模式可能包含一或多個路徑區段。如同 Unix 路徑的慣例,這些區段會以 / 分隔。模式中的路徑區段會與路徑的區段進行比對。片段可包含 * 萬用字元:這會比對路徑片段中的任何子字串 (甚至是空白子字串),但不包含目錄分隔符 /。這個萬用字元可以在單一路徑區段中重複使用。此外,** 萬用字元可比對零或多個完整路徑片段,但必須宣告為獨立路徑片段。
foo/bar.txt與這個套件中的foo/bar.txt檔案完全相符 (除非foo/是子套件)- 如果檔案結尾為
.txt,foo/*.txt會比對foo/目錄中的每個檔案 (除非foo/是子專案) foo/a*.htm*會比對foo/目錄中以a開頭的每個檔案,接著會比對任意字串 (可為空白),然後比對.htm,最後比對另一個任意字串 (除非foo/是子套件),例如foo/axx.htm和foo/a.html或foo/axxx.htmlfoo/*會比對foo/目錄中的每個檔案 (除非foo/是子包);即使exclude_directories設為 0,也不會比對foo目錄本身foo/**會比對套件第一層子目錄foo/下方每個非子套件子目錄中的每個檔案;如果exclude_directories設為 0,foo目錄本身也會符合模式;在這種情況下,**會視為符合零個路徑區段**/a.txt會比對這個套件目錄和非子包子目錄中的a.txt檔案。- 如果產生路徑中至少有一個目錄名為
bar(例如xxx/bar/yyy/zzz/a.txt或bar/a.txt) (請注意,**也會比對零個區段) 或bar/zzz/a.txt,**/bar/**/*.txt就會比對這個套件的每個非子套件子目錄中的每個.txt檔案 **會比對這個套件的每個非子套件子目錄中的每個檔案foo**/a.txt是無效的模式,因為**必須獨立於區段foo/是無效的模式,因為在/後定義的第二個區段是空字串
如果啟用 exclude_directories 引數 (設為 1),系統會從結果中省略目錄類型檔案 (預設為 1)。
如果 allow_empty 引數設為 False,如果結果是空白清單,glob 函式就會傳回錯誤。
這項功能有幾項重要限制和警告事項:
-
由於
glob()會在 BUILD 檔案評估期間執行,因此glob()只會比對來源樹狀結構中的檔案,絕不會比對產生的檔案。如果您建構的目標需要原始檔案和產生的檔案,則必須將明確的產生檔案清單附加至 glob。請參閱以下範例,其中包含:mylib和:gen_java_srcs。 -
如果規則的名稱與相符的來源檔案相同,規則會「遮蔽」該檔案。
如要瞭解這項功能,請注意
glob()會傳回路徑清單,因此在其他規則屬性 (例如srcs = glob(["*.cc"])) 中使用glob()的效果,就等同於明確列出相符的路徑。舉例來說,如果glob()產生["Foo.java", "bar/Baz.java"],但套件中也有名為「Foo.java」的規則 (雖然 Bazel 會發出警告,但這項操作是允許的),則glob()的使用者會使用「Foo.java」規則 (其輸出內容),而非「Foo.java」檔案。詳情請參閱 GitHub 問題 #10395。 - Glob 可能會比對子目錄中的檔案。子目錄名稱可使用萬用字元。不過...
-
標籤不得跨越套件邊界,且 glob 不符合子套件中的檔案。
舉例來說,如果
x/y是套件 (可為x/y/BUILD或套件路徑中的其他位置),套件x中的 glob 運算式**/*.cc就不會包含x/y/z.cc。也就是說,glob 運算式的結果實際上取決於 BUILD 檔案是否存在。也就是說,如果沒有名為x/y的套件,或已使用 --deleted_packages 標記為已刪除,同樣的 glob 運算式會包含x/y/z.cc。 - 上述限制適用於所有 glob 運算式,不論使用哪個萬用字元皆然。
-
檔案名稱以
.開頭的隱藏檔案,會完全符合**和*通配字元。如果您想使用複合模式比對隱藏的檔案,模式開頭必須是.。舉例來說,*和.*.txt會與.foo.txt相符,但*.txt則不會。隱藏的目錄也會以相同方式進行比對。隱藏的資料夾可能包含不需要做為輸入內容的檔案,並可能增加不必要的 globbed 檔案數量和記憶體消耗量。如要排除隱藏的目錄,請將這些目錄新增至「exclude」清單引數。 -
「**」萬用字元有一個極端情況:模式
"**"不符合套件的目錄路徑。也就是說,glob(["**"], exclude_directories = False)會嚴格地比對目前套件目錄下所有檔案和目錄的傳遞 (但當然不會進入子套件的目錄 - 請參閱前述的相關附註)。
一般來說,您應該嘗試提供適當的副檔名 (例如 *.html),而不是使用裸字元 '*' 做為 glob 模式。更明確的名稱既可自註解,也可確保您不會不小心比對備份檔案或 emacs/vi/... 自動儲存檔案。
編寫建構規則時,您可以列舉 glob 的元素。這可讓您為每個輸入內容產生個別規則,例如請參閱下方的擴充 glob 範例。
Glob 範例
建立 Java 程式庫,該程式庫是使用這個目錄中的所有 Java 檔案,以及 :gen_java_srcs 規則產生的所有檔案所建構而成。
java_library(
name = "mylib",
srcs = glob(["*.java"]) + [":gen_java_srcs"],
deps = "...",
)
genrule(
name = "gen_java_srcs",
outs = [
"Foo.java",
"Bar.java",
],
...
)
除了 experimental.txt 之外,請納入 testdata 目錄中的所有 txt 檔案。請注意,testdata 子目錄中的檔案不會納入。如果您想納入這些檔案,請使用遞迴 glob (**)。
sh_test(
name = "mytest",
srcs = ["mytest.sh"],
data = glob(
["testdata/*.txt"],
exclude = ["testdata/experimental.txt"],
),
)
遞迴 Glob 範例
讓測試依附於 testdata 目錄和任何子目錄 (以及其子目錄等) 中的所有 txt 檔案。系統會忽略包含 BUILD 檔案的子目錄。(請參閱上述限制和注意事項)。
sh_test(
name = "mytest",
srcs = ["mytest.sh"],
data = glob(["testdata/**/*.txt"]),
)
建立程式庫,從這個目錄和所有子目錄中的所有 Java 檔案建立,但路徑包含名為 testing 的目錄除外。盡可能避免使用這種模式,因為這可能會降低建構增量,進而增加建構時間。
java_library(
name = "mylib",
srcs = glob(
["**/*.java"],
exclude = ["**/testing/**"],
),
)
展開的 Glob 範例
在目前目錄中為 *_test.cc 建立個別的 genrule,用於計算檔案中的行數。
# Conveniently, the build language supports list comprehensions.
[genrule(
name = "count_lines_" + f[:-3], # strip ".cc"
srcs = [f],
outs = ["%s-linecount.txt" % f[:-3]],
cmd = "wc -l $< >$@",
) for f in glob(["*_test.cc"])]
如果上述 BUILD 檔案位於 //foo 套件中,且套件包含三個相符的檔案 (a_test.cc、b_test.cc 和 c_test.cc),則執行 bazel query '//foo:all' 會列出所有產生的規則:
$ bazel query '//foo:all' | sort //foo:count_lines_a_test //foo:count_lines_b_test //foo:count_lines_c_test
選取
select(
{conditionA: valuesA, conditionB: valuesB, ...},
no_match_error = "custom message"
)
select() 是輔助函式,可讓規則屬性可設定。它可以取代幾乎所有屬性指派的右側,因此其值取決於指令列 Bazel 標記。舉例來說,您可以使用這個選項來定義特定平台的依附元件,或是根據規則是在「開發人員」模式還是「發布」模式下建構,來嵌入不同的資源。
基本用法如下:
sh_binary(
name = "mytarget",
srcs = select({
":conditionA": ["mytarget_a.sh"],
":conditionB": ["mytarget_b.sh"],
"//conditions:default": ["mytarget_default.sh"]
})
)
這樣一來,您就能透過將 sh_binary 的一般標籤清單指派項目替換為 select 呼叫,讓 srcs 屬性可進行設定,進而將設定條件對應至相符的值。每個條件都是參照 config_setting 或 constraint_value 的標籤,如果目標設定符合預期的值集,就會「相符」。mytarget#srcs 的值隨後會變成與目前叫用相符的標籤清單。
注意:
- 每次呼叫都會選取一個條件。
- 如果有多個條件相符,且其中一個條件是其他條件的專門領域,系統會優先採用專門領域。如果條件 B 與條件 A 具有相同的標記和限制值,且還包含一些額外的標記或限制值,則系統會將條件 B 視為條件 A 的專門化。這也表示專屬解析並非用於建立排序,如以下範例 2 所示。
- 如果有多個條件相符,但其中一個條件並非其他條件的專門化,則 Bazel 會失敗並顯示錯誤訊息,除非所有條件都解析為相同的值。
- 如果沒有其他條件符合,系統會視為特殊的虛擬標籤
//conditions:default相符。如果省略這個條件,則必須符合其他規則,才能避免發生錯誤。 select可嵌入較大的屬性指派。因此,srcs = ["common.sh"] + select({ ":conditionA": ["myrule_a.sh"], ...})和srcs = select({ ":conditionA": ["a.sh"]}) + select({ ":conditionB": ["b.sh"]})都是有效的運算式。select可用於大多數屬性,但並非全部。說明文件中會將不相容的屬性標示為nonconfigurable。子檔案包
subpackages(include, exclude=[], allow_empty=True)
subpackages()是輔助函式,類似於glob(),但會列出子套件,而非檔案和目錄。它使用與glob()相同的路徑模式,可比對目前載入的 BUILD 檔案的直接子項的任何子套件。如需包含和排除模式的詳細說明和範例,請參閱 glob。系統會以排序順序傳回產生的子套件清單,其中包含相對於目前載入套件的路徑,且與
include中指定的模式相符,而非exclude中的模式。範例
以下範例會列出套件
foo/BUILD的所有直接子包# The following BUILD files exist: # foo/BUILD # foo/bar/baz/BUILD # foo/bar/but/bad/BUILD # foo/sub/BUILD # foo/sub/deeper/BUILD # # In foo/BUILD a call to subs1 = subpackages(include = ["**"]) # results in subs1 == ["sub", "bar/baz", "bar/but/bad"] # # 'sub/deeper' is not included because it is a subpackage of 'foo/sub' not of # 'foo' subs2 = subpackages(include = ["bar/*"]) # results in subs2 = ["bar/baz"] # # Since 'bar' is not a subpackage itself, this looks for any subpackages under # all first level subdirectories of 'bar'. subs3 = subpackages(include = ["bar/**"]) # results in subs3 = ["bar/baz", "bar/but/bad"] # # Since bar is not a subpackage itself, this looks for any subpackages which are # (1) under all subdirectories of 'bar' which can be at any level, (2) not a # subpackage of another subpackages. subs4 = subpackages(include = ["sub"]) subs5 = subpackages(include = ["sub/*"]) subs6 = subpackages(include = ["sub/**"]) # results in subs4 and subs6 being ["sub"] # results in subs5 = []. # # In subs4, expression "sub" checks whether 'foo/sub' is a package (i.e. is a # subpackage of 'foo'). # In subs5, "sub/*" looks for subpackages under directory 'foo/sub'. Since # 'foo/sub' is already a subpackage itself, the subdirectories will not be # traversed anymore. # In subs6, 'foo/sub' is a subpackage itself and matches pattern "sub/**", so it # is returned. But the subdirectories of 'foo/sub' will not be traversed # anymore.
一般來說,建議使用者使用 skylib 的「subpackages」模組,而非直接呼叫這個函式。