cquery
é uma variante de query
que processa corretamente
select()
e os efeitos das opções de build no gráfico
de build.
Para isso, ela executa os resultados da fase de
análise do Bazel,
que integra esses efeitos. O query
, por outro lado, executa os 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 o cquery
é executado no gráfico de destino configurado, ele não tem insights
sobre artefatos, como ações de build ou acesso às regras test_suite
,
porque eles não são destinos configurados. Para o primeiro, consulte aquery
.
Sintaxe básica
Uma chamada cquery
simples tem esta aparência:
bazel cquery "function(//target)"
A expressão de consulta "function(//target)"
consiste no seguinte:
function(...)
é a função a ser executada no destino.cquery
oferece suporte à maioria das funções dequery
, além de algumas novas.//target
é a expressão fornecida à 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 consulta para conferir exemplos.
A cquery
exige que um destino seja 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 dos 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 de opção de build que definem a
configuração.
Para conferir o conteúdo completo da configuração, execute:
$ bazel config 9f87702
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 acompanhar. O cquery
entende qualquer prefixo
válido de um ID completo, semelhante aos
hashes curtos do Git.
Para ver os IDs completos, execute $ bazel config
.
Avaliação do padrão 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 é
determinística, mas cquery
não garante a 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 an exec-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 (exec)
Se você quiser declarar precisamente qual instância será consultada, use
a função config
.
Consulte a documentação de
padrão de destino do query
para mais informações sobre padrões de destino.
Funções
Do conjunto de funções
compatível com query
, cquery
oferece suporte a todas, exceto
allrdeps
,
buildfiles
,
rbuildfiles
,
siblings
, tests
e
visible
.
O 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 pela configuração especificada pelo
segundo argumento.
Os valores válidos para o segundo argumento são null
ou um
hash de configuração personalizada. Os hashes podem ser recuperados de $
bazel config
ou da saída de uma cquery
anterior.
Exemplos:
$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (exec) //baz (exec) $ bazel cquery "config(//baz, 3732cc8)"
Se nem todos os resultados do primeiro argumento puderem ser encontrados na configuração especificada, somente aqueles que puderem ser encontrados serão retornados. Se nenhum resultado for encontrado na configuração especificada, a consulta falhará.
Opções
Opções de build
O cquery
é executado em um build regular 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 deles seja diferente da dependência. Essa flag permite que você consulte 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_binary( name = "tool", srcs = ["tool.cpp"], )
O Genrules configura as ferramentas na configuração de execução para que as consultas a seguir produzam 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(execconfig) |
Se essa flag estiver definida, o conteúdo dela será criado. Se não estiver definido, todos os destinos
mencionados na expressão de consulta serão criados. O fechamento transitivo das
metas criadas é usado como o universo da consulta. De qualquer forma, os destinos a
ser 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 vantajoso 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 para você. Isso 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
completamente de outra maneira no momento. 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 são definidos explicitamente no arquivo BUILD e são definidos em outro lugar pelo Bazel. Isso inclui a filtragem de cadeias de ferramentas resolução.
--tool_deps
(booleano, padrão=True)
Definir essa flag como "false" filtra todos os destinos configurados em que o
caminho do destino consultado para eles cruza uma transição entre a configuração
do destino e as
configurações não-alvo.
Se o destino consultado estiver na configuração de destino, a configuração --notool_deps
só vai retornar destinos que também estiverem na configuração de destino. Se o destino
consultado estiver em uma configuração que não é de destino, a configuração --notool_deps
só retornará
destinos também em configurações que não são de destino. Essa configuração geralmente não afeta a filtragem
de toolchains resolvidas.
--include_aspects
(booleano, padrão=verdadeiro)
Inclua dependências adicionadas por aspectos.
Se essa flag estiver desativada, cquery somepath(X, Y)
e
cquery deps(X) | grep 'Y'
omitirão Y se X só depender dele por um aspecto.
Formatos de saída
Por padrão, a cquery gera resultados em uma lista de pares de rótulos e configurações ordenada por dependência. Há também outras opções para expor os resultados.
Transições
--transitions=lite --transitions=full
As transições de configuração são usadas para criar destinos abaixo dos destinos de nível superior em configurações diferentes dos destinos de nível superior.
Por exemplo, um destino pode impor uma transição à configuração "exec" em todas as
dependências no atributo tools
. Elas são conhecidas como transições
de atributos. 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 mostra informações sobre
essas transições, como o tipo delas e o efeito que elas têm nas opções
de build.
Esse formato de saída é acionado pela flag --transitions
, que é definida como NONE
por padrão. Pode ser definido como o modo FULL
ou LITE
. O modo FULL
gera informações sobre transições de classe de regras e de atributos, incluindo uma diferença detalhada das opções antes e depois da transição. O modo LITE
exibe as mesmas informações sem a diferença entre as opções.
Saída da 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_v2.proto.
CqueryResult
é a mensagem de nível superior que contém os resultados da cquery. Ela
tem uma lista de mensagens ConfiguredTarget
e uma lista de mensagens
Configuration
. 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 a saída proto formatada exatamente como a saída proto da consulta, defina essa flag como falsa.
Consulte a documentação de saída do .proto da consulta para mais opções relacionadas à saída do .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 do query
para mais detalhes. O 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 correspondido pela consulta, semelhante à lista impressa no final de uma invocação bazel build
. A saída contém apenas os arquivos divulgados nos grupos de saída solicitados, conforme determinado pela sinalização --output_groups
.
Ele inclui arquivos de origem.
Todos os caminhos emitidos por esse formato de saída são relativos ao
execroot, que pode ser acessado
por bazel info execution_root
. Se o link simbólico de conveniência bazel-out
existir,
os caminhos para arquivos no repositório principal também serão resolvidos em relação ao diretório
do espaço de trabalho.
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 sinalização --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 Target no resultado da consulta. Como alternativa, para maior comodidade, você pode especificar apenas o
corpo de uma função declarada como def format(target): return expr
usando a
flag --starlark:expr
.
Dialeto "cquery" do Starlark
O ambiente Starlark do cquery é diferente de um arquivo BUILD ou .bzl. Ele inclui todas as constantes e funçõesprincipais do Starlark, além de algumas específicas de cquery descritas abaixo, mas não (por exemplo) glob
, native
ou rule
e não aceita instruções de carregamento.
build_options(target)
build_options(target)
retorna um mapa com chaves que são identificadores de opções de build (consulte
Configurações)
e valores que são valores do Starlark. As opções de build cujos valores não são valores válidos do Starlark
são omitidas deste mapa.
Se o destino for um arquivo de entrada, build_options(target)
retornará None, porque os destinos de arquivo de entrada
têm uma configuração nula.
provedores(destino)
providers(target)
retorna um mapa com chaves que são nomes de
provedores
(por exemplo, "DefaultInfo"
) e valores que são os valores do Starlark. Os provedores com valores de Starlark não legais são omitidos do mapa.
Exemplos
Mostre 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()])"
Mostre uma lista separada por espaços dos caminhos de todos os arquivos produzidos por destinos rule em
//bar
e nos subpacotes:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
Mostra uma lista das mnemônicas de todas as ações registradas pelo //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
Mostre uma lista de saídas de compilação registradas por um //baz
cc_library
.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
Imprime 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
Imprime o rótulo de cada destino que é 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 consulta
cquery
e query
se complementam e se destacam em
diferentes nichos. Considere o seguinte para decidir qual é a melhor opção:
- O
cquery
segue ramos específicos deselect()
para modelar o gráfico exato que você cria.query
não sabe qual ramificação o build escolhe, então faz uma aproximação incluindo todas as ramificações. - A precisão de
cquery
requer a criação de mais do gráfico do quequery
. Especificamente,cquery
avalia destinos configurados, enquantoquery
só avalia destinos. Isso leva mais tempo e usa mais memória. - A interpretação de
cquery
da linguagem de consulta apresenta ambiguidade quequery
evita. Por exemplo, se"//foo"
existir em duas configurações, qual delas deve ser usada porcquery "deps(//foo)"
? A funçãoconfig
pode ajudar com isso. - Como uma ferramenta mais recente,
cquery
não oferece suporte a determinados casos de uso. Consulte Problemas conhecidos para mais detalhes.
Problemas conhecidos
Todos os destinos que cquery
"criar" precisam ter a mesma configuração.
Antes de avaliar as consultas, o cquery
aciona um build up pouco
antes do ponto em que as ações de build seriam executadas. Os destinos que ele
cria são selecionados por padrão entre 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 elas geralmente compartilhem a configuração "alvo" 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.
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 é compatível com o --output=xml
.
Saída não determinista.
O cquery
não limpa automaticamente o gráfico de build de
comandos anteriores e, portanto, é propenso a coletar resultados de consultas
anteriores. Por exemplo, genquery
exerce uma transição de execução no
atributo tools
, ou seja, ele configura as ferramentas na
configuração de execução.
Confira os efeitos remanescentes dessa transição abaixo.
$ 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 (exec_config) ... $ bazel cquery "//foo:tool" tool(exec_config)
Solução alternativa: mude qualquer opção de inicialização para forçar a reanálise das metas configuradas.
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 explicitamente //foo/...
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 "+" -))"