Bazel 查詢參考資料

使用 bazel query 分析建構依附元件時,會使用本頁的 Bazel 查詢語言參考手冊。同時也說明 bazel query 支援的輸出格式。

如需實際用途,請參閱 Bazel 查詢操作說明

其他查詢參考

除了在載入後階段目標圖表上執行的 query 外,Bazel 也包含動作圖查詢可設定的查詢

動作圖表查詢

動作圖查詢 (aquery) 會在分析後設定的目標圖上運作,並顯示動作構件及其關係的相關資訊。如果您對已設定的目標圖表產生的動作/構件的屬性感興趣,aquery 便相當實用。舉例來說,實際指令會執行,並顯示其輸入內容、輸出內容和記憶。

詳情請參閱查詢參考資料

可設定的查詢

傳統的 Bazel 查詢會在載入後的階段目標圖上執行,因此沒有設定的概念及相關概念。值得注意的是,系統不會正確解析選取陳述式,而是會傳回所有可能的選取解析度。不過,可設定的查詢環境 cquery 可正確處理設定,但無法提供這項原始查詢的所有功能。

詳情請參閱 cquery 參考資料

範例

使用者如何使用 bazel query?常見的例子如下:

為什麼 //foo 樹狀結構仰賴 //bar/baz?顯示路徑:

somepath(foo/..., //bar/baz:all)

哪些 C++ 程式庫的所有 foo 測試都依賴 foo_bin 目標?

kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))

Tokens:詞法語法

查詢語言中的運算式由下列符記組成:

  • 關鍵字,例如 let。關鍵字是該語言的保留字詞,下文說明每個關鍵字。完整的關鍵字組合如下:

  • 字詞,例如「foo/...」、「.*test rule」或「//bar/baz:all」。如果字元序列是「引號」 (開頭為單引號和結尾為單引號,或開頭並以雙引號 " 結尾),則表示其為字詞。如果字元序列未加引號,系統仍可能將字元序列剖析為字詞。未加引號的字詞是由字母 A-Za-z 字母字元、0-9 數字和特殊字元 */@.-_:$~[] (星號、正斜線、@、句號、連字號、底線、冒號、錢幣符號、波狀、左方括號、右方大括號) 所繪製的字元序列。然而,未加引號的字詞不一定以連字號 - 或星號 * 開頭,即使相對 [目標名稱][(/concepts/labels#target-names) 可能會以這些字元開頭。

    即使目標名稱可以使用這些字元,未加引號的字詞也不得包含加號 + 或等號 =。當您編寫可產生查詢運算式的程式碼時,目標名稱應加上引號。

    編寫根據使用者提供值建構 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)。這是唯一的資料類型。

集合和圖表參照的資料類型相同,但強調資料的不同面向,例如:

  • 設定:目標的部分順序未有趣。
  • 圖表:指定的目標順序特別重要。

依附元件圖表中的週期

建構依附元件圖表應具有循環。

查詢語言使用的演算法適用於循環圖表,但適用於循環週期。系統不會指定處理週期的詳細資料,因此不應仰賴這些資料。

隱性依附元件

除了在 BUILD 檔案中明確定義的建構依附元件之外,Bazel 會將其他「隱含」依附元件新增至規則。例如,每個 Java 規則都以隱含方式依附於 JavaBuilder。隱式依附元件是以開頭為 $ 的屬性建立,且無法在 BUILD 檔案中覆寫。

根據預設的 bazel query,在計算查詢結果時,會將隱含依附元件納入考量。您可以使用 --[no]implicit_deps 選項變更這個行為。請注意,由於查詢不會考慮設定,因此絕對不會考慮潛在的工具鍊。

音效

Bazel 查詢語言運算式會透過建構依附元件圖表運作,也就是由所有 BUILD 檔案中所有規則宣告以隱含方式定義的圖表。請務必瞭解,這張圖表稍微抽象,不構成如何執行建構所有步驟的完整說明。如要執行建構,請一併進行設定,詳情請參閱《使用手冊》的設定一節。

對於所有設定,Bazel 查詢語言評估運算式的結果都是真實的,也就是說,這可能是系統較保守的估計值,而不是完全相同。如果您使用查詢工具來計算建構期間所需的所有來源檔案組合,則回報的結果可能會超過實際所需的數量。舉例來說,查詢工具會納入支援訊息翻譯所需的所有檔案,即使您不打算在建構作業中使用該功能亦然。

