Referência de consulta do Bazel

Esta página é o manual de referência da Linguagem de consulta Bazel usada quando você usa 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 (em inglês).

Referência de consulta adicional

Além de query, que é executado no gráfico de destino da fase de pós-carregamento, o Bazel inclui consulta do gráfico de ações e 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 reais são executados e as entradas, saídas e mneumônicas deles.

Para mais detalhes, consulte a referência sobre aquery.

Consulta configurável

A consulta tradicional do Bazel é executada no gráfico de destino da fase de pós-carregamento e, portanto, não tem conceito de configurações nem dos conceitos relacionados. Além disso, ela não resolve corretamente 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 de cquery (em inglês).

Exemplos

Como as pessoas usam o bazel query? Veja alguns exemplos:

Por que a árvore //foo depende de //bar/baz? Mostre um caminho:

somepath(foo/..., //bar/baz:all)

De quais bibliotecas C++ todos os testes foo dependem do destino foo_bin, não?

kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))

Tokens: a sintaxe lexical

As expressões na linguagem da consulta são compostas pelos seguintes tokens:

  • Palavras-chave, como let. Palavras-chave são as 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 estiver entre aspas, ela ainda poderá ser analisada como uma palavra. As palavras sem aspas são sequências de caracteres extraídas dos caracteres do alfabeto A-Za-z, dos numerais de 0 a 9 e dos caracteres especiais */@.-_:$~[] (asterisco, barra, arroba, ponto, hífen, sublinhado, dois-pontos, sinal de dólar, til, chave quadrada esquerda e chave quadrada direita). No entanto, palavras sem aspas não podem começar com um hífen - ou asterisco *, mesmo que [nomes de destino relativos][(/concepts/labels#target-names) comecem com esses caracteres.

    Palavras sem aspas também não podem incluir os caracteres de mais + ou de igual =, embora esses caracteres sejam permitidos em nomes de destino. Ao escrever o código que gera expressões de consulta, os nomes de destino precisam estar entre aspas.

    É necessário usar aspas ao escrever scripts que constroem expressões de consulta do Bazel com base em 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 é além de qualquer cota que possa ser exigida pelo shell, como:

    bazel query ' "//foo:bar=wiz" '   # single-quotes for shell, double-quotes for Bazel.
    

    As palavras-chave, quando citadas, são tratadas como palavras comuns. Por exemplo, some é uma palavra-chave, mas "algum" é uma palavra. Tanto foo quanto "foo" são palavras.

    No entanto, tenha cuidado ao usar aspas simples ou duplas nos nomes de destino. Ao citar um ou mais nomes de destino, use apenas um tipo de aspas simples ou duplas.

    A seguir estão exemplos do que 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 não seja preciso usar aspas na maioria dos casos. O exemplo de ".*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 colocadas entre aspas.

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 é de expressões. Cada expressão é avaliada como um conjunto parcialmente ordenado de destinos ou, de maneira equivalente, um gráfico (DAG) de destinos. Esse é o único tipo de dado.

O conjunto e o gráfico se referem ao mesmo tipo de dados, mas enfatizam diferentes aspectos dele, por exemplo:

  • Definir:a ordem parcial das segmentações não é interessante.
  • Gráfico:a ordem parcial das segmentações é significativa.

Ciclos no gráfico de dependências

Os gráficos de dependência de build precisam ser acíclicos.

Os algoritmos usados pela linguagem de consulta se destinam ao uso em gráficos acíclicos, mas são robustos para ciclos. Os detalhes de como os ciclos são tratados não são especificados e não são considerados 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. Por exemplo, cada regra Java depende implicitamente do JavaBuilder. As dependências implícitas são estabelecidas usando atributos que começam com $ e não podem ser substituídas em arquivos BUILD.

Por padrão, bazel query considera as dependências implícitas ao calcular o resultado da consulta. Esse comportamento pode ser mudado com a opção --[no]implicit_deps. Como a consulta não considera configurações, os possíveis conjuntos de ferramentas nunca são considerados.

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 criar 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 precisa. Se você usa a ferramenta de consulta para calcular o conjunto de todos os arquivos de origem necessários durante uma criação, ela pode relatar mais do que o necessário porque, por exemplo, ela vai incluir todos os arquivos necessários para a tradução de mensagens, mesmo que você não pretenda usar esse recurso no build.

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". Considere um exemplo: se você emitir uma consulta para determinar o fechamento transitivo das dependências de um destino específico, o conjunto resultante será ordenado de acordo com o gráfico de dependência. 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 do 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 é garantida para preservar 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 deles em deps(x) em relação àqueles em y (exceto para os destinos em y que também estão em deps(x)).

Os operadores que introduzem restrições de ordenação incluem: allpaths, deps, rdeps, somepath e os caracteres curinga do padrão de destino package:*, dir/... etc.

Consulta no Sky

A Consulta do Sky é 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 não fazem sentido para uma consulta normal.

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". Especificamente, os operadores allrdeps e rbuildfiles retornam resultados apenas 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 exclusivos de destino 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 exclusivos de destino nesta 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 reversas 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 de tests dos destinos em alguns diretórios que dependem transitivamente de destinos com definição que 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 por conta própria.

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 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 ela 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. A vantagem é 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 gráfico, que é o que a implementação padrão faz. Assim, em algumas circunstâncias, o processo é 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

Sintticamente, 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 como 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 avaliado para um conjunto que contém todas as regras no pacote bar/baz, mas não os subpacotes dele.

Da mesma forma, foo/...:* é um padrão de destino avaliado como 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 os subpacotes dele.

Como o caractere curinga :* corresponde a arquivos e regras, ele geralmente é mais útil que :all para consultas. Por outro lado, o caractere curinga :all, implícito em padrões de destino, como foo/..., é mais útil para builds.

Os padrões de destino bazel query funcionam da mesma forma que os destinos de build bazel build. Para saber mais, 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), para um conjunto que contém muitos elementos (como no caso de foo/..., que tem milhares de elementos) ou para o conjunto vazio, se o padrão de destino não corresponder a nenhum destino.

Todos os nós no resultado de uma expressão de padrão de destino sã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. Nenhuma garantia é feita em relação à ordem relativa dos nós de resultado em relação a outros nós. Para mais detalhes, consulte a seção ordem do gráfico.

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 = ... dentro é 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 extra de que seja um identificador legal na linguagem de programação C. As referências à variável precisam ser precedidas pelo caractere "$".

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 legal.

Tecnicamente falando, as expressões let não aumentam a expressividade da linguagem de consulta: qualquer consulta expressável na linguagem também pode ser expressada 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 argumento.

Operações de conjunto algébico: interseção, união, diferença

expr ::= expr intersect expr
       | expr ^ expr
       | expr union expr
       | expr + expr
       | expr except expr
       | expr - expr

Esses três operadores computam as operações habituais de conjunto em vez dos 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/...

é avaliada como o conjunto de destinos 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), enquanto except (-) é assimétrica. O analisador trata todos os três operadores como associativos à esquerda e de precedência igual. Assim, você pode precisar de 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, set() fornece um meio de salvar os resultados de uma consulta em um arquivo de texto normal, manipulando esse arquivo de texto usando outros programas (como ferramentas shell UNIX padrão) e, em seguida, introduzindo o resultado de volta 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 comandos do shell diferentes de cat também podem ser usados, como o comando awk anterior.

