Bazel 查詢參考資料

回報問題 查看來源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

如需實用案例,請參閱「Bazel 查詢使用指南」。

其他查詢參考資料

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

動作圖形查詢

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

詳情請參閱 aquery 參考資料

可設定的查詢

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

詳情請參閱 cquery 參考資料

範例

使用者會將 bazel query 用於哪些用途?以下列舉一些常見的例子:

為什麼 //foo 樹狀結構會依附於 //bar/baz? 顯示路徑:

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

所有 foo 測試依附的 C++ 程式庫,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)。這是唯一的資料型別。

「集合」和「圖表」是指同一種資料類型,但強調的層面不同,例如:

  • 設定:目標的部分順序並不重要。
  • 圖表:目標的部分順序相當重要。

依附元件圖表中的週期

建構依附元件圖表應為非循環圖。

查詢語言使用的演算法可有效防範週期,不會將週期回報為錯誤。

請注意,載入後階段未設定的目標圖表可能包含已設定目標圖表中不存在的週期。bazel query 系統會偵測設定目標圖形中的週期,並透過 bazel cquerybazel aquery 回報錯誤。

隱含依附元件

除了在 BUILD 檔案中明確定義的建構依附元件之外,Bazel 還會將其他隱含依附元件新增至規則。隱含依附元件可透過下列方式定義:

根據預設,bazel query 在計算查詢結果時會將隱含依附元件納入考量。您可以使用 --[no]implicit_deps 選項變更這項行為。

請注意,由於查詢不會考量設定,因此潛在的工具鍊實作項目不會視為依附元件,只有必要的工具鍊類型會視為依附元件。請參閱工具鍊說明文件

健全性

Bazel 查詢語言運算式會對建構依附元件圖執行運算,而這個圖是由所有 BUILD 檔案中的所有規則宣告隱含定義。請務必瞭解,這個圖表在某種程度上是抽象的,並未完整說明如何執行建構的所有步驟。如要執行建構作業,也需要設定;詳情請參閱使用者指南的「設定」一節。

在 Bazel 查詢語言中評估運算式的結果適用於所有設定,這表示結果可能是保守的過度近似值,而非精確值。如果您使用查詢工具計算建構期間所需的所有來源檔案集,系統可能會回報超出實際需求的檔案,舉例來說,查詢工具會納入支援訊息翻譯功能所需的所有檔案,即使您不打算在建構中使用該功能也是如此。

保留圖表順序

作業會保留從子運算式繼承的任何排序限制。您可以將此視為「偏序守恆定律」。舉例來說,如果您發出查詢,判斷特定目標的依附元件的遞移閉包,產生的集合會依據依附元件圖排序。如果您將該集合篩選為只包含 file 類型的目標,則結果子集中的每對目標之間,都會存在相同的遞移偏序關係,即使原始圖形中沒有任何一對目標直接相連也一樣。(建構依附元件圖表中沒有檔案對檔案的邊緣)。

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

deps(x) union y

最終結果集的順序保證會保留子運算式的所有排序限制,也就是說,x 的所有遞移依附元件都會彼此正確排序。不過,查詢無法保證 y 中的目標順序,也無法保證 deps(x) 中的目標順序與 y 中的目標順序之間的關係 (y 中也屬於 deps(x) 的目標除外)。

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

天空查詢

Sky 查詢是一種查詢模式,可在指定宇宙範圍內運作。

僅適用於 SkyQuery 的特殊函式

Sky Query 模式還提供額外的查詢函式 allrdepsrbuildfiles。這些函式會在整個宇宙範圍內運作 (這也是這些函式不適用於一般查詢的原因)。

指定宇宙範圍

如要啟用 Sky 查詢模式,請傳遞下列兩個旗標:(--universe_scope--infer_universe_scope) 和 --order_output=no--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)"

但該查詢的結果只有 //my:target;根據建構方式,//my:target 的任何反向依附元件都不在宇宙中!--universe_scope另一方面,請考慮:

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 Query 有些優缺點。主要缺點是無法依圖表順序排序輸出內容,因此禁止使用特定輸出格式。優點是提供預設查詢中沒有的兩個運算子 (allrdepsrbuildfiles)。此外,Sky Query 會透過內省 Skyframe 圖表來完成工作,而不是建立新圖表 (這是預設實作方式)。因此在某些情況下,速度會更快,記憶體用量也會較少。

運算式:文法的語法和語意

這是以 EBNF 標記表示的 Bazel 查詢語言文法:

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

變數參照 name 的出現位置若不是在封閉的 let 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 ...) 運算子會計算以空白分隔 (不含半形逗號) 的一組零或多個目標模式的聯集。

