Cquery (Configurable Query)
Overview
cquery
is a command complementary to query
that properly handles
configurations. While cquery
returns answers that are more correct, it does not
replace query
as it does not support all of query
's functions.
cquery
achieves configuration awareness by running after the
analysis phase
of a build, unlike traditional query
, which runs after the loading phase.
The most common use for cquery
is obtaining answers that correctly evaluate
select()
statements in configurable attributes. For example:
$ 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 $ bazel query "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash //tree:white-ash //tree:manna-ash //tree:common-ash #cquery $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (hash-of-config) //tree:manna-ash (hash-of-config)
In parentheses after each configured target, there is information about the configuration in which that target was built. For most targets, this is an (opaque) hash of the build options and values in that configuration. Targets configured in the host configuration are marked with HOST. Input files, like those found in the
srcsattribute of many library rules, have no need for configuration and are marked with null.
Keep in mind that cquery
works only on the configured target graph. Because of this,
it does not have insight into artifacts like build actions nor access to
test_suite
rules as they are not configured targets.
Basic Syntax
A simple example of the syntax for cquery
is as follows:
bazel cquery "function(//target)"
The query expression (in quotes) consists of the following:
-
function(...)
is the function to run on the target.cquery
supports most of the same functions as traditionalquery
. //target
is the expression fed to the function. In this example, the expression is a simple target, but the query language also allows nesting of functions. See the Query How-To for examples.
cquery
requires a target on which to run the loading and analysis
phases. Unless otherwise specified, cquery
parses the target(s)
listed in the query expression. See the --universe_scope
option
below for querying targets built under other targets.
Functions
Of the set of functions
supported by the traditional query
, cquery
supports
all but siblings, buildfiles, and tests.
The following functions are also in query
, but
have cquery
-specific notes:
somepath
expr ::= somepath(expr, expr)
query
's somepath
operator functions almost exactly like query
's: it computes paths between two sets of targets. But since cquery
runs on configured targets, cquery(//foo, //bar)
parses as "find a path from //foo
in the target configuration to //bar
in the target configuration".
If somepath
isn't returning any paths, try grepping for
your to target from deps(//from-target)
, i.e. bazel
cquery 'deps(//from-target)' | grep '//to-target'
. If you can
find //to-target
in the results in some other configuration, you
know there is a path. If you can find //to-target
in a standard
configuration (i.e. HOST
or null
), then you can
combine somepath
with the config
operator to find the path to that configured target (e.g. bazel cquery 'somepath(//from-target, config(//to-target, host))'
).
The following functions are unique to cquery
:
config
expr ::= config(expr, word)
The config
operator attempts to return the result of the first argument, configured
in the configuration specified by the second argument. Today, the second argument can only take in
three options target
, host
, or null
but we hope to expand
this functionality to be able to input custom configurations (or custom configuration diffs from
the default target configuration).
$ bazel cquery config(//foo, host) --universe_scope=//bar
Note that the above example query will return //foo
configured in the host configuration
if and only if //foo
exists in the host configuration in the universe of
this query (which we've set to the transitive closure of //bar
).
If not all results of the first argument can be found in the specified configuration, then only those that can be found are returned. If no results of the first argument can be found in the specified configuration, an error is thrown.
Options
Build Options
cquery
runs on top of a regular Bazel build and thus inherits the set of
options
available during a build.
Cquery options
--universe_scope
(comma-separated list)
Often, the dependencies of configured targets go through transitions, which causes their configuration to differ from their dependent. This flag allows you to query a target as if it were built as a dependency or a transitive dependency of another target. For example:
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", )
Genrules configure their tools in the host configuration so the following queries would produce the following outputs:
Query | Target Built | Output |
---|---|---|
bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(hostconfig) |
If this flag is set, its contents are built. If it's not set, all targets
mentioned in the query expression are built instead. The transitive closure of the
built targets are used as the universe of the query. Either way, the targets to
be built must be buildable at the top level (that is, compatible with top-level
options). cquery
returns results in the transitive closure of these
top-level targets.
Even if it's possible to build all targets in a query expression at the top
level, it may be beneficial to not do so. For example, explicitly setting
--universe_scope
could prevent building targets multiple times in
configurations you don't care about. It could also help specify which configuration version of a
target you're looking for (since it's not currently possible
to fully specify this any other way). We recommend that you set this
flag if your query expression is more complex than deps(//foo)
.
--implicit_deps
(boolean, default=True)
Setting this flag to false filters out all results that aren't explicitly set in the BUILD file and instead set elsewhere by Bazel.
--tool_deps
(boolean, default=True)
Setting this flag to false filters out all configured targets for which the
path from the queried target to them crosses a transition between the target
configuration and the
non-target configurations.
If the queried target is in the target configuration, setting --notool_deps
will
only return targets that also are in the target configuration. If the queried
target is in a non-target configuration, setting --notool_deps
will only return
targets also in non-target configurations.
Output Formats
By default, cquery outputs results in a dependency-ordered list of label and configuration pairs. There are other options for exposing the results as well.
Transitions
--transitions=lite --transitions=full
Configuration transitions are used to build targets underneath the top level targets in different configurations than the top level targets.
For example, a target might impose a transition to the host transition on all
dependencies in its tools
attribute. These are known as attribute
transitions. Rules can also impose transitions on their own configurations,
known as rule class transitions. This output format outputs information about
these transitions such as what type they are and the effect they have on build
options.
This output format is triggered by the --transitions
flag which by default is set to
NONE
. It can be set to FULL
or LITE
mode. FULL
mode outputs information about rule class transitions and attribute transitions including a detailed
diff of the options before and after the transition. LITE
mode outputs the same information
without the options diff.
Known Issues
-
Inaccessible configurations. With the exception of the host configuration being
printed as
HOST
, Configurations are currently output as hashes and there is no way for the user to input them (and thus to directly specify the configuration to query a target in). - No support for aspects, output options, or recursive target patterns (/...).
-
Non-deterministic output.
Cquery
does not automatically wipe the build graph from previous commands and is therefore prone to picking up results from past queries. For example,genquery
exerts a host transition on itstools
attribute - that is, it configures its tools in the host configuration. We can see the lingering effects of that transition below.
$ 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)
Workaround: change any startup option to force re-analysis of configured targets. For example,
add --test_arg=<whatever>
to your build command.
Updates
The Bazel configurability team is continuously improving cquery
. If you want to
ask questions, stay updated, or get involved, contact juliexxia@google.com