本頁是使用 bazel query
分析建構依附元件時,用於 Bazel 查詢語言的參考手冊。並說明 bazel query
支援的輸出格式。
如要瞭解實際用途,請參閱 Bazel 查詢使用方法。
其他查詢參考資料
除了在載入後階段目標圖表上執行的 query
,Bazel 還包含動作圖表查詢和可設定查詢。
動作圖表查詢
動作圖表查詢 (aquery
) 會針對已分析的設定目標圖表運作,並提供有關動作、構件及其關係的資訊。當您對設定的目標圖表產生的動作/成果感興趣時,aquery
非常實用。舉例來說,實際指令會執行,以及指令的輸入內容、輸出內容和助詞。
詳情請參閱 aquery 參考資料。
可設定的查詢
傳統的 Bazel 查詢會在載入後目標圖表上執行,因此沒有設定及其相關概念的概念。值得注意的是,它無法正確解析 select 陳述式,而是會傳回所有可能的 select 解析。不過,可設定的查詢環境 cquery
會正確處理設定,但不會提供這項原始查詢的所有功能。
詳情請參閱 cquery 參考資料。
範例
使用者會如何使用 bazel query
?以下列舉一些常見的例子:
為什麼 //foo
樹狀結構會依附於 //bar/baz
?顯示路徑:
somepath(foo/..., //bar/baz:all)
所有 foo
測試都依附於 foo_bin
目標為何?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
符記:詞法語法
查詢語言中的運算式由下列符記組成:
關鍵字,例如
let
。關鍵字是該語言的保留字詞,下文會說明每個關鍵字。完整的關鍵字組合如下:字詞,例如「
foo/...
」、「.*test rule
」或「//bar/baz:all
」。如果字元序列為「引號」(開頭和結尾為單引號 ' 或開頭加上雙引號 ),即為字詞。如果字元序列未加上引號,系統仍可能會將其剖析為字詞。不含引號的字詞是從英文字母 A-Za-z、數字 0-9 和特殊字元*/@.-_:$~[]
(星號、反斜線、小老鼠符號、句號、連字號、底線、冒號、美元符號、波浪號、左方括號、右方括號) 所組成的字元序列。不過,未加引號的字詞不能以連字號-
或*
星號為開頭,但相對目標名稱可能會以這些字元開頭。即使目標名稱允許使用這些字元,不含引號的字詞也不可包含加號
+
或等號=
字元。編寫會產生查詢運算式的程式碼時,應將目標名稱加上引號。在撰寫用來從使用者提供的值建構 Bazel 查詢運算式的指令碼時,必須使用引號「」。
//foo:bar+wiz # WRONG: scanned as //foo:bar + wiz. //foo:bar=wiz # WRONG: scanned as //foo:bar = wiz. "//foo:bar+wiz" # OK. "//foo:bar=wiz" # OK.
請注意,本引號外是其他殼層可能需要的引用,例如:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
關鍵字和運算子 (在引號中) 會視為一般字詞。例如,
some
是關鍵字,但「some」是字詞。foo
和 "foo" 都是字詞。不過,請留意在目標名稱中使用單引號或雙引號。引用一或多個目標名稱時,請只使用一種類型的引號 (單引號或全雙引號皆可)。
以下是 Java 查詢字串的範例:
'a"'a' # WRONG: Error message: unclosed quotation. "a'"a" # WRONG: Error message: unclosed quotation. '"a" + 'a'' # WRONG: Error message: unexpected token 'a' after query expression '"a" + ' "'a' + "a"" # WRONG: Error message: unexpected token 'a' after query expression ''a' + ' "a'a" # OK. 'a"a' # OK. '"a" + "a"' # OK "'a' + 'a'" # OK
我們選擇了這種語法,因此在大多數情況下,都不需要加上引號。不尋常的
".*test rule"
範例需要引號:開頭為句號,且包含空格。引用"cc_library"
並非必要,但不會造成任何傷害。標點符號,例如括號
()
、句號.
和逗號,
。含有標點符號的字詞 (除了上述例外狀況) 必須加上引號。
引用字詞外的空白字元會遭到忽略。
Bazel 查詢語言概念
Bazel 查詢語言是一種運算式,每個運算式都會評估為目標的部分排序集合,或等同於目標的圖表 (DAG)。這是唯一的資料類型。
集合和圖表參照相同資料類型,但需要特別留意不同的面向,例如:
- Set:目標的部分順序不重要。
- 圖表:指定目標的部分順序相當重要。
依附元件圖中的循環
建構依附元件圖表應循環出現。
查詢語言使用的演算法適用於非循環圖,但非常適合用於循環圖。未指定循環的處理方式,因此不應仰賴這種做法。
隱含依附性
除了建構在 BUILD
檔案中明確定義的依附元件之外,Bazel 也會將額外的「隱含」依附元件新增至規則。舉例來說,每個 Java 規則都會間接依附於 JavaBuilder。隱含依附元件是使用開頭為 $
的屬性建立,且無法在 BUILD
檔案中覆寫。
根據預設,bazel query
會在計算查詢結果時考量隱含的依附元件。您可以使用 --[no]implicit_deps
選項變更這項行為。請注意,由於查詢不會考量設定,因此不會考量潛在的工具鏈。
健全性
Bazel 查詢語言運算式會在建構依附元件圖表上執行,這是由所有 BUILD
檔案中所有規則宣告,以隱含方式定義的圖表。請務必瞭解,這張圖表比較抽象,並未完整說明如何執行建構作業的所有步驟。如要執行建構作業,您也需要設定。詳情請參閱使用者指南的「設定」一節。
針對「所有設定」,對 Bazel 查詢語言中的運算式評估為 true 的結果,這意味著它可能是保守的高估值,而不是精確的結果。如果您使用查詢工具計算建構期間所需的所有來源檔案集,回報次數可能會超過實際需求量,這是因為即使您並未在建構中使用該功能,查詢工具仍會包含支援訊息翻譯所需的所有檔案。
關於圖表順序的保留
作業會保留從子運算式沿用的所有排序限制。您可以將這視為「部分順序守恆定律」。請試想一個範例:如果您發出查詢來判斷特定目標的依附元件遞移性,會根據依附元件圖表排序結果集。如果您篩選該集合,只納入 file
類型的目標,則在結果子集的每個目標組合之間,都會維持相同的傳遞部分排序關係,即使這些組合在原始圖中並未實際直接連結也一樣。(建構依附元件圖表中沒有檔案-檔案邊緣)。
不過,雖然所有運算子都會保留順序,但某些運算 (例如集合運算) 並不會引入任何順序限制。請考慮以下運算式:
deps(x) union y
最終結果集的順序保證會保留其子運算式的所有排序限制,也就是說,x
的所有傳遞式依附元件都會以正確的順序排列。但是,查詢並不保證 y
中的目標順序,或相對於 y
中的目標順序,亦不對 deps(x)
中的目標順序 (y
中也會出現在 deps(x)
中的目標除外)。
引入排序限制的運算子包括:allpaths
、deps
、rdeps
、somepath
和目標模式萬用字元 package:*
、dir/...
等
Sky 查詢
「Sky Query」是一種查詢模式,可針對指定「宇宙」運作。
僅適用於 SkyQuery 的特殊函式
Sky 查詢模式提供額外的查詢函式 allrdeps
和 rbuildfiles
。這些函式會在整個 Universe 範圍內運作 (這也是為何不建議用於一般查詢的原因)。
指定宇宙範圍
傳遞下列兩個標記 (--universe_scope
或 --infer_universe_scope
) 和 --order_output=no
即可啟用 Sky Query 模式。--universe_scope=<target_pattern1>,...,<target_patternN>
會指示查詢預先載入目標模式指定目標模式的傳遞關閉,這可以是加法和減法。系統會在這個「範圍」中評估所有查詢。具體來說,allrdeps
和 rbuildfiles
運算子只會傳回這個範圍內的結果。--infer_universe_scope
會告知 Bazel 從查詢運算式推論 --universe_scope
的值。這個推斷值是查詢運算式中的不重複目標模式清單,但這可能不是您想要的結果。例如:
bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"
這個查詢運算式中的不重複目標模式清單為 ["//my:target"]
,因此 Bazel 會將其視為與叫用相同:
bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"
不過,使用 --universe_scope
進行查詢的結果只有 //my:target
;由於 //my:target
的反向依附元件並未在建構中,另一方面,請考慮以下事項:
bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"
這是有意義的查詢叫用,會嘗試在某些目錄下的目標 tests
展開中計算測試目標,這些目錄會間接依賴定義使用特定 .bzl
檔案的目標。此處的 --infer_universe_scope
是便利的,特別是在選擇 --universe_scope
時,必須自行剖析查詢運算式。
因此,如果查詢運算式使用了 allrdeps
和 rbuildfiles
等全域範圍運算子,請務必只在其行為符合您需求時使用 --infer_universe_scope
。
與預設查詢相比,Sky 查詢有幾項優點和缺點。主要的缺點是無法根據圖表順序排序輸出內容,因此不允許特定輸出格式。這種做法的優點是提供了兩個預設查詢無法使用的運算子 (allrdeps
和 rbuildfiles
)。此外,Sky 查詢會透過檢視 Skyframe 圖表來執行工作,而非建立新圖表 (這是預設實作方式)。因此,在某些情況下,它會變得更快,並使用更少的記憶體。
運算式:文法的語法和語意
以下是 Bazel 查詢語言的文法,以 EBNF 標記法表示:
expr ::= word
| let name = expr in expr
| (expr)
| expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
| set(word *)
| word '(' int | word | expr ... ')'
以下各節依序說明這個文法的所有產生過程。
目標模式
expr ::= word
就語法上來說,「目標模式」只是一個字詞。會解讀為 (未排序) 的目標組合。最簡單的目標模式是一種標籤,用於識別單一目標 (檔案或規則)。舉例來說,目標模式 //foo:bar
會評估為包含一個元素的集合,也就是目標 bar
規則。
目標模式可將標籤泛用化,以便在套件和目標中加入萬用字元。舉例來說,foo/...:all
(或僅 foo/...
) 是目標模式,會評估為包含 foo
目錄下方每個套件中所有 規則的集合;bar/baz:all
是目標模式,會評估為包含 bar/baz
套件中所有規則的集合,但不包含其子套件。
同樣地,foo/...:*
是一個目標模式,會以遞迴方式評估 foo
目錄下每個套件中的所有「目標」 (規則「和」檔案);bar/baz:*
會評估為包含 bar/baz
套件中所有目標的集合,而非其子套件。
由於 :*
萬用字會比對檔案和規則,因此在查詢中通常比 :all
更實用。相反地,:all
萬用字元 (在 foo/...
等目標模式中隱含) 通常更適合用於建構。
bazel query
目標模式的運作方式與 bazel build
建構目標相同。詳情請參閱「目標模式」或輸入 bazel help target-syntax
。
目標模式可能會評估為單例模式集 (在標籤的情況下)、包含許多元素的集合 (例如 foo/...
中具有數千個元素) 或空白組合 (如果目標模式符合無目標)。
系統會根據依附元件關係,正確排序目標模式運算式產生的所有節點。因此,foo:*
的結果不僅是套件 foo
中的目標集合,也是這些目標的圖表。(我們無法保證結果節點相對於其他節點的相對順序。)詳情請參閱「圖表順序」一節。
變數
expr ::= let name = expr1 in expr2
| $name
Bazel 查詢語言允許變數定義和參照。評估 let
運算式的結果與 expr2 相同,變數 name 的所有自由出現都會替換為 expr1 的值。
例如,let v = foo/... in allpaths($v, //common) intersect $v
相當於 allpaths(foo/...,//common) intersect foo/...
。
除了內含的 let name = ...
運算式以外,出現變數參照 name
的情況是錯誤。換句話說,頂層查詢運算式不得包含自由變數。
在上述文法產生情境中,name
與 word 類似,但有額外限制,即是 C 程式設計語言中的法律 ID。變數參照的前面必須加上「$」字元。
每個 let
運算式都只能定義單一變數,但您可以為其建立巢狀結構。
目標模式和變數參照都是由單一符記 (一個字詞) 組成,會造成語法模糊不清。不過,由於屬於合法變數名稱的字詞子集與合法目標模式的字詞子集沒有關聯,因此沒有語意模稜兩可。
從技術層面來說,let
運算式不會提高查詢語言的表達性,任何能以該語言表達的任何查詢也能表示,即使沒有該語言查詢,也能表達。但可以提高許多查詢的精簡度,也可能提升查詢評估的效率。
使用括號的運算式
expr ::= (expr)
半形括號可連結子運算式,強制評估順序。帶有括號的運算式會評估為其引數的值。
代數集運算:交集、聯集、設定差異
expr ::= expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
這三個運算子會針對引數計算一般集合運算。每個運算子都有兩種形式:名義形式 (例如 intersect
) 和符號形式 (例如 ^
)。兩種形式都相同,但符號形式的輸入速度較快。(為求清楚,本頁面的其餘部分會使用名詞形式)。
例如:
foo/... except foo/bar/...
會評估符合 foo/...
但不含 foo/bar/...
的目標組合。
您可以編寫相同的查詢:
foo/... - foo/bar/...
intersect
(^
) 和 union
(+
) 作業為可交換 (對稱) 作業;except
(-
) 不對稱。剖析器會將這三個運算子視為左關聯,且優先順序相同,因此建議您使用括號。舉例來說,以下前兩個運算式是相等的,但第三個則不是:
x intersect y union z
(x intersect y) union z
x intersect (y union z)
從外部來源讀取目標:組合
expr ::= set(word *)
set(a b c ...)
運算子會計算一組零或多個目標模式的聯集,並以空白字元 (無逗號) 分隔。
set()
與 Bourne shell 的 $(...)
功能搭配使用時,可透過以下方式儲存單一查詢的結果:使用其他程式 (例如標準 UNIX shell 工具) 操作該文字檔,然後將結果重新導入查詢工具,做為進一步處理的值。例如:
bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"
在下一個範例中,系統會使用 awk
程式篩選 maxrank
值,藉此計算 kind(cc_library, deps(//some_dir/foo:main, 5))
。
bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"
在這些範例中,$(<foo)
是 $(cat foo)
的簡寫,但您也可以使用 cat
以外的殼層指令,例如先前的 awk
指令。
函式
expr ::= word '(' int | word | expr ... ')'
查詢語言定義了幾個函式。函式名稱會決定所需的引數數量和類型。可用的函式如下:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
遞移依附元件: deps
expr ::= deps(expr)
| deps(expr, depth)
deps(x)
運算子會評估由其引數集 x 的遞移關閉後產生的圖表。舉例來說,deps(//foo)
的值是根源於單一節點 foo
的依附元件圖表,包括所有依附元件。deps(foo/...)
的值是依附元件圖表,其根目錄為 foo
目錄下每個套件的所有規則。在這個情況下,「依附元件」僅指規則和檔案目標,因此建立這些目標所需的 BUILD
和 Starlark 檔案並未納入其中。為此,您應該使用 buildfiles
運算子。
產生的圖表會依依附元件關係排序。詳情請參閱「圖表順序」一節。
deps
運算子接受選用的第二個引數,該引數是指定搜尋深度上限的整數常值。因此 deps(foo:*, 0)
會傳回 foo
套件中的所有目標,而 deps(foo:*, 1)
則會進一步納入 foo
套件中任何目標的直接必要條件,deps(foo:*, 2)
則會進一步納入可從 deps(foo:*, 1)
中的節點直接存取的節點,以此類推。(這些數字對應至 minrank
輸出格式中顯示的排名)。如果省略 depth 參數,則搜尋不受限制,會計算先決條件的可遞移過渡關閉。
遞移依附元件的遞移依附元件:rdeps
expr ::= rdeps(expr, expr)
| rdeps(expr, expr, depth)
rdeps(u, x)
運算子會評估宇宙集合 u 的傳遞閉包內,引數集合 x 的反向依附元件。
產生的圖表會依依附元件關係排序。詳情請參閱「圖表順序」一節。
rdeps
運算子可接受選用的第三個引數,也就是指定搜尋深度上限的整數值。在產生的圖表中,節點只會包含與引數集內任何節點相距相距指定深度之間的節點。因此,rdeps(//foo, //common, 1)
會對直接依附於 //common
的遞移性封閉期間//foo
的所有節點進行評估。(這些數字與 minrank
輸出格式中顯示的排名相對應)。如果省略 depth 參數,搜尋範圍就沒有限制。
所有反向依附元件的遞移閉包:allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
allrdeps
運算子的運作方式與 rdeps
運算子相同,唯一差別在於「universe set」是 --universe_scope
標記評估的結果,而非另外指定。因此,如果傳遞 --universe_scope=//foo/...
,則 allrdeps(//bar)
等同於 rdeps(//foo/..., //bar)
。
同一個套件中的直接反向依附元件:same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
same_pkg_direct_rdeps(x)
運算子會評估與引數集目標位於相同套件中的一整組目標,而哪些目標直接依附於該套件。
處理目標的套件:同層級
expr ::= siblings(expr)
siblings(x)
運算子會評估為完整的目標集,這些目標與引數集的目標位於相同套件中。
任意選擇:部分
expr ::= some(expr)
| some(expr, count )
some(x, k)
運算子會從其引數集 x 中任意選取 k 目標,並評估為只包含這些目標的組合。k 是選用參數;如未提供,結果會是只有一個目標的單例模式集。如果引數集 x 的大小小於 k,系統會傳回整個引數集 x。
舉例來說,運算式 some(//foo:main union //bar:baz)
會評估為包含 //foo:main
或 //bar:baz
的單例模式集,但您並未定義該集。運算式 some(//foo:main union //bar:baz, 2)
或 some(//foo:main union //bar:baz, 3)
會同時傳回 //foo:main
和 //bar:baz
。
如果引數是單例模式,則 some
會計算身分函式:some(//foo:main)
等同於 //foo:main
。
如果指定的引數集為空,則在運算式 some(//foo:main intersect //bar:baz)
中會是錯誤。
路徑運算子:somepath、allpaths
expr ::= somepath(expr, expr)
| allpaths(expr, expr)
somepath(S, E)
和 allpaths(S, E)
運算子會計算兩組目標之間的路徑。這兩個查詢都接受兩個引數,一組起點的 S 和一組終點 E。somepath
會傳回某些任意路徑上的節點圖表,從 S 中的目標到 E 中的目標;allpaths
會傳回所有路徑上的節點圖表,從 S 中的任何目標到 E 中的任何目標。
產生的圖表會按照依附元件關係排序。詳情請參閱「圖表順序」一節。
目標類型篩選:kind
expr ::= kind(word, expr)
kind(pattern, input)
運算子會將篩選器套用到一組目標,並捨棄超出預期類型的目標。pattern 參數可指定要比對的目標類型。
舉例來說,下表說明 BUILD
檔案 (適用於套件 p
) 定義的四個目標種類:
程式碼 | 目標 | 種類 |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
Genrule 規則 |
//p:a.in |
來源檔案 | |
//p:a.out |
產生的檔案 | |
//p:BUILD |
來源檔案 |
因此,kind("cc_.* rule", foo/...)
會評估所有 cc_library
、cc_binary
等的組合,foo
底下的規則目標,kind("source file", deps(//foo))
則評估為 //foo
目標依附元件隱含收尾中的所有來源檔案組合。
一般來說,您必須加入 pattern 引數,因為如果沒有引號,許多規則運算式 (例如 source
file
和 .*_test
) 就不會被剖析器視為字詞。
比對 package group
時,結尾為 :all
的目標可能不會產生任何結果。請改用 :all-targets
。
目標名稱篩選:篩選器
expr ::= filter(word, expr)
filter(pattern, input)
運算子會將篩選器套用到一組目標,並捨棄標籤 (絕對格式) 與模式不相符的目標;其評估為部分目標的子集。
第一個引數 pattern 是一個字詞,內含比目標名稱的規則運算式。filter
運算式會評估為包含所有目標 x 的集合,以便 x 成為集合 input 的元素,而 x 的標籤 (以絕對形式,例如 //foo:bar
) 則包含規則運算式 pattern 的 (未錨定) 比對項目。由於所有目標名稱都以 //
開頭,因此可用於取代 ^
規則運算式錨點。
這個運算子通常可提供比 intersect
運算子更快速、更可靠的替代方案。例如,如要查看 //foo:foo
目標的所有 bar
依附元件,一項可能會評估
deps(//foo) intersect //bar/...
不過,這個陳述式需要剖析 bar
樹狀結構中的所有 BUILD
檔案,處理速度會變慢,且容易在不相關的 BUILD
檔案中發生錯誤。替代做法如下:
filter(//bar, deps(//foo))
這個方法會先計算 //foo
依附元件的集合,然後只篩選符合提供模式的目標,也就是名稱含有 //bar
做為子字串的目標。
filter(pattern,
expr)
運算子的另一個常見用法是按照名稱或副檔名篩選特定檔案。例如:
filter("\.cc$", deps(//foo))
將會提供一份清單,列出所有用於建構 //foo
的 .cc
檔案。
規則屬性篩選:attr
expr ::= attr(word, word, expr)
attr(name, pattern, input)
運算子會將篩選器套用至一組目標,並捨棄非規則的目標、未定義屬性 name 的規則目標,或屬性值不符合提供的規則運算式 pattern 的規則目標;它會評估輸入內容的子集。
第一個引數 name 是規則屬性名稱,應與提供的規則運算式模式進行比對。第二個引數 pattern 是屬性值的規則運算式。attr
運算式會評估包含所有目標 x 的集合,使 x 是組合 input 的成員,是具有已定義屬性 name 且屬性值包含與規則運算式 pattern 相符 (未定位) 的規則。如果 name 是選用屬性,且規則未明確指定這項屬性,系統會使用預設屬性值進行比較。例如:
attr(linkshared, 0, deps(//foo))
將會選取可具有 linkshared 屬性 (例如 cc_binary
規則) 的所有 //foo
依附元件,並將其明確設為 0,或是完全不設定,但預設值為 0 (例如 cc_binary
規則)。
清單類型屬性 (例如 srcs
、data
等) 會轉換為 [value<sub>1</sub>, ..., value<sub>n</sub>]
格式的字串,開頭為 [
括號,結尾為 ]
括號,並使用「,
」(半形逗號、空格) 分隔多個值。標籤會以標籤的絕對形式轉換為字串。舉例來說,屬性 deps=[":foo",
"//otherpkg:bar", "wiz"]
會轉換為字串 [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
。方括號一律會出現,因此空白清單會使用字串值 []
進行比對。例如:
attr("srcs", "\[\]", deps(//foo))
會選取 //foo
依附元件中所有具有空白 srcs
屬性的規則,而
attr("data", ".{3,}", deps(//foo))
將會選取 //foo
依附元件中在 data
屬性中指定至少一個值的所有規則 (由於 //
和 :
的關係,每個標籤至少要有 3 個字元)。
如要在清單類型屬性中,選取具有特定 value
的 //foo
依附元件中的所有規則,請使用
attr("tags", "[\[ ]value[,\]]", deps(//foo))
這是因為 value
前方的字元會是 [
或空格,而 value
後方的字元會是逗號或 ]
。
規則瀏覽權限篩選:可見
expr ::= visible(expr, expr)
visible(predicate, input)
運算子會將篩選器套用至一組目標,並捨棄沒有必要顯示度的目標。
第一個引數 predicate 是一組目標,必須能夠看到輸出內容中的所有目標。visible 運算式會評估為包含所有目標 x 的集合,以便 x 成為集合 input 的成員,且 predicate 中的所有目標 y 對 y 皆可見。例如:
visible(//foo, //bar:*)
將會選取 //foo
套件中 //bar
可依附的所有目標,而不會違反瀏覽權限限制。
評估「label」類型的規則屬性
expr ::= labels(word, expr)
labels(attr_name, inputs)
運算子會傳回 inputs 組合中某些規則中,類型為「label」(標籤) 或「label of label」(標籤清單) 的 attr_name 屬性中指定的一組目標。
舉例來說,labels(srcs, //foo)
會傳回 //foo
規則 srcs
屬性中顯示的目標集合。如果 inputs 集合中有多個含有 srcs
屬性的規則,系統會傳回這些 srcs
的聯集。
展開並篩選 test_suites:測試
expr ::= tests(expr)
tests(x)
運算子會傳回 x 集合中的所有測試規則集合,將任何 test_suite
規則展開為其參照的個別測試集合,並套用 tag
和 size
篩選條件。
根據預設,查詢評估會忽略所有 test_suite
規則中的非測試目標。這可以透過 --strict_test_suite
選項變更為錯誤。
舉例來說,查詢 kind(test, foo:*)
會列出 foo
套件中的所有 *_test
和 test_suite
規則。所有結果都是 (根據定義) foo
套件的成員。相反地,查詢 tests(foo:*)
會傳回 bazel test
foo:*
執行的所有個別測試:這可能包括屬於其他套件的測試,這些套件透過 test_suite
規則直接或間接參照。
套件定義檔:buildfiles
expr ::= buildfiles(expr)
buildfiles(x)
運算子會傳回檔案集,這些檔案會定義 x 集合中每個目標的套件;換句話說,每個套件都會傳回其 BUILD
檔案,以及透過 load
參照的任何 .bzl 檔案。請注意,這也會傳回包含這些已 load
檔案的套件 BUILD
檔案。
這個運算子通常用於判斷建構指定目標所需的檔案或套件,通常會與下方的 --output package
選項搭配使用。例如:
bazel query 'buildfiles(deps(//foo))' --output package
會傳回 //foo
間接依附的所有套件組合。
套件定義檔案:rbuildfiles
expr ::= rbuildfiles(word, ...)
rbuildfiles
運算子會採用以半形逗號分隔的路徑片段清單,並傳回以遞迴方式依賴這些路徑片段的 BUILD
檔案集。舉例來說,如果 //foo
是套件,rbuildfiles(foo/BUILD)
就會傳回 //foo:BUILD
目標。如果 foo/BUILD
檔案中包含 load('//bar:file.bzl'...
,則 rbuildfiles(bar/file.bzl)
會傳回 //foo:BUILD
目標,以及任何其他載入 //bar:file.bzl
的 BUILD
檔案目標
--universe_scope
標記指定的宇宙。未直接對應至 BUILD
檔案和 .bzl
檔案的檔案不會影響結果。舉例來說,即使 BUILD
檔案中明確提及來源檔案 (例如 foo.cc
),系統仍會予以忽略。不過,系統會遵循符號連結,因此如果 foo/BUILD
是指向 bar/BUILD
的符號連結,則 rbuildfiles(bar/BUILD)
的結果會包含 //foo:BUILD
。
rbuildfiles
運算子幾乎是 buildfiles
運算子的反函式。不過,這種道德倒置現象在某個方向上更為明顯:rbuildfiles
的輸出內容就像 buildfiles
的輸入內容;前者只會在套件中包含 BUILD
檔案目標,而後者則可能包含這類目標。反之,通訊則較弱。buildfiles
運算子的輸出內容是與所有套件和 對應的目標。特定輸入內容所需的 bzl
檔案。不過,rbuildfiles
運算子的輸入內容並非這些目標,而是與這些目標相對應的路徑片段。
套件定義檔:loadfiles
expr ::= loadfiles(expr)
loadfiles(x)
運算子會傳回所需的 Starlark 檔案組合,在集合 x 中載入每個目標的套件。換句話說,每個套件都會傳回從其 BUILD
檔案參照的 .bzl 檔案。
輸出格式
bazel query
會產生圖表。您可以透過 --output
命令列選項,指定 bazel query
呈現此圖表的內容、格式和排序。
使用 Sky Query 執行時,只能選擇與未排序輸出相容的輸出格式。具體來說,系統禁止使用 graph
、minrank
和 maxrank
輸出格式。
有些輸出格式接受其他選項。每個輸出選項的名稱前面都會加上所適用的輸出格式,因此 --graph:factored
只會在使用 --output=graph
時套用;如果使用 graph
以外的輸出格式,就不會生效。同樣地,--xml:line_numbers
只會在使用 --output=xml
時套用。
根據結果的排序
雖然查詢運算式一律會遵循「法律守恆法」,但結果可透過依依附元件排序或未排序的方式「呈現」結果。這「不會」影響結果集的目標或查詢的計算方式。只會影響結果如何輸出至標準輸出。此外,在依附項目順序中,相等的節點不一定會依字母順序排列。--order_output
旗標可用來控管這項行為。(--[no]order_results
標記含有 --order_output
標記的部分功能,且已淘汰)。
此標記的預設值為 auto
,會以詞幹順序顯示結果。不過,使用 somepath(a,b)
時,結果會改為以 deps
順序顯示。
如果這個旗標為 no
,而 --output
為 build
、label
、label_kind
、location
、package
、proto
或 xml
之一,則輸出內容會以任意順序列印。這通常是最快的選項。不過,如果 --output
是 graph
、minrank
或 maxrank
之一,則不支援此機制。如果採用這些格式,Bazel 一律會依據依附元件順序或排名顯示結果。
如果這個標記為 deps
,Bazel 會以某種拓樸順序 (即先列出依附元件) 列印結果。但是,如果節點沒有按照依附元件順序排序 (因為沒有路徑之間的路徑位於兩者之間沒有路徑),系統可能會以任何順序列印。
如果這個旗標為 full
,Bazel 會以完全確定 (總) 順序列印節點。首先,所有節點會按照字母順序排列。然後,系統會使用清單中的每個節點做為「先後深度搜尋」的起始作業,該搜尋會依照字母順序掃遍至未造訪節點的連出邊緣,並按字母順序掃遍後續節點。最後,節點會以相反的順序列印,也就是與訪問順序相反。
依這個順序列印節點的速度可能較慢,因此請只在確定性很重要的情況下才使用這個標記。
顯示 BUILD 中顯示的目標來源形式
--output build
使用這個選項時,每個目標的表示方式就像是使用 BUILD 語言手寫的一樣。所有變數和函式呼叫 (例如 glob、巨集) 都會展開,這有助於查看 Starlark 巨集的效果。此外,每個有效規則都會回報 generator_name
和/或 generator_function
值,提供評估產生有效規則的巨集名稱。
雖然輸出內容採用與 BUILD
檔案相同的語法,但無法保證會產生有效的 BUILD
檔案。
列印每個目標的標籤
--output label
使用這個選項時,系統會按照拓撲順序 (除非指定 --noorder_results
,請參閱結果排序的附註),在產生的圖表中一行一行的列印每個目標的名稱 (或標籤) 組合。(拓樸排序是指圖形節點會比所有後續節點更早出現。)當然,圖表有許多可能的拓樸排序 (反向後序只是其中一種),但系統不會指定要選擇哪一種。
列印 somepath
查詢的輸出內容時,節點的列印順序即為路徑順序。
注意:在某些情況下,可能會有兩個不同的目標使用同一個標籤。例如,sh_binary
規則及其單一 (隱含) srcs
檔案都可能同時稱為 foo.sh
。如果查詢結果同時包含這兩個目標,輸出內容 (採用 label
格式) 看起來會像是重複項目。使用 label_kind
(請參閱下文) 格式時,兩者之間的差異就會變得明顯:兩個目標名稱相同,但其中一個的類型為 sh_binary rule
,另一個則為 source file
。
列印每個目標的標籤和種類
--output label_kind
就像 label
一樣,這個輸出格式會以拓樸順序,在結果圖中列印每個目標的標籤,但標籤前會加上目標的 kind。
以通訊協定緩衝區格式列印目標
--output proto
將查詢輸出內容列印為 QueryResult
通訊協定緩衝區。
以長度分隔的通訊協定緩衝區格式列印目標
--output streamed_proto
列印長度分隔的 Target
通訊協定緩衝區串流。當 Bazel 仍在輸出時,(i) 要瞭解通訊協定緩衝區的大小限制,或者 (ii) 在 Bazel 仍在輸出時開始處理。QueryResult
以文字前置格式列印目標
--output textproto
與 --output proto
類似,會列印 QueryResult
通訊協定緩衝區,但使用的是文字格式。
以 ndjson 格式列印目標
--output streamed_jsonproto
與 --output streamed_proto
類似,可以列印 Target
通訊協定緩衝區串流,但採用 ndjson 格式。
依排名順序列印每個目標的標籤
--output minrank --output maxrank
和 label
一樣,minrank
和 maxrank
輸出格式會在結果圖表中顯示每個目標的標籤,但是不會按照頂端順序顯示,而是按照排名順序顯示,並在前面加上排名編號。這些項目不會受到結果排序 --[no]order_results
旗標的影響 (請參閱結果排序的相關注意事項)。
此格式有兩個變化版本:minrank
會根據從根節點到該節點之間的最短路徑長度,為每個節點排名。「根」節點 (沒有傳入邊的節點) 的等級為 0,其後繼節點的等級為 1,依此類推 (邊一律從目標指向其必要條件:目標所依賴的目標)。
maxrank
會根據從根節點到該節點的最長路徑長度,為每個節點排序。再次提醒,「根節點」的排名為 0,所有其他節點的排名都高於所有先前節點的最高排名 1。
系統會將週期中的所有節點視為相同排名,(大多數圖表都是無環的,但循環確實會發生,原因在於 BUILD
檔案包含錯誤的循環)。
這些輸出格式可用於瞭解圖表的深度。如果用於 deps(x)
、rdeps(x)
或 allpaths
查詢的結果,則排名數字等於從 x
到該排名中節點的最短 (使用 minrank
) 或最長 (使用 maxrank
) 路徑長度。maxrank
可用來判斷建構目標所需的最長建構步驟序列。
例如,當指定 --output minrank
和 --output maxrank
時,左圖將分別產生右側圖表的輸出內容。
minrank 0 //c:c 1 //b:b 1 //a:a 2 //b:b.cc 2 //a:a.cc |
maxrank 0 //c:c 1 //b:b 2 //a:a 2 //b:b.cc 3 //a:a.cc |
列印每個目標的位置
--output location
與 label_kind
一樣,這個選項會針對結果中的每個目標,列印目標類型和標籤,但會在前面加上描述該目標位置的字串,例如檔案名稱和行號。格式與 grep
的輸出內容類似。因此,可剖析後者的工具 (例如 Emacs 或 vi) 也可以使用查詢輸出內容逐步執行一系列比對,讓 Bazel 查詢工具能夠做為可辨識依附元件的「grep for BUILD 檔案」。
位置資訊會因目標類型而異 (請參閱 kind 運算子)。針對規則,系統會列印規則宣告在 BUILD
檔案中的位置。對於來源檔案,系統會列印實際檔案的第 1 行位置。針對產生的檔案,系統會列印產生檔案的規則位置。(查詢工具沒有足夠的資訊可找出產生的檔案實際位置,而且如果尚未執行建構作業,該檔案可能不存在)。
列印套件組合
--output package
這個選項會列印結果集中某些目標所屬的所有套件名稱。名稱會按照字母順序列印,但排除重複。正式來說,這是從一組標籤 (套件、目標) 到套件的投影。
外部存放區中的套件格式為 @repo//foo/bar
,主存放區中的套件格式為 foo/bar
。
這個輸出選項可與 deps(...)
查詢搭配使用,找出建構指定一組目標時必須檢查的套件組合。
顯示結果圖表
--output graph
這個選項會使查詢結果以熱門的 AT&T GraphViz 格式顯示為引導式圖表。結果通常會儲存至 .png
或 .svg
等檔案。(如果您的工作站上未安裝 dot
程式,您可以使用 sudo apt-get install graphviz
指令安裝)。如需叫用範例,請參閱下方範例。
這個輸出格式特別適合 allpaths
、deps
或 rdeps
查詢,其中的結果包含以線性形式算繪時 (例如 --output label
) 無法輕鬆視覺化的路徑組合。
根據預設,圖表會以「因數」格式呈現。也就是說,拓樸學上等價的節點會合併為單一節點,並附上多個標籤。由於一般結果圖表含有高度重複的模式,因此圖表更簡潔易讀。舉例來說,java_library
規則可能會依賴由同一個 genrule
產生的數百個 Java 來源檔案;在分解圖表中,所有這些檔案都由單一節點代表。您可以使用 --nograph:factored
選項停用這項行為。
--graph:node_limit n
此選項可指定輸出中圖表節點的標籤字串長度上限。過長的標籤將遭到截斷;-1 會停用截斷功能。由於圖表通常列印的因素較多,節點標籤可能會很長。GraphViz 無法處理超過 1024 個字元的標籤,也就是此選項的預設值。除非使用 --output=graph
,否則這個選項沒有作用。
--[no]graph:factored
根據預設,圖表會以因式展開的形式顯示,如上文所述。如果指定 --nograph:factored
,系統在列印圖表時不會考量因素。這使得使用 GraphViz 進行視覺化呈現的做法不切實際,但簡單的格式或許能讓其他工具 (例如 grep) 更容易處理。除非使用 --output=graph
,否則這個選項不會有任何作用。
XML
--output xml
這個選項會導致產生的目標以 XML 格式輸出。輸出內容的開頭為 XML 標頭,如下所示
<?xml version="1.0" encoding="UTF-8"?>
<query version="2">
然後,針對結果圖表中的每個目標,依頂端順序繼續處理 XML 元素 (除非要求未排序的結果),並在結束後結束
</query>
系統會針對 file
類型的目標產生簡單的項目:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
不過,針對規則,XML 會採用結構化方式,並包含規則的所有屬性定義,包括規則 BUILD
檔案中未明確指定值的屬性。
此外,結果還包含 rule-input
和 rule-output
元素,因此您無須知道 srcs
屬性的元素是前向依附元件 (先決條件),而 outs
屬性的內容是後向依附元件 (消費者),即可重建依附元件圖表的拓樸結構。
如果指定 --noimplicit_deps
,系統會抑制隱含依附元件的 rule-input
元素。
<rule class='cc_binary rule' name='//foo:foo' ...>
<list name='srcs'>
<label value='//foo:foo_main.cc'/>
<label value='//foo:bar.cc'/>
...
</list>
<list name='deps'>
<label value='//common:common'/>
<label value='//collections:collections'/>
...
</list>
<list name='data'>
...
</list>
<int name='linkstatic' value='0'/>
<int name='linkshared' value='0'/>
<list name='licenses'/>
<list name='distribs'>
<distribution value="INTERNAL" />
</list>
<rule-input name="//common:common" />
<rule-input name="//collections:collections" />
<rule-input name="//foo:foo_main.cc" />
<rule-input name="//foo:bar.cc" />
...
</rule>
目標的每個 XML 元素都包含 name
屬性和 location
屬性,其值是目標的標籤,如 --output location
所示。
--[no]xml:line_numbers
根據預設,XML 輸出內容中顯示的位置會包含行號。指定 --noxml:line_numbers
時,系統不會列印行號。
--[no]xml:default_values
根據預設,XML 輸出不會包含值是該屬性預設值的規則屬性 (例如,未在 BUILD
檔案中指定值,或已明確提供預設值)。這個選項會使這類屬性值包含在 XML 輸出中。
規則運算式
查詢語言中的規則運算式會使用 Java 規則運算式程式庫,因此您可以使用 java.util.regex.Pattern
的完整語法。
使用外部存放區查詢
如果建構作業取決於外部存放區的規則 (在 WORKSPACE 檔案中定義的規則),查詢結果就會包含這些依附元件。舉例來說,如果 //foo:bar
依附 //external:some-lib
,而 //external:some-lib
已繫結至 @other-repo//baz:lib
,bazel query 'deps(//foo:bar)'
就會將 @other-repo//baz:lib
和 //external:some-lib
列為依附元件。
外部存放區本身不是建構作業的依附元件。也就是說,在上述範例中,//external:other-repo
並非依附元件。不過,您可以將其視為 //external
套件的成員進行查詢,例如:
# Querying over all members of //external returns the repository.
bazel query 'kind(http_archive, //external:*)'
//external:other-repo
# ...but the repository is not a dependency.
bazel query 'kind(http_archive, deps(//foo:bar))'
INFO: Empty results