搭配 Bourne Shell 的 $(...) 功能,set() 可將查詢結果儲存到一般文字檔、使用其他程式 (例如標準 UNIX Shell 工具) 操控該文字檔,然後將結果重新導入查詢工具做為值,以進行進一步處理。例如:

bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"

在下一個範例中,kind(cc_library, deps(//some_dir/foo:main, 5)) 是透過使用 awk 程式篩選 maxrank 值來計算。

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
somepath(S1 + S2, E),一個可能的結果。
Somepath
somepath(S1 + S2, E),另一個可能的結果。
Allpaths
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/...) 會評估 foo 底下所有 cc_librarycc_binary 等規則目標的集合,而 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/...

不過,這項陳述式需要剖析 BUILD 樹狀結構中的所有 bar 檔案,因此速度緩慢,且容易在不相關的 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 屬性的 //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 後的字元會是半形逗號或 ]

如要在 dict 類型屬性的特定 //foo 依附元件中選取所有規則,請使用keyvalue

attr("some_dict_attribute", "[\{ ]key=value[,\}]", deps(//foo))

如果 //foo 定義為//foo

some_rule(
  name = "foo",
  some_dict_attribute = {
    "key": "value",
  },
)

這是因為 key=value 前的字元會是 { 或空格,而 key=value 後的字元會是半形逗號或 }

規則瀏覽權限篩選:可見

expr ::= visible(expr, expr)

visible(predicate, input) 運算子會對一組目標套用篩選器,並捨棄不符合必要可見度的目標。

第一個引數 predicate 是一組目標,輸出內容中的所有目標都必須對這些目標顯示。visible 運算式會評估包含所有目標 x 的集合,因此 x 是集合 input 的成員,且對於 predicate 中的所有目標 yx 都對 y 可見。例如:

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

會選取套件中所有可依附的目標,且不會違反可見度限制。//bar//foo

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

expr ::= labels(word, expr)

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

舉例來說,labels(srcs, //foo) 會傳回 //foo 規則的 srcs 屬性中顯示的目標集。如果 inputs 集中有多個規則含有 srcs 屬性,系統會傳回這些屬性的聯集。srcs

展開並篩選 test_suites:tests

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 檔案。請注意,這也會傳回包含這些 loaded 檔案的套件 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 檔案的目標

rbuildfiles 運算子的範圍是 --universe_scope 標記指定的宇宙。如果檔案並非直接對應到 BUILD 檔案和 .bzl 檔案,就不會影響結果。舉例來說,即使 BUILD 檔案中明確提及來源檔案 (例如 foo.cc),系統仍會忽略這些檔案。不過,系統會遵守符號連結,因此如果 foo/BUILDbar/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 會產生圖表。 您可以使用 --output 指令列選項,指定 bazel query 顯示這個圖表的內容、格式和順序。

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

部分輸出格式接受其他選項。每個輸出選項的名稱都會加上適用的輸出格式做為前置字串,因此 --graph:factored 只會在 --output=graph 輸出格式使用時生效,如果使用 graph 以外的輸出格式,則不會有任何效果。同樣地,只有在使用 --output=xml 時,才會套用 --xml:line_numbers

結果排序

雖然查詢運算式一律會遵循「圖形順序守恆定律」,但呈現結果時,可以依據依附元件排序,也可以不排序。這不會影響結果集中的目標,也不會影響查詢的計算方式。這只會影響結果列印至 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 proto

QueryResult 通訊協定緩衝區的形式,輸出查詢結果。

--output streamed_proto

列印長度分隔Target通訊協定緩衝區的串流。這項功能有助於(i) 解決通訊協定緩衝區的大小限制,避免目標過多而無法納入單一 QueryResult,或(ii) 在 Bazel 仍在輸出時開始處理。

--output textproto

--output proto 類似,會輸出QueryResult通訊協定緩衝區,但採用文字格式

--output streamed_jsonproto

--output streamed_proto 類似,但會以 ndjson 格式輸出 Target 通訊協定緩衝區串流。

--output minrank --output maxrank

label 類似,minrankmaxrank 輸出格式會列印結果圖中每個目標的標籤,但這些標籤會依等級順序顯示,而非拓撲順序,且前面會加上等級編號。這些結果不受結果排序 --[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 查詢工具做為「BUILD 檔案的 grep」,並瞭解依附元件圖。

地點資訊會因目標種類而異 (請參閱 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 規則可能取決於數百個 Java 來源檔案,而這些檔案都是由同一個 genrule 產生;在因式分解圖中,所有這些檔案都由單一節點表示。您可以使用 --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 的完整語法。

使用外部存放區查詢

如果建構作業依附於外部存放區的規則,查詢結果就會包含這些依附元件。舉例來說,如果 //foo:bar 依附於 @other-repo//baz:lib,則 bazel query 'deps(//foo:bar)' 會將 @other-repo//baz:lib 列為依附元件。