remotas

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:

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 de 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 do gráfico.

O operador deps aceita um segundo argumento opcional, que é um literal de número inteiro 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 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 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 do gráfico para mais detalhes.

O operador rdeps aceita um terceiro argumento opcional, que é um literal de número inteiro que especifica um limite superior na profundidade da pesquisa. O gráfico resultante inclui apenas nós dentro de 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 da mesma forma que o operador rdeps, exceto pelo fato de que o "universo" é o que a sinalização --universe_scope avalia, em vez de ser especificada 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) é avaliado para 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: alguns

expr ::= some(expr)
       | some(expr, count )

O operador some(x, k) seleciona, no máximo, destinos k arbitrariamente no conjunto de argumentos x e avalia para um conjunto que contém apenas esses destinos. O parâmetro k é opcional. Se 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, embora ele não esteja 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.

Será 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 de partida 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 do gráfico para mais detalhes.

Algum caminho
somepath(S1 + S2, E), um resultado possível.
Algum caminho
somepath(S1 + S2, E), outro resultado possível.
Todos os caminhos
allpaths(S1 + S2, E)

Filtragem do tipo de destino: tipo

expr ::= kind(word, expr)

O operador kind(pattern, input) aplica um filtro a um conjunto de destinos e descarta aqueles que não são do tipo esperado. O parâmetro pattern especifica o tipo de segmentação a ser correspondida.