系統會保留圖表順序

作業會保留從子運算式繼承的所有排序限制。這可以想成「部分順序守恆定律」。例如,如果您發出查詢來決定特定目標的依附元件轉換關閉情形,結果集會根據依附元件圖表排序。如果您篩選的範圍設為僅包含 file 種類的目標,則結果子集中的各組目標之間都具有相同的遞移部分排序關係,即使這些組合實際上並未與原始圖形中直接關聯也一樣。(建構依附元件圖表中沒有檔案檔案邊緣)。

不過,雖然所有運算子都會「保留」順序,但某些作業 (例如集合作業) 不會「導入」本身的任何排序限制。以這個運算式為例:

deps(x) union y

最終結果集的順序保證會保留子運算式的所有排序限制,也就是說,x 的所有遞移依附元件都已正確排序。然而,該查詢不保證在 y 中的目標順序,也不保證與 y 中的目標相對於 deps(x) 中的目標順序 (除了 y 中剛在 deps(x) 中的目標除外)。

產生排序限制的運算子包括:allpathsdepsrdepssomepath,以及目標模式萬用字元 package:*dir/... 等。

天空查詢

「天空查詢」是一種查詢模式,可根據指定宇宙範圍進行運作。

僅適用於 SkyQuery 的特殊函式

Sky 查詢模式具備 allrdepsrbuildfiles 額外的查詢函式。這些函式會在整個宇宙範圍內運作 (因此對一般查詢沒有意義)。

指定宇宙範圍

系統會傳遞下列兩個標記 (--universe_scope--infer_universe_scope) 和 --order_output=no,來啟用 Sky 查詢模式。--universe_scope=<target_pattern1>,...,<target_patternN> 會指示查詢預先載入目標模式指定目標模式的轉換關閉率,也可以加入累加和減法。接著,這個「範圍」會評估所有查詢。請特別注意,allrdepsrbuildfiles 運算子只會傳回這個範圍的結果。--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 時,您需要自行剖析查詢運算式。

因此,如果查詢運算式使用 allrdepsrbuildfiles 等範圍限定範圍運算子,請務必只在執行所需行為時使用 --infer_universe_scope

相較於預設查詢,Sky 查詢具備了一些優缺點。主要的缺點是它無法根據圖表順序排序輸出內容,因此也禁止特定的輸出格式。此做法的優點在於提供預設查詢中沒有的兩個運算子 (allrdepsrbuildfiles)。此外,Sky Query 顯示的是「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 套件中的目標組合,也是針對這些目標進行的圖形。(無法保證結果節點與其他節點的相對順序)。詳情請參閱圖形順序一節。

Variables

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/...

如果變數參照 name 出現在包含的 let name = ... 運算式以外,就會發生錯誤。換句話說,頂層查詢運算式不能有免費變數。

在上述文法製作中,name 與「字詞」類似,但有額外限制,這是 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 殼層工具) 操控該文字檔案,然後再將結果導入查詢工具做為進一步處理的值。例如:

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 ... ')'

查詢語言可定義多個函式。函式的名稱決定其需要的引數數量和類型。可用的函式如下:

遞移依附元件: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) 運算子會評估引數集 x 在宇宙集 u 遞移期間的反向依附元件。

產生的圖表會根據依附元件關係進行排序。詳情請參閱圖形順序一節。

rdeps 運算子可接受第三個引數,這是用於指定搜尋深度上限的整數文字。產生的圖表只會包含從引數集內任何節點指定深度附近的節點。因此,rdeps(//foo, //common, 1) 會評估 //foo 遞移封閉中直接依附於 //common 的所有節點。(這些數字與 minrank 輸出格式中顯示的排名相對應)。如果省略 depth 參數,搜尋就不會有界限。

所有反向依附元件的遞移性關閉:allrdeps

expr ::= allrdeps(expr)
       | allrdeps(expr, depth)

allrdeps 運算子的運作方式與 rdeps 運算子相同,但「宇宙集」是任何 --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 和終點的集合 Esomepath 會傳回「部分」任意路徑的節點圖表,從 S 的目標到 E 中的目標;allpaths 會將 S 中任何目標的所有路徑節點圖表傳回 E 中的任何目標。

產生的圖表會根據依附元件關係進行排序。詳情請參閱圖表順序一節。

一些路徑
somepath(S1 + S2, E),1 項可能結果。
一些路徑
somepath(S1 + S2, E),另一項可能結果。
所有路徑
allpaths(S1 + S2, E)

目標種類篩選:種類

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_librarycc_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))

