cquery
é uma variante de query
que processa corretamente
os efeitos de select()
e das opções de build no gráfico
de build.
Para isso, ele executa os resultados da fase
de análise do Bazel,
que integra esses efeitos. 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 foi criado.
Como cquery
é executado no gráfico de destino configurado, ele não tem insights
de artefatos, como ações de build, nem acesso a regras [test_suite](/versions/6.2.0/reference/be/general#test_suite)
,
porque elas não são destinos configurados. Para o primeiro caso, consulte [aquery](/versions/6.2.0/docs/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 alimentada à função. Neste exemplo, a expressão é um destino simples. Mas a linguagem de consulta também permite o aninhamento de funções. Consulte o artigo Como fazer consultas para ver exemplos.
cquery
requer 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. Confira --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 acessar o conteúdo completo da configuração, execute:
$ bazel config 9f87702
A configuração do host usa o ID especial (HOST)
. Os arquivos de origem não gerados, como
os comumente encontrados em srcs
, usam o ID especial (null)
, porque
não precisam ser configurados.
9f87702
é um prefixo do ID completo. Isso ocorre porque os IDs completos são
hashes SHA-256, longos e difíceis de seguir. cquery
entende qualquer prefixo
válido de um ID completo, semelhante aos
hashes Git short.
Para acessar os IDs completos, execute $ bazel config
.
Avaliação do padrão de destino
//foo
tem um significado diferente para cquery
do que para query
. Isso ocorre porque
cquery
avalia destinos configurados, e o gráfico do 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 ordem além do
contrato de ordenação da consulta principal.
Isso produz resultados mais sutis para expressões de consulta do que com query
.
Por exemplo, o comando a seguir 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 em qual instância a consulta será feita, use
a função config
.
Consulte a documentação do padrão de destino
de query
para mais informações sobre padrões de destino.
remotas
Do conjunto de funções
compatíveis com query
, cquery
oferece suporte a todos, exceto visible
, siblings
, buildfiles
e tests
.
cquery
também introduz estas 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 da $
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 forem 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
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 dos destinos configurados passam por transições, o que faz com que a configuração deles seja diferente dos dependentes. 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_library( name = "tool", )
As regras gerais configuram as ferramentas na configuração do host de modo que as consultas a seguir produzam as seguintes saídas:
Consulta | Criados | 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 for definida, o conteúdo dela será criado. Se ele não for definido, 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
ser criados precisam ser compilados 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 você não importa. Ela 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 totalmente de qualquer outra maneira. Defina essa sinalização
se sua expressão de consulta for mais complexa que deps(//foo)
.
--implicit_deps
(booleano, padrão=True)
Definir essa sinalização como falsa filtra todos os resultados que não estão explicitamente definidos no arquivo BUILD e, em vez disso, foram 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 falsa filtra todos os destinos configurados para os quais
o caminho do destino consultado passa por uma transição entre a configuração
de destino e as
configurações que não são de destino.
Se o destino consultado estiver na configuração de destino, a definição de --notool_deps
vai retornar
apenas destinos que também estão na configuração de destino. Se o destino consultado
estiver em uma configuração que não seja de destino, a definição de --notool_deps
retornará
apenas 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)
Os aspectos podem adicionar
outras dependências a um build. Por padrão, cquery
não segue aspectos porque
aumentam o gráfico consultável, o que usa mais memória. Mas segui-las produz resultados mais
precisos.
Se você não estiver preocupado com o impacto de grandes consultas na memória, ative essa sinalização por padrão no bazelrc.
Se você fizer uma consulta com aspectos desativados, poderá encontrar 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 meio de um aspecto.
Formatos de saída
Por padrão, a saída do cquery resulta em uma lista ordenada por dependência de pares de rótulos e configurações. Também há 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 para a configuração do host em todas
as dependências no atributo tools
. Isso é conhecido 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 gera informações sobre
essas transições, por exemplo, qual é o tipo delas e o efeito que elas têm nas opções de
build.
Esse formato de saída é acionado pela sinalização --transitions
que, por padrão, é
definida como NONE
. Ela pode ser definida no modo FULL
ou LITE
. O modo FULL
gera
informações sobre transições de classes de regras e transições de atributos, incluindo uma
comparação detalhada das opções antes e depois da transição. O modo LITE
gera as mesmas informações sem a diferença entre as 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. Ele
tem uma lista de mensagens ConfiguredTarget
e uma lista de mensagens
Configuration
. Cada ConfiguredTarget
tem um configuration_id
com o valor igual
ao do campo id
da mensagem Configuration
correspondente.
--[no]proto:include_configurations
Por padrão, os resultados do 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 que é formatada exatamente como a saída proto da consulta, defina essa flag como "false".
Consulte a documentação de saída do proto da consulta para mais opções relacionadas à saída do proto.
Saída do 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 do gráfico de query
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 correspondido
pela consulta, semelhante à lista mostrada no final de uma invocação
bazel build
. A saída contém apenas os arquivos anunciados nos grupos de saída solicitados, conforme determinado pela sinalização --output_groups
.
mas 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 mostra 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 Target
no resultado da consulta. Como alternativa, por conveniência, é possível especificar apenas o
corpo de uma função declarada como def format(target): return expr
usando a
flag --starlark:expr
.
Dialeto Starlark "cquery"
O ambiente cquery Starlark é diferente de um arquivo BUILD ou .bzl. Ela inclui
todas as principais
constantes e funções integradas do Starlark,
além de algumas específicas do cquery descritas abaixo, mas não (por exemplo) glob
,
native
ou rule
, além de não oferecer suporte a 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 com valores do Starlark. As opções de build com valores não legais do Starlark são omitidas deste mapa.
Se o destino for um arquivo de entrada, build_options(target)
retornará None, porque os destinos do 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 com valores que são os valores do Starlark. Os provedores com valores não legais do Starlark são omitidos desse mapa.
Exemplos
Mostre uma lista separada por espaços dos nomes 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 seus subpacotes:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
Mostra uma lista das mneumônicas de todas as ações registradas por //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
Mostra 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()]"
Mostre 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']"
Mostre o rótulo de cada destino com exatamente uma saída. Esse exemplo usa funções do 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
Mostre o rótulo de cada destino, que é estritamente Python 3. Esse exemplo usa funções do 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
Extrair 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 e query
cquery
e query
se complementam e se sobressaem em
nichos diferentes. Considere o seguinte e decida qual é a melhor para você:
cquery
segue ramificaçõesselect()
específicas para modelar o gráfico exato que você criou.query
não sabe qual ramificação a build escolhe, então ela é aproximada 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
avalia apenas destinos. Isso leva mais tempo e usa mais memória. - A interpretação de
cquery
da linguagem da consulta introduz ambiguidade quequery
evita. Por exemplo, se"//foo"
existir em duas configurações, qual delascquery "deps(//foo)"
precisará usar? A função[config](#config)
pode ajudar com isso. - Por ser uma ferramenta mais recente, a
cquery
não oferece suporte a alguns casos de uso. Consulte Problemas conhecidos para ver mais detalhes.
Problemas conhecidos
Todos os destinos que cquery
"criam" precisam ter a mesma configuração.
Antes de avaliar as consultas, cquery
aciona uma criação até o ponto
em que as ações de build seriam executadas. Os destinos que ela
cria são selecionados por padrão entre todos os rótulos que aparecem na expressão
de consulta (que pode ser substituído
por --universe_scope
). Eles
precisam ter a mesma configuração.
Embora elas geralmente compartilhem a configuração de "destino" de nível superior,
as regras podem alterar a própria configuração com
transições de borda de entrada.
É aqui que cquery
fica aquém.
Solução alternativa: se possível, defina --universe_scope
para um escopo
mais rigoroso. 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 o --output=xml
.
Saída não determinista.
cquery
não exclui automaticamente o gráfico de build dos
comandos anteriores e, portanto, está propenso a coletar resultados de
consultas anteriores. Por exemplo, genquery
executa uma transição de host no
atributo tools
, ou seja, ele configura as ferramentas na
configuração do host.
Veja abaixo os efeitos da 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: altere qualquer opção de inicialização para forçar uma nova análise dos destinos configurados.
Por exemplo, adicione --test_arg=<whatever>
ao seu 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 algum destino em //foo/...
não
pode criar 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 "+" -))"