目錄
套件
package(default_deprecation, default_package_metadata, default_testonly, default_visibility, features)
這個函式會宣告適用於套件中所有規則的中繼資料。在套件 (BUILD 檔案) 中最多使用一次。
對於宣告套用至整個存放區每個規則的中繼資料,請在存放區根目錄的 REPO.bazel
檔案中使用 repo()
函式。repo()
函式使用的引數與 package()
完全相同。
在檔案頂端的所有 load() 陳述式之後,應在規則前面呼叫 package() 函式。
引數
屬性 | 說明 |
---|---|
default_applicable_licenses |
|
default_visibility |
標籤清單;預設為 這個套件中規則的預設瀏覽權限。 除非規則的 |
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
屬性中參照標籤。
套件群組主要用於控管瀏覽權限。您可以從原始碼樹狀結構中的每個套件參照公開可見的目標。不公開可見的目標只能在自身套件 (而非子套件) 中參照。在這類極端之間,目標可能會允許存取自身的套件,以及一或多個套件群組描述的任何套件。如需瀏覽權限系統的詳細說明,請參閱瀏覽權限屬性。
如果特定套件與 packages
屬性相符,或已包含在 includes
屬性中提及的其他套件群組中,系統就會將該套件視為位於群組中。
就技術上來說,套件群組是目標,但並非由規則建立,本身也沒有任何瀏覽權限保護功能。
引數
屬性 | 說明 |
---|---|
name |
名稱;必填 這個目標的專屬名稱。 |
packages |
字串清單;預設為 零或多個套件規格的清單。 每個套件規格字串都可以使用下列其中一種格式:
此外,前兩種套件規格也可能加上 套件群組包含任何套件,且該套件至少與其中一個正版規格相符,且完全沒有排除規格。例如, 除了公開瀏覽權限外,您無法直接指定目前存放區以外的套件。 如果缺少這項屬性,就等同於將其設為空白清單,這與將這項屬性設為只包含 注意:在 Bazel 6.0 之前, 注意:在 Bazel 6.0 之前,如果這項屬性經序列化為 |
includes |
標籤清單;預設為 此項目包含的其他套件群組。 此屬性中的標籤必須參照其他套件群組。參照的套件群組中的套件會隸屬於這個套件群組。這是遞移性。如果套件群組 請注意,與否定的套件規格搭配使用時,系統會先分別計算每個群組的套件組合,然後再聯集結果。也就是說,在一個群組中否定的規格,就不會影響另一個群組中的規格。 |
示例
下列 package_group
宣告會指定名為「熱帶」的套件群組,其中含有熱帶水果。
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/
是子套件),foo/*.txt
會比對foo/
目錄中的每個檔案 foo/a*.htm*
會比對foo/
目錄中所有開頭為a
的檔案,然後會有任意字串 (可以是空白),然後含有.htm
,且結尾是任意字串 (除非foo/
是子套件);例如foo/axx.htm
和foo/a.html
或foo/axxx.html
。foo/*
會比對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。 - Globs 可比對子目錄中的檔案。此外,子目錄名稱可以使用萬用字元。不過...
-
標籤不能超過套件邊界,而且 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
不會。 此外,隱藏目錄也是如此。隱藏的目錄可能包含做為輸入內容的必要檔案,這類檔案可能會增加不必要的大量拼湊檔案和記憶體用量。如要排除隱藏的目錄,請將這類目錄加入「排除」清單引數。 -
「**」萬用字元具有一個角大小寫:模式
"**"
與套件的目錄路徑不符。也就是說,glob(["**"], exclude_directories = 0)
會嚴格比對所有檔案和目錄,並嚴格比對目前套件目錄下的所有檔案和目錄 (但當然不會進入子套件的目錄,請參閱之前的注意事項)。
一般來說,您應嘗試提供適當的副檔名 (例如 *.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", ], ... )
將所有 txt 檔案加入目錄 test 資料 (Experimental.txt 除外)。 請注意,系統不會納入 testdata 子目錄中的檔案。如果您想納入這些檔案,請使用遞迴 glob (**)。
sh_test( name = "mytest", srcs = ["mytest.sh"], data = glob( ["testdata/*.txt"], exclude = ["testdata/experimental.txt"], ), )
遞迴 Glob 範例
確保測試依附於 testdata 目錄及其任何子目錄及其子目錄,依此類推。系統會忽略含有 BUILD 檔案的子目錄。(請參閱上述限制和注意事項)。
sh_test( name = "mytest", srcs = ["mytest.sh"], data = glob(["testdata/**/*.txt"]), )
建立從這個目錄中所有 Java 檔案以及所有子目錄建構的程式庫,但路徑包含已命名的目錄除外。請盡可能避免使用這個模式,因為這可以減少建構累加性,進而增加建構時間。
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"] }) )
這麼做會將一般標籤清單指派作業替換為 select
呼叫 (將設定條件對應至相符值),藉此設定 sh_binary
的 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 的「子套件」模組,而非直接呼叫這個函式。