cquery
là một biến thể của query
xử lý chính xác
select()
và các tuỳ chọn xây dựng các hiệu ứng đối với bản dựng
biểu đồ.
Công cụ này thực hiện điều này bằng cách xem xét các kết quả từ phân tích của Bazel
,
kết hợp các hiệu ứng này. Ngược lại, query
chạy qua kết quả của
Giai đoạn tải Bazel, trước khi đánh giá các lựa chọn.
Ví dụ:
$ cat > tree/BUILD <<EOF sh_library( name = "ash", deps = select({ ":excelsior": [":manna-ash"], ":americana": [":white-ash"], "//conditions:default": [":common-ash"], }), ) sh_library(name = "manna-ash") sh_library(name = "white-ash") sh_library(name = "common-ash") config_setting( name = "excelsior", values = {"define": "species=excelsior"}, ) config_setting( name = "americana", values = {"define": "species=americana"}, ) EOF
# Traditional query: query doesn't know which select() branch you will choose, # so it conservatively lists all of possible choices, including all used config_settings. $ bazel query "deps(//tree:ash)" --noimplicit_deps //tree:americana //tree:ash //tree:common-ash //tree:excelsior //tree:manna-ash //tree:white-ash # cquery: cquery lets you set build options at the command line and chooses # the exact dependencies that implies (and also the config_setting targets). $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (9f87702) //tree:manna-ash (9f87702) //tree:americana (9f87702) //tree:excelsior (9f87702)
Mỗi kết quả đều có một giá trị nhận dạng duy nhất (9f87702)
của
cấu hình
nhắm mục tiêu.
Vì cquery
chạy trên biểu đồ mục tiêu đã định cấu hình. không có thông tin chi tiết
thành các cấu phần phần mềm như thao tác tạo bản dựng cũng như quyền truy cập vào [test_suite](/versions/6.5.0/reference/be/general#test_suite)
vì chúng không được định cấu hình mục tiêu. Đối với trường hợp trước, hãy xem [aquery](/versions/6.5.0/docs/aquery)
.
Cú pháp cơ bản
Một lệnh gọi cquery
đơn giản sẽ có dạng như sau:
bazel cquery "function(//target)"
Biểu thức truy vấn "function(//target)"
bao gồm:
function(...)
là hàm chạy trên mục tiêu.cquery
hỗ trợ nhiều nhất hàm củaquery
, cộng với một vài nhà quảng cáo mới.//target
là biểu thức được đưa vào hàm. Trong ví dụ này, phương thức là một mục tiêu đơn giản. Tuy nhiên, ngôn ngữ truy vấn cũng cho phép lồng các hàm. Xem Hướng dẫn truy vấn để biết ví dụ.
cquery
yêu cầu một mục tiêu để chạy thông qua quy trình tải và phân tích
. Trừ phi có quy định khác, cquery
phân tích cú pháp(các) mục tiêu được liệt kê trong
biểu thức truy vấn. Xem --universe_scope
để truy vấn các phần phụ thuộc của mục tiêu bản dựng cấp cao nhất.
Cấu hình
Dòng:
//tree:ash (9f87702)
có nghĩa là //tree:ash
được tạo ở cấu hình có mã 9f87702
. Đối với hầu hết
, đây là hàm băm mờ của các giá trị tùy chọn bản dựng xác định
.
Để xem nội dung đầy đủ của cấu hình, hãy chạy mã:
$ bazel config 9f87702
Cấu hình máy chủ lưu trữ sử dụng mã nhận dạng đặc biệt (HOST)
. Tệp nguồn không được tạo, chẳng hạn như
các mã thường có trong srcs
, hãy sử dụng mã nhận dạng đặc biệt (null)
(vì chúng
không cần định cấu hình).
9f87702
là tiền tố của mã nhận dạng đầy đủ. Điều này là do mã nhận dạng hoàn chỉnh
Hàm băm SHA-256 dài và khó theo dõi. cquery
hiểu rằng mọi quy tắc hợp lệ
tiền tố của một mã nhận dạng hoàn chỉnh, tương tự như
Hàm băm ngắn trên Git.
Để xem mã nhận dạng đầy đủ, hãy chạy $ bazel config
.
Đánh giá mẫu mục tiêu
//foo
có nghĩa khác cho cquery
so với query
. Điều này là do
cquery
đánh giá các mục tiêu đã định cấu hình và biểu đồ bản dựng có thể có nhiều
các phiên bản đã định cấu hình của //foo
.
Đối với cquery
, mẫu mục tiêu trong biểu thức truy vấn sẽ đánh giá
cho mọi mục tiêu được định cấu hình có nhãn khớp với mẫu đó. Đầu ra là
mang tính tất định, nhưng cquery
không đảm bảo đặt hàng ngoài
hợp đồng đặt hàng truy vấn chính.
Điều này tạo ra kết quả tinh tế hơn cho biểu thức truy vấn so với query
.
Ví dụ: thao tác sau có thể tạo ra nhiều kết quả:
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on a host-configured # //foo. So there are two configured target instances of //foo in # the build graph. $ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool //foo (9f87702) //foo (HOST)
Nếu bạn muốn khai báo chính xác thực thể nào cần truy vấn, hãy sử dụng
hàm config
.
Xem mẫu mục tiêu của query
để biết thêm thông tin về mẫu mục tiêu.
Hàm
Về tập hợp hàm
được hỗ trợ bởi query
, cquery
hỗ trợ tất cả trừ
allrdeps
,
buildfiles
,
rbuildfiles
,
siblings
,
tests
và
visible
.
cquery
cũng giới thiệu các hàm mới sau đây:
cấu hình
expr ::= config(expr, word)
Toán tử config
cố gắng tìm mục tiêu đã định cấu hình cho
nhãn được biểu thị bằng đối số và cấu hình đầu tiên được chỉ định bởi phương thức
đối số thứ hai.
Các giá trị hợp lệ cho đối số thứ hai là target
, host
, null
hoặc a
băm cấu hình tuỳ chỉnh. Bạn có thể truy xuất hàm băm từ $
bazel config
hoặc kết quả của cquery
trước đó.
Ví dụ:
$ bazel cquery "config(//bar, host)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (HOST) //baz (3732cc8) $ bazel cquery "config(//baz, 3732cc8)"
Nếu không tìm thấy tất cả kết quả của đối số đầu tiên trong đối số được chỉ định , chỉ những dữ liệu có thể tìm thấy mới được trả về. Nếu không có kết quả có thể được tìm thấy trong cấu hình được chỉ định, thì truy vấn không thành công.
Tùy chọn
Tuỳ chọn tạo bản dựng
cquery
chạy trên bản dựng Bazel thông thường và do đó kế thừa tập hợp
các tuỳ chọn có sẵn trong quá trình tạo bản dựng.
Sử dụng các tuỳ chọn cquery
--universe_scope
(danh sách được phân tách bằng dấu phẩy)
Thông thường, các phần phụ thuộc của các mục tiêu đã định cấu hình sẽ trải qua chuyển đổi, khiến cấu hình của chúng khác với phần phụ thuộc. Cờ này cho phép bạn truy vấn một mục tiêu như thể mục tiêu đó được tạo dưới dạng phần phụ thuộc hoặc bắc cầu phần phụ thuộc của một mục tiêu khác. Ví dụ:
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", )
Genrules định cấu hình công cụ của họ trong cấu hình máy chủ lưu trữ vì vậy, các truy vấn sau sẽ cho ra kết quả sau:
Truy vấn | Đã tạo mục tiêu | Đầu ra |
---|---|---|
bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(hostconfig) |
Nếu bạn đặt cờ này thì nội dung của cờ sẽ được tạo. Nếu bạn không đặt chính sách này, tất cả mục tiêu
được đề cập trong biểu thức truy vấn được tạo. Đóng bắc cầu của
mục tiêu đã tạo được sử dụng làm thành phần chính của truy vấn. Dù bằng cách nào, mục tiêu
phải xây dựng được ở cấp cao nhất (tức là tương thích với
). cquery
trả về kết quả trong việc đóng bắc cầu của các truy vấn này
mục tiêu cấp cao nhất.
Ngay cả khi có thể tạo tất cả mục tiêu trong một biểu thức truy vấn ở trên cùng
nên nếu bạn không làm như vậy, Ví dụ: cài đặt rõ ràng
--universe_scope
có thể ngăn việc tạo mục tiêu nhiều lần trong
mà bạn không quan tâm. Điều này cũng có thể giúp chỉ định phiên bản cấu hình của
mà bạn đang tìm kiếm (vì hiện tại không thể
để chỉ định đầy đủ mã này theo bất kỳ cách nào khác). Bạn nên đặt cờ này
nếu biểu thức truy vấn của bạn phức tạp hơn deps(//foo)
.
--implicit_deps
(boolean, default=True)
Việc đặt cờ này thành false sẽ lọc tất cả kết quả không được đặt rõ ràng trong tệp BUILD và thay vào đó được Bazel đặt ở nơi khác. Điều này bao gồm lọc đã được giải quyết chuỗi công cụ.
--tool_deps
(boolean, default=True)
Nếu bạn đặt cờ này thành false (sai), thì hệ thống sẽ lọc ra tất cả các mục tiêu đã định cấu hình mà
đường dẫn từ mục tiêu được truy vấn đến chúng vượt qua quá trình chuyển đổi giữa các mục tiêu
và
cấu hình không phải mục tiêu.
Nếu mục tiêu được truy vấn nằm trong cấu hình mục tiêu, việc thiết lập --notool_deps
sẽ
chỉ các mục tiêu trả về cũng nằm trong cấu hình mục tiêu. Nếu thuộc tính được truy vấn
mục tiêu nằm trong cấu hình không phải mục tiêu, việc cài đặt --notool_deps
sẽ chỉ trả về
cả mục tiêu trong cấu hình không phải mục tiêu. Chế độ cài đặt này thường không ảnh hưởng đến việc lọc
gồm chuỗi công cụ được phân giải.
--include_aspects
(boolean, default=True)
Các khía cạnh có thể thêm
các phần phụ thuộc bổ sung vào bản dựng. Theo mặc định, cquery
không theo các khía cạnh vì
chúng làm cho biểu đồ có thể truy vấn lớn hơn, việc này sử dụng nhiều bộ nhớ hơn. Tuy nhiên, việc theo dõi họ sẽ tạo ra nhiều kết quả hơn
kết quả chính xác.
Nếu bạn không lo lắng về tác động đối với bộ nhớ của các truy vấn lớn, hãy bật cờ này theo mặc định trong bazelrc của bạn.
Nếu truy vấn với các khía cạnh bị vô hiệu hoá, bạn có thể gặp vấn đề trong đó mục tiêu X không thành công trong khi
đang tạo mục tiêu Y nhưng cquery somepath(Y, X)
và cquery deps(Y) | grep 'X'
không trả về kết quả nào vì sự phụ thuộc xảy ra thông qua một khía cạnh.
Định dạng đầu ra
Theo mặc định, cquery cho ra kết quả trong một danh sách các cặp nhãn và cấu hình theo thứ tự phụ thuộc. Bạn cũng có những lựa chọn khác để hiện kết quả.
Kiểu chuyển cảnh
--transitions=lite --transitions=full
Chuyển đổi cấu hình được dùng để tạo các mục tiêu bên dưới mục tiêu cấp cao nhất trong so với mục tiêu cấp cao nhất.
Ví dụ: một mục tiêu có thể áp dụng hiệu ứng chuyển đổi sang cấu hình máy chủ trên tất cả
các phần phụ thuộc trong thuộc tính tools
của nó. Những thông tin này được gọi là thuộc tính
chuyển đổi. Quy tắc cũng có thể áp đặt chuyển đổi trên cấu hình riêng của chúng,
được gọi là chuyển đổi lớp quy tắc. Định dạng đầu ra này xuất ra thông tin về
những chuyển đổi này như loại chúng và
ảnh hưởng của chúng đối với việc tạo bản dựng
.
Định dạng đầu ra này được kích hoạt bởi cờ --transitions
, theo mặc định là
được đặt thành NONE
. Bạn có thể đặt chế độ này ở chế độ FULL
hoặc LITE
. Đầu ra của chế độ FULL
thông tin về chuyển đổi lớp quy tắc và chuyển đổi thuộc tính bao gồm
điểm khác biệt chi tiết về các tuỳ chọn trước và sau khi chuyển đổi. LITE
loại phương tiện
cho ra cùng một thông tin mà không có sự khác biệt về tuỳ chọn.
Đầu ra của thông báo giao thức
--output=proto
Tuỳ chọn này khiến các mục tiêu kết quả được in trong một giao thức nhị phân biểu mẫu đệm. Bạn có thể tìm thấy định nghĩa của vùng đệm giao thức tại src/main/protobuf/analysis.proto.
CqueryResult
là thông báo cấp cao nhất chứa kết quả của truy vấn. Nó
có danh sách ConfiguredTarget
tin nhắn và danh sách Configuration
tin nhắn. Mỗi ConfiguredTarget
có một configuration_id
có giá trị bằng nhau
vào trường id
của thông báo Configuration
tương ứng.
--[no]proto:include_configurations
Theo mặc định, kết quả cquery trả về thông tin cấu hình dưới dạng một phần của mỗi mục tiêu đã định cấu hình. Nếu bạn muốn bỏ qua thông tin này và nhận kết quả proto được định dạng chính xác như đầu ra proto của truy vấn, hãy đặt cờ này thành false.
Xem tài liệu về kết quả proto của truy vấn để biết thêm các tuỳ chọn liên quan đến đầu ra proto.
Kết quả đầu ra trên đồ thị
--output=graph
Tuỳ chọn này tạo kết quả dưới dạng tệp .dot tương thích với Graphviz. Xem query
tài liệu về kết quả biểu đồ để biết chi tiết. cquery
cũng hỗ trợ --graph:node_limit
và
--graph:factored
.
Dữ liệu đầu ra của tệp
--output=files
Tuỳ chọn này in danh sách các tệp đầu ra do mỗi mục tiêu phù hợp tạo ra
bằng truy vấn tương tự như danh sách in ở cuối bazel build
lời gọi. Đầu ra chỉ chứa các tệp được quảng cáo trong
các nhóm đầu ra như được xác định bởi
Cờ --output_groups
.
Bản sao này có bao gồm các tệp nguồn.
Xác định định dạng đầu ra bằng Starlark
--output=starlark
Định dạng đầu ra này gọi Starlark
cho mỗi mục tiêu được định cấu hình trong kết quả truy vấn và in giá trị
được cuộc gọi trả về. Cờ --starlark:file
chỉ định vị trí của một
Tệp Starlark xác định một hàm có tên là format
với một tham số duy nhất,
target
. Hàm này được gọi cho mỗi Target (Mục tiêu)
trong kết quả truy vấn. Ngoài ra, để thuận tiện, bạn có thể chỉ định
phần nội dung của hàm được khai báo là def format(target): return expr
bằng cách sử dụng
Cờ --starlark:expr
.
"cquery" Phương ngữ Starlark
Môi trường Starlark cquery khác với tệp BUILD hoặc .bzl. Bộ công cụ này bao gồm
tất cả Starlark cốt lõi
hằng số và hàm tích hợp sẵn,
cộng với một vài truy vấn cụ thể được mô tả bên dưới, nhưng không phải (ví dụ) glob
,
native
hoặc rule
và không hỗ trợ câu lệnh tải.
build_options(target)
build_options(target)
trả về một bản đồ có khoá là giá trị nhận dạng tuỳ chọn tạo (xem
Cấu hình)
và có giá trị là giá trị Starlark. Tuỳ chọn tạo bản dựng có giá trị không phải là Starlark hợp pháp
các giá trị bị loại bỏ khỏi bản đồ này.
Nếu mục tiêu là tệp đầu vào, build_options(target)
sẽ trả về giá trị None (Không có) dưới dạng tệp đầu vào
các mục tiêu có cấu hình rỗng.
nhà cung cấp(mục tiêu)
providers(target)
trả về một tệp ánh xạ có các khoá là tên của
nhà cung cấp
(ví dụ: "DefaultInfo"
) và có giá trị là giá trị Starlark tương ứng. Nhà cung cấp
có giá trị không phải là giá trị Starlark hợp lệ sẽ bị loại khỏi bản đồ này.
Ví dụ
In danh sách tên cơ sở được phân tách bằng dấu cách gồm tất cả các tệp do //foo
tạo:
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
In danh sách các đường dẫn được phân tách bằng dấu cách gồm tất cả các tệp do mục tiêu quy tắc tạo ra trong
//bar
và các gói con của nó:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
In danh sách ghi nhớ của tất cả thao tác do //foo
đăng ký.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
In danh sách đầu ra biên dịch được cc_library
//baz
đăng ký.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
In giá trị của tuỳ chọn dòng lệnh --javacopt
khi tạo //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
In nhãn của từng mục tiêu bằng đúng một kết quả đầu ra. Ví dụ này sử dụng Các hàm Starlark được xác định trong một tệp.
$ cat example.cquery def has_one_output(target): return len(target.files.to_list()) == 1 def format(target): if has_one_output(target): return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
In nhãn của từng mục tiêu hoàn toàn là Python 3. Ví dụ này sử dụng Các hàm Starlark được xác định trong một tệp.
$ cat example.cquery def format(target): p = providers(target) py_info = p.get("PyInfo") if py_info and py_info.has_py3_only_sources: return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
Trích xuất một giá trị từ một Nhà cung cấp do người dùng xác định.
$ cat some_package/my_rule.bzl MyRuleInfo = provider(fields={"color": "the name of a color"}) def _my_rule_impl(ctx): ... return [MyRuleInfo(color="red")] my_rule = rule( implementation = _my_rule_impl, attrs = {...}, ) $ cat example.cquery def format(target): p = providers(target) my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'") if my_rule_info: return my_rule_info.color return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
cquery so với truy vấn
cquery
và query
bổ trợ cho nhau và vượt trội về khả năng
ngách khác nhau. Hãy xem xét những điều sau để quyết định xem công cụ nào phù hợp với bạn:
cquery
đi theo các nhánhselect()
cụ thể đến vào mô hình biểu đồ chính xác mà bạn tạo.query
không biết lựa chọn nào phân nhánh mà bản dựng chọn, vì vậy kết quả gần đúng bằng cách bao gồm tất cả các nhánh.- Độ chính xác của
cquery
yêu cầu bạn phải tạo nhiều biểu đồ hơnquery
có. Cụ thể,cquery
đánh giá các mục tiêu được định cấu hình trong khi chỉquery
đánh giá mục tiêu. Quá trình này mất nhiều thời gian hơn và tốn nhiều bộ nhớ hơn. - Diễn giải của
cquery
về ngôn ngữ truy vấn gây ra sự không rõ ràng màquery
tránh được. Ví dụ: nếu"//foo"
tồn tại ở hai cấu hình, một cấu hình sẽcquery "deps(//foo)"
có nên dùng không? Hàm[config](#config)
có thể giúp bạn làm việc này. - Là một công cụ mới hơn,
cquery
không hỗ trợ một số mục đích sử dụng nhất định trường hợp. Hãy xem phần Các vấn đề đã biết để biết thông tin chi tiết.
Vấn đề đã biết
Tất cả mục tiêu mà cquery
"xây dựng" phải có cùng cấu hình.
Trước khi đánh giá truy vấn, cquery
sẽ kích hoạt quá trình tạo
trước thời điểm thực thi các hành động liên quan đến bản dựng. Mục tiêu
"công trình" được chọn theo mặc định từ tất cả các nhãn xuất hiện trong truy vấn
biểu thức (có thể ghi đè
với --universe_scope
). Các
phải có cùng cấu hình.
Mặc dù những đối tượng này thường có chung "mục tiêu" cấp cao nhất cấu hình,
các quy tắc có thể thay đổi cấu hình của chính chúng với
hiệu ứng chuyển đổi cạnh viền sắp tới.
Đây là điểm thiếu sót của cquery
.
Giải pháp: Nếu có thể, hãy đặt --universe_scope
thành nghiêm ngặt hơn
phạm vi. Ví dụ:
# This command attempts to build the transitive closures of both //foo and # //bar. //bar uses an incoming edge transition to change its --cpu flag. $ bazel cquery 'somepath(//foo, //bar)' ERROR: Error doing post analysis query: Top-level targets //foo and //bar have different configurations (top-level targets with different configurations is not supported) # This command only builds the transitive closure of //foo, under which # //bar should exist in the correct configuration. $ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo
Không hỗ trợ --output=xml
.
Đầu ra không xác định.
cquery
không tự động xoá biểu đồ bản dựng khỏi
các lệnh trước đó và do đó có thể chọn được kết quả từ các
truy vấn. Ví dụ: genquery
thực hiện quá trình chuyển đổi máy chủ lưu trữ
thuộc tính tools
của mình – tức là thuộc tính này định cấu hình các công cụ trong
cấu hình máy chủ lưu trữ.
Bạn có thể xem các hiệu ứng kéo dài của quá trình chuyển đổi đó ở bên dưới.
$ cat > foo/BUILD <<<EOF genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", ) EOF $ bazel cquery "//foo:tool" tool(target_config) $ bazel cquery "deps(//foo:my_gen)" my_gen (target_config) tool (host_config) ... $ bazel cquery "//foo:tool" tool(host_config)
Giải pháp: thay đổi bất kỳ tuỳ chọn khởi động nào để buộc phân tích lại các mục tiêu đã định cấu hình.
Ví dụ: thêm --test_arg=<whatever>
vào lệnh tạo.
Khắc phục sự cố
Mẫu mục tiêu đệ quy (/...
)
Nếu bạn gặp phải:
$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)" ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]' because package is not in scope. Check that all target patterns in query expression are within the --universe_scope of this query.
điều này cho thấy không chính xác gói //foo
không nằm trong phạm vi mặc dù
--universe_scope=//foo:app
có tính năng này. Điều này là do những hạn chế về thiết kế trong
cquery
. Để giải quyết vấn đề này, hãy thể hiện rõ //foo/...
trong vũ trụ
phạm vi:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Nếu cách này không hiệu quả (ví dụ: do một số mục tiêu trong //foo/...
không thể
bằng các cờ bản dựng đã chọn), hãy gỡ gói mẫu vào
các gói thành phần có truy vấn xử lý trước:
# Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into # a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge. # Output looks like "//foo:*+//foo/bar:*+//foo/baz". # $ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/... --output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"