Trang này là tài liệu tham khảo cho Ngôn ngữ truy vấn Bazel được dùng khi bạn sử dụng bazel query
để phân tích các phần phụ thuộc của bản dựng. Nó cũng mô tả các định dạng đầu ra mà bazel query
hỗ trợ.
Để biết các trường hợp sử dụng thực tế, hãy xem Hướng dẫn về truy vấn Bazel.
Tài liệu tham khảo về truy vấn bổ sung
Ngoài query
chạy trên biểu đồ mục tiêu giai đoạn tải sau, Bazel còn có truy vấn biểu đồ hành động và truy vấn có thể định cấu hình.
Truy vấn biểu đồ hành động
Truy vấn biểu đồ hành động (aquery
) hoạt động trên Biểu đồ mục tiêu đã định cấu hình sau phân tích và hiển thị thông tin về Hành động, Hiện vật và mối quan hệ của chúng. aquery
sẽ hữu ích khi bạn quan tâm đến các thuộc tính của Hành động/Hiện vật được tạo từ Biểu đồ mục tiêu đã định cấu hình.
Ví dụ: các lệnh thực tế được chạy và đầu vào, đầu ra cũng như các từ gợi nhớ của lệnh.
Để biết thêm chi tiết, hãy xem tài liệu tham khảo về aquery.
Truy vấn có thể thiết lập
Truy vấn Bazel truyền thống chạy trên biểu đồ mục tiêu giai đoạn sau tải và do đó không có khái niệm về cấu hình và các khái niệm liên quan. Đáng chú ý là nó không phân giải chính xác câu lệnh chọn mà thay vào đó trả về tất cả các cách phân giải có thể có của câu lệnh chọn. Tuy nhiên, môi trường truy vấn có thể định cấu hình, cquery
, xử lý đúng các cấu hình nhưng không cung cấp tất cả chức năng của truy vấn ban đầu này.
Để biết thêm chi tiết, hãy xem tài liệu tham khảo về cquery.
Ví dụ
Mọi người dùng bazel query
để làm gì? Sau đây là một số ví dụ tiêu biểu:
Tại sao cây //foo
lại phụ thuộc vào //bar/baz
?
Hiện đường dẫn:
somepath(foo/..., //bar/baz:all)
Tất cả các kiểm thử foo
phụ thuộc vào những thư viện C++ nào mà mục tiêu foo_bin
không phụ thuộc?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
Mã thông báo: Cú pháp từ vựng
Các biểu thức trong ngôn ngữ truy vấn bao gồm các mã thông báo sau:
Từ khoá, chẳng hạn như
let
. Từ khoá là các từ dành riêng của ngôn ngữ và mỗi từ khoá được mô tả bên dưới. Bộ từ khoá hoàn chỉnh là:Từ, chẳng hạn như "
foo/...
" hoặc ".*test rule
" hoặc "//bar/baz:all
". Nếu một chuỗi ký tự được "đặt trong dấu ngoặc kép" (bắt đầu và kết thúc bằng dấu ngoặc đơn ' hoặc bắt đầu và kết thúc bằng dấu ngoặc kép "), thì đó là một từ. Nếu một chuỗi ký tự không nằm trong dấu ngoặc kép, thì chuỗi đó vẫn có thể được phân tích cú pháp dưới dạng một từ. Các từ không được đặt trong dấu ngoặc kép là chuỗi ký tự được lấy từ các ký tự chữ cái A-Za-z, chữ số 0-9 và các ký tự đặc biệt*/@.-_:$~[]
(dấu hoa thị, dấu gạch chéo lên, dấu @, dấu chấm, dấu gạch ngang, dấu gạch dưới, dấu hai chấm, dấu đô la, dấu ngã, dấu ngoặc vuông trái, dấu ngoặc vuông phải). Tuy nhiên, các từ không được đặt trong dấu ngoặc kép không được bắt đầu bằng dấu gạch nối-
hoặc dấu hoa thị*
ngay cả khi tên mục tiêu tương đối có thể bắt đầu bằng các ký tự đó. Theo một quy tắc đặc biệt nhằm đơn giản hoá việc xử lý các nhãn đề cập đến kho lưu trữ bên ngoài, các từ không được trích dẫn bắt đầu bằng@@
có thể chứa các ký tự+
.Các từ không nằm trong dấu ngoặc kép cũng không được chứa dấu cộng
+
hoặc dấu bằng=
, mặc dù những ký tự đó được phép xuất hiện trong tên mục tiêu. Khi viết mã tạo biểu thức truy vấn, bạn nên đặt tên đích trong dấu ngoặc kép.Bạn cần phải trích dẫn khi viết tập lệnh tạo biểu thức truy vấn Bazel từ các giá trị do người dùng cung cấp.
//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.
Xin lưu ý rằng việc trích dẫn này là ngoài mọi việc trích dẫn mà trình bao của bạn có thể yêu cầu, chẳng hạn như:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
Khi được đặt trong dấu ngoặc kép, từ khoá và toán tử sẽ được coi là các từ thông thường. Ví dụ:
some
là một từ khoá nhưng "some" là một từ. Cảfoo
và "foo" đều là từ.Tuy nhiên, hãy cẩn thận khi sử dụng dấu ngoặc đơn hoặc dấu ngoặc kép trong tên mục tiêu. Khi trích dẫn một hoặc nhiều tên mục tiêu, chỉ sử dụng một loại dấu ngoặc kép (tất cả dấu ngoặc đơn hoặc tất cả dấu ngoặc kép).
Sau đây là ví dụ về chuỗi truy vấn 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
Chúng tôi chọn cú pháp này để bạn không cần dùng dấu ngoặc kép trong hầu hết các trường hợp. Ví dụ
".*test rule"
(bất thường) cần có dấu ngoặc kép: ví dụ này bắt đầu bằng dấu chấm và chứa một khoảng trắng. Không cần thiết nhưng không gây hại khi trích dẫn"cc_library"
.Dấu câu, chẳng hạn như dấu ngoặc đơn
()
, dấu chấm.
và dấu phẩy,
. Bạn phải đặt các từ có dấu chấm câu (ngoại trừ các trường hợp ngoại lệ nêu trên) trong dấu ngoặc kép.
Các ký tự khoảng trắng bên ngoài một từ có dấu ngoặc kép sẽ bị bỏ qua.
Các khái niệm về ngôn ngữ truy vấn Bazel
Ngôn ngữ truy vấn Bazel là một ngôn ngữ biểu thức. Mọi biểu thức đều được đánh giá thành một tập hợp đích được sắp xếp một phần hoặc tương đương với một đồ thị (DAG) của các đích. Đây là kiểu dữ liệu duy nhất.
Tập hợp và biểu đồ đề cập đến cùng một kiểu dữ liệu, nhưng nhấn mạnh các khía cạnh khác nhau của kiểu dữ liệu đó, ví dụ:
- Tập hợp: Thứ tự một phần của các mục tiêu không quan trọng.
- Đồ thị: Thứ tự một phần của các mục tiêu là rất quan trọng.
Các chu kỳ trong biểu đồ phần phụ thuộc
Biểu đồ phần phụ thuộc của bản dựng không được có chu kỳ.
Các thuật toán mà ngôn ngữ truy vấn sử dụng được thiết kế để dùng trong đồ thị không chu trình, nhưng có khả năng chống lại các chu trình. Thông tin chi tiết về cách xử lý các chu kỳ không được chỉ định và không nên dựa vào.
Phần phụ thuộc ngầm
Ngoài các phần phụ thuộc của bản dựng được xác định rõ ràng trong các tệp BUILD
, Bazel sẽ thêm các phần phụ thuộc ẩn bổ sung vào các quy tắc. Ví dụ: mọi quy tắc Java đều phụ thuộc ngầm vào JavaBuilder. Các phần phụ thuộc ngầm được thiết lập bằng cách sử dụng các thuộc tính bắt đầu bằng $
và không thể ghi đè các thuộc tính này trong tệp BUILD
.
Theo mặc định, bazel query
sẽ tính đến các phần phụ thuộc ngầm khi tính toán kết quả truy vấn. Bạn có thể thay đổi hành vi này bằng lựa chọn --[no]implicit_deps
. Xin lưu ý rằng vì truy vấn không xem xét các cấu hình, nên không bao giờ xem xét các chuỗi công cụ tiềm năng.
Tính hợp lý
Các biểu thức ngôn ngữ truy vấn Bazel hoạt động trên biểu đồ phần phụ thuộc của bản dựng. Đây là biểu đồ được xác định ngầm định bằng tất cả các khai báo quy tắc trong tất cả các tệp BUILD
. Điều quan trọng là bạn phải hiểu rằng biểu đồ này có phần trừu tượng và không phải là nội dung mô tả đầy đủ về cách thực hiện tất cả các bước của quy trình tạo. Để thực hiện một bản dựng, bạn cũng cần có một cấu hình; hãy xem phần cấu hình trong Hướng dẫn sử dụng để biết thêm thông tin chi tiết.
Kết quả của việc đánh giá một biểu thức trong ngôn ngữ truy vấn Bazel là đúng cho tất cả các cấu hình, tức là kết quả đó có thể là một phép xấp xỉ quá mức bảo thủ và không hoàn toàn chính xác. Nếu bạn sử dụng công cụ truy vấn để tính toán tập hợp tất cả các tệp nguồn cần thiết trong quá trình tạo bản dựng, thì công cụ này có thể báo cáo nhiều tệp hơn mức cần thiết. Ví dụ: công cụ truy vấn sẽ bao gồm tất cả các tệp cần thiết để hỗ trợ dịch thông báo, mặc dù bạn không có ý định sử dụng tính năng đó trong bản dựng của mình.
Về việc duy trì thứ tự đồ thị
Các thao tác sẽ giữ lại mọi ràng buộc về thứ tự được kế thừa từ các biểu thức con. Bạn có thể coi đây là "quy luật bảo toàn thứ tự một phần". Hãy xem xét một ví dụ: nếu bạn đưa ra một truy vấn để xác định bao đóng của các phần phụ thuộc của một mục tiêu cụ thể, thì tập hợp kết quả sẽ được sắp xếp theo biểu đồ phần phụ thuộc. Nếu bạn lọc tập hợp đó để chỉ bao gồm các mục tiêu thuộc loại file
, thì mối quan hệ sắp xếp một phần bắc cầu tương tự sẽ được duy trì giữa mọi cặp mục tiêu trong tập hợp con kết quả – ngay cả khi không có cặp nào trong số này thực sự được kết nối trực tiếp trong biểu đồ ban đầu.
(Không có cạnh tệp-tệp trong biểu đồ phần phụ thuộc của bản dựng).
Tuy nhiên, mặc dù tất cả các toán tử đều giữ nguyên thứ tự, nhưng một số thao tác (chẳng hạn như các thao tác thiết lập) không đưa ra bất kỳ hạn chế nào về thứ tự. Hãy xem xét biểu thức này:
deps(x) union y
Thứ tự của tập hợp kết quả cuối cùng được đảm bảo giữ lại tất cả các ràng buộc về thứ tự của biểu thức con, cụ thể là tất cả các phần phụ thuộc bắc cầu của x
được sắp xếp chính xác với nhau. Tuy nhiên, truy vấn không đảm bảo điều gì về thứ tự của các mục tiêu trong y
, cũng như thứ tự của các mục tiêu trong deps(x)
so với các mục tiêu trong y
(ngoại trừ những mục tiêu trong y
cũng nằm trong deps(x)
).
Các toán tử giới thiệu những ràng buộc về thứ tự bao gồm: allpaths
, deps
, rdeps
, somepath
và các ký tự đại diện cho mẫu mục tiêu package:*
, dir/...
, v.v.
Truy vấn về bầu trời
Sky Query là một chế độ truy vấn hoạt động trong một phạm vi vũ trụ cụ thể.
Các hàm đặc biệt chỉ có trong SkyQuery
Chế độ Sky Query có các hàm truy vấn bổ sung là allrdeps
và rbuildfiles
. Các hàm này hoạt động trên toàn bộ phạm vi vũ trụ (đó là lý do tại sao chúng không có ý nghĩa đối với Truy vấn thông thường).
Chỉ định phạm vi vũ trụ
Chế độ Sky Query được kích hoạt bằng cách truyền 2 cờ sau: (--universe_scope
hoặc --infer_universe_scope
) và --order_output=no
.
--universe_scope=<target_pattern1>,...,<target_patternN>
yêu cầu truy vấn tải trước bao đóng của mẫu mục tiêu do các mẫu mục tiêu chỉ định. Các mẫu này có thể vừa mang tính bổ sung vừa mang tính trừu tượng. Sau đó, tất cả các truy vấn sẽ được đánh giá trong "phạm vi" này. Cụ thể, các toán tử allrdeps
và rbuildfiles
chỉ trả về kết quả trong phạm vi này.
--infer_universe_scope
yêu cầu Bazel suy luận một giá trị cho --universe_scope
từ biểu thức truy vấn. Giá trị được suy luận này là danh sách các mẫu mục tiêu duy nhất trong biểu thức truy vấn, nhưng đây có thể không phải là điều bạn muốn. Ví dụ:
bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"
Danh sách các mẫu mục tiêu duy nhất trong biểu thức truy vấn này là ["//my:target"]
, vì vậy Bazel coi biểu thức này giống như lệnh gọi:
bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"
Nhưng kết quả của truy vấn đó với --universe_scope
chỉ là //my:target
; không có phần phụ thuộc đảo ngược nào của //my:target
trong vũ trụ, theo cấu trúc! Mặt khác, hãy cân nhắc:
bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"
Đây là một lệnh gọi truy vấn có ý nghĩa, đang cố gắng tính toán các mục tiêu kiểm thử trong quá trình mở rộng tests
của các mục tiêu trong một số thư mục phụ thuộc bắc cầu vào các mục tiêu có định nghĩa sử dụng một tệp .bzl
nhất định. Ở đây, --infer_universe_scope
là một tiện ích, đặc biệt là trong trường hợp lựa chọn --universe_scope
sẽ yêu cầu bạn tự phân tích cú pháp biểu thức truy vấn.
Vì vậy, đối với các biểu thức truy vấn sử dụng toán tử có phạm vi toàn cầu như allrdeps
và rbuildfiles
, hãy nhớ chỉ sử dụng --infer_universe_scope
nếu hành vi của toán tử này là hành vi bạn muốn.
Sky Query có một số ưu điểm và nhược điểm so với truy vấn mặc định. Nhược điểm chính là không thể sắp xếp đầu ra theo thứ tự đồ thị, do đó, một số định dạng đầu ra bị cấm. Lợi thế của chế độ này là cung cấp 2 toán tử (allrdeps
và rbuildfiles
) không có trong truy vấn mặc định.
Ngoài ra, Sky Query thực hiện công việc của mình bằng cách xem xét kỹ lưỡng biểu đồ Skyframe, thay vì tạo một biểu đồ mới (đây là những gì mà quá trình triển khai mặc định thực hiện). Do đó, có một số trường hợp mà việc này sẽ nhanh hơn và sử dụng ít bộ nhớ hơn.
Biểu thức: Cú pháp và ngữ nghĩa của ngữ pháp
Đây là ngữ pháp của ngôn ngữ truy vấn Bazel, được biểu thị bằng ký hiệu 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 ... ')'
Các phần sau đây mô tả từng sản phẩm của ngữ pháp này theo thứ tự.
Mẫu mục tiêu
expr ::= word
Về mặt cú pháp, mẫu mục tiêu chỉ là một từ. Đây được hiểu là một tập hợp (không có thứ tự) các mục tiêu. Mẫu mục tiêu đơn giản nhất là nhãn, xác định một mục tiêu duy nhất (tệp hoặc quy tắc). Ví dụ: mẫu mục tiêu //foo:bar
đánh giá thành một tập hợp chứa một phần tử, mục tiêu, quy tắc bar
.
Mẫu mục tiêu khái quát hoá nhãn để bao gồm các ký tự đại diện trên các gói và mục tiêu. Ví dụ: foo/...:all
(hoặc chỉ foo/...
) là một mẫu đích đánh giá thành một tập hợp chứa tất cả quy tắc trong mọi gói một cách đệ quy bên dưới thư mục foo
; bar/baz:all
là một mẫu đích đánh giá thành một tập hợp chứa tất cả các quy tắc trong gói bar/baz
, nhưng không phải các gói con của gói đó.
Tương tự, foo/...:*
là một mẫu mục tiêu đánh giá thành một tập hợp chứa tất cả các mục tiêu (các tệp quy tắc và) trong mọi gói một cách đệ quy bên dưới thư mục foo
; bar/baz:*
đánh giá thành một tập hợp chứa tất cả các mục tiêu trong gói bar/baz
, nhưng không phải các gói con của gói đó.
Vì ký tự đại diện :*
khớp với cả tệp và quy tắc, nên ký tự này thường hữu ích hơn :all
cho các truy vấn. Ngược lại, ký tự đại diện :all
(ngầm trong các mẫu mục tiêu như foo/...
) thường hữu ích hơn cho các bản dựng.
bazel query
target pattern hoạt động giống như bazel build
build target. Để biết thêm thông tin chi tiết, hãy xem Target Patterns (Mẫu mục tiêu) hoặc nhập bazel help target-syntax
.
Mẫu mục tiêu có thể đánh giá thành một tập hợp đơn lẻ (trong trường hợp nhãn), thành một tập hợp chứa nhiều phần tử (như trong trường hợp foo/...
, có hàng nghìn phần tử) hoặc thành tập hợp trống, nếu mẫu mục tiêu không khớp với mục tiêu nào.
Tất cả các nút trong kết quả của biểu thức mẫu mục tiêu đều được sắp xếp chính xác tương ứng với nhau theo mối quan hệ phụ thuộc. Vì vậy, kết quả của foo:*
không chỉ là tập hợp các mục tiêu trong gói foo
, mà còn là đồ thị trên các mục tiêu đó. (Không có gì đảm bảo về thứ tự tương đối của các nút kết quả so với các nút khác.) Để biết thêm thông tin chi tiết, hãy xem phần thứ tự đồ thị.
Biến
expr ::= let name = expr1 in expr2
| $name
Ngôn ngữ truy vấn Bazel cho phép định nghĩa và tham chiếu đến các biến. Kết quả đánh giá biểu thức let
cũng giống như kết quả đánh giá expr2, với tất cả các lần xuất hiện tự do của biến name được thay thế bằng giá trị của expr1.
Ví dụ: let v = foo/... in allpaths($v, //common) intersect $v
tương đương với allpaths(foo/...,//common) intersect foo/...
.
Một lần xuất hiện của tham chiếu biến name
ngoài biểu thức let name = ...
bao quanh là một lỗi. Nói cách khác, biểu thức truy vấn cấp cao nhất không được có các biến số tự do.
Trong các sản phẩm ngữ pháp ở trên, name
giống như word, nhưng có thêm ràng buộc rằng đó phải là một giá trị nhận dạng hợp pháp trong ngôn ngữ lập trình C. Bạn phải thêm ký tự "$" vào trước các tham chiếu đến biến.
Mỗi biểu thức let
chỉ xác định một biến duy nhất, nhưng bạn có thể lồng các biểu thức này.
Cả mẫu mục tiêu và các tham chiếu biến chỉ bao gồm một mã thông báo duy nhất, một từ, tạo ra sự mơ hồ về cú pháp. Tuy nhiên, không có sự mơ hồ về ngữ nghĩa, vì tập hợp con của các từ là tên biến hợp lệ không giao nhau với tập hợp con của các từ là mẫu mục tiêu hợp lệ.
Về mặt kỹ thuật, các biểu thức let
không làm tăng tính biểu đạt của ngôn ngữ truy vấn: mọi truy vấn có thể biểu đạt bằng ngôn ngữ này cũng có thể được biểu đạt mà không cần các biểu thức đó. Tuy nhiên, các từ khoá này giúp nhiều truy vấn trở nên ngắn gọn hơn và cũng có thể dẫn đến việc đánh giá truy vấn hiệu quả hơn.
Biểu thức trong dấu ngoặc đơn
expr ::= (expr)
Dấu ngoặc đơn liên kết các biểu thức con để bắt buộc một thứ tự đánh giá. Một biểu thức trong dấu ngoặc đơn sẽ được đánh giá thành giá trị của đối số.
Các phép toán đại số trên tập hợp: giao, hợp, hiệu
expr ::= expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
Ba toán tử này tính toán các thao tác tập hợp thông thường trên các đối số của chúng.
Mỗi toán tử có hai dạng, một dạng danh nghĩa, chẳng hạn như intersect
và một dạng biểu tượng, chẳng hạn như ^
. Cả hai dạng đều tương đương nhau; dạng ký hiệu gõ nhanh hơn. (Để cho rõ ràng, phần còn lại của trang này sử dụng các dạng danh nghĩa.)
Ví dụ:
foo/... except foo/bar/...
đánh giá thành tập hợp các mục tiêu khớp với foo/...
nhưng không khớp với foo/bar/...
.
Bạn có thể viết cùng một truy vấn như sau:
foo/... - foo/bar/...
Các phép toán intersect
(^
) và union
(+
) có tính giao hoán (đối xứng); except
(-
) có tính bất đối xứng. Trình phân tích cú pháp coi cả ba toán tử này là kết hợp từ trái sang và có độ ưu tiên bằng nhau, vì vậy, bạn có thể muốn dùng dấu ngoặc đơn. Ví dụ: hai biểu thức đầu tiên trong số này tương đương nhau, nhưng biểu thức thứ ba thì không:
x intersect y union z
(x intersect y) union z
x intersect (y union z)
Đọc mục tiêu từ một nguồn bên ngoài: đặt
expr ::= set(word *)
Toán tử set(a b c ...)
tính toán hợp của một tập hợp gồm 0 hoặc nhiều mẫu mục tiêu, được phân tách bằng khoảng trắng (không có dấu phẩy).
Kết hợp với tính năng $(...)
của Bourne shell, set()
cung cấp một phương tiện để lưu kết quả của một truy vấn trong một tệp văn bản thông thường, thao tác với tệp văn bản đó bằng các chương trình khác (chẳng hạn như các công cụ shell UNIX tiêu chuẩn), sau đó đưa kết quả trở lại công cụ truy vấn dưới dạng một giá trị để xử lý thêm. Ví dụ:
bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"
Trong ví dụ tiếp theo,kind(cc_library, deps(//some_dir/foo:main, 5))
được tính bằng cách lọc các giá trị maxrank
bằng chương trình awk
.
bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"
Trong các ví dụ này, $(<foo)
là cách viết tắt của $(cat foo)
, nhưng bạn cũng có thể sử dụng các lệnh shell khác ngoài cat
, chẳng hạn như lệnh awk
trước đó.
Hàm
expr ::= word '(' int | word | expr ... ')'
Ngôn ngữ truy vấn xác định một số hàm. Tên của hàm xác định số lượng và loại đối số mà hàm đó yêu cầu. Bạn có thể sử dụng các hàm sau:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
Đóng bắc cầu của các phần phụ thuộc: deps
expr ::= deps(expr)
| deps(expr, depth)
Toán tử deps(x)
đánh giá đồ thị được tạo bởi bao đóng bắc cầu của tập hợp đối số x. Ví dụ: giá trị của deps(//foo)
là biểu đồ phần phụ thuộc bắt nguồn từ một nút duy nhất foo
, bao gồm tất cả các phần phụ thuộc của nút đó. Giá trị của deps(foo/...)
là các biểu đồ phần phụ thuộc có gốc là tất cả các quy tắc trong mọi gói bên dưới thư mục foo
. Trong ngữ cảnh này, "phần phụ thuộc" chỉ có nghĩa là các mục tiêu quy tắc và tệp. Do đó, các tệp BUILD
và Starlark cần thiết để tạo các mục tiêu này không được đưa vào đây. Để làm việc đó, bạn nên sử dụng toán tử buildfiles
.
Biểu đồ thu được được sắp xếp theo mối quan hệ phụ thuộc. Để biết thêm thông tin chi tiết, hãy xem phần về thứ tự đồ thị.
Toán tử deps
chấp nhận đối số thứ hai không bắt buộc, là một số nguyên theo nghĩa đen chỉ định giới hạn trên về độ sâu của tìm kiếm. Vì vậy, deps(foo:*, 0)
trả về tất cả các mục tiêu trong gói foo
, trong khi deps(foo:*, 1)
bao gồm thêm các điều kiện tiên quyết trực tiếp của mọi mục tiêu trong gói foo
, còn deps(foo:*, 2)
bao gồm thêm các nút có thể truy cập trực tiếp từ các nút trong deps(foo:*, 1)
, v.v. (Những con số này tương ứng với thứ hạng xuất hiện trong định dạng đầu ra minrank
.)
Nếu bạn bỏ qua tham số depth, thì quá trình tìm kiếm sẽ không bị giới hạn: quá trình này sẽ tính toán bao đóng phản xạ bắc cầu của các điều kiện tiên quyết.
Đóng bắc cầu của các phần phụ thuộc đảo ngược: rdeps
expr ::= rdeps(expr, expr)
| rdeps(expr, expr, depth)
Toán tử rdeps(u, x)
đánh giá các phần phụ thuộc đảo ngược của tập hợp đối số x trong bao đóng của tập hợp vũ trụ u.
Biểu đồ thu được được sắp xếp theo mối quan hệ phụ thuộc. Hãy xem phần về thứ tự đồ thị để biết thêm thông tin chi tiết.
Toán tử rdeps
chấp nhận đối số thứ ba không bắt buộc, là một giá trị cố định số nguyên chỉ định giới hạn trên về độ sâu của tìm kiếm. Biểu đồ kết quả chỉ bao gồm các nút trong phạm vi khoảng cách có độ sâu đã chỉ định từ bất kỳ nút nào trong tập hợp đối số. Vì vậy, rdeps(//foo, //common, 1)
sẽ đánh giá tất cả các nút trong bao đóng bắc cầu của //foo
phụ thuộc trực tiếp vào //common
. (Các số này tương ứng với thứ hạng xuất hiện trong định dạng đầu ra minrank
.) Nếu bạn bỏ qua tham số depth, thì phạm vi tìm kiếm sẽ không bị giới hạn.
Đóng bắc cầu của tất cả các phần phụ thuộc đảo ngược: allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
Toán tử allrdeps
hoạt động giống như toán tử rdeps
, ngoại trừ việc "tập hợp vũ trụ" là bất cứ thứ gì mà cờ --universe_scope
đánh giá, thay vì được chỉ định riêng. Do đó, nếu --universe_scope=//foo/...
được truyền, thì allrdeps(//bar)
sẽ tương đương với rdeps(//foo/..., //bar)
.
Phụ thuộc đảo ngược trực tiếp trong cùng một gói: same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
Toán tử same_pkg_direct_rdeps(x)
đánh giá toàn bộ tập hợp mục tiêu nằm trong cùng một gói với một mục tiêu trong tập hợp đối số và phụ thuộc trực tiếp vào mục tiêu đó.
Xử lý gói của mục tiêu: anh chị em
expr ::= siblings(expr)
Toán tử siblings(x)
đánh giá toàn bộ nhóm mục tiêu nằm trong cùng một gói với một mục tiêu trong nhóm đối số.
Lựa chọn tuỳ ý: một số
expr ::= some(expr)
| some(expr, count )
Toán tử some(x, k)
chọn tối đa k mục tiêu tuỳ ý từ tập hợp đối số x và đánh giá thành một tập hợp chỉ chứa những mục tiêu đó. Tham số k là không bắt buộc; nếu thiếu, kết quả sẽ là một tập hợp đơn lẻ chỉ chứa một mục tiêu được chọn tuỳ ý. Nếu kích thước của tập hợp đối số x nhỏ hơn k, thì toàn bộ tập hợp đối số x sẽ được trả về.
Ví dụ: biểu thức some(//foo:main union //bar:baz)
đánh giá thành một tập hợp đơn chứa //foo:main
hoặc //bar:baz
– mặc dù không xác định được tập hợp nào. Biểu thức some(//foo:main union //bar:baz, 2)
hoặc some(//foo:main union //bar:baz, 3)
trả về cả //foo:main
và //bar:baz
.
Nếu đối số là một singleton, thì some
sẽ tính toán hàm nhận dạng: some(//foo:main)
tương đương với //foo:main
.
Đây là lỗi nếu tập hợp đối số được chỉ định là trống, như trong biểu thức some(//foo:main intersect //bar:baz)
.
Toán tử đường dẫn: somepath, allpaths
expr ::= somepath(expr, expr)
| allpaths(expr, expr)
Các toán tử somepath(S, E)
và allpaths(S, E)
tính toán các đường dẫn giữa hai nhóm mục tiêu. Cả hai truy vấn đều chấp nhận hai đối số, một tập hợp S gồm các điểm bắt đầu và một tập hợp E gồm các điểm kết thúc. somepath
trả về biểu đồ các nút trên một đường dẫn tuỳ ý nào đó từ một đích đến trong S đến một đích đến trong E; allpaths
trả về biểu đồ các nút trên tất cả các đường dẫn từ bất kỳ đích đến nào trong S đến bất kỳ đích đến nào trong E.
Các biểu đồ thu được được sắp xếp theo mối quan hệ phụ thuộc. Hãy xem phần về thứ tự đồ thị để biết thêm thông tin.
somepath(S1 + S2, E) , một kết quả có thể xảy ra. |
somepath(S1 + S2, E) , một kết quả có thể khác. |
allpaths(S1 + S2, E) |
Lọc theo loại mục tiêu: loại
expr ::= kind(word, expr)
Toán tử kind(pattern, input)
áp dụng một bộ lọc cho một nhóm mục tiêu và loại bỏ những mục tiêu không thuộc loại dự kiến. Tham số pattern chỉ định loại mục tiêu cần so khớp.
Ví dụ: các loại cho 4 mục tiêu do tệp BUILD
xác định (cho gói p
) như minh hoạ dưới đây trong bảng:
Mã | Mục tiêu | Loại |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
quy tắc genrule |
//p:a.in |
tệp nguồn | |
//p:a.out |
tệp được tạo | |
//p:BUILD |
tệp nguồn |
Do đó, kind("cc_.* rule", foo/...)
đánh giá tập hợp của tất cả cc_library
, cc_binary
, v.v., các mục tiêu quy tắc bên dưới foo
và kind("source file", deps(//foo))
đánh giá tập hợp của tất cả các tệp nguồn trong bao đóng bắc cầu của các phần phụ thuộc của mục tiêu //foo
.
Bạn thường phải trích dẫn đối số pattern vì nếu không, nhiều biểu thức chính quy, chẳng hạn như source
file
và .*_test
, sẽ không được trình phân tích cú pháp coi là từ.
Khi so khớp cho package group
, các mục tiêu kết thúc bằng :all
có thể không mang lại kết quả nào. Thay vào đó, hãy sử dụng :all-targets
.
Lọc tên mục tiêu: bộ lọc
expr ::= filter(word, expr)
Toán tử filter(pattern, input)
áp dụng một bộ lọc cho một nhóm mục tiêu và loại bỏ những mục tiêu có nhãn (ở dạng tuyệt đối) không khớp với mẫu; toán tử này đánh giá thành một tập hợp con của đầu vào.
Đối số đầu tiên, pattern là một từ chứa biểu thức chính quy trên tên mục tiêu. Biểu thức filter
đánh giá thành tập hợp chứa tất cả các mục tiêu x sao cho x là một phần tử của tập hợp input và nhãn (ở dạng tuyệt đối, chẳng hạn như //foo:bar
) của x chứa một kết quả khớp (không cố định) cho biểu thức chính quy pattern. Vì tất cả tên mục tiêu đều bắt đầu bằng //
, nên bạn có thể dùng tên này làm lựa chọn thay thế cho neo biểu thức chính quy ^
.
Toán tử này thường cung cấp một giải pháp thay thế nhanh hơn và mạnh mẽ hơn nhiều so với toán tử intersect
. Ví dụ: để xem tất cả các phần phụ thuộc bar
của mục tiêu //foo:foo
, người ta có thể đánh giá
deps(//foo) intersect //bar/...
Tuy nhiên, câu lệnh này sẽ yêu cầu phân tích cú pháp tất cả các tệp BUILD
trong cây bar
, điều này sẽ diễn ra chậm và dễ xảy ra lỗi trong các tệp BUILD
không liên quan. Một lựa chọn khác là:
filter(//bar, deps(//foo))
trước tiên sẽ tính toán tập hợp các phần phụ thuộc //foo
, sau đó chỉ lọc các mục tiêu khớp với mẫu đã cung cấp – nói cách khác, các mục tiêu có tên chứa //bar
dưới dạng chuỗi con.
Một trường hợp sử dụng phổ biến khác của toán tử filter(pattern,
expr)
là lọc các tệp cụ thể theo tên hoặc đuôi của tệp. Ví dụ:
filter("\.cc$", deps(//foo))
sẽ cung cấp danh sách tất cả các tệp .cc
dùng để tạo //foo
.
Lọc thuộc tính quy tắc: attr
expr ::= attr(word, word, expr)
Toán tử attr(name, pattern, input)
sẽ áp dụng một bộ lọc cho một nhóm mục tiêu và loại bỏ những mục tiêu không phải là quy tắc, mục tiêu quy tắc không có thuộc tính name được xác định hoặc mục tiêu quy tắc có giá trị thuộc tính không khớp với biểu thức chính quy pattern đã cho; toán tử này đánh giá thành một tập hợp con của đầu vào.
Đối số đầu tiên, name là tên của thuộc tính quy tắc cần được so khớp với mẫu biểu thức chính quy đã cung cấp. Đối số thứ hai, pattern là một biểu thức chính quy trên các giá trị thuộc tính. Biểu thức attr
đánh giá tập hợp chứa tất cả các mục tiêu x sao cho x là một phần tử của tập hợp input, là một quy tắc có thuộc tính name được xác định và giá trị thuộc tính chứa một kết quả trùng khớp (không cố định) cho biểu thức chính quy pattern. Nếu name là một thuộc tính không bắt buộc và quy tắc không chỉ định rõ ràng thì giá trị thuộc tính mặc định sẽ được dùng để so sánh. Ví dụ:
attr(linkshared, 0, deps(//foo))
sẽ chọn tất cả các phần phụ thuộc //foo
được phép có thuộc tính linkshared (chẳng hạn như quy tắc cc_binary
) và đặt thuộc tính đó một cách rõ ràng thành 0 hoặc không đặt thuộc tính đó nhưng giá trị mặc định là 0 (chẳng hạn như đối với các quy tắc cc_binary
).
Các thuộc tính thuộc loại danh sách (chẳng hạn như srcs
, data
, v.v.) được chuyển đổi thành các chuỗi có dạng [value<sub>1</sub>, ..., value<sub>n</sub>]
, bắt đầu bằng dấu ngoặc [
, kết thúc bằng dấu ngoặc ]
và sử dụng ",
" (dấu phẩy, dấu cách) để phân tách nhiều giá trị.
Nhãn được chuyển đổi thành chuỗi bằng cách sử dụng dạng tuyệt đối của nhãn. Ví dụ: thuộc tính deps=[":foo",
"//otherpkg:bar", "wiz"]
sẽ được chuyển đổi thành chuỗi [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
.
Dấu ngoặc vuông luôn xuất hiện, vì vậy, danh sách trống sẽ sử dụng giá trị chuỗi []
cho mục đích so khớp. Ví dụ:
attr("srcs", "\[\]", deps(//foo))
sẽ chọn tất cả các quy tắc trong số //foo
phần phụ thuộc có thuộc tính srcs
trống, trong khi
attr("data", ".{3,}", deps(//foo))
sẽ chọn tất cả các quy tắc trong số //foo
phần phụ thuộc chỉ định ít nhất một giá trị trong thuộc tính data
(mỗi nhãn có độ dài ít nhất là 3 ký tự do //
và :
).
Để chọn tất cả các quy tắc trong số //foo
phần phụ thuộc có một value
cụ thể trong thuộc tính kiểu danh sách, hãy sử dụng
attr("tags", "[\[ ]value[,\]]", deps(//foo))
Điều này có hiệu quả vì ký tự trước value
sẽ là [
hoặc dấu cách và ký tự sau value
sẽ là dấu phẩy hoặc ]
.
Lọc chế độ hiển thị quy tắc: hiển thị
expr ::= visible(expr, expr)
Toán tử visible(predicate, input)
sẽ áp dụng một bộ lọc cho một nhóm mục tiêu và loại bỏ những mục tiêu không có chế độ hiển thị bắt buộc.
Đối số đầu tiên, predicate, là một tập hợp các mục tiêu mà tất cả các mục tiêu trong đầu ra phải hiển thị. Biểu thức visible đánh giá tập hợp chứa tất cả các mục tiêu x sao cho x là một phần tử của tập hợp input và đối với tất cả các mục tiêu y trong predicate, x sẽ hiển thị cho y. Ví dụ:
visible(//foo, //bar:*)
sẽ chọn tất cả các mục tiêu trong gói //bar
mà //foo
có thể phụ thuộc vào mà không vi phạm các hạn chế về khả năng hiển thị.
Đánh giá các thuộc tính quy tắc thuộc loại nhãn: nhãn
expr ::= labels(word, expr)
Toán tử labels(attr_name, inputs)
trả về tập hợp các mục tiêu được chỉ định trong thuộc tính attr_name thuộc loại "nhãn" hoặc "danh sách nhãn" trong một số quy tắc trong tập hợp inputs.
Ví dụ: labels(srcs, //foo)
trả về tập hợp các mục tiêu xuất hiện trong thuộc tính srcs
của quy tắc //foo
. Nếu có nhiều quy tắc có thuộc tính srcs
trong tập hợp inputs, thì hợp của srcs
sẽ được trả về.
Mở rộng và lọc test_suites: tests
expr ::= tests(expr)
Toán tử tests(x)
trả về tập hợp tất cả các quy tắc kiểm thử trong tập hợp x, mở rộng mọi quy tắc test_suite
thành tập hợp các kiểm thử riêng lẻ mà chúng tham chiếu đến và áp dụng tính năng lọc theo tag
và size
.
Theo mặc định, quá trình đánh giá truy vấn sẽ bỏ qua mọi mục tiêu không phải mục tiêu kiểm thử trong tất cả các quy tắc test_suite
. Bạn có thể thay đổi chế độ này thành lỗi bằng tuỳ chọn --strict_test_suite
.
Ví dụ: truy vấn kind(test, foo:*)
liệt kê tất cả các quy tắc *_test
và test_suite
trong gói foo
. Tất cả kết quả đều là thành viên của gói foo
(theo định nghĩa). Ngược lại, truy vấn tests(foo:*)
sẽ trả về tất cả các kiểm thử riêng lẻ mà bazel test
foo:*
sẽ thực thi: điều này có thể bao gồm các kiểm thử thuộc về các gói khác, được tham chiếu trực tiếp hoặc gián tiếp thông qua các quy tắc test_suite
.
Tệp định nghĩa gói: buildfiles
expr ::= buildfiles(expr)
Toán tử buildfiles(x)
trả về tập hợp các tệp xác định các gói của mỗi mục tiêu trong tập hợp x; nói cách khác, đối với mỗi gói, tệp BUILD
của gói đó, cộng với mọi tệp .bzl mà gói đó tham chiếu thông qua load
. Xin lưu ý rằng thao tác này cũng trả về các tệp BUILD
của những gói chứa các tệp load
này.
Thao tác này thường được dùng khi xác định những tệp hoặc gói cần thiết để tạo một mục tiêu cụ thể, thường kết hợp với lựa chọn --output package
(bên dưới). Ví dụ:
bazel query 'buildfiles(deps(//foo))' --output package
trả về tập hợp tất cả các gói mà //foo
phụ thuộc một cách bắc cầu.
Tệp định nghĩa gói: rbuildfiles
expr ::= rbuildfiles(word, ...)
Toán tử rbuildfiles
lấy danh sách các đoạn đường dẫn được phân tách bằng dấu phẩy và trả về tập hợp các tệp BUILD
phụ thuộc bắc cầu vào các đoạn đường dẫn này. Ví dụ: nếu //foo
là một gói, thì rbuildfiles(foo/BUILD)
sẽ trả về mục tiêu //foo:BUILD
. Nếu tệp foo/BUILD
có load('//bar:file.bzl'...
trong đó, thì rbuildfiles(bar/file.bzl)
sẽ trả về mục tiêu //foo:BUILD
, cũng như các mục tiêu cho mọi tệp BUILD
khác tải //bar:file.bzl
Phạm vi của toán tử --universe_scope
chỉ định. Những tệp không tương ứng trực tiếp với tệp BUILD
và tệp .bzl
sẽ không ảnh hưởng đến kết quả. Ví dụ: các tệp nguồn (như foo.cc
) sẽ bị bỏ qua, ngay cả khi chúng được đề cập rõ ràng trong tệp BUILD
. Tuy nhiên, các đường liên kết tượng trưng sẽ được tôn trọng, do đó, nếu foo/BUILD
là một đường liên kết tượng trưng đến bar/BUILD
, thì rbuildfiles(bar/BUILD)
sẽ bao gồm //foo:BUILD
trong kết quả.
Toán tử rbuildfiles
gần như là nghịch đảo của toán tử buildfiles
. Tuy nhiên, sự đảo ngược về mặt đạo đức này có hiệu lực mạnh hơn theo một hướng: đầu ra của rbuildfiles
giống như đầu vào của buildfiles
; đầu ra của rbuildfiles
sẽ chỉ chứa các mục tiêu tệp BUILD
trong các gói và đầu ra của buildfiles
có thể chứa các mục tiêu như vậy. Theo hướng ngược lại, mối tương ứng sẽ yếu hơn. Đầu ra của toán tử buildfiles
là các mục tiêu tương ứng với tất cả các gói và .bzl
các tệp cần thiết cho một đầu vào nhất định. Tuy nhiên, các đầu vào của toán tử rbuildfiles
không phải là các mục tiêu đó mà là các mảnh đường dẫn tương ứng với các mục tiêu đó.
Tệp định nghĩa gói: loadfiles
expr ::= loadfiles(expr)
Toán tử loadfiles(x)
trả về tập hợp các tệp Starlark cần thiết để tải các gói của từng mục tiêu trong tập hợp x. Nói cách khác, đối với mỗi gói, nó sẽ trả về các tệp .bzl được tham chiếu từ các tệp BUILD
của gói đó.
Định dạng đầu ra
bazel query
tạo một biểu đồ.
Bạn chỉ định nội dung, định dạng và thứ tự mà bazel query
trình bày biểu đồ này bằng cách sử dụng tuỳ chọn dòng lệnh --output
.
Khi chạy bằng Sky Query, bạn chỉ được phép sử dụng các định dạng đầu ra tương thích với đầu ra không theo thứ tự. Cụ thể, bạn không được dùng các định dạng đầu ra graph
, minrank
và maxrank
.
Một số định dạng đầu ra chấp nhận các lựa chọn bổ sung. Tên của mỗi lựa chọn đầu ra đều có tiền tố là định dạng đầu ra mà lựa chọn đó áp dụng, vì vậy, --graph:factored
chỉ áp dụng khi --output=graph
đang được sử dụng; lựa chọn này sẽ không có hiệu lực nếu bạn sử dụng định dạng đầu ra khác ngoài graph
. Tương tự, --xml:line_numbers
chỉ áp dụng khi --output=xml
đang được sử dụng.
Về thứ tự của kết quả
Mặc dù biểu thức truy vấn luôn tuân theo "quy luật bảo toàn thứ tự đồ thị", nhưng bạn có thể trình bày kết quả theo cách có thứ tự phụ thuộc hoặc không có thứ tự. Điều này không ảnh hưởng đến các mục tiêu trong tập kết quả hoặc cách tính toán truy vấn. Nó chỉ ảnh hưởng đến cách kết quả được in ra stdout. Ngoài ra, các nút tương đương theo thứ tự phụ thuộc có thể được sắp xếp theo bảng chữ cái hoặc không.
Bạn có thể dùng cờ --order_output
để kiểm soát hành vi này.
(Cờ --[no]order_results
có một tập hợp con các chức năng của cờ --order_output
và không còn được dùng nữa.)
Giá trị mặc định của cờ này là auto
, in kết quả theo thứ tự từ điển. Tuy nhiên, khi somepath(a,b)
được dùng, các kết quả sẽ được in theo thứ tự deps
.
Khi cờ này là no
và --output
là một trong các giá trị build
, label
, label_kind
, location
, package
, proto
hoặc xml
, các đầu ra sẽ được in theo thứ tự tuỳ ý. Đây thường là lựa chọn nhanh nhất. Tuy nhiên, Bazel không hỗ trợ khi --output
là một trong các graph
, minrank
hoặc maxrank
: với các định dạng này, Bazel luôn in kết quả theo thứ tự hoặc thứ hạng của phần phụ thuộc.
Khi cờ này là deps
, Bazel sẽ in kết quả theo một số thứ tự liên kết – tức là các phần phụ thuộc trước. Tuy nhiên, các nút không được sắp xếp theo thứ tự phụ thuộc (vì không có đường dẫn từ nút này đến nút kia) có thể được in theo thứ tự bất kỳ.
Khi cờ này là full
, Bazel sẽ in các nút theo thứ tự hoàn toàn xác định (tổng).
Trước tiên, tất cả các nút được sắp xếp theo thứ tự bảng chữ cái. Sau đó, mỗi nút trong danh sách được dùng làm điểm bắt đầu của một tìm kiếm theo chiều sâu sau thứ tự, trong đó các cạnh đi đến các nút chưa được truy cập sẽ được duyệt theo thứ tự bảng chữ cái của các nút kế thừa. Cuối cùng, các nút được in theo thứ tự ngược lại với thứ tự mà chúng được truy cập.
Việc in các nút theo thứ tự này có thể chậm hơn, vì vậy bạn chỉ nên sử dụng khi tính xác định là quan trọng.
In biểu mẫu nguồn của các mục tiêu như chúng sẽ xuất hiện trong BUILD
--output build
Với lựa chọn này, mỗi mục tiêu được biểu thị như thể được viết tay bằng ngôn ngữ BUILD. Tất cả các biến và lệnh gọi hàm (chẳng hạn như glob, macro) đều được mở rộng, điều này rất hữu ích khi xem hiệu ứng của macro Starlark. Ngoài ra, mỗi quy tắc có hiệu lực sẽ báo cáo một giá trị generator_name
và/hoặc generator_function
, cho biết tên của macro đã được đánh giá để tạo ra quy tắc có hiệu lực.
Mặc dù đầu ra sử dụng cùng một cú pháp như các tệp BUILD
, nhưng không đảm bảo tạo ra một tệp BUILD
hợp lệ.
In nhãn của từng mục tiêu
--output label
Với lựa chọn này, tập hợp tên (hoặc nhãn) của mỗi mục tiêu trong biểu đồ kết quả sẽ được in, mỗi nhãn trên một dòng, theo thứ tự liên kết (trừ phi bạn chỉ định --noorder_results
, hãy xem ghi chú về thứ tự của kết quả).
(Thứ tự liên kết là thứ tự mà một nút đồ thị xuất hiện sớm hơn tất cả các nút kế nhiệm của nó.) Tất nhiên, có nhiều thứ tự liên kết có thể có của một biểu đồ (thứ tự đảo ngược chỉ là một trong số đó); thứ tự nào được chọn không được chỉ định.
Khi in kết quả của một truy vấn somepath
, thứ tự in các nút là thứ tự của đường dẫn.
Lưu ý: trong một số trường hợp đặc biệt, có thể có 2 mục tiêu riêng biệt có cùng nhãn; ví dụ: quy tắc sh_binary
và tệp srcs
duy nhất (ngầm ẩn) của quy tắc đó có thể được gọi là foo.sh
. Nếu kết quả của một truy vấn chứa cả hai mục tiêu này, thì đầu ra (ở định dạng label
) sẽ xuất hiện để chứa một bản sao. Khi sử dụng định dạng label_kind
(xem bên dưới), sự khác biệt sẽ trở nên rõ ràng: hai mục tiêu có cùng tên, nhưng một mục tiêu có loại sh_binary rule
và mục tiêu còn lại có loại source file
.
In nhãn và loại của từng mục tiêu
--output label_kind
Giống như label
, định dạng đầu ra này in nhãn của từng mục tiêu trong biểu đồ kết quả, theo thứ tự liên kết, nhưng ngoài ra, định dạng này còn đặt loại của mục tiêu trước nhãn.
In các mục tiêu ở định dạng vùng đệm giao thức
--output proto
In kết quả truy vấn dưới dạng vùng đệm giao thức QueryResult
.
In các mục tiêu ở định dạng vùng đệm giao thức có độ dài phân cách
--output streamed_proto
In một luồng phân cách theo độ dài của vùng đệm giao thức Target
. Điều này hữu ích để (i) khắc phục giới hạn về kích thước của vùng đệm giao thức khi có quá nhiều mục tiêu để phù hợp với một QueryResult
hoặc (ii) để bắt đầu xử lý trong khi Bazel vẫn đang xuất.
In các mục tiêu ở định dạng văn bản proto
--output textproto
Tương tự như --output proto
, in vùng đệm giao thức QueryResult
nhưng ở định dạng văn bản.
In các mục tiêu ở định dạng ndjson
--output streamed_jsonproto
Tương tự như --output streamed_proto
, in một luồng Target
vùng đệm giao thức nhưng ở định dạng ndjson.
In nhãn của từng mục tiêu theo thứ tự xếp hạng
--output minrank --output maxrank
Giống như label
, các định dạng đầu ra minrank
và maxrank
in nhãn của từng mục tiêu trong biểu đồ kết quả, nhưng thay vì xuất hiện theo thứ tự liên kết, chúng xuất hiện theo thứ tự xếp hạng, trước đó là số thứ hạng. Những kết quả này không bị ảnh hưởng bởi cờ --[no]order_results
sắp xếp kết quả (xem ghi chú về việc sắp xếp kết quả).
Định dạng này có hai biến thể: minrank
xếp hạng từng nút theo độ dài của đường dẫn ngắn nhất từ một nút gốc đến nút đó.
Các nút "gốc" (những nút không có cạnh đến) có thứ hạng là 0, các nút kế nhiệm có thứ hạng là 1, v.v. (Như thường lệ, các cạnh trỏ từ mục tiêu đến các điều kiện tiên quyết: các mục tiêu mà mục tiêu đó phụ thuộc vào.)
maxrank
xếp hạng từng nút theo độ dài của đường dẫn dài nhất từ một nút gốc đến nút đó. Tương tự, "các gốc" có thứ hạng là 0, tất cả các nút khác có thứ hạng lớn hơn thứ hạng tối đa của tất cả các nút tiền nhiệm của chúng.
Tất cả các nút trong một chu kỳ đều được coi là có thứ hạng bằng nhau. (Hầu hết các biểu đồ đều không có chu kỳ, nhưng chu kỳ vẫn xảy ra chỉ vì các tệp BUILD
chứa các chu kỳ sai.)
Các định dạng đầu ra này rất hữu ích để khám phá độ sâu của một biểu đồ. Nếu được dùng cho kết quả của truy vấn deps(x)
, rdeps(x)
hoặc allpaths
, thì số thứ hạng sẽ bằng độ dài của đường dẫn ngắn nhất (với minrank
) hoặc dài nhất (với maxrank
) từ x
đến một nút trong thứ hạng đó. maxrank
có thể được dùng để xác định chuỗi dài nhất gồm các bước xây dựng cần thiết để xây dựng một mục tiêu.
Ví dụ: biểu đồ ở bên trái sẽ cho ra các đầu ra ở bên phải khi --output minrank
và --output maxrank
được chỉ định, tương ứng.
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 |
In vị trí của từng mục tiêu
--output location
Giống như label_kind
, lựa chọn này in ra, đối với mỗi mục tiêu trong kết quả, loại và nhãn của mục tiêu, nhưng được thêm tiền tố bằng một chuỗi mô tả vị trí của mục tiêu đó, dưới dạng tên tệp và số dòng. Định dạng này giống với đầu ra của grep
. Do đó, những công cụ có thể phân tích cú pháp sau (chẳng hạn như Emacs hoặc vi) cũng có thể sử dụng đầu ra truy vấn để thực hiện từng bước qua một loạt kết quả trùng khớp, cho phép sử dụng công cụ truy vấn Bazel làm "grep cho các tệp BUILD" có nhận biết đồ thị phần phụ thuộc.
Thông tin vị trí sẽ khác nhau tuỳ theo loại mục tiêu (xem toán tử kind). Đối với các quy tắc, vị trí khai báo quy tắc trong tệp BUILD
sẽ được in.
Đối với các tệp nguồn, vị trí của dòng 1 trong tệp thực tế sẽ được in. Đối với một tệp được tạo, vị trí của quy tắc tạo tệp đó sẽ được in. (Công cụ truy vấn không có đủ thông tin để tìm vị trí thực tế của tệp đã tạo và trong mọi trường hợp, tệp đó có thể không tồn tại nếu chưa thực hiện bản dựng.)
In bộ gói
--output package
Lựa chọn này sẽ in tên của tất cả các gói mà một số mục tiêu trong tập kết quả thuộc về. Tên được in theo thứ tự từ điển; các tên trùng lặp sẽ bị loại trừ. Về mặt hình thức, đây là một phép chiếu từ tập hợp nhãn (gói, mục tiêu) lên các gói.
Các gói trong kho lưu trữ bên ngoài được định dạng là @repo//foo/bar
, còn các gói trong kho lưu trữ chính được định dạng là foo/bar
.
Kết hợp với truy vấn deps(...)
, bạn có thể dùng lựa chọn đầu ra này để tìm tập hợp các gói phải được kiểm tra để tạo một tập hợp mục tiêu nhất định.
Hiển thị biểu đồ kết quả
--output graph
Lựa chọn này khiến kết quả truy vấn được in dưới dạng đồ thị có hướng theo định dạng GraphViz phổ biến của AT&T. Thông thường, kết quả sẽ được lưu vào một tệp, chẳng hạn như .png
hoặc .svg
.
(Nếu chưa cài đặt chương trình dot
trên máy trạm, bạn có thể cài đặt bằng lệnh sudo apt-get install graphviz
.) Hãy xem phần ví dụ bên dưới để biết một lệnh gọi mẫu.
Định dạng đầu ra này đặc biệt hữu ích cho các truy vấn allpaths
, deps
hoặc rdeps
, trong đó kết quả bao gồm một tập hợp các đường dẫn mà bạn không thể dễ dàng hình dung khi được kết xuất ở dạng tuyến tính, chẳng hạn như với --output label
.
Theo mặc định, biểu đồ được hiển thị ở dạng phân tích. Tức là các nút tương đương về mặt tô pô được hợp nhất với nhau thành một nút duy nhất có nhiều nhãn. Điều này giúp biểu đồ trở nên gọn gàng và dễ đọc hơn, vì các biểu đồ kết quả thông thường chứa các mẫu lặp lại nhiều lần. Ví dụ: một quy tắc java_library
có thể phụ thuộc vào hàng trăm tệp nguồn Java, tất cả đều do cùng một genrule
tạo ra; trong biểu đồ được phân tích, tất cả các tệp này đều được biểu thị bằng một nút duy nhất. Bạn có thể tắt hành vi này bằng lựa chọn --nograph:factored
.
--graph:node_limit n
Tuỳ chọn này chỉ định độ dài tối đa của chuỗi nhãn cho một nút đồ thị trong đầu ra. Nhãn dài hơn sẽ bị cắt ngắn; -1
sẽ tắt tính năng cắt ngắn. Do dạng phân tích mà các biểu đồ thường được in, nên nhãn nút có thể rất dài. GraphViz không thể xử lý các nhãn vượt quá 1024 ký tự, đây là giá trị mặc định của lựa chọn này. Tuỳ chọn này không có hiệu lực trừ phi bạn đang sử dụng --output=graph
.
--[no]graph:factored
Theo mặc định, các biểu đồ được hiển thị ở dạng thừa số, như đã giải thích ở trên.
Khi --nograph:factored
được chỉ định, các đồ thị sẽ được in mà không cần tính đến hệ số. Điều này khiến việc trực quan hoá bằng GraphViz trở nên không thực tế, nhưng định dạng đơn giản hơn có thể giúp các công cụ khác (chẳng hạn như grep) dễ dàng xử lý hơn. Tuỳ chọn này không có hiệu lực trừ phi bạn đang sử dụng --output=graph
.
XML
--output xml
Lựa chọn này khiến các mục tiêu kết quả được in ở dạng XML. Đầu ra bắt đầu bằng một tiêu đề XML, chẳng hạn như tiêu đề này
<?xml version="1.0" encoding="UTF-8"?>
<query version="2">
rồi tiếp tục với một phần tử XML cho mỗi đích trong biểu đồ kết quả, theo thứ tự liên kết (trừ phi bạn yêu cầu kết quả không theo thứ tự), rồi kết thúc bằng một
</query>
Các mục đơn giản được phát ra cho các mục tiêu thuộc loại file
:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
Nhưng đối với các quy tắc, XML được cấu trúc và chứa định nghĩa của tất cả các thuộc tính của quy tắc, bao gồm cả những thuộc tính có giá trị không được chỉ định rõ ràng trong tệp BUILD
của quy tắc.
Ngoài ra, kết quả này bao gồm các phần tử rule-input
và rule-output
để có thể tái tạo cấu trúc liên kết của biểu đồ phần phụ thuộc mà không cần biết rằng, chẳng hạn như các phần tử của thuộc tính srcs
là phần phụ thuộc chuyển tiếp (điều kiện tiên quyết) và nội dung của thuộc tính outs
là phần phụ thuộc ngược (người dùng).
Các phần tử rule-input
cho phần phụ thuộc ngầm sẽ bị chặn nếu bạn chỉ định --noimplicit_deps
.
<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>
Mỗi phần tử XML cho một đích đến đều chứa một thuộc tính name
. Giá trị của thuộc tính này là nhãn của đích đến và một thuộc tính location
. Giá trị của thuộc tính này là vị trí của đích đến do --output location
in.
--[no]xml:line_numbers
Theo mặc định, các vị trí xuất hiện trong đầu ra XML có chứa số dòng.
Khi bạn chỉ định --noxml:line_numbers
, số dòng sẽ không được in.
--[no]xml:default_values
Theo mặc định, đầu ra XML không bao gồm thuộc tính quy tắc có giá trị là giá trị mặc định cho loại thuộc tính đó (ví dụ: nếu thuộc tính đó không được chỉ định trong tệp BUILD
hoặc giá trị mặc định được cung cấp một cách rõ ràng). Lựa chọn này khiến các giá trị thuộc tính như vậy được đưa vào đầu ra XML.
Cụm từ thông dụng
Biểu thức chính quy trong ngôn ngữ truy vấn sử dụng thư viện biểu thức chính quy Java, vì vậy, bạn có thể sử dụng cú pháp đầy đủ cho java.util.regex.Pattern
.
Truy vấn bằng kho lưu trữ bên ngoài
Nếu bản dựng phụ thuộc vào các quy tắc từ kho lưu trữ bên ngoài, thì kết quả truy vấn sẽ bao gồm các phần phụ thuộc này. Ví dụ: nếu //foo:bar
phụ thuộc vào @other-repo//baz:lib
, thì bazel query 'deps(//foo:bar)'
sẽ liệt kê @other-repo//baz:lib
là phần phụ thuộc.