Por exemplo, os tipos para os quatro destinos definidos pelo arquivo BUILD (para o pacote p) mostrados abaixo são ilustrados na tabela:

Código Objetivo Tipo
        genrule(
            name = "a",
            srcs = ["a.in"],
            outs = ["a.out"],
            cmd = "...",
        )
      
//p:a regra de geração
//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.

A aspas do argumento pattern costuma ser necessária porque, sem ela, 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 resultados. 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 os 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 no 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 calcularia o conjunto de dependências //foo e depois filtraria 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 regras: atributo

expr ::= attr(word, word, expr)

O operador attr(name, pattern, input) aplica um filtro a um conjunto de destinos e descarta os destinos que não são regras, destinos 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 é avaliado como um subconjunto da entrada.

O primeiro argumento, name, é o nome do atributo de regra que precisa ser correspondido 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, seja uma regra com o atributo definido name e o valor do atributo contenha 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))

selecionará todas as dependências //foo que podem ter um atributo linkshared (como a regra cc_binary) e o definirá explicitamente como 0 ou não o definirá, mas o valor padrão é 0 (como para 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 ] 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, então 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 //foo que têm um atributo srcs vazio, enquanto

attr("data", ".{3,}", deps(//foo))

selecionará todas as regras entre as dependências //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 como o conjunto que contém todos os destinos x, de modo que x seja membro do conjunto input e para todos os destinos y em predicate x esteja visível para y. Exemplo:

visible(//foo, //bar:*)

selecionará todos os destinos no pacote //bar de que o //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 regras test_suite.

Arquivos de definição de pacote: buildfiles

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 e todos os arquivos .bzl que ele referencia via load. Observe que isso também retorna os arquivos BUILD dos pacotes que contêm esses arquivos load.

Esse operador normalmente é usado para 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 de 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) 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 qualquer outro arquivo BUILD que carregue //bar:file.bzl

O escopo do operador rbuildfiles é o universo especificado pela sinalização --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, de modo que 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 de 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, ela retorna os arquivos .bzl referenciados nos arquivos BUILD.

Formatos de saída

bazel query gera um gráfico. Use a opção de linha de comando --output para especificar o conteúdo, o formato e a ordem em que bazel query apresenta esse gráfico.

Ao executar com o Sky Query, somente formatos de saída compatíveis com saída não ordenada 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 tem efeito se um formato de saída diferente de graph for usado. Da mesma forma, --xml:line_numbers se aplica somente quando --output=xml está sendo usado.

Na ordem dos resultados

As expressões de consulta sempre seguem a "lei de conservação da ordem do gráfico", mas a apresentação dos resultados pode ser feita de maneira ordenada 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 em stdout. Além disso, os nós que são equivalentes na ordem de dependência podem ou não ser classificados 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 sinalização é auto, que imprime 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 é no e --output é uma destas build, label, label_kind, location, package, proto ou xml, as saídas são impressas em ordem arbitrária. Geralmente, essa é a opção mais rápida. No entanto, não há suporte quando --output é graph, minrank ou maxrank: com esses formatos, o Bazel sempre mostra os 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. No entanto, os nós que não estiverem ordenados pela ordem das dependências (por não haver 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 arestas de saída para nós não visitados são transferidas em ordem alfabética dos nós sucessores. Por fim, os nós são mostrados no inverso da ordem em que foram visitados.

A impressão dos nós nessa ordem pode ser mais lenta. Portanto, use apenas quando o determinismo for importante.

Mostre a forma de origem dos destinos como eles 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ções (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 válido seja produzido.

--output label

Com essa opção, o conjunto de nomes (ou rótulos) de cada destino no gráfico resultante é mostrado, 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 há muitas ordens topológicas possíveis de um gráfico (a pós-ordem reversa é apenas uma). Qual delas é 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.

Atenção: em alguns casos específicos, pode haver dois destinos diferentes com o mesmo rótulo. Por exemplo, uma regra sh_binary e o único arquivo srcs (implícito) podem ser chamados de foo.sh. Se o resultado de uma consulta contiver os dois destinos, a saída (no formato label) aparecerá contendo 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.

--output label_kind

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.

--output minrank --output maxrank

Como label, os formatos de saída minrank e maxrank exibem os rótulos de cada destino no gráfico resultante. No entanto, em vez de aparecerem na ordem topológica, eles aparecem na 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 comprimento do caminho mais curto de um nó raiz até ele. 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 bordas apontam de um destino para seus pré-requisitos: 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 classificação máxima de todos os antecessores.

Todos os nós de um ciclo são considerados de 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 para o resultado de uma consulta deps(x), rdeps(x) ou allpaths, o número da classificação será igual ao tamanho 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.

Fora da classificação
      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
      
--output location

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, ferramentas que podem analisar a segunda opção (como Emacs ou vi) também podem usar a saída da consulta para percorrer uma série de correspondências, permitindo 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 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 gera é mostrado. A ferramenta de consulta não tem informações suficientes para encontrar o local real do arquivo gerado e, em qualquer caso, ele pode não existir se uma versão ainda não tiver sido executada.

--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; duplicatas são excluídas. Formalmente, isso é uma projeção do conjunto de rótulos (package, target) nos 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.

Mostrar 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 sua estação de trabalho, instale-o usando o comando sudo apt-get install graphviz. Consulte a seção de exemplo abaixo para ver um exemplo de invocação.

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 em um formato fatorado. Ou seja, 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 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 do rótulo para um nó de gráfico na saída. Rótulos mais longos serão truncados, e -1 desativa o truncamento. Devido à forma fatorada em que os gráficos geralmente são impressos, os rótulos dos nós 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 não terá efeito, a menos que --output=graph esteja sendo usado.

--[no]graph:factored

Por padrão, os gráficos são exibidos na 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 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 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 especificamente explicitamente especificado 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 definido como o rótulo do destino, e um atributo location, em que o valor é o local do destino, conforme mostrado pelo --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 de linha não são mostrados.

--[no]xml:default_values

Por padrão, a saída XML não inclui o atributo de regra cujo valor é o valor padrão para esse tipo de atributo (por exemplo, se ele 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 regex Java para que você possa usar a sintaxe completa de java.util.regex.Pattern.

Como consultar repositórios externos

Se o build depender de regras de repositórios externos (definidos no arquivo do ESPAÇO DE TRABALHO), os resultados da consulta vão incluir essas dependências. Por exemplo, se //foo:bar depender de //external:some-lib e //external:some-lib estiver vinculado a @other-repo//baz:lib, bazel query 'deps(//foo:bar)' vai listar @other-repo//baz:lib e //external:some-lib como dependências.

Os repositórios externos não são dependências de um build. Ou seja, no exemplo acima, //external:other-repo não é uma dependência. No entanto, ele pode ser consultado como membro do pacote //external. Por exemplo:

  # Querying over all members of //external returns the repository.
  bazel query 'kind(http_archive, //external:*)'
  //external:other-repo

  # ...but the repository is not a dependency.
  bazel query 'kind(http_archive, deps(//foo:bar))'
  INFO: Empty results