cquery é uma variante de query que processa corretamente os efeitos de
select() e das opções de build no gráfico de build.
Ele faz isso executando os resultados da fase de análise
do Bazel,
que integra esses efeitos. query, por outro lado, é executado nos resultados da fase de carregamento do
Bazel, antes que as opções sejam avaliadas.
Exemplo:
$ 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)
Cada resultado inclui um identificador exclusivo (9f87702) da configuração com que o destino é criado.
Como cquery é executado no gráfico de destino configurado, ele não tem insights
sobre artefatos como ações de build nem acesso a [test_suite](/versions/6.2.0/reference/be/general#test_suite)
regras, porque não são destinos configurados. Para o primeiro, consulte [aquery](/versions/6.2.0/docs/aquery).
Sintaxe básica
Uma chamada cquery simples é assim:
bazel cquery "function(//target)"
A expressão de consulta "function(//target)" consiste no seguinte:
function(...)é a função a ser executada no destino.cqueryoferece suporte à maioria das funções dequery, além de algumas novas.//targeté a expressão transmitida à função. Neste exemplo, a expressão é um destino simples. No entanto, a linguagem de consulta também permite o aninhamento de funções. Consulte o guia de consultas para exemplos.
cquery exige um destino para ser executado nas fases de carregamento e análise. A menos que especificado de outra forma, cquery analisa os destinos listados na
expressão de consulta. Consulte --universe_scope
para consultar dependências de destinos de build de nível superior.
Configurações
A linha:
//tree:ash (9f87702)
significa que //tree:ash foi criado em uma configuração com o ID 9f87702. Para a maioria dos
destinos, esse é um hash opaco dos valores da opção de build que definem a
configuração.
Para conferir o conteúdo completo da configuração, execute:
$ bazel config 9f87702
A configuração do host usa o ID especial (HOST). Arquivos de origem não gerados, como
aqueles encontrados comumente em srcs, usam o ID especial (null), porque eles
não precisam ser configurados.
9f87702 é um prefixo do ID completo. Isso ocorre porque os IDs completos são
hashes SHA-256, que são longos e difíceis de seguir. cquery entende qualquer prefixo válido de um ID completo, semelhante a
hashes curtos do Git.
Para conferir IDs completos, execute $ bazel config.
Avaliação de padrões de destino
//foo tem um significado diferente para cquery e query. Isso ocorre porque
cquery avalia destinos configurados e o gráfico de build pode ter várias versões
configuradas de //foo.
Para cquery, um padrão de destino na expressão de consulta é avaliado
para cada destino configurado com um rótulo que corresponde a esse padrão. A saída é
determinista, mas cquery não oferece garantia de ordenação além do
contrato de ordenação de consulta principal.
Isso produz resultados mais sutis para expressões de consulta do que com query.
Por exemplo, o seguinte pode produzir vários resultados:
# 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)
Se você quiser declarar com precisão qual instância consultar, use
a config função.
Consulte a documentação do padrão de destino de query's padrão de destino
para mais informações sobre padrões de destino.
Funções
Do conjunto de funções
com suporte de query, cquery oferece suporte a todas, exceto
allrdeps,
buildfiles,
rbuildfiles,
siblings, tests e
visible.
cquery também apresenta as seguintes novas funções:
config
expr ::= config(expr, word)
O operador config tenta encontrar o destino configurado para
o rótulo indicado pelo primeiro argumento e a configuração especificada pelo
segundo argumento.
Os valores válidos para o segundo argumento são target, host, null, ou um
hash de configuração personalizado. Os hashes podem ser recuperados de $
bazel config ou da saída de um cquery anterior.
Exemplos:
$ bazel cquery "config(//bar, host)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (HOST) //baz (3732cc8) $ bazel cquery "config(//baz, 3732cc8)"
Se nem todos os resultados do primeiro argumento puderem ser encontrados na configuração especificada, apenas aqueles que puderem ser encontrados serão retornados. Se nenhum resultado puder ser encontrado na configuração especificada, a consulta falhará.
Opções
Opções de build
cquery é executado em um build normal do Bazel e, portanto, herda o conjunto de
opções disponíveis durante um build.
Como usar opções de cquery
--universe_scope (lista separada por vírgulas)
Muitas vezes, as dependências de destinos configurados passam por transições, o que faz com que a configuração delas seja diferente da dependente. Essa flag permite consultar um destino como se ele fosse criado como uma dependência ou uma dependência transitiva de outro destino. Exemplo:
# x/BUILD
genrule(
name = "my_gen",
srcs = ["x.in"],
outs = ["x.cc"],
cmd = "$(locations :tool) $< >$@",
tools = [":tool"],
)
cc_library(
name = "tool",
)
As genrules configuram as ferramentas na configuração do host . Portanto, as consultas a seguir produziriam as seguintes saídas:
| Consulta | Destino criado | Saída |
|---|---|---|
| bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
| bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(hostconfig) |
Se essa flag estiver definida, o conteúdo dela será criado. Se ela não estiver definida, todos os destinos
mencionados na expressão de consulta serão criados. O fechamento transitivo dos
destinos criados é usado como o universo da consulta. De qualquer forma, os destinos a
serem criados precisam ser criados no nível superior, ou seja, compatíveis com as opções de nível superior
. cquery retorna resultados no fechamento transitivo desses
destinos de nível superior.
Mesmo que seja possível criar todos os destinos em uma expressão de consulta no nível superior, pode ser benéfico não fazer isso. Por exemplo, definir explicitamente --universe_scope pode impedir a criação de destinos várias vezes em configurações que não são importantes. Também pode ajudar a especificar qual versão de configuração de um
destino você está procurando, já que não é possível
especificar isso de outra forma. Defina essa flag
se a expressão de consulta for mais complexa do que deps(//foo).
--implicit_deps (booleano, padrão=True)
Definir essa flag como "false" filtra todos os resultados que não estão definidos explicitamente no arquivo BUILD e, em vez disso, são definidos em outro lugar pelo Bazel. Isso inclui a filtragem de conjuntos de ferramentas resolvidos.
--tool_deps (booleano, padrão=True)
Definir essa flag como "false" filtra todos os destinos configurados para os quais o
caminho do destino consultado até eles cruza uma transição entre a configuração de destino
e as
configurações não de destino.
Se o destino consultado estiver na configuração de destino, definir --notool_deps vai
retornar apenas os destinos que também estão na configuração de destino. Se o destino consultado
estiver em uma configuração não de destino, definir --notool_deps vai retornar apenas
os destinos também em configurações não de destino. Essa configuração geralmente não afeta a filtragem
de conjuntos de ferramentas resolvidos.
--include_aspects (booleano, padrão=True)
Aspectos podem adicionar
dependências extras a um build. Por padrão, cquery não segue aspectos porque
eles aumentam o gráfico consultável, o que usa mais memória. No entanto, segui-los produz resultados mais
precisos.
Se você não estiver preocupado com o impacto de memória de consultas grandes, ative essa flag por padrão em seu bazelrc.
Se você consultar com os aspectos desativados, poderá ocorrer um problema em que o destino X falha ao
criar o destino Y, mas cquery somepath(Y, X) e cquery deps(Y) | grep 'X' não retornam resultados porque a dependência ocorre por um aspecto.
Formatos de saída
Por padrão, cquery gera resultados em uma lista de pares de rótulos e configurações ordenados por dependência. Há outras opções para expor os resultados.
Transições
--transitions=lite --transitions=full
Por exemplo, um destino pode impor uma transição para a configuração do host em todas as
dependências no atributo tools. Essas são conhecidas como transições de atributo. As regras também podem impor transições nas próprias configurações,
conhecidas como transições de classe de regra. Esse formato de saída gera informações sobre
essas transições, como o tipo e o efeito que elas têm nas opções de build.
Esse formato de saída é acionado pela flag --transitions, que por padrão é
definida como NONE. Ela pode ser definida como modo FULL ou LITE. O modo FULL gera
informações sobre transições de classe de regra e transições de atributo, incluindo um
diff detalhado das opções antes e depois da transição. O modo LITE
gera as mesmas informações sem o diff de opções.
Saída de mensagem de protocolo
--output=proto
Essa opção faz com que os destinos resultantes sejam impressos em um formulário de buffer de protocolo binário. A definição do buffer de protocolo pode ser encontrada em src/main/protobuf/analysis.proto.
CqueryResult é a mensagem de nível superior que contém os resultados da cquery. Ela
tem uma lista de ConfiguredTarget mensagens e uma lista de Configuration
mensagens. Cada ConfiguredTarget tem um configuration_id cujo valor é igual
ao do campo id da mensagem Configuration correspondente.
--[no]proto:include_configurations
Por padrão, os resultados da cquery retornam informações de configuração como parte de cada destino configurado. Se você quiser omitir essas informações e receber uma saída proto formatada exatamente como a saída proto da consulta, defina essa flag como "false".
Consulte a documentação de saída proto da consulta para mais opções relacionadas à saída proto.
Saída de gráfico
--output=graph
Essa opção gera a saída como um arquivo .dot compatível com o Graphviz. Consulte a documentação de saída de gráfico de query's
para mais detalhes. cquery
também oferece suporte a --graph:node_limit e
--graph:factored.
Saída de arquivos
--output=files
Essa opção imprime uma lista dos arquivos de saída produzidos por cada destino correspondente
à consulta, semelhante à lista impressa no final de uma bazel build
invocação. A saída contém apenas os arquivos anunciados nos grupos de saída solicitados
, conforme determinado pela
--output_groups flag.
Ela inclui arquivos de origem.
Como definir o formato de saída usando o Starlark
--output=starlark
Esse formato de saída chama uma função
Starlark para cada destino configurado no resultado da consulta e imprime o valor
retornado pela chamada. A flag --starlark:file especifica o local de um
arquivo Starlark que define uma função chamada format com um único parâmetro,
target. Essa função é chamada para cada destino
no resultado da consulta. Como alternativa, para sua conveniência, você pode especificar apenas o
corpo de uma função declarada como def format(target): return expr usando a
--starlark:expr flag.
Dialeto Starlark "cquery"
O ambiente Starlark da cquery é diferente de um arquivo BUILD ou .bzl. Ele inclui
todas as constantes e funções integradas do Starlark
principal,
além de algumas específicas da cquery descritas abaixo, mas não (por exemplo) glob,
native, ou rule, e não oferece suporte a instruções de carregamento.
build_options(target)
build_options(target) retorna um mapa cujas chaves são identificadores de opção de build (consulte
Configurações)
e cujos valores são os valores Starlark. As opções de build cujos valores não são valores Starlark
válidos são omitidas desse mapa.
Se o destino for um arquivo de entrada, build_options(target) vai retornar "None", já que os destinos de arquivo de entrada
têm uma configuração nula.
providers(target)
providers(target) retorna um mapa cujas chaves são nomes de
provedores
(por exemplo, "DefaultInfo") e cujos valores são os valores Starlark. Os provedores
cujos valores não são valores Starlark válidos são omitidos desse mapa.
Exemplos
Imprima uma lista separada por espaços dos nomes de base de todos os arquivos produzidos por //foo:
bazel cquery //foo --output=starlark \
--starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
Imprima uma lista separada por espaços dos caminhos de todos os arquivos produzidos por regra destinos em
//bar e seus subpacotes:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \
--starlark:expr="' '.join([f.path for f in target.files.to_list()])"
Imprima uma lista dos mnemônicos de todas as ações registradas por //foo.
bazel cquery //foo --output=starlark \
--starlark:expr="[a.mnemonic for a in target.actions]"
Imprima uma lista de saídas de compilação registradas por um cc_library //baz.
bazel cquery //baz --output=starlark \
--starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
Imprima o valor da opção de linha de comando --javacopt ao criar //foo.
bazel cquery //foo --output=starlark \
--starlark:expr="build_options(target)['//command_line_option:javacopt']"
Imprima o rótulo de cada destino com exatamente uma saída. Este exemplo usa funções Starlark definidas em um arquivo.
$ 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
Imprima o rótulo de cada destino que seja estritamente Python 3. Este exemplo usa funções Starlark definidas em um arquivo.
$ 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
Extraia um valor de um provedor definido pelo usuário.
$ 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 x query
cquery e query se complementam e se destacam em
nichos diferentes. Considere o seguinte para decidir qual é a melhor opção para você:
cquerysegue ramificaçõesselect()específicas para modelar o gráfico exato que você cria.querynão sabe qual ramificação o build escolhe, então faz uma superaproximação incluindo todas as ramificações.- A precisão de
cquery's exige a criação de mais do gráfico do quequeryfaz. Especificamente,cqueryavalia destinos configurados enquantoqueryapenas avalia destinos. Isso leva mais tempo e usa mais memória. - A interpretação da linguagem de consulta de
cquery's introduz ambiguidade quequeryevita. Por exemplo, se"//foo"existir em duas configurações, qual deverácquery "deps(//foo)"usar? A função[config](#config)pode ajudar com isso. - Como uma ferramenta mais recente,
cquerynão oferece suporte a determinados casos de uso. Consulte Problemas conhecidos para mais detalhes.
Problemas conhecidos
Todos os destinos que cquery "cria" precisam ter a mesma configuração.
Antes de avaliar as consultas, cquery aciona um build até o ponto em que as ações de build seriam executadas. Os destinos que ele"cria" são selecionados por padrão em todos os rótulos que aparecem na expressão de consulta (isso pode ser substituído por --universe_scope). Eles precisam ter a mesma configuração.
Embora eles geralmente compartilhem a configuração de "destino" de nível superior,
as regras podem mudar a própria configuração com
transições de borda de entrada.
É aí que cquery fica aquém.
Solução alternativa: se possível, defina --universe_scope como um escopo mais restrito. Exemplo:
# 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
Não há suporte para --output=xml.
Saída não determinista.
cquery não limpa automaticamente o gráfico de build de
comandos anteriores e, portanto, está sujeito a receber resultados de consultas anteriores. Por exemplo, genquery exerce uma transição de host no
atributo tools - ou seja, ele configura as ferramentas na
configuração do host.
Confira abaixo os efeitos persistentes dessa transição.
$ 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)
Solução alternativa: mude qualquer opção de inicialização para forçar a reanálise dos destinos configurados.
Por exemplo, adicione --test_arg=<whatever> ao comando de build.
Solução de problemas
Padrões de destino recursivos (/...)
Se você encontrar:
$ 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.
isso sugere incorretamente que o pacote //foo não está no escopo, mesmo que
--universe_scope=//foo:app o inclua. Isso ocorre devido a limitações de design em
cquery. Como solução alternativa, inclua //foo/... explicitamente no escopo do universo:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Se isso não funcionar (por exemplo, porque alguns destinos em //foo/... não podem
ser criados com as flags de build escolhidas), descompacte manualmente o padrão nos
pacotes constituintes com uma consulta de pré-processamento:
# 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 "+" -))"