Esta página é o manual de referência da Linguagem de consulta Bazel usada
ao usar bazel query
para analisar dependências de build. Ela também
descreve os formatos de saída compatíveis com o bazel query
.
Para casos de uso práticos, consulte as Instruções de consulta do Bazel.
Referência de consulta adicional
Além de query
, que é executado no gráfico de destino da fase pós-carregamento,
o Bazel inclui a consulta do gráfico de ações e a consulta configurável.
Consulta do gráfico de ações
A consulta do gráfico de ações (aquery
) opera no gráfico de destino
configurado pós-análise e expõe informações sobre Ações, Artefatos e
os relacionamentos deles. aquery
é útil quando você tem interesse nas
propriedades das ações/artefatos gerados pelo gráfico de destino configurado.
Por exemplo, os comandos executados e as entradas, saídas e mnemônicas deles.
Para mais detalhes, confira a referência sobre aquery.
Consulta configurável
A consulta tradicional do Bazel é executada no gráfico de destino da fase pós-carregamento e,
portanto, não tem conceito de configurações nem dos conceitos relacionados. É importante notar que
ela não resolve corretamente as instruções de seleção
e retorna todas as resoluções possíveis de seleções. No entanto, o
ambiente de consulta configurável, cquery
, processa corretamente as configurações, mas
não fornece toda a funcionalidade da consulta original.
Para mais detalhes, consulte a referência sobre cquery.
Exemplos
Como as pessoas usam o bazel query
? Veja alguns exemplos:
Por que a árvore //foo
depende de //bar/baz
?
Mostrar um caminho:
somepath(foo/..., //bar/baz:all)
De quais bibliotecas C++ todos os testes de foo
dependem das quais
o destino foo_bin
não depende?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
Tokens: a sintaxe léxica
As expressões na linguagem de consulta são compostas pelos seguintes tokens:
Palavras-chave, como
let
. Palavras-chave são palavras reservadas do idioma, e cada uma delas é descrita abaixo. O conjunto completo de palavras-chave é:Palavras, como "
foo/...
", ".*test rule
" ou "//bar/baz:all
". Se uma sequência de caracteres estiver entre aspas (começa e termina com aspas simples ' ou começa e termina com aspas duplas "), ela é uma palavra. Se uma sequência de caracteres não for citada, ela ainda poderá ser analisada como uma palavra. Palavras sem aspas são sequências de caracteres retirados dos caracteres alfabéticos A-Za-z, os números 0-9 e os caracteres especiais*/@.-_:$~[]
(asterisco, barra, arroba, ponto, hífen, sublinhado, dois-pontos, cifrão, til, chave quadrada esquerda, chave quadrada direita). No entanto, palavras sem aspas não podem começar com um hífen-
ou asterisco*
, mesmo que os nomes de destino relativos comecem com esses caracteres.Palavras sem aspas também não podem incluir os caracteres de sinal de adição
+
ou de igual=
, mesmo que esses caracteres sejam permitidos em nomes de destino. Ao escrever um código que gera expressões de consulta, os nomes de destino precisam estar entre aspas.Os aspas são necessários ao escrever scripts que constroem expressões de consulta do Bazel a partir de valores fornecidos pelo usuário.
//foo:bar+wiz # WRONG: scanned as //foo:bar + wiz. //foo:bar=wiz # WRONG: scanned as //foo:bar = wiz. "//foo:bar+wiz" # OK. "//foo:bar=wiz" # OK.
Observe que essa citação é adicionada a qualquer aspas que possa ser exigida pelo shell, como:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
As palavras-chave e os operadores, quando citados, são tratados como palavras comuns. Por exemplo,
some
é uma palavra-chave, mas "algum" é uma palavra. Tantofoo
quanto "foo" são palavras.No entanto, tenha cuidado ao usar aspas simples ou duplas em nomes de destino. Ao citar um ou mais nomes de destino, use apenas um tipo de aspas: todas as aspas simples ou todas as aspas duplas.
Confira abaixo exemplos de como será a string de consulta Java:
'a"'a' # WRONG: Error message: unclosed quotation. "a'"a" # WRONG: Error message: unclosed quotation. '"a" + 'a'' # WRONG: Error message: unexpected token 'a' after query expression '"a" + ' "'a' + "a"" # WRONG: Error message: unexpected token 'a' after query expression ''a' + ' "a'a" # OK. 'a"a' # OK. '"a" + "a"' # OK "'a' + 'a'" # OK
Escolhemos essa sintaxe para que aspas não sejam necessárias na maioria dos casos. O exemplo
".*test rule"
(incomum) precisa de aspas: começa com um ponto e contém um espaço. Citar"cc_library"
é desnecessário, mas é inofensivo.Pontuação, como parênteses
()
, ponto.
e vírgula,
. Palavras que contêm pontuação (exceto as exceções listadas acima) precisam ser citadas.
Os caracteres de espaço em branco fora de uma palavra entre aspas são ignorados.
Conceitos da linguagem de consulta do Bazel
A linguagem de consulta do Bazel é uma linguagem de expressões. Cada expressão é avaliada como um conjunto parcialmente ordenado de destinos ou, equivalente, um gráfico (DAG) de destinos. Esse é o único tipo de dados.
O conjunto e o gráfico se referem ao mesmo tipo de dados, mas enfatizam aspectos diferentes dele, por exemplo:
- Definir:a ordem parcial das segmentações não é interessante.
- Gráfico:a ordem parcial das metas é significativa.
Ciclos no gráfico de dependências
Os gráficos de dependência do build precisam ser acíclicos.
Os algoritmos usados pela linguagem de consulta destinam-se ao uso em gráficos acíclicos, mas são robustos contra ciclos. Os detalhes de como os ciclos são tratados não são especificados e não podem ser confiáveis.
Dependências implícitas
Além das dependências de build que são definidas explicitamente em arquivos BUILD
,
o Bazel adiciona outras dependências implícitas às regras. As dependências implícitas
podem ser definidas por:
Por padrão, bazel query
considera as dependências implícitas
ao calcular o resultado da consulta. Esse comportamento pode ser alterado com
a opção --[no]implicit_deps
.
Observe que, como a consulta não considera configurações, possíveis implementações de conjunto de ferramentas não são consideradas dependências, apenas os tipos de conjunto de ferramentas necessários. Consulte a documentação do conjunto de ferramentas.
Solidez
As expressões da linguagem de consulta do Bazel operam no gráfico
de dependência de build, que é o gráfico definido implicitamente por todas
as declarações de regras em todos os arquivos BUILD
. É importante entender
que esse gráfico é um pouco abstrato e não constitui uma
descrição completa de como executar todas as etapas de um build. Para executar um build, também é necessário ter uma configuração. Consulte a seção de configurações do Guia do usuário para mais detalhes.
O resultado da avaliação de uma expressão na linguagem de consulta do Bazel é verdadeiro para todas as configurações, o que significa que pode ser uma aproximação conservadora e não exatamente precisa. Se você usar a ferramenta de consulta para calcular o conjunto de todos os arquivos de origem necessários durante uma compilação, ela poderá relatar mais do que o necessário porque, por exemplo, a ferramenta de consulta incluirá todos os arquivos necessários para oferecer suporte à tradução de mensagens, mesmo que você não pretenda usar esse recurso na compilação.
Sobre a preservação da ordem do gráfico
As operações preservam todas as restrições
de ordenação herdadas das subexpressões delas. Você pode pensar nisso como "a lei da conservação da ordem parcial". Veja um
exemplo: se você emitir uma consulta para determinar o fechamento transitivo das
dependências de um destino específico, o conjunto resultante é ordenado
de acordo com o gráfico de dependências. Se você filtrar esse conjunto para incluir apenas os destinos do tipo file
, a mesma relação de ordenação parcial transitiva será mantida entre cada par de destinos no subconjunto resultante, mesmo que nenhum desses pares esteja diretamente conectado no gráfico original.
Não há bordas de arquivo no gráfico de dependência de build.
No entanto, todos os operadores preservam a ordem, mas algumas operações, como as operações set, não introduzem nenhuma restrição de ordenação. Considere esta expressão:
deps(x) union y
A ordem do conjunto de resultados final garante a preservação de todas as
restrições de ordenação das subexpressões, ou seja, que todas as
dependências transitivas de x
sejam ordenadas corretamente em
relação umas às outras. No entanto, a consulta não garante nada sobre
a ordem dos destinos em y
, nem sobre
a ordem dos destinos em deps(x)
em relação àquelas em
y
(exceto para os destinos em
y
que também estão em deps(x)
).
Os operadores que introduzem restrições de ordem incluem:
allpaths
, deps
, rdeps
, somepath
e os caracteres curinga de padrão de destino
package:*
, dir/...
etc.
Consulta sobre o Sky
A consulta do céu é um modo de consulta que opera em um escopo universal especificado.
Funções especiais disponíveis somente no SkyQuery
O modo de consulta do Sky tem as funções de consulta adicionais allrdeps
e
rbuildfiles
. Essas funções operam em todo o escopo do universo, e é por isso que elas não fazem sentido para consultas normais.
Como especificar um escopo do universo
O modo de consulta do Sky é ativado transmitindo as duas sinalizações a seguir: (--universe_scope
ou --infer_universe_scope
) e --order_output=no
.
--universe_scope=<target_pattern1>,...,<target_patternN>
instrui a consulta a
pré-carregar o fechamento transitivo do padrão de destino especificado pelos padrões de destino, que pode
ser aditivo e subtrativo. Todas as consultas são avaliadas nesse "escopo". Em particular,
os operadores
allrdeps
e
rbuildfiles
retornam apenas resultados desse escopo.
--infer_universe_scope
diz ao Bazel para inferir um valor para --universe_scope
a partir da expressão de consulta. Esse valor inferido é a lista de padrões de destino exclusivos na expressão de consulta, mas talvez não seja o que você quer. Exemplo:
bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"
A lista de padrões de destino exclusivos nessa expressão de consulta é ["//my:target"]
. Portanto, o Bazel trata isso da mesma forma que a invocação:
bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"
Mas o resultado dessa consulta com --universe_scope
é apenas //my:target
.
Nenhuma das dependências inversas de //my:target
está no universo, por
construção. Por outro lado, considere:
bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"
Essa é uma invocação de consulta significativa que tenta computar os destinos de teste na expansão tests
dos destinos em alguns diretórios que dependem transitivamente de destinos cuja definição usa um determinado arquivo .bzl
. Aqui, --infer_universe_scope
é uma conveniência, especialmente no caso em que a escolha de --universe_scope
exigiria que você analisasse a expressão de consulta.
Portanto, para expressões de consulta que usam operadores com escopo do universo, como
allrdeps
e
rbuildfiles
, use
--infer_universe_scope
apenas se o comportamento dele for o que você quer.
A consulta do Sky tem algumas vantagens e desvantagens em comparação com a consulta padrão. A principal desvantagem é que ele não pode ordenar a saída de acordo com a ordem do gráfico e, portanto, determinados formatos de saída são proibidos. As vantagens são que ele fornece dois operadores (allrdeps
e rbuildfiles
) que não estão disponíveis na consulta padrão.
Além disso, o Sky Query faz seu trabalho introspectivamente o gráfico do Skyframe, em vez de criar um novo, que é a implementação padrão. Assim, há algumas circunstâncias em que
ele é mais rápido e usa menos memória.
Expressões: sintaxe e semântica da gramática
Esta é a gramática da linguagem de consulta do Bazel, expressa na notação EBNF:
expr ::= word
| let name = expr in expr
| (expr)
| expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
| set(word *)
| word '(' int | word | expr ... ')'
As seções a seguir descrevem cada uma das produções desta gramática em ordem.
Padrões de destino
expr ::= word
Sintaticamente, um padrão de destino é apenas uma palavra. Ele é interpretado como um
conjunto (não ordenado) de destinos. O padrão de destino mais simples é um rótulo, que
identifica um único destino (arquivo ou regra). Por exemplo, o padrão de destino
//foo:bar
é avaliado como um conjunto que contém um elemento, o destino, a regra
bar
.
Os padrões de destino generalizam rótulos para incluir caracteres curinga em pacotes e destinos. Por exemplo, foo/...:all
(ou apenas foo/...
) é um padrão de destino
que é avaliado para um conjunto que contém todas as regras em cada pacote recursivamente
abaixo do diretório foo
. bar/baz:all
é um padrão de destino avalia
como um conjunto que contém todas as regras no pacote bar/baz
, mas não nos
subpacotes dele.
Da mesma forma, foo/...:*
é um padrão de destino que é avaliado para um conjunto que contém todos os destinos (regras e arquivos) em cada pacote recursivamente abaixo do diretório foo
. bar/baz:*
avalia como um conjunto que contém todos os destinos no pacote bar/baz
, mas não seus subpacotes.
Como o caractere curinga :*
corresponde a arquivos e regras, geralmente ele é mais útil do que :all
para consultas. Por outro lado, o caractere curinga :all
(implícito em
padrões de destino, como foo/...
) costuma ser mais útil para builds.
Os padrões de destino bazel query
funcionam da mesma forma que os destinos de build bazel build
.
Para mais detalhes, consulte Padrões de destino ou
digite bazel help target-syntax
.
Os padrões de destino podem ser avaliados como um conjunto singleton (no caso de um rótulo), um
conjunto que contém muitos elementos (como no caso de foo/...
, que tem milhares
de elementos) ou como um conjunto vazio se o padrão de destino não corresponder a nenhuma meta.
Todos os nós no resultado de uma expressão de padrão de destino estão ordenados corretamente
em relação uns aos outros de acordo com a relação de dependência. Portanto, o resultado de
foo:*
não é apenas o conjunto de destinos no pacote foo
, ele também é o
gráfico sobre esses destinos. Não há garantias sobre a ordem relativa dos nós de resultado em relação a outros nós. Para mais detalhes, consulte a seção
Ordem dos gráficos.
Variáveis
expr ::= let name = expr1 in expr2
| $name
A linguagem de consulta do Bazel permite definições e referências a
variáveis. O resultado da avaliação de uma expressão let
é o mesmo de expr2, com todas as ocorrências livres da variável name substituídas pelo valor de expr1.
Por exemplo, let v = foo/... in allpaths($v, //common) intersect $v
é
equivalente a allpaths(foo/...,//common) intersect foo/...
.
Uma ocorrência de uma referência de variável name
diferente de uma expressão let name = ...
de inclusão é um erro. Em outras palavras, as expressões de consulta de nível superior não podem ter variáveis livres.
Nas produções gramaticais acima, name
é como uma palavra, mas com a
restrição adicional de ser um identificador legal na linguagem de programação
C. As referências à variável precisam incluir o caractere "$" antes.
Cada expressão let
define apenas uma variável, mas você pode aninhá-las.
Tanto os padrões de destino quanto as referências de variáveis consistem em um único token, uma palavra, criando uma ambiguidade sintática. No entanto, não há ambiguidade semântica, porque o subconjunto de palavras que são nomes de variáveis legais é separado do subconjunto de palavras que são padrões de destino legais.
Tecnicamente, as expressões let
não aumentam a expressividade da linguagem de consulta: qualquer consulta expressa na linguagem também pode ser expressa sem elas. No entanto, elas melhoram a concisão de muitas consultas e também podem levar a uma avaliação de consulta mais eficiente.
Expressões entre parênteses
expr ::= (expr)
Os parênteses associam subexpressões para forçar uma ordem de avaliação. Uma expressão entre parênteses é avaliada como o valor do seu argumento.
Operações algébricas de conjunto: interseção, união, diferença de definir
expr ::= expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
Esses três operadores calculam as operações usuais de conjunto nos respectivos argumentos.
Cada operador tem duas formas, uma forma nominal, como intersect
, e uma
forma simbólica, como ^
. Ambas as formas são equivalentes. As formas simbólicas são
mais rápidas de digitar. Para maior clareza, o restante desta página usa as formas nominais.
Por exemplo:
foo/... except foo/bar/...
avalia para o conjunto de segmentações que correspondem a foo/...
, mas não a foo/bar/...
.
É possível escrever a mesma consulta como:
foo/... - foo/bar/...
As operações intersect
(^
) e union
(+
) são comutativas (simétricas),
e except
(-
) é assimétrica. O analisador trata os três operadores como
associativos à esquerda e de igual precedência, então recomendamos que use parênteses. Por exemplo, as duas primeiras expressões são equivalentes, mas a terceira não é:
x intersect y union z
(x intersect y) union z
x intersect (y union z)
Ler destinos de uma fonte externa: definir
expr ::= set(word *)
O operador set(a b c ...)
calcula a união de um conjunto de zero ou mais padrões de destino, separados por espaços em branco (sem vírgulas).
Em conjunto com o recurso $(...)
do shell Bourne, o set()
fornece um meio de salvar os resultados de uma consulta em um arquivo de texto normal, manipular esse arquivo de texto usando outros programas (como ferramentas de shell UNIX padrão) e, em seguida, introduzir o resultado na ferramenta de consulta como um valor para processamento adicional. Exemplo:
bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"
No próximo exemplo,kind(cc_library, deps(//some_dir/foo:main, 5))
é
calculado filtrando os valores maxrank
usando um programa awk
.
bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"
Nesses exemplos, $(<foo)
é uma abreviação de $(cat foo)
, mas também é possível usar comandos do shell diferentes de cat
, como o comando awk
anterior.
Funções
expr ::= word '(' int | word | expr ... ')'
A linguagem de consulta define várias funções. O nome da função determina o número e o tipo de argumentos necessários. As seguintes funções estão disponíveis:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
Fechamento transitivo de dependências: dependências
expr ::= deps(expr)
| deps(expr, depth)
O operador deps(x)
é avaliado para o gráfico formado pelo fechamento transitivo das dependências do conjunto de argumentos x. Por exemplo, o valor de deps(//foo)
é o
gráfico de dependência com acesso root no único nó foo
, incluindo todas as
dependências dele. O valor de deps(foo/...)
são os gráficos de dependência cujas raízes
são todas as regras em todos os pacotes abaixo do diretório foo
. Nesse contexto,
"dependências" significa apenas destinos de regras e arquivos. Portanto, os arquivos BUILD
e
Starlark necessários para criar esses destinos não estão incluídos aqui. Para isso,
use o operador buildfiles
.
O gráfico resultante é ordenado de acordo com a relação de dependência. Para mais detalhes, consulte a seção sobre ordem dos gráficos.
O operador deps
aceita um segundo argumento opcional, que é um número inteiro literal que especifica um limite superior na profundidade da pesquisa. Portanto, deps(foo:*, 0)
retorna todos os destinos no pacote foo
, enquanto
deps(foo:*, 1)
inclui ainda mais os pré-requisitos diretos de qualquer destino no
pacote foo
, e deps(foo:*, 2)
inclui ainda os nós diretamente
acessíveis dos nós em deps(foo:*, 1)
e assim por diante. Esses números
correspondem às classificações mostradas no formato de saída minrank
.
Se o parâmetro depth for omitido, a pesquisa será ilimitada: ela calculará o fechamento transitivo reflexivo dos pré-requisitos.
Fechamento transitivo de dependências reversas: rdeps
expr ::= rdeps(expr, expr)
| rdeps(expr, expr, depth)
O operador rdeps(u, x)
avalia para as dependências reversas do conjunto de argumentos
x dentro do fechamento transitivo do conjunto do universo
u.
O gráfico resultante é ordenado de acordo com a relação de dependência. Consulte a seção sobre ordem dos gráficos para saber mais.
O operador rdeps
aceita um terceiro argumento opcional, que é um número inteiro literal que especifica um limite superior na profundidade da pesquisa. O gráfico
resultante inclui apenas nós a uma distância da profundidade especificada de qualquer
nó no conjunto de argumentos. Portanto, rdeps(//foo, //common, 1)
avalia todos os nós no fechamento transitivo de //foo
que dependem diretamente de //common
. Esses
números correspondem às classificações mostradas no formato de saída
minrank
. Se o parâmetro depth for omitido, a pesquisa será ilimitada.
Fechamento transitivo de todas as dependências reversas: allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
O operador allrdeps
se comporta como o operador rdeps
, exceto pelo fato de que o "conjunto universal" é o que for a sinalização --universe_scope
avaliada, em vez de ser especificado separadamente. Assim, se
--universe_scope=//foo/...
tiver sido transmitido, allrdeps(//bar)
será
equivalente a rdeps(//foo/..., //bar)
.
Dependências reversas diretas no mesmo pacote: same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
O operador same_pkg_direct_rdeps(x)
avalia o conjunto completo de destinos
que estão no mesmo pacote que um destino no conjunto de argumentos e que dependem diretamente dele.
Como lidar com o pacote de um destino: irmãos
expr ::= siblings(expr)
O operador siblings(x)
avalia o conjunto completo de destinos que estão no
mesmo pacote que um destino no conjunto de argumentos.
Escolha arbitrária: algumas
expr ::= some(expr)
| some(expr, count )
O operador some(x, k)
seleciona no máximo k destinos arbitrariamente do
conjunto de argumentos x e avalia para um conjunto que contém
apenas essas metas. O parâmetro k é opcional. Se estiver ausente, o resultado será um conjunto singleton contendo apenas um destino selecionado arbitrariamente. Se o tamanho do conjunto de argumentos x for menor que k, todo o conjunto de argumentos x será retornado.
Por exemplo, a expressão some(//foo:main union //bar:baz)
é avaliada como um
conjunto Singleton que contém //foo:main
ou //bar:baz
, mas
qual não está definido. A expressão some(//foo:main union //bar:baz, 2)
ou
some(//foo:main union //bar:baz, 3)
retorna //foo:main
e
//bar:baz
.
Se o argumento for um singleton, some
calculará a função de identidade: some(//foo:main)
é equivalente a //foo:main
.
Um erro se o conjunto de argumentos especificado estiver vazio, como na
expressão some(//foo:main intersect //bar:baz)
.
Operadores de caminho: somepath, allpaths
expr ::= somepath(expr, expr)
| allpaths(expr, expr)
Os operadores somepath(S, E)
e
allpaths(S, E)
calculam
caminhos entre dois conjuntos de destinos. As duas consultas aceitam dois
argumentos, um conjunto S de pontos iniciais e um conjunto
E de pontos finais. somepath
retorna o gráfico de nós em algum caminho arbitrário de um destino em S para um destino em E. allpaths
retorna o gráfico de nós em todos os caminhos de qualquer destino em S para qualquer destino em E.
Os gráficos resultantes são ordenados de acordo com a relação de dependência. Consulte a seção sobre ordem dos gráficos para mais detalhes.
Filtragem do tipo de segmentação: tipo
expr ::= kind(word, expr)
O operador kind(pattern, input)
aplica um filtro a um conjunto de destinos e descarta os destinos
que não sejam do tipo esperado. O parâmetro pattern especifica o tipo de destino a ser correspondido.
Por exemplo, os tipos para os quatro destinos definidos pelo arquivo BUILD
(para o pacote p
) mostrados abaixo são ilustrados na tabela:
Programar | Objetivo | Tipo |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
regra de regra geral |
//p:a.in |
arquivo de origem | |
//p:a.out |
arquivo gerado | |
//p:BUILD |
arquivo de origem |
Assim, kind("cc_.* rule", foo/...)
é avaliado para o conjunto
de todos os destinos de regras cc_library
, cc_binary
etc.
abaixo de foo
, e kind("source file", deps(//foo))
é avaliado como o conjunto de todos os arquivos de origem no fechamento transitivo
de dependências do destino //foo
.
Muitas vezes, é necessário usar as aspas do argumento pattern
porque, sem ele, muitas expressões regulares, como source
file
e .*_test
, não são consideradas palavras pelo analisador.
Ao fazer a correspondência para package group
, as segmentações que terminam em :all
podem não gerar nenhum resultado. Em vez disso, use :all-targets
.
Filtragem de nome de destino: filtro
expr ::= filter(word, expr)
O operador filter(pattern, input)
aplica um filtro a um conjunto de destinos e descarta destinos cujos
rótulos (em formato absoluto) não correspondem ao padrão. Ele é
avaliado como um subconjunto da entrada.
O primeiro argumento, pattern, é uma palavra que contém uma expressão regular sobre nomes de destino. Uma expressão filter
é avaliada para o conjunto que contém todos os destinos x, de modo que x é membro do conjunto input e o rótulo (em forma absoluta, como //foo:bar
) de x contém uma correspondência (não ancorada) para a expressão regular pattern. Como todos os
nomes de destino começam com //
, eles podem ser usados como uma alternativa
à âncora de expressão regular ^
.
Esse operador geralmente oferece uma alternativa muito mais rápida e robusta ao
operador intersect
. Por exemplo, para ver todas as
dependências bar
do destino //foo:foo
, é possível
avaliar
deps(//foo) intersect //bar/...
No entanto, essa instrução exigirá a análise de todos os arquivos BUILD
na árvore
bar
, que será lenta e propensa a erros em
arquivos BUILD
irrelevantes. Uma alternativa seria:
filter(//bar, deps(//foo))
que primeiro calcula o conjunto de dependências de //foo
e,
em seguida, filtra apenas os destinos correspondentes ao padrão fornecido. Em outras
palavras, destinos com nomes contendo //bar
como uma substring.
Outro uso comum do operador filter(pattern,
expr)
é filtrar arquivos específicos por nome ou extensão. Por exemplo:
filter("\.cc$", deps(//foo))
fornecerá uma lista de todos os arquivos .cc
usados para criar //foo
.
Filtragem de atributos de regra: attr
expr ::= attr(word, word, expr)
O operador
attr(name, pattern, input)
aplica um filtro a um conjunto de metas e descarta as metas que não são
regras, segmentações de regras que não têm o atributo name
definido ou metas de regras em que o valor do atributo não corresponde à
expressão regular pattern fornecida. Ele avalia
um subconjunto da entrada.
O primeiro argumento, name, é o nome do atributo de regra que precisa corresponder ao padrão de expressão regular fornecido. O segundo argumento,
pattern, é uma expressão regular sobre os valores de
atributo. Uma expressão attr
é avaliada para o conjunto que contém todos os destinos
x, de modo que x seja um
membro do conjunto input, é uma regra com o atributo definido
name e o valor do atributo contém uma
correspondência (não ancorada) para a expressão regular
pattern. Se name for um
atributo opcional e a regra não o especificar explicitamente, o valor do
atributo padrão será usado para comparação. Por exemplo:
attr(linkshared, 0, deps(//foo))
vai selecionar todas as dependências de //foo
que têm permissão para ter um
atributo linkshared (como uma regra cc_binary
) e vai fazer com que ele
seja explicitamente definido como 0 ou não o defina, mas o valor padrão é 0 (como para as
regras cc_binary
).
Os atributos do tipo lista (como srcs
, data
etc.) são
convertidos em strings no formato [value<sub>1</sub>, ..., value<sub>n</sub>]
,
começando com um colchete [
, terminando com um colchete ]
e usando ",
" (vírgula, espaço) para delimitar vários valores.
Os rótulos são convertidos em strings usando a forma absoluta deles. Por exemplo, um atributo deps=[":foo",
"//otherpkg:bar", "wiz"]
seria convertido na
string [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
.
Os colchetes estão sempre presentes. Portanto, a lista vazia usaria o valor de string []
para fins de correspondência. Por exemplo:
attr("srcs", "\[\]", deps(//foo))
selecionará todas as regras entre as dependências de //foo
que tenham um
atributo srcs
vazio, enquanto
attr("data", ".{3,}", deps(//foo))
vai selecionar todas as regras entre as dependências de //foo
que especificam
pelo menos um valor no atributo data
(cada rótulo tem pelo menos
três caracteres devido a //
e :
).
Para selecionar todas as regras entre as dependências de //foo
com um value
específico em um
atributo do tipo lista, use
attr("tags", "[\[ ]value[,\]]", deps(//foo))
Isso funciona porque o caractere antes de value
será [
ou um espaço e o
caractere depois de value
será uma vírgula ou ]
.
Filtragem de visibilidade da regra: visível
expr ::= visible(expr, expr)
O operador visible(predicate, input)
aplica um filtro a um conjunto de destinos e descarta os destinos sem a
visibilidade necessária.
O primeiro argumento, predicate, é um conjunto de destinos para os quais todos os destinos na saída precisam estar visíveis. Uma expressão visible é avaliada para o conjunto que contém todos os destinos x, de modo que x é um membro do conjunto input, e para todos os destinos y em predicate x é visível para y. Exemplo:
visible(//foo, //bar:*)
vai selecionar todos os destinos no pacote //bar
de que //foo
pode depender sem violar as restrições de visibilidade.
Avaliação de atributos de regra do tipo label: rótulos
expr ::= labels(word, expr)
O operador labels(attr_name, inputs)
retorna o conjunto de destinos especificados no atributo attr_name do tipo "rótulo" ou "lista de rótulos" em alguma regra no conjunto inputs.
Por exemplo, labels(srcs, //foo)
retorna o conjunto de
destinos que aparece no atributo srcs
da
regra //foo
. Se houver várias regras
com atributos srcs
no conjunto inputs, a
união dos srcs
será retornada.
Expandir e filtrar test_suites: testes
expr ::= tests(expr)
O operador tests(x)
retorna o conjunto de todas as regras
de teste no conjunto x, expandindo todas as regras test_suite
para
o conjunto de testes individuais a que se referem e aplicando a filtragem por
tag
e size
.
Por padrão, a avaliação da consulta
ignora todos os destinos que não sejam de teste em todas as regras test_suite
. Isso pode ser
alterado para erros com a opção --strict_test_suite
.
Por exemplo, a consulta kind(test, foo:*)
lista todas
as regras *_test
e test_suite
no pacote foo
. Todos os resultados são, por
definição, membros do pacote foo
. Por outro lado,
a consulta tests(foo:*)
retornará todos os
testes individuais que seriam executados por bazel test
foo:*
: isso pode incluir testes pertencentes a outros pacotes,
referenciados direta ou indiretamente
por meio de regras test_suite
.
Arquivos de definição do pacote: arquivos de build
expr ::= buildfiles(expr)
O operador buildfiles(x)
retorna o conjunto
de arquivos que definem os pacotes de cada destino no
conjunto x. Em outras palavras, para cada pacote, o arquivo BUILD
dele, além de todos os arquivos .bzl a que ele faz referência via load
. Observe que isso
também retorna os arquivos BUILD
dos pacotes que contêm esses
arquivos com load
.
Esse operador normalmente é usado ao determinar quais arquivos ou
pacotes são necessários para criar um destino especificado, geralmente em conjunto com
a opção --output package
abaixo. Por exemplo:
bazel query 'buildfiles(deps(//foo))' --output package
retorna o conjunto de todos os pacotes dos quais //foo
depende transitivamente.
Arquivos de definição do pacote: rbuildfiles
expr ::= rbuildfiles(word, ...)
O operador rbuildfiles
usa uma lista separada por vírgulas de fragmentos de caminho e retorna
o conjunto de arquivos BUILD
que dependem transitivamente desses fragmentos de caminho. Por exemplo, se
//foo
for um pacote, rbuildfiles(foo/BUILD)
vai retornar o
destino //foo:BUILD
. Se o arquivo foo/BUILD
tiver
load('//bar:file.bzl'...
, rbuildfiles(bar/file.bzl)
vai
retornar o destino //foo:BUILD
, bem como os destinos de quaisquer outros arquivos BUILD
que
carreguem //bar:file.bzl
O escopo do operador --universe_scope
. Arquivos que não correspondem diretamente a arquivos BUILD
e .bzl
não afetam os resultados. Por exemplo, arquivos de origem (como foo.cc
) são ignorados,
mesmo que sejam explicitamente mencionados no arquivo BUILD
. No entanto, os links simbólicos são respeitados. Portanto, se foo/BUILD
for um link simbólico para bar/BUILD
, rbuildfiles(bar/BUILD)
incluirá //foo:BUILD
nos resultados.
O operador rbuildfiles
é quase moralmente o inverso do operador
buildfiles
. No entanto, essa inversão moral
se mantém mais forte em uma direção: as saídas de rbuildfiles
são como as
entradas de buildfiles
. A primeira vai conter apenas destinos de arquivo BUILD
em pacotes,
e a última poderá conter esses destinos. Na outra direção, a correspondência é mais fraca. As saídas do operador buildfiles
são destinos correspondentes a todos os pacotes e .bzl
necessários para uma determinada entrada. No entanto, as entradas do operador rbuildfiles
não são esses destinos, mas os fragmentos de caminho que correspondem a esses destinos.
Arquivos de definição do pacote: loadfiles
expr ::= loadfiles(expr)
O operador loadfiles(x)
retorna o conjunto de
arquivos Starlark necessários para carregar os pacotes de cada destino no
conjunto x. Em outras palavras, para cada pacote, ele retorna os
arquivos .bzl referenciados nos arquivos BUILD
.
Formatos de saída
bazel query
gera um gráfico.
Especifique o conteúdo, o formato e a ordem em que
bazel query
apresenta esse gráfico
usando a opção de linha de comando --output
.
Ao executar com Sky Query, somente formatos de saída compatíveis com
saídas não ordenadas são permitidos. Especificamente, os formatos de saída graph
, minrank
e
maxrank
são proibidos.
Alguns dos formatos de saída aceitam opções adicionais. O nome de
cada opção de saída é prefixado com o formato de saída a que
se aplica. Portanto, --graph:factored
se aplica somente
quando --output=graph
está sendo usado. Ele não terá efeito se
um formato de saída diferente de graph
for usado. Da mesma forma,
--xml:line_numbers
se aplica apenas quando --output=xml
está sendo usado.
Na ordenação dos resultados
Embora as expressões de consulta sempre sigam a "lei de
conservação da ordem gráfica", a apresentação dos resultados pode ser feita
de maneira ordenada por dependência ou não. Isso não
influencia as metas no conjunto de resultados nem a forma como a consulta é calculada. Ele apenas
afeta a forma como os resultados são impressos no stdout. Além disso, os nós equivalentes na ordem das dependências podem ou não estar em ordem alfabética.
A sinalização --order_output
pode ser usada para controlar esse comportamento.
A sinalização --[no]order_results
tem um subconjunto da funcionalidade
da sinalização --order_output
e foi descontinuada.
O valor padrão dessa flag é auto
, que mostra os resultados em ordem
lexicográfica. No entanto, quando somepath(a,b)
for usado, os resultados serão impressos na ordem deps
.
Quando essa flag for no
e --output
for
build
, label
, label_kind
, location
, package
, proto
ou
xml
, as saídas serão impressas em ordem arbitrária. Geralmente,
essa é a opção mais rápida. Mas não há suporte quando
--output
é graph
, minrank
ou
maxrank
: com esses formatos, o Bazel sempre exibe resultados
ordenados pela ordem ou classificação de dependência.
Quando essa flag é deps
, o Bazel mostra os resultados em uma ordem topológica, ou seja,
as dependências primeiro e as dependências depois. No entanto, os nós que não estão ordenados pela
ordem de dependência (porque não há caminho de um para o outro) podem ser
impressos em qualquer ordem.
Quando essa flag é full
, o Bazel imprime nós em uma ordem totalmente determinística (total).
Primeiro, todos os nós são classificados em ordem alfabética. Em seguida, cada nó da lista é usado como o início de uma
pesquisa de profundidade pós-ordem, em que as bordas de saída para nós não visitados são atravessadas em
ordem alfabética dos nós sucessores. Por fim, os nós são impressos no inverso da ordem em que foram visitados.
A impressão dos nós nessa ordem pode ser mais lenta, por isso use-os apenas quando o determinismo for importante.
Imprime a forma de origem dos destinos como apareceriam em BUILD
--output build
Com essa opção, a representação de cada destino é como se fosse
escrita à mão na linguagem BUILD. Todas as variáveis e chamadas de função
(como glob e macros) são expandidas, o que é útil para ver o efeito
das macros Starlark. Além disso, cada regra efetiva informa um valor generator_name
e/ou generator_function
), fornecendo o nome da macro que foi avaliada para produzir a regra em vigor.
Embora a saída use a mesma sintaxe que os arquivos BUILD
, não é garantido que um arquivo BUILD
seja válido.
Imprimir a etiqueta de cada destino
--output label
Com essa opção, o conjunto de nomes (ou rótulos) de cada destino
no gráfico resultante é impresso, um rótulo por linha, em
ordem topológica (a menos que --noorder_results
seja especificado, consulte
observações sobre a ordem dos resultados).
Uma ordenação topológica é aquela em que um nó de grafo aparece antes de todos os sucessores. É claro que existem muitas ordens topologias possíveis para um gráfico (a pós-ordem inversa é apenas uma). Qual é a escolhida não é especificada.
Ao imprimir a saída de uma consulta somepath
, a ordem
em que os nós são impressos é a ordem do caminho.
Observação: em alguns casos específicos, pode haver dois destinos distintos com
o mesmo rótulo. Por exemplo, uma regra sh_binary
e o
único arquivo srcs
(implícito) podem ser chamados
foo.sh
. Se o resultado de uma consulta contiver esses dois destinos, a saída (no formato label
) parecerá conter uma cópia. Ao usar o formato label_kind
(veja
abaixo), a diferença fica clara: os dois destinos têm
o mesmo nome, mas um tem o tipo sh_binary rule
e o
outro tipo source file
.
Imprima a etiqueta e o tipo de cada destino
--output label_kind
Assim como label
, esse formato de saída imprime os rótulos de
cada destino no gráfico resultante, em ordem topológica, mas também
antecede o rótulo pelo tipo do destino.
Imprimir alvos no formato de buffer de protocolo
--output proto
Exibe a saída da consulta como um
buffer de protocolo
QueryResult
.
Imprimir alvos no formato de buffer de protocolo delimitado por comprimento
--output streamed_proto
Imprime um stream
delimitado por comprimento de
buffers de protocolo
Target
. Isso é útil para (i) contornar
limitações de tamanho
dos buffers de protocolo quando há muitos destinos para caber em um único
QueryResult
ou (ii) para iniciar o processamento durante a saída do Bazel.
Imprimir destinos no formato .proto de texto
--output textproto
De forma semelhante a --output proto
, mostra o
buffer de protocolo QueryResult
,
mas no
formato de texto.
Imprimir destinos no formato ndjson
--output streamed_jsonproto
Semelhante a --output streamed_proto
, exibe um fluxo de buffers de protocolo
Target
,
mas no formato ndjson.
Imprimir a etiqueta de cada alvo, em ordem de classificação
--output minrank --output maxrank
Como label
, os formatos de saída minrank
e maxrank
imprimem os rótulos de cada destino no gráfico resultante. No entanto, em vez de aparecer em ordem topológica, eles aparecem em ordem de classificação, precedidos pelo número da classificação. Eles não são afetados pela sinalização --[no]order_results
de ordenação de resultados. Consulte as observações sobre a ordem dos resultados.
Há duas variantes desse formato: minrank
classifica
cada nó pelo tamanho do caminho mais curto de um nó raiz até ele.
Os nós "raiz" (aqueles que não têm bordas de entrada) têm classificação 0, seus sucessores têm classificação 1 etc. Como sempre, as arestas apontam de um destino para os pré-requisitos dele: os destinos de que ele depende.
maxrank
classifica cada nó pelo tamanho do caminho mais longo
de um nó raiz até ele. Novamente, as "raízes" têm classificação 0, e todos os outros nós têm uma classificação maior do que a máxima de todos os antecessores.
Todos os nós em um ciclo são considerados com a mesma classificação. A maioria dos gráficos é
acíclica, mas os ciclos ocorrem
simplesmente porque os arquivos BUILD
contêm ciclos incorretos.
Esses formatos de saída são úteis para descobrir a profundidade de um gráfico. Se usado no resultado de uma consulta deps(x)
, rdeps(x)
ou allpaths
, o número da classificação é igual ao comprimento do caminho mais curto (com minrank
) ou mais longo (com maxrank
) de x
para um nó nessa classificação. maxrank
pode ser usado para determinar a
sequência mais longa de etapas de build necessárias para criar um destino.
Por exemplo, o gráfico à esquerda produz as saídas à direita
quando --output minrank
e --output maxrank
são especificados, respectivamente.
minrank 0 //c:c 1 //b:b 1 //a:a 2 //b:b.cc 2 //a:a.cc |
maxrank 0 //c:c 1 //b:b 2 //a:a 2 //b:b.cc 3 //a:a.cc |
Imprimir a localização de cada destino
--output location
Assim como label_kind
, essa opção imprime, para cada
destino no resultado, o tipo e o rótulo do destino, mas é
prefixado por uma string que descreve o local desse destino, como um
nome de arquivo e número de linha. O formato é semelhante à saída de
grep
. Assim, as ferramentas que podem analisar a segunda opção, como o Emacs
ou o vi, também podem usar a saída da consulta para percorrer uma série de
correspondências. Isso permite que a ferramenta de consulta do Bazel seja usada como um "grep para arquivos BUILD" com reconhecimento de gráfico de dependência.
As informações de local variam de acordo com o tipo de destino (consulte o operador Kind). Para as regras, o
local da declaração da regra no arquivo BUILD
é mostrado.
Para arquivos de origem, o local da linha 1 do arquivo real é
impresso. Para um arquivo gerado, o local da regra
que o gera é impresso. A ferramenta de consulta não tem informações suficientes para encontrar o local real do arquivo gerado e, em qualquer caso, pode não existir se uma versão ainda não foi executada.
Imprimir o conjunto de pacotes
--output package
Esta opção imprime o nome de todos os pacotes aos quais algum destino no conjunto de resultados pertence. Os nomes são impressos em ordem lexicográfica. As cópias são excluídas. Formalmente, isso é uma projeção do conjunto de rótulos (pacote, destino) para pacotes.
Os pacotes em repositórios externos são formatados como
@repo//foo/bar
, enquanto os pacotes no repositório principal são
formatados como foo/bar
.
Em conjunto com a consulta deps(...)
, essa opção de saída pode ser usada para encontrar o conjunto de pacotes que precisam ser verificados para criar um determinado conjunto de destinos.
Exibir um gráfico do resultado
--output graph
Essa opção faz com que o resultado da consulta seja impresso como um gráfico direcionado no conhecido formato GraphViz da AT&T. Normalmente, o
resultado é salvo em um arquivo, como .png
ou .svg
.
Se o programa dot
não estiver instalado na estação de trabalho, instale-o usando o comando sudo apt-get install graphviz
. Consulte a seção de exemplo abaixo para ver uma invocação de exemplo.
Esse formato de saída é particularmente útil para consultas allpaths
,
deps
ou rdeps
, em que o resultado
inclui um conjunto de caminhos que não podem ser facilmente visualizados quando
renderizados em formato linear, como com --output label
.
Por padrão, o gráfico é renderizado de forma faturada. Ou seja, os nós equivalentes topológicos são mesclados em um único nó com vários rótulos. Isso torna o gráfico mais compacto e legível, porque os gráficos de resultados típicos contêm padrões altamente repetitivos. Por exemplo, uma regra java_library
pode depender de centenas de arquivos de origem Java, todos gerados pelo
mesmo genrule
. No gráfico fatorado, todos esses arquivos
são representados por um único nó. Esse comportamento pode ser desativado
com a opção --nograph:factored
.
--graph:node_limit n
A opção especifica o comprimento máximo da string de rótulo para um
nó de gráfico na saída. Rótulos mais longos serão truncados, enquanto -1 desativa o truncamento. Devido à forma fatorada em que os gráficos geralmente são impressos, os rótulos de nó podem ser muito longos. O GraphViz não
processa rótulos que excedem 1.024 caracteres, que é o valor padrão
dessa opção. Essa opção só terá efeito se
--output=graph
estiver sendo usado.
--[no]graph:factored
Por padrão, os gráficos são exibidos de forma fatorada, conforme explicado acima.
Quando --nograph:factored
é especificado, os gráficos são
impressos sem fatoração. Isso torna a visualização usando o GraphViz impraticável, mas o formato mais simples pode facilitar o processamento por outras ferramentas (como o grep). Essa opção só terá efeito
se --output=graph
estiver sendo usado.
XML
--output xml
Essa opção faz com que os destinos resultantes sejam impressos em um formato XML. A saída começa com um cabeçalho XML como este
<?xml version="1.0" encoding="UTF-8"?>
<query version="2">
e depois continua com um elemento XML para cada destino no gráfico de resultados, em ordem topológica (a menos que resultados não ordenados sejam solicitados) e termina com uma
</query>
Entradas simples são emitidas para destinos do tipo file
:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
Mas para as regras, o XML é estruturado e contém definições de todos
os atributos da regra, incluindo aqueles cujo valor não foi
especificado explicitamente no arquivo BUILD
da regra.
Além disso, o resultado inclui elementos rule-input
e
rule-output
para que a topologia do
gráfico de dependência possa ser reconstruída sem precisar saber que,
por exemplo, os elementos do atributo srcs
são
dependências diretas (pré-requisitos) e o conteúdo do
atributo outs
são dependências anteriores (consumidores).
Elementos rule-input
para dependências implícitas serão suprimidos se
--noimplicit_deps
for especificado.
<rule class='cc_binary rule' name='//foo:foo' ...>
<list name='srcs'>
<label value='//foo:foo_main.cc'/>
<label value='//foo:bar.cc'/>
...
</list>
<list name='deps'>
<label value='//common:common'/>
<label value='//collections:collections'/>
...
</list>
<list name='data'>
...
</list>
<int name='linkstatic' value='0'/>
<int name='linkshared' value='0'/>
<list name='licenses'/>
<list name='distribs'>
<distribution value="INTERNAL" />
</list>
<rule-input name="//common:common" />
<rule-input name="//collections:collections" />
<rule-input name="//foo:foo_main.cc" />
<rule-input name="//foo:bar.cc" />
...
</rule>
Cada elemento XML de um destino contém um atributo name
, que tem o valor do rótulo do destino, e
um atributo location
, em que o valor é o local
de destino conforme mostrado pela --output location
.
--[no]xml:line_numbers
Por padrão, os locais exibidos na saída XML contêm números de linha.
Quando --noxml:line_numbers
é especificado, os números das linhas não são mostrados.
--[no]xml:default_values
Por padrão, a saída XML não inclui um atributo de regra em que o valor
seja o valor padrão para esse tipo de atributo (por exemplo, se
não tiver sido especificado no arquivo BUILD
ou se o valor padrão tiver sido
fornecido explicitamente). Essa opção faz com que esses valores de atributo sejam
incluídos na saída XML.
Expressões regulares
As expressões regulares na linguagem de consulta usam a biblioteca de regex Java. Portanto, você pode usar a
sintaxe completa para
java.util.regex.Pattern
.
Como consultar repositórios externos
Se o build depender de regras de repositórios externos,
os resultados da consulta incluirão essas dependências. Por
exemplo, se //foo:bar
depender de @other-repo//baz:lib
, bazel query 'deps(//foo:bar)'
listará @other-repo//baz:lib
como uma
dependência.