將會選取所有允許具有連結共用屬性的 //foo 依附元件 (例如 cc_binary 規則),並明確設為 0,或是完全不設定,但預設值為 0 (例如 cc_binary 規則)。

清單類型屬性 (例如 srcsdata 等) 會轉換為 [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 x 中的所有目標 y 可以看見。y例如:

visible(//foo, //bar:*)

將選取 //bar 套件中 //foo 可以依附的所有目標,而不會違反瀏覽權限限制。

評估類型為標籤的規則屬性:label

expr ::= labels(word, expr)

labels(attr_name, inputs) 運算子會傳回集合 inputs 中部分規則中「label」或「標籤清單」類型的 attr_name 屬性指定的一組目標。

舉例來說,labels(srcs, //foo) 會傳回出現在 //foo 規則 srcs 屬性中的目標組合。如果 inputs 組合中有多個包含 srcs 屬性的規則,會傳回其 srcs 的聯集。

展開及篩選 test_suites:測試

expr ::= tests(expr)

tests(x) 運算子會傳回 x 集中的所有測試規則組合,展開任何 test_suite 規則至其參照的個別測試組合,並依據 tagsize 套用篩選。

根據預設,查詢評估會忽略所有 test_suite 規則中的任何非測試目標。這可透過 --strict_test_suite 選項變更為錯誤。

舉例來說,查詢 kind(test, foo:*) 會列出 foo 套件中的所有 *_testtest_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.bzlBUILD 檔案目標。

rbuildfiles 運算子的範圍是 --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) 運算子會傳回一組在 x 中載入每個目標套件所需的 Starlark 檔案組合。換句話說,每個套件都會傳回從其 BUILD 檔案參照的 .bzl 檔案。

輸出格式

bazel query 會產生圖表。您可以指定 bazel query 透過 --output 指令列選項呈現此圖表的內容、格式和順序。

執行 Sky Query 時,只允許使用與未排序輸出相容的輸出格式。具體來說,禁止使用 graphminrankmaxrank 輸出格式。

部分輸出格式可接受其他選項。每個輸出選項的名稱開頭都須符合其適用的輸出格式,因此 --graph:factored 只有在使用 --output=graph 時才會套用;如果使用 graph 以外的輸出格式,則不會產生任何影響。同樣地,--xml:line_numbers 僅適用於使用 --output=xml 時。

按照結果的順序

雖然查詢運算式一律遵循「圖形順序法」一節,但「呈現」結果可能是依依附元件排序或未排序。這「不會」影響結果集中的目標或查詢的計算方式。這只會影響到 stdout 顯示結果的方式。此外,依附元件順序相等的節點不一定會按字母順序排列。--order_output 旗標可用來控管這個行為。(--[no]order_results 旗標具有 --order_output 旗標的部分功能,已淘汰)。

此標記的預設值為 auto,會按字母順序排序列印結果。不過,使用 somepath(a,b) 時,結果會改以 deps 順序列印。

如果這個標記為 no--outputbuildlabellabel_kindlocationpackageprotoxml 其中之一,系統會按任意順序輸出輸出內容。這通常是最快的選項。不過,當 --outputgraphminrankmaxrank 其中之一時,系統不支援這項功能:使用這些格式時,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 minrank --output maxrank

label 一樣,minrankmaxrank 輸出格式會在結果圖表中列印每個目標的標籤,但這些目標不會依照字母順序顯示,而是按排名順序顯示,前面加上排名編號。這些結果不會受到結果排序 --[no]order_results 標記的影響 (請參閱結果排序的附註)。

這個格式有兩個變體:minrank 會根據根節點間最短的路徑長度來排名每個節點。「根」(沒有傳入邊緣) 的節點排名為 0,後續節點為排名 1,以此類推 (同樣從目標指向目標的邊緣:其仰賴的目標)。

maxrank 會按照根節點間最長路徑的長度,決定每個節點的排名。同樣地,「roots」的排名為 0,所有其他節點的排名高於所有節點前一的排名上限。

系統會將週期內所有節點視為同等排名。(大多數圖表都具有循環性質,但循環之所以會發生,是因為 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 指令進行安裝)。

此輸出格式特別適合用於 allpathsdepsrdeps 查詢,其中結果包含無法以線性形式算繪的路徑組合,例如使用 --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-inputrule-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