Bazel 查詢參考資料

回報問題 查看來源

本頁面提供使用 bazel query 分析建構依附元件時使用的 Bazel Query Language 參考手冊。同時也說明 bazel query 支援的輸出格式。

如要瞭解實際用途,請參閱 Bazel 查詢使用方法

其他查詢參考資料

除了 query (在載入後目標圖表上執行),Bazel 還包含「動作圖查詢」和「可設定的查詢」

動作圖表查詢

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

詳情請參閱查詢參考資料

可設定的查詢

傳統的 Bazel 查詢會在載入後目標圖表上執行,因此沒有設定及其相關概念的概念。值得注意的是,它無法正確解析選取陳述式,而是會傳回所有可能的選取解析度。不過,可設定的查詢環境 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 和特殊字元 */@.-_:$~[] (星號、正斜線、@、句號、連字號、底線、冒號、美元符號、波浪號、左方括號、右方括號)。不過,未加引號的字詞不能以連字號 - 或星號 * 開頭,但相對 [目標名稱][(/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 查詢語言中的運算式評估為 true 的結果,這意味著它可能是保守的高估值,而不是精確的結果。如果您使用查詢工具計算建構期間所需的所有來源檔案集,回報次數可能會超過實際需求量,這是因為即使您並未在建構中使用該功能,查詢工具仍會包含支援訊息翻譯所需的所有檔案。

保存圖表順序

作業會保留從子運算式沿用的所有排序限制。您可以將此視為「部分排序的守則」。請試想一個範例:如果您發出查詢來判斷特定目標的依附元件遞移性,會根據依附元件圖表排序結果集。如果您進行篩選,設為僅包含 file 種類的目標,即使這些組合實際上並未直接連接原始圖表中,相同的「轉換」部分排序關係也會保留在結果子集中的每組目標之間。(建構依附元件圖表中沒有檔案檔案邊緣)。

不過,雖然所有運算子都會「保留」順序,但部分作業 (例如「集合作業」) 並未「導入」本身的任何排序限制。請參考以下運算式:

deps(x) union y

最終結果集的順序保證會保留其子運算式的所有排序限制,也就是 x 的所有遞移依附元件皆已正確排序。但是,查詢並不保證 y 中的目標順序,或相對於 y 中的目標順序,亦不對 deps(x) 中的目標順序 (y 中也會出現在 deps(x) 中的目標除外)。

造成排序限制的運算子包括:allpathsdepsrdepssomepath 和目標模式萬用字元 package:*dir/...

星空查詢

「Sky Query」是一種查詢模式,可針對指定「宇宙」運作。

僅適用於 SkyQuery 的特殊函式

Sky Query 模式具有額外的查詢函式 allrdepsrbuildfiles,這些函式在整個宇宙範圍內運作 (因此不適合一般查詢)。

指定宇宙範圍

傳遞下列兩個標記 (--universe_scope--infer_universe_scope) 和 --order_output=no 即可啟用 Sky Query 模式。--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

與預設查詢相比,「星空查詢」有一些優缺點。主要的缺點是無法根據圖表順序排序輸出內容,因此不允許特定輸出格式。這種做法的優點是提供了兩個預設查詢無法使用的運算子 (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 中的目標集,同時也是這些目標的圖表。(我們不保證結果節點與其他節點的相對排序)。詳情請參閱「圖表順序」一節。

變數

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 的情況是錯誤。換句話說,頂層查詢運算式不能使用任意變數。

在上述文法產生情境中,nameword 類似,但有額外限制,即是 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 ...) 運算子會計算由零個或更多的集合組合而成的聯集,目標模式以空格分隔 (無逗號)。

與 Bourne 殼層的 $(...) 功能搭配使用,set() 可讓您將單一查詢的結果儲存在一般文字檔案中,使用其他程式 (例如標準 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) 會對直接依附於 //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 和一組終點 Esomepath 會將「部分」任意路徑的節點圖表 (從 S 中的目標到 E 中的目標) 傳回至 E 中的目標;allpaths 會將 S 中任何目標的「所有」路徑上的節點圖表傳回至 E 中的任何目標。

產生的圖表會按照依附元件關係排序。詳情請參閱「圖表順序」一節。

部分路徑
somepath(S1 + S2, E),一筆可能的結果。
部分路徑
somepath(S1 + S2, E),另一個可能的結果。
所有路徑
allpaths(S1 + S2, 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_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 的集合,因此 xinput 組合的成員,而 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 規則)。

清單類型屬性 (例如 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 的集合,因此 xinput 組合的成員,而且 y 也可以看到 predicate x 中的所有目標 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 規則展開為其參照的個別測試組合,再依照 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) 運算子會傳回所需的 Starlark 檔案組合,在集合 x 中載入每個目標的套件。換句話說,每個套件都會傳回從其 BUILD 檔案參照的 .bzl 檔案。

輸出格式

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

使用 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 一樣,此輸出格式會以頂端順序顯示每個目標的標籤,但還會在目標的「種類」標籤之前。

--output minrank --output maxrank

label 一樣,minrankmaxrank 輸出格式會在結果圖表中顯示每個目標的標籤,但是不會按照頂端順序顯示,而是按照排名順序顯示,並在前面加上排名編號。這些方法不受結果排序 --[no]order_results 標記的影響 (請參閱結果排序的相關注意事項)。

此格式有兩個變化版本:minrank 會根據從根節點到該節點之間的最短路徑長度,為每個節點排名。「根」節點 (沒有連入邊緣) 排名為 0,其後續項目的排名為 1,依此類推 (一如往常,從目標指向其必要條件的目標。)

maxrank 會根據節點與根節點之間最長路徑的長度,來排名每個節點。再次提醒,「根節點」的排名為 0,所有其他節點的排名都高於所有先前節點的最高排名 1。

系統會將週期中的所有節點視為相同排名,(大部分圖表都是非循環現象,但循環確實發生,因為 BUILD 檔案包含錯誤的循環)。

這些輸出格式有助於探索圖表的深度。如果用於 deps(x)rdeps(x)allpaths 查詢的結果,排名數字等於該排名中一個節點的最短路徑長度 (搭配 minrank) 或最長路徑 (含 maxrank)。xmaxrank 可用來判斷建構目標所需的最長建構步驟序列。

例如,當指定 --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