cquery
é uma variante de query
que processa corretamente
select()
e os efeitos das opções de build no
gráfico de build.
Isso é feito 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 o cquery
é executado no gráfico de destino configurado, ele não tem insights sobre artefatos como ações de build nem acesso a regras test_suite
, já que não são destinos configurados. Para o primeiro caso, consulte aquery
.
Sintaxe básica
Uma chamada simples de cquery
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. Ocquery
é compatível com a maioria das funções doquery
, além de algumas novas.//target
é a expressão transmitida à 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 guia de consultas para ver exemplos.
cquery
exige um destino para passar pelas 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 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 acontece porque os IDs completos são hashes SHA-256, que são longos e difíceis de seguir. 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 desejado
//foo
tem um significado diferente para cquery
e query
. Isso acontece 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 como 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 principal de ordenação de consultas.
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 quiser declarar precisamente qual instância consultar, use a função config
.
Consulte a documentação sobre padrões de destino do query
para mais informações.
Funções
Do conjunto de funções
compatíveis com query
, o cquery
é compatível com 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 a 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 extraídos de $
bazel config
ou da saída de um 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, apenas aqueles que puderem ser encontrados serão retornados. Se nenhum resultado for encontrado na configuração especificada, a consulta vai falhar.
Opções
Opções de build
O 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 dos 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_binary( name = "tool", srcs = ["tool.cpp"], )
As genrules configuram as ferramentas na configuração de execução para que as consultas a seguir produzam estas 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 dos destinos criados é usado como o universo da consulta. De qualquer forma, os destinos
a serem criados precisam ser criáveis no nível superior (ou seja, compatíveis com
opções de nível superior). cquery
retorna resultados no fechamento transitivo dessas metas de nível superior.
Mesmo que seja possível criar todas as metas em uma expressão de consulta no nível superior, talvez seja melhor não fazer isso. Por exemplo, definir explicitamente --universe_scope
pode impedir a criação de metas várias vezes em configurações que não são importantes para você. Também pode ajudar a especificar qual versão de configuração de um destino você está procurando. Defina essa flag
se a expressão de consulta for mais complexa 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 cadeias de ferramentas resolvidas.
--tool_deps
(booleano, padrão=True)
Definir essa flag como "false" filtra todos os destinos configurados em que o caminho do destino consultado até eles cruza uma transição entre a configuração de destino e as configurações não destinadas. Se o destino consultado estiver na configuração de destino, definir --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 é de destino, definir --notool_deps
vai retornar apenas 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=True)
Inclua dependências adicionadas por aspectos.
Se essa flag estiver desativada, cquery somepath(X, Y)
e
cquery deps(X) | grep 'Y'
vão omitir Y se X depender dele apenas por um aspecto.
Formatos de saída
Por padrão, o cquery gera resultados em uma lista de pares de rótulo e configuração ordenados por dependência. 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 de nível superior em configurações diferentes.
Por exemplo, um destino pode impor uma transição para a configuração de execução em todas as dependências no atributo tools
. Elas 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 mostra informações sobre
essas transições, como o tipo e o efeito delas nas opções de
build.
Esse formato de saída é acionado pela flag --transitions
, que por padrão é definida como NONE
. Ele pode ser definido como o modo FULL
ou LITE
. O modo FULL
gera informações sobre transições de classe de regra e de atributo, incluindo uma diferença detalhada das opções antes e depois da transição. O modo LITE
gera as mesmas informações sem a diferença de opções.
Saída de mensagem de protocolo
--output=proto
Essa opção faz com que os destinos resultantes sejam impressos em um 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 outra 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 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 do gráfico
--output=graph
Essa opção gera a saída como um arquivo .dot compatível com Graphviz. Consulte a documentação de saída de gráficos do query
para mais detalhes. O cquery
também é compatível com --graph:node_limit
e
--graph:factored
.
Arquivos de saída
--output=files
Essa opção imprime uma lista dos arquivos de saída produzidos por cada destino correspondente
pela consulta, semelhante à lista impressa no final de uma invocação de bazel build
. A saída contém apenas os arquivos anunciados nos grupos de saída solicitados, conforme determinado pela flag --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 obtido por bazel info execution_root
. Se o symlink 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.
Definir o formato de saída usando 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 Target 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
flag --starlark:expr
.
Dialeto Starlark "cquery"
O ambiente Starlark do cquery é diferente de um arquivo BUILD ou .bzl. Ele inclui todas as constantes e funções integradas principais do Starlark, além de algumas específicas do 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 em que as chaves são identificadores de opções de build (consulte Configurações) e os valores são os valores do Starlark. As opções de build cujos valores não são válidos em Starlark são omitidas desse mapa.
Se o destino for um arquivo de entrada, build_options(target)
vai retornar "None", já que os destinos de arquivos de entrada têm uma configuração nula.
providers(target)
providers(target)
retorna um mapa em que as chaves são nomes de provedores (por exemplo, "DefaultInfo"
) e os valores são os valores do Starlark.
Os provedores cujos valores não são válidos em Starlark 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 providers(target)['DefaultInfo'].files.to_list()])"
Imprima 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 providers(target)['DefaultInfo'].files.to_list()])"
Imprime 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]"
Imprime 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()]"
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 do Starlark definidas em um arquivo.
$ cat example.cquery def has_one_output(target): return len(providers(target)["DefaultInfo"].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 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
Extrai 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ê:
cquery
segue ramificaçõesselect()
específicas para modelar o gráfico exato que você cria.query
não sabe qual ramificação a build escolhe, então faz uma superestimativa incluindo todas as ramificações.- A precisão do
cquery
exige a criação de mais partes do gráfico do que oquery
. Especificamente, ocquery
avalia destinos configurados, enquanto oquery
avalia apenas destinos. Isso leva mais tempo e usa mais memória. - A interpretação de
cquery
da linguagem de consulta introduz uma ambiguidade quequery
evita. Por exemplo, se"//foo"
existir em duas configurações, qual delascquery "deps(//foo)"
vai usar? A funçãoconfig
pode ajudar com isso.
Saída não determinística
O cquery
não limpa automaticamente o gráfico de build de comandos anteriores.
Por isso, ele tende a escolher resultados de consultas anteriores.
Por exemplo, genrule
exerce uma transição de execução no atributo tools
. Ou seja, ele configura as ferramentas na configuração de execução.
Confira abaixo os efeitos persistentes dessa transição.
$ cat > foo/BUILD <<
Isso pode ser desejável ou não, dependendo do que você está tentando avaliar.
Para desativar isso, execute blaze clean
antes de cquery
para garantir um gráfico de análise atualizado.
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 no
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 algumas metas em //foo/...
não podem
ser criadas com as flags de build escolhidas), desencapsule 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 "+" -))"