cquery
é uma variante de query
que processa corretamente
select()
e os efeitos das opções de build no gráfico
de build.
Isso é possível ao executar 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 de avaliar as opções.
Por 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
executa o gráfico de destino configurado, ele não tem insights
sobre artefatos como ações de versão nem acesso a regras test_suite
,
porque não são destinos configurados. Para a primeira opção, 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. Ocquery
é compatível com a maioria das funções doquery
, além de algumas novas.//target
é a expressão alimentada na 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 consulta 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. 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, é um hash opaco dos valores da opção de versão que definem a configuração.
Para ver 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. cquery
entende qualquer prefixo válido de um ID completo, semelhante a hashes curtos do Git (em inglês).
Para ver IDs completos, execute $ bazel config
.
Avaliação de 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 de compilação 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 tem garantia de ordenação além do contrato de ordenação de consultas principais.
Isso produz resultados mais sutis para expressões de consulta do que com query
.
O exemplo a seguir 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 com precisão qual instância consultar, use
a função config
.
Consulte a documentação de padrões de destino de query
para mais informações sobre padrões de destino.
Funções
Do conjunto de funções
compatíveis com query
, cquery
é compatível com todos, exceto visible
, siblings
, buildfiles
e tests
.
cquery
também introduz as novas funções a seguir:
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 personalizado. Os hashes podem ser recuperados 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 forem encontrados na configuração especificada, apenas aqueles que podem ser encontrados serão retornados. Se nenhum resultado puder ser encontrado na configuração especificada, a consulta falhará.
Opções
Opções de versão
cquery
é executado em uma compilação normal do Bazel e, portanto, herda o conjunto de opções disponíveis durante uma versão.
Como usar opções de consulta
--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 seja diferente dos dependentes. Essa sinalização permite consultar um destino como se ele fosse criado como uma dependência ou uma dependência transitiva de outro destino. Por 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 regras gerais configuram as ferramentas na configuração exec de modo que as seguintes consultas produzam as seguintes saídas:
Consulta | Destino criado | Saída |
---|---|---|
consulta ao "//x:tool" do Bazel | //x:tool | //x:tool(targetconfig) |
consultação "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(execconfig) |
Se essa sinalização for 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 criados 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 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 nas 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, já que não é possível especificar isso de outra maneira. Defina essa sinalização se a expressão de consulta for mais complexa que deps(//foo)
.
--implicit_deps
(booleano, padrão=True)
Definir essa sinalização como falso filtra todos os resultados que não estão explicitamente definidos no arquivo BUILD e são definidos em outro lugar pelo Bazel. Isso inclui filtrar conjuntos de ferramentas resolvidos.
--tool_deps
(booleano, padrão=True)
Definir essa sinalização como falsa filtra todos os destinos configurados para os quais o caminho do destino consultado cruza uma transição entre a configuração de destino e as configurações não relacionadas a destinos.
Se o destino consultado estiver na configuração de destino, a definição de --notool_deps
só retornará destinos que também estão na configuração de destino. Se o destino consultado estiver em uma configuração sem destino, a definição de --notool_deps
só retornará destinos também em configurações não segmentadas. Essa configuração geralmente não afeta a filtragem de conjuntos de ferramentas resolvidos.
--include_aspects
(booleano, padrão=True)
Inclua dependências adicionadas por aspects.
Se essa sinalização estiver desativada, cquery somepath(X, Y)
e
cquery deps(X) | grep 'Y'
omitirão Y se X só depender dela por meio de um aspecto.
Formatos de saída
Por padrão, o cquery gera resultados em uma lista ordenada por dependência de pares de rótulo e configuração. 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 para a configuração exec em todas as dependências em seu 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 exibe 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 sinalização --transitions
, que, por padrão, é definida como NONE
. Ele pode ser definido no modo FULL
ou LITE
. O modo FULL
exibe
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 a mesma informação sem as diferenças de opções.
Saída de mensagem de protocolo
--output=proto
Essa opção faz com que os destinos resultantes sejam impressos em um formato 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 consulta. Ele 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 de consulta 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 sinalização como "false".
Consulte a documentação de saída do proto da consulta para ver mais opções relacionadas à proto saída.
Saída do gráfico
--output=graph
Essa opção gera uma saída como um arquivo .dot compatível com Graphviz. Consulte a documentação de saída do gráfico de query
para detalhes. cquery
também é compatível com --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 exibida no final de uma invocação bazel build
. A saída contém apenas os arquivos anunciados nos grupos 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 recebido
via bazel info execution_root
. Se o link simbólico bazel-out
existir, os caminhos para os 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 facilitar, especifique apenas o corpo de uma função declarada como def format(target): return expr
usando a sinalização --starlark:expr
.
Dialeto 'cquery' do Starlark
O ambiente do Starlark do cquery é diferente de um arquivo BUILD ou .bzl. Ela inclui todas as constantes e funções integradas principais do Starlark, além de algumas específicas da cquery descritas abaixo, mas não (por exemplo) glob
, native
ou rule
e não é compatível com instruções de carregamento.
build_options(destino)
build_options(target)
retorna um mapa cujas chaves são identificadores de opção de versão (consulte Configurações) e quais são os valores do Starlark. As opções de compilação cujos valores não são valores legais do Starlark são omitidas do mapa.
Se o destino for um arquivo de entrada, build_options(target)
retornará None, já que os destinos do arquivo de entrada têm uma configuração nula.
provider(target)
providers(target)
retorna um mapa cujas chaves são nomes de provedores (por exemplo, "DefaultInfo"
) e cujos valores são os valores de Starlark. Os provedores com valores que não são valores legais do Starlark são omitidos deste mapa.
Exemplos
Mostre uma lista separada por espaço 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ço dos caminhos de todos os arquivos produzidos por destinos de 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()])"
Imprime uma lista dos elementos mnemônicos de todas as ações registradas por //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 cc_library
//baz
.
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']"
Imprima o rótulo de cada destino com exatamente uma saída. Neste exemplo, usamos as 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
Imprima o marcador de cada destino estritamente Python 3. Neste exemplo, usamos as 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 x consulta
cquery
e query
se complementam e se destacam em
diferentes nichos. Considere o seguinte para decidir o que é melhor para você:
cquery
segue ramificaçõesselect()
específicas para modelar o gráfico exato que você cria. Oquery
não sabe qual ramificação o build escolhe. Por isso, ele se sobrepõe ao incluir todos os branches.- A precisão de
cquery
requer a criação de mais do gráfico que oquery
. 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 de consulta introduz ambiguidade quequery
evita. Por exemplo, se"//foo"
existir em duas configurações, qual delascquery "deps(//foo)"
precisará usar? A funçãoconfig
pode ajudar com isso. - Como uma ferramenta mais recente,
cquery
não é compatível com determinados casos de uso. Consulte Problemas conhecidos para detalhes.
Problemas conhecidos
Todos os destinos que cquery
cria precisam ter a mesma configuração.
Antes de avaliar as consultas, cquery
aciona uma versão até
antes do ponto em que as ações de compilação serão executadas. Os destinos que ele "cria" são selecionados por padrão de todos os rótulos que aparecem na expressão da consulta. Isso 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.
É aí que fica a cquery
.
Solução: se possível, defina --universe_scope
como um escopo mais rigoroso. Por 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 determinística.
cquery
não exclui automaticamente os gráficos de build de comandos anteriores e, portanto, está propenso a coletar resultados de consultas anteriores. Por exemplo, genquery
exerce uma transição exec no
atributo tools
, ou seja, ele configura suas ferramentas na
configuração exec.
Você pode ver 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: altere qualquer opção de inicialização para forçar uma nova aná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 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 sinalizações de compilação escolhidas), descompacte manualmente o padrão nos
pacotes que o constituem 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 "+" -))"