Referencia de la consulta de Bazel

Informar un problema Ver fuente Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

En esta página, se incluye el manual de referencia del lenguaje de consultas de Bazel que se usa cuando se utiliza bazel query para analizar las dependencias de compilación. También describe los formatos de salida que admite bazel query.

Para conocer casos de uso prácticos, consulta la Guía práctica de Bazel Query.

Referencia de consultas adicionales

Además de query, que se ejecuta en el gráfico de destino de la fase posterior a la carga, Bazel incluye la consulta del gráfico de acción y la consulta configurable.

Consulta del gráfico de acción

La consulta del gráfico de acción (aquery) opera en el gráfico de destino configurado posterior al análisis y expone información sobre las acciones, los artefactos y sus relaciones. aquery es útil cuando te interesan las propiedades de las acciones o los artefactos generados a partir del gráfico de destino configurado. Por ejemplo, los comandos reales que se ejecutan y sus entradas, salidas y mnemónicos.

Para obtener más detalles, consulta la referencia de aquery.

Consulta configurable

La consulta tradicional de Bazel se ejecuta en el gráfico de destino de la fase posterior a la carga y, por lo tanto, no tiene ningún concepto de configuraciones ni de sus conceptos relacionados. En particular, no resuelve correctamente las sentencias de selección y, en su lugar, devuelve todas las resoluciones posibles de las selecciones. Sin embargo, el entorno de consultas configurable, cquery, controla correctamente las configuraciones, pero no proporciona toda la funcionalidad de esta consulta original.

Para obtener más detalles, consulta la referencia de cquery.

Ejemplos

¿Cómo usan las personas bazel query? Estos son algunos ejemplos típicos:

¿Por qué el árbol //foo depende de //bar/baz? Mostrar una ruta:

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

¿De qué bibliotecas de C++ dependen todas las pruebas de foo de las que no depende el destino de foo_bin?

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

Tokens: La sintaxis léxica

Las expresiones del lenguaje de búsqueda se componen de los siguientes tokens:

  • Palabras clave, como let Las palabras clave son las palabras reservadas del lenguaje, y cada una de ellas se describe a continuación. El conjunto completo de palabras clave es el siguiente:

  • Palabras, como "foo/...", ".*test rule" o "//bar/baz:all". Si una secuencia de caracteres está "entre comillas" (comienza y termina con una comilla simple "'" o comienza y termina con una comilla doble """), es una palabra. Si una secuencia de caracteres no está entre comillas, es posible que se analice como una palabra. Las palabras sin comillas son secuencias de caracteres extraídos del alfabeto (A-Za-z), los números (0-9) y los caracteres especiales */@.-_:$~[] (asterisco, barra, arroba, punto, guion, guion bajo, dos puntos, signo de dólar, virgulilla, corchete izquierdo, corchete derecho). Sin embargo, las palabras sin comillas no pueden comenzar con un guion - o un asterisco *, aunque los [nombres de destino][(/concepts/labels#target-names) relativos pueden comenzar con esos caracteres.

    Las palabras sin comillas tampoco pueden incluir los caracteres signo más + o signo igual =, aunque esos caracteres se permiten en los nombres de destino. Cuando escribas código que genere expresiones de búsqueda, los nombres de destino deben estar entre comillas.

    Las comillas son necesarias cuando se escriben secuencias de comandos que construyen expresiones de consulta de Bazel a partir de valores proporcionados por el usuario.

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

    Ten en cuenta que estas comillas se suman a las que tu shell pueda requerir, como las siguientes:

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

    Las palabras clave, cuando se escriben entre comillas, se tratan como palabras comunes. Por ejemplo, some es una palabra clave, pero "algunos" es una palabra. Tanto foo como "foo" son palabras.

    Sin embargo, ten cuidado cuando uses comillas simples o dobles en los nombres de destino. Cuando cites uno o más nombres de destino, usa solo un tipo de comillas (todas simples o todas dobles).

    A continuación, se muestran ejemplos de cómo se verá la cadena de consulta de 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
    

    Elegimos esta sintaxis para que no se necesiten comillas en la mayoría de los casos. El ejemplo (inusual) ".*test rule" necesita comillas: comienza con un punto y contiene un espacio. No es necesario, pero tampoco perjudicial, incluir "cc_library" entre comillas.

  • Puntuación, como paréntesis (), punto . y coma ,. Las palabras que contienen signos de puntuación (excepto las excepciones mencionadas anteriormente) deben estar entre comillas.

Se ignoran los caracteres de espacio en blanco fuera de una palabra entre comillas.

Conceptos del lenguaje de consultas de Bazel

El lenguaje de consultas de Bazel es un lenguaje de expresiones. Cada expresión se evalúa como un conjunto parcialmente ordenado de destinos o, de manera equivalente, como un gráfico (DAG) de destinos. Este es el único tipo de datos.

Los términos "conjunto" y "gráfico" hacen referencia al mismo tipo de datos, pero enfatizan diferentes aspectos de este, por ejemplo:

  • Conjunto: El orden parcial de los objetivos no es interesante.
  • Gráfico: El orden parcial de los objetivos es significativo.

Ciclos en el gráfico de dependencias

Los gráficos de dependencias de compilación deben ser acíclicos.

Los algoritmos que usa el lenguaje de consultas están diseñados para usarse en gráficos acíclicos, pero son sólidos contra los ciclos. No se especifican los detalles sobre cómo se tratan los ciclos, por lo que no se debe confiar en ellos.

Dependencias implícitas

Además de las dependencias de compilación que se definen de forma explícita en los archivos BUILD, Bazel agrega dependencias implícitas adicionales a las reglas. Por ejemplo, cada regla de Java depende de forma implícita de JavaBuilder. Las dependencias implícitas se establecen con atributos que comienzan con $ y no se pueden anular en los archivos BUILD.

De forma predeterminada, bazel query tiene en cuenta las dependencias implícitas cuando calcula el resultado de la búsqueda. Este comportamiento se puede cambiar con la opción --[no]implicit_deps. Ten en cuenta que, como la búsqueda no considera las configuraciones, nunca se consideran las posibles cadenas de herramientas.

Solidez

Las expresiones del lenguaje de consultas de Bazel operan sobre el gráfico de dependencias de compilación, que es el gráfico definido de forma implícita por todas las declaraciones de reglas en todos los archivos BUILD. Es importante comprender que este gráfico es algo abstracto y no constituye una descripción completa de cómo realizar todos los pasos de una compilación. Para realizar una compilación, también se requiere una configuración. Consulta la sección Configuraciones de la Guía del usuario para obtener más detalles.

El resultado de evaluar una expresión en el lenguaje de consultas de Bazel es verdadero para todas las configuraciones, lo que significa que puede ser una sobreaproximación conservadora y no exactamente precisa. Si usas la herramienta de consultas para calcular el conjunto de todos los archivos fuente necesarios durante una compilación, es posible que informe más de los que realmente se necesitan porque, por ejemplo, la herramienta de consultas incluirá todos los archivos necesarios para admitir la traducción de mensajes, aunque no tengas la intención de usar esa función en tu compilación.

Sobre la conservación del orden de los gráficos

Las operaciones conservan las restricciones de orden heredadas de sus subexpresiones. Puedes pensar en esto como "la ley de conservación del orden parcial". Considera un ejemplo: si emites una consulta para determinar el cierre transitivo de las dependencias de un destino en particular, el conjunto resultante se ordena según el grafo de dependencias. Si filtras ese conjunto para incluir solo los destinos de tipo file, la misma relación de orden parcial transitiva se mantiene entre cada par de destinos en el subconjunto resultante, aunque ninguno de estos pares esté conectado directamente en el gráfico original. (no hay bordes entre archivos en el gráfico de dependencia de compilación).

Sin embargo, si bien todos los operadores conservan el orden, algunas operaciones, como las operaciones de conjunto, no introducen ninguna restricción de orden propia. Considera esta expresión:

deps(x) union y

Se garantiza que el orden del conjunto de resultados final conserva todas las restricciones de ordenamiento de sus subexpresiones, es decir, que todas las dependencias transitivas de x se ordenan correctamente entre sí. Sin embargo, la consulta no garantiza nada sobre el orden de los destinos en y ni sobre el orden de los destinos en deps(x) en relación con los de y (excepto aquellos destinos en y que también se encuentran en deps(x)).

Los operadores que introducen restricciones de ordenamiento incluyen los siguientes: allpaths, deps, rdeps, somepath y los comodines de patrones de destino package:*, dir/..., etcétera.

Consulta de cielo

Sky Query es un modo de consulta que opera en un alcance del universo especificado.

Funciones especiales disponibles solo en SkyQuery

El modo Sky Query tiene las funciones de consulta adicionales allrdeps y rbuildfiles. Estas funciones operan en todo el alcance del universo (por eso no tienen sentido para la consulta normal).

Cómo especificar un alcance del universo

El modo Sky Query se activa pasando las siguientes dos marcas: (--universe_scope o --infer_universe_scope) y --order_output=no. --universe_scope=<target_pattern1>,...,<target_patternN> indica a la búsqueda que precargue el cierre transitivo del patrón objetivo especificado por los patrones objetivo, que pueden ser tanto aditivos como sustractivos. Luego, todas las búsquedas se evalúan en este "alcance". En particular, los operadores allrdeps y rbuildfiles solo devuelven resultados de este alcance. --infer_universe_scope le indica a Bazel que infiera un valor para --universe_scope a partir de la expresión de consulta. Este valor inferido es la lista de patrones de destino únicos en la expresión de búsqueda, pero es posible que no sea lo que deseas. Por ejemplo:

bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"

La lista de patrones de destino únicos en esta expresión de consulta es ["//my:target"], por lo que Bazel la trata de la misma manera que la invocación:

bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"

Sin embargo, el resultado de esa consulta con --universe_scope es solo //my:target; ninguna de las dependencias inversas de //my:target está en el universo, por construcción. Por otro lado, considera lo siguiente:

bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"

Esta es una invocación de consulta significativa que intenta calcular los objetivos de prueba en la expansión tests de los objetivos en algunos directorios que dependen de forma transitiva de objetivos cuya definición usa un determinado archivo .bzl. Aquí, --infer_universe_scope es una comodidad, especialmente en el caso en que la elección de --universe_scope requeriría que analizaras la expresión de la consulta por tu cuenta.

Por lo tanto, para las expresiones de consulta que usan operadores con alcance del universo, como allrdeps y rbuildfiles, asegúrate de usar --infer_universe_scope solo si su comportamiento es el que deseas.

Sky Query tiene algunas ventajas y desventajas en comparación con la búsqueda predeterminada. La principal desventaja es que no puede ordenar su salida según el orden del gráfico, por lo que se prohíben ciertos formatos de salida. Sus ventajas son que proporciona dos operadores (allrdeps y rbuildfiles) que no están disponibles en la consulta predeterminada. Además, Sky Query realiza su trabajo inspeccionando el gráfico de Skyframe, en lugar de crear un gráfico nuevo, que es lo que hace la implementación predeterminada. Por lo tanto, hay algunas circunstancias en las que es más rápido y usa menos memoria.

Expresiones: Sintaxis y semántica de la gramática

Esta es la gramática del lenguaje de consultas de Bazel, expresada en notación 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 ... ')'

En las siguientes secciones, se describe cada una de las producciones de esta gramática en orden.

Patrones de destino

expr ::= word

Sintácticamente, un patrón objetivo es solo una palabra. Se interpreta como un conjunto (no ordenado) de destinos. El patrón de destino más simple es una etiqueta, que identifica un solo destino (archivo o regla). Por ejemplo, el patrón de destino //foo:bar se evalúa como un conjunto que contiene un elemento, el destino, la regla bar.

Los patrones de destino generalizan las etiquetas para incluir comodines en paquetes y destinos. Por ejemplo, foo/...:all (o solo foo/...) es un patrón de destino que se evalúa como un conjunto que contiene todas las reglas de cada paquete de forma recursiva debajo del directorio foo. bar/baz:all es un patrón de destino que se evalúa como un conjunto que contiene todas las reglas del paquete bar/baz, pero no sus subpaquetes.

Del mismo modo, foo/...:* es un patrón de destino que se evalúa como un conjunto que contiene todos los destinos (archivos de reglas y) en cada paquete de forma recursiva debajo del directorio foo. bar/baz:* se evalúa como un conjunto que contiene todos los destinos en el paquete bar/baz, pero no sus subpaquetes.

Dado que el comodín :* coincide con archivos y reglas, suele ser más útil que :all para las búsquedas. Por el contrario, el comodín :all (implícito en los patrones de destino como foo/...) suele ser más útil para las compilaciones.

Los patrones de destino bazel query funcionan de la misma manera que los destinos de compilación bazel build. Para obtener más detalles, consulta Patrones de destino o escribe bazel help target-syntax.

Los patrones de destino pueden evaluarse como un conjunto singleton (en el caso de una etiqueta), como un conjunto que contiene muchos elementos (como en el caso de foo/..., que tiene miles de elementos) o como el conjunto vacío, si el patrón de destino no coincide con ningún destino.

Todos los nodos en el resultado de una expresión de patrón de destino se ordenan correctamente entre sí según la relación de dependencia. Por lo tanto, el resultado de foo:* no es solo el conjunto de destinos en el paquete foo, sino también el gráfico sobre esos destinos. (No se ofrecen garantías sobre el orden relativo de los nodos de resultado en comparación con otros nodos). Para obtener más detalles, consulta la sección orden del gráfico.

Variables

expr ::= let name = expr1 in expr2
       | $name

El lenguaje de consultas de Bazel permite definir variables y hacer referencia a ellas. El resultado de la evaluación de una expresión let es el mismo que el de expr2, con todas las ocurrencias libres de la variable name reemplazadas por el valor de expr1.

Por ejemplo, let v = foo/... in allpaths($v, //common) intersect $v es equivalente a allpaths(foo/...,//common) intersect foo/....

Una ocurrencia de una referencia de variable name que no se encuentre en una expresión let name = ... circundante es un error. En otras palabras, las expresiones de consulta de nivel superior no pueden tener variables libres.

En las producciones gramaticales anteriores, name es como word, pero con la restricción adicional de que debe ser un identificador legal en el lenguaje de programación C. Las referencias a la variable deben comenzar con el carácter “$”.

Cada expresión let define solo una variable, pero puedes anidarlas.

Tanto los patrones de destino como las referencias de variables constan de un solo token, una palabra, lo que crea una ambigüedad sintáctica. Sin embargo, no hay ambigüedad semántica, ya que el subconjunto de palabras que son nombres de variables válidos es disjunto del subconjunto de palabras que son patrones de destino válidos.

Técnicamente, las expresiones let no aumentan la expresividad del lenguaje de consulta: cualquier consulta que se pueda expresar en el lenguaje también se puede expresar sin ellas. Sin embargo, mejoran la concisión de muchas búsquedas y también pueden generar una evaluación de búsquedas más eficiente.

Expresiones entre paréntesis

expr ::= (expr)

Los paréntesis asocian subexpresiones para forzar un orden de evaluación. Una expresión entre paréntesis se evalúa como el valor de su argumento.

Operaciones algebraicas de conjuntos: intersección, unión y diferencia de conjuntos

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

Estos tres operadores calculan las operaciones de conjuntos habituales sobre sus argumentos. Cada operador tiene dos formas: una nominal, como intersect, y una simbólica, como ^. Ambas formas son equivalentes, pero las formas simbólicas son más rápidas de escribir. (Para mayor claridad, en el resto de esta página se usan las formas nominales).

Por ejemplo:

foo/... except foo/bar/...

se evalúa como el conjunto de destinos que coinciden con foo/..., pero no con foo/bar/....

Puedes escribir la misma consulta de la siguiente manera:

foo/... - foo/bar/...

Las operaciones intersect (^) y union (+) son conmutativas (simétricas); except (-) es asimétrica. El analizador trata los tres operadores como asociativos a la izquierda y de igual precedencia, por lo que es posible que desees usar paréntesis. Por ejemplo, las dos primeras expresiones son equivalentes, pero la tercera no lo es:

x intersect y union z
(x intersect y) union z
x intersect (y union z)

Objetivos de lectura de una fuente externa: establecer

expr ::= set(word *)

El operador set(a b c ...) calcula la unión de un conjunto de cero o más patrones de destino, separados por espacios en blanco (sin comas).

En conjunto con la función $(...) de Bourne Shell, set() proporciona un medio para guardar los resultados de una consulta en un archivo de texto normal, manipular ese archivo de texto con otros programas (como las herramientas estándar de shell de UNIX) y, luego, volver a introducir el resultado en la herramienta de consulta como un valor para su posterior procesamiento. Por ejemplo:

bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"

En el siguiente ejemplo,kind(cc_library, deps(//some_dir/foo:main, 5)) se calcula filtrando los valores de maxrank con un programa awk.

bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"

En estos ejemplos, $(<foo) es una abreviatura de $(cat foo), pero también se pueden usar otros comandos de shell que no sean cat, como el comando awk anterior.

Funciones

expr ::= word '(' int | word | expr ... ')'

El lenguaje de consultas define varias funciones. El nombre de la función determina la cantidad y el tipo de argumentos que requiere. Las siguientes funciones están disponibles:

Cierre transitivo de dependencias: deps

expr ::= deps(expr)
       | deps(expr, depth)

El operador deps(x) se evalúa como el grafo formado por el cierre transitivo de las dependencias de su conjunto de argumentos x. Por ejemplo, el valor de deps(//foo) es el gráfico de dependencias con la raíz en el único nodo foo, incluidas todas sus dependencias. El valor de deps(foo/...) son los gráficos de dependencia cuyas raíces son todas las reglas de cada paquete debajo del directorio foo. En este contexto, "dependencias" significa solo destinos de reglas y archivos, por lo que los archivos BUILD y Starlark necesarios para crear estos destinos no se incluyen aquí. Para ello, debes usar el operador buildfiles.

El gráfico resultante se ordena según la relación de dependencia. Para obtener más detalles, consulta la sección sobre el orden del gráfico.

El operador deps acepta un segundo argumento opcional, que es un literal entero que especifica un límite superior para la profundidad de la búsqueda. Por lo tanto, deps(foo:*, 0) devuelve todos los destinos del paquete foo, mientras que deps(foo:*, 1) incluye además los requisitos previos directos de cualquier destino del paquete foo, y deps(foo:*, 2) incluye además los nodos a los que se puede acceder directamente desde los nodos de deps(foo:*, 1), y así sucesivamente. (Estos números corresponden a los rangos que se muestran en el formato de salida minrank). Si se omite el parámetro depth, la búsqueda no está limitada: calcula el cierre transitivo reflexivo de los requisitos previos.

Cierre transitivo de las dependencias inversas: rdeps

expr ::= rdeps(expr, expr)
       | rdeps(expr, expr, depth)

El operador rdeps(u, x) evalúa las dependencias inversas del conjunto de argumentos x dentro del cierre transitivo del conjunto universal u.

El gráfico resultante se ordena según la relación de dependencia. Para obtener más detalles, consulta la sección sobre el orden del gráfico.

El operador rdeps acepta un tercer argumento opcional, que es un literal entero que especifica un límite superior para la profundidad de la búsqueda. El gráfico resultante solo incluye nodos dentro de una distancia de la profundidad especificada desde cualquier nodo del conjunto de argumentos. Por lo tanto, rdeps(//foo, //common, 1) se evalúa en todos los nodos del cierre transitivo de //foo que dependen directamente de //common. (Estos números corresponden a los rangos que se muestran en el formato de salida de minrank). Si se omite el parámetro depth, la búsqueda no tendrá límites.

Cierre transitivo de todas las dependencias inversas: allrdeps

expr ::= allrdeps(expr)
       | allrdeps(expr, depth)

El operador allrdeps se comporta igual que el operador rdeps, excepto que el "conjunto universal" es el resultado de la evaluación de la marca --universe_scope, en lugar de especificarse por separado. Por lo tanto, si se pasó --universe_scope=//foo/..., allrdeps(//bar) es equivalente a rdeps(//foo/..., //bar).

Dependencias inversas directas en el mismo paquete: same_pkg_direct_rdeps

expr ::= same_pkg_direct_rdeps(expr)

El operador same_pkg_direct_rdeps(x) se evalúa como el conjunto completo de destinos que se encuentran en el mismo paquete que un destino del conjunto de argumentos y que dependen directamente de él.

Cómo manejar el paquete de un objetivo: hermanos

expr ::= siblings(expr)

El operador siblings(x) se evalúa como el conjunto completo de destinos que se encuentran en el mismo paquete que un destino en el conjunto de argumentos.

Elección arbitraria: Algunos

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

El operador some(x, k) selecciona, como máximo, k destinos de forma arbitraria de su conjunto de argumentos x y se evalúa como un conjunto que contiene solo esos destinos. El parámetro k es opcional. Si falta, el resultado será un conjunto singleton que contiene solo un objetivo seleccionado de forma arbitraria. Si el tamaño del conjunto de argumentos x es menor que k, se devolverá todo el conjunto de argumentos x.

Por ejemplo, la expresión some(//foo:main union //bar:baz) se evalúa como un conjunto singleton que contiene //foo:main o //bar:baz, aunque no se define cuál. La expresión some(//foo:main union //bar:baz, 2) o some(//foo:main union //bar:baz, 3) devuelve //foo:main y //bar:baz.

Si el argumento es un singleton, some calcula la función de identidad: some(//foo:main) es equivalente a //foo:main.

Es un error si el conjunto de argumentos especificado está vacío, como en la expresión some(//foo:main intersect //bar:baz).

Operadores de ruta: somepath, allpaths

expr ::= somepath(expr, expr)
       | allpaths(expr, expr)

Los operadores somepath(S, E) y allpaths(S, E) calculan rutas entre dos conjuntos de destinos. Ambas consultas aceptan dos argumentos: un conjunto S de puntos de partida y un conjunto E de puntos de destino. somepath devuelve el grafo de nodos en alguna ruta arbitraria desde un destino en S hasta un destino en E; allpaths devuelve el grafo de nodos en todas las rutas desde cualquier destino en S hasta cualquier destino en E.

Los gráficos resultantes se ordenan según la relación de dependencia. Consulta la sección sobre el orden del gráfico para obtener más detalles.

Somepath
somepath(S1 + S2, E), un posible resultado.
Somepath
somepath(S1 + S2, E), otro resultado posible.
Allpaths
allpaths(S1 + S2, E)

Filtrado de tipo de destino: tipo

expr ::= kind(word, expr)

El operador kind(pattern, input) aplica un filtro a un conjunto de objetivos y descarta aquellos que no son del tipo esperado. El parámetro pattern especifica qué tipo de objetivo se debe correlacionar.

Por ejemplo, los tipos de los cuatro destinos definidos por el archivo BUILD (para el paquete p) que se muestran a continuación se ilustran en la tabla:

Código Objetivo Tipo
        genrule(
            name = "a",
            srcs = ["a.in"],
            outs = ["a.out"],
            cmd = "...",
        )
      
//p:a Regla genrule
//p:a.in archivo fuente
//p:a.out Archivo generado
//p:BUILD archivo fuente

Por lo tanto, kind("cc_.* rule", foo/...) se evalúa como el conjunto de todos los destinos de reglas cc_library, cc_binary, etcétera, debajo de foo, y kind("source file", deps(//foo)) se evalúa como el conjunto de todos los archivos fuente en el cierre transitivo de las dependencias del destino //foo.

A menudo, se requiere la inclusión de comillas en el argumento pattern porque, sin ellas, muchas expresiones regulares, como source file y .*_test, no se consideran palabras para el analizador.

Cuando se realiza la correlación para package group, es posible que los destinos que terminan en :all no arrojen ningún resultado. Utiliza :all-targets en lugar de esta función.

Filtrado por nombre del objetivo: filtro

expr ::= filter(word, expr)

El operador filter(pattern, input) aplica un filtro a un conjunto de destinos y descarta los destinos cuyas etiquetas (en formato absoluto) no coinciden con el patrón. Se evalúa como un subconjunto de su entrada.

El primer argumento, pattern, es una palabra que contiene una expresión regular sobre los nombres de destino. Una expresión filter se evalúa como el conjunto que contiene todos los destinos x, de modo que x sea miembro del conjunto input y la etiqueta (en formato absoluto, como //foo:bar) de x contenga una coincidencia (sin anclaje) para la expresión regular pattern. Dado que todos los nombres de destino comienzan con //, se puede usar como alternativa al anclaje de expresión regular ^.

Este operador suele proporcionar una alternativa mucho más rápida y sólida al operador intersect. Por ejemplo, para ver todas las dependencias de bar del destino //foo:foo, se podría evaluar lo siguiente:

deps(//foo) intersect //bar/...

Sin embargo, esta instrucción requerirá el análisis de todos los archivos BUILD en el árbol bar, lo que será lento y propenso a errores en archivos BUILD irrelevantes. Una alternativa sería la siguiente:

filter(//bar, deps(//foo))

que primero calcularía el conjunto de dependencias de //foo y, luego, filtraría solo los destinos que coinciden con el patrón proporcionado, es decir, los destinos con nombres que contienen //bar como subcadena.

Otro uso común del operador filter(pattern, expr) es filtrar archivos específicos por su nombre o extensión. Por ejemplo:

filter("\.cc$", deps(//foo))

proporcionará una lista de todos los archivos .cc que se usaron para compilar //foo.

Filtrado de atributos de regla: attr

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

El operador attr(name, pattern, input) aplica un filtro a un conjunto de destinos y descarta los destinos que no son reglas, los destinos de reglas que no tienen definido el atributo name o los destinos de reglas en los que el valor del atributo no coincide con la expresión regular pattern proporcionada. Se evalúa como un subconjunto de su entrada.

El primer argumento, name, es el nombre del atributo de regla que debe coincidir con el patrón de expresión regular proporcionado. El segundo argumento, pattern, es una expresión regular sobre los valores del atributo. Una expresión attr se evalúa como el conjunto que contiene todos los objetivos x, de modo que x sea miembro del conjunto input, sea una regla con el atributo definido name y el valor del atributo contenga una coincidencia (sin anclaje) para la expresión regular pattern. Si name es un atributo opcional y la regla no lo especifica de forma explícita, se usará el valor predeterminado del atributo para la comparación. Por ejemplo:

attr(linkshared, 0, deps(//foo))

seleccionará todas las dependencias de //foo que pueden tener un atributo linkshared (como la regla cc_binary) y que se hayan establecido explícitamente en 0 o no se hayan establecido en absoluto, pero el valor predeterminado es 0 (como para las reglas cc_binary).

Los atributos de tipo lista (como srcs, data, etcétera) se convierten en cadenas con el formato [value<sub>1</sub>, ..., value<sub>n</sub>], que comienzan con un corchete [, terminan con un corchete ] y usan "," (coma y espacio) para delimitar varios valores. Las etiquetas se convierten en cadenas usando la forma absoluta de la etiqueta. Por ejemplo, un atributo deps=[":foo", "//otherpkg:bar", "wiz"] se convertiría en la cadena [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]. Los corchetes siempre están presentes, por lo que la lista vacía usaría el valor de cadena [] para fines de coincidencia. Por ejemplo:

attr("srcs", "\[\]", deps(//foo))

seleccionará todas las reglas entre las dependencias de //foo que tengan un atributo srcs vacío, mientras que

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

seleccionará todas las reglas entre las dependencias de //foo que especifiquen al menos un valor en el atributo data (cada etiqueta tiene al menos 3 caracteres de longitud debido a // y :).

Para seleccionar todas las reglas entre las dependencias de //foo con un value particular en un atributo de tipo lista, usa

attr("tags", "[\[ ]value[,\]]", deps(//foo))

Esto funciona porque el carácter anterior a value será [ o un espacio, y el carácter posterior a value será una coma o ].

Filtrado de visibilidad de la regla: Visible

expr ::= visible(expr, expr)

El operador visible(predicate, input) aplica un filtro a un conjunto de segmentaciones y descarta las segmentaciones sin la visibilidad requerida.

El primer argumento, predicate, es un conjunto de destinos para los que todos los destinos de la salida deben ser visibles. Una expresión visible se evalúa como el conjunto que contiene todos los destinos x tales que x es miembro del conjunto input y, para todos los destinos y en predicate, x es visible para y. Por ejemplo:

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

seleccionará todos los destinos del paquete //bar de los que //foo puede depender sin incumplir las restricciones de visibilidad.

Evaluación de los atributos de regla del tipo etiqueta: etiquetas

expr ::= labels(word, expr)

El operador labels(attr_name, inputs) devuelve el conjunto de destinos especificados en el atributo attr_name de tipo "etiqueta" o "lista de etiquetas" en alguna regla del conjunto inputs.

Por ejemplo, labels(srcs, //foo) devuelve el conjunto de destinos que aparecen en el atributo srcs de la regla //foo. Si hay varias reglas con atributos srcs en el conjunto inputs, se devuelve la unión de sus srcs.

Expande y filtra test_suites: pruebas

expr ::= tests(expr)

El operador tests(x) devuelve el conjunto de todas las reglas de prueba del conjunto x, expandiendo cualquier regla test_suite en el conjunto de pruebas individuales a las que se refiere y aplicando el filtrado por tag y size.

De forma predeterminada, la evaluación de consultas ignora cualquier destino que no sea de prueba en todas las reglas test_suite. Esto se puede cambiar a errores con la opción --strict_test_suite.

Por ejemplo, la consulta kind(test, foo:*) enumera todas las reglas *_test y test_suite del paquete foo. Todos los resultados son (por definición) miembros del paquete foo. En cambio, la consulta tests(foo:*) devolverá todas las pruebas individuales que ejecutaría bazel test foo:*: esto puede incluir pruebas que pertenecen a otros paquetes, a los que se hace referencia directa o indirectamente a través de reglas test_suite.

Archivos de definición de paquetes: buildfiles

expr ::= buildfiles(expr)

El operador buildfiles(x) devuelve el conjunto de archivos que definen los paquetes de cada destino en el conjunto x; en otras palabras, para cada paquete, su archivo BUILD, más cualquier archivo .bzl al que haga referencia a través de load. Ten en cuenta que esto también devuelve los archivos BUILD de los paquetes que contienen estos archivos load.

Por lo general, este operador se usa cuando se determina qué archivos o paquetes son necesarios para compilar un destino especificado, a menudo junto con la opción --output package (que se describe más abajo). Por ejemplo:

bazel query 'buildfiles(deps(//foo))' --output package

Devuelve el conjunto de todos los paquetes de los que //foo depende de forma transitiva.

Archivos de definición de paquetes: rbuildfiles

expr ::= rbuildfiles(word, ...)

El operador rbuildfiles toma una lista separada por comas de fragmentos de ruta y devuelve el conjunto de archivos BUILD que dependen de forma transitiva de estos fragmentos de ruta. Por ejemplo, si //foo es un paquete, rbuildfiles(foo/BUILD) devolverá el destino //foo:BUILD. Si el archivo foo/BUILD contiene load('//bar:file.bzl'..., rbuildfiles(bar/file.bzl) devolverá el destino //foo:BUILD, así como los destinos de cualquier otro archivo BUILD que cargue //bar:file.bzl.

El alcance del operador rbuildfiles es el universo especificado por la marca --universe_scope. Los archivos que no corresponden directamente a archivos BUILD y .bzl no afectan los resultados. Por ejemplo, se ignoran los archivos fuente (como foo.cc), incluso si se mencionan de forma explícita en el archivo BUILD. Sin embargo, se respetan los symlinks, de modo que, si foo/BUILD es un symlink a bar/BUILD, rbuildfiles(bar/BUILD) incluirá //foo:BUILD en sus resultados.

El operador rbuildfiles es casi la inversa del operador buildfiles. Sin embargo, esta inversión moral se mantiene con más fuerza en una dirección: los resultados de rbuildfiles son como las entradas de buildfiles; el primero solo contendrá destinos de archivos BUILD en paquetes, y el segundo puede contener tales destinos. En la otra dirección, la correspondencia es más débil. Los resultados del operador buildfiles son destinos que corresponden a todos los paquetes y a .Archivos bzl necesarios para una entrada determinada. Sin embargo, las entradas del operador rbuildfiles no son esos destinos, sino los fragmentos de ruta que corresponden a esos destinos.

Archivos de definición de paquetes: loadfiles

expr ::= loadfiles(expr)

El operador loadfiles(x) devuelve el conjunto de archivos de Starlark que se necesitan para cargar los paquetes de cada destino en el conjunto x. En otras palabras, para cada paquete, devuelve los archivos .bzl a los que se hace referencia desde sus archivos BUILD.

Formatos de salida

bazel query genera un gráfico. Puedes especificar el contenido, el formato y el orden en que bazel query presenta este gráfico por medio de la opción de línea de comandos --output.

Cuando se ejecuta con Sky Query, solo se permiten los formatos de salida que son compatibles con la salida no ordenada. En específico, se prohíben los formatos de salida graph, minrank y maxrank.

Algunos formatos de salida aceptan opciones adicionales. El nombre de cada opción de salida tiene como prefijo el formato de salida al que se aplica, por lo que --graph:factored solo se aplica cuando se usa --output=graph y no tiene efecto si se usa un formato de salida que no sea graph. Del mismo modo, --xml:line_numbers solo se aplica cuando se usa --output=xml.

Sobre el orden de los resultados

Si bien las expresiones de búsqueda siempre siguen la "ley de conservación del orden del gráfico", la presentación de los resultados puede realizarse de forma ordenada por dependencia o sin ordenar. Esto no influye en los destinos del conjunto de resultados ni en la forma en que se calcula la búsqueda. Solo afecta la forma en que se imprimen los resultados en stdout. Además, los nodos que son equivalentes en el orden de dependencia pueden estar ordenados alfabéticamente o no. Se puede usar la marca --order_output para controlar este comportamiento. (La marca --[no]order_results tiene un subconjunto de la funcionalidad de la marca --order_output y dejó de estar disponible).

El valor predeterminado de esta marca es auto, que imprime los resultados en orden lexicográfico. Sin embargo, cuando se usa somepath(a,b), los resultados se imprimirán en orden de deps.

Cuando esta marca es no y --output es uno de los siguientes valores: build, label, label_kind, location, package, proto o xml, los resultados se imprimirán en un orden arbitrario. Por lo general, esta es la opción más rápida. Sin embargo, no se admite cuando --output es uno de los formatos graph, minrank o maxrank: con estos formatos, Bazel siempre imprime los resultados ordenados por el orden o la clasificación de las dependencias.

Cuando esta marca es deps, Bazel imprime los resultados en algún orden topológico, es decir, primero las dependencias. Sin embargo, los nodos que no están ordenados según el orden de dependencia (porque no hay una ruta de acceso de uno a otro) se pueden imprimir en cualquier orden.

Cuando esta marca es full, Bazel imprime los nodos en un orden totalmente determinístico (total). Primero, todos los nodos se ordenan alfabéticamente. Luego, cada nodo de la lista se usa como el inicio de una búsqueda en profundidad posterior al pedido en la que los bordes salientes a los nodos no visitados se atraviesan en orden alfabético de los nodos sucesores. Por último, los nodos se imprimen en el orden inverso al que se visitaron.

Imprimir los nodos en este orden puede ser más lento, por lo que solo se debe usar cuando el determinismo es importante.

Imprime el formulario de origen de los destinos tal como aparecerían en BUILD

--output build

Con esta opción, la representación de cada destino es como si se hubiera escrito a mano en el lenguaje BUILD. Se expanden todas las variables y las llamadas a funciones (como glob y macros), lo que resulta útil para ver el efecto de las macros de Starlark. Además, cada regla vigente informa un valor de generator_name o generator_function, que indica el nombre de la macro que se evaluó para producir la regla vigente.

Si bien el resultado usa la misma sintaxis que los archivos BUILD, no se garantiza que produzca un archivo BUILD válido.

--output label

Con esta opción, se imprime el conjunto de nombres (o etiquetas) de cada destino en el gráfico resultante, una etiqueta por línea, en orden topológico (a menos que se especifique --noorder_results; consulta las notas sobre el orden de los resultados). (Un ordenamiento topológico es aquel en el que un nodo del gráfico aparece antes que todos sus sucesores). Por supuesto, hay muchos ordenamientos topológicos posibles de un gráfico (el orden inverso posterior es solo uno); no se especifica cuál se elige.

Cuando se imprime el resultado de una consulta somepath, el orden en el que se imprimen los nodos es el orden de la ruta.

Advertencia: En algunos casos excepcionales, puede haber dos destinos distintos con la misma etiqueta; por ejemplo, una regla sh_binary y su único archivo srcs (implícito) pueden llamarse foo.sh. Si el resultado de una búsqueda contiene ambos destinos, la salida (en formato label) parecerá contener un duplicado. Cuando se usa el formato label_kind (consulta a continuación), la distinción se vuelve clara: los dos destinos tienen el mismo nombre, pero uno tiene el tipo sh_binary rule y el otro, el tipo source file.

--output label_kind

Al igual que label, este formato de salida imprime las etiquetas de cada destino en el gráfico resultante, en orden topológico, pero también antepone la etiqueta al tipo del destino.

--output minrank --output maxrank

Al igual que label, los formatos de salida minrank y maxrank imprimen las etiquetas de cada destino en el gráfico resultante, pero, en lugar de aparecer en orden topológico, aparecen en orden de clasificación, precedidas por su número de clasificación. Estos no se ven afectados por la marca --[no]order_results de ordenamiento de resultados (consulta las notas sobre el ordenamiento de los resultados).

Existen dos variantes de este formato: minrank clasifica cada nodo según la longitud de la ruta más corta desde un nodo raíz hasta él. Los nodos "raíz" (aquellos que no tienen aristas entrantes) tienen rango 0, sus sucesores tienen rango 1, etcétera (como siempre, las aristas apuntan de un objetivo a sus requisitos previos: los objetivos de los que depende).

maxrank clasifica cada nodo según la longitud de la ruta más larga desde un nodo raíz hasta él. Nuevamente, las "raíces" tienen el rango 0, y todos los demás nodos tienen un rango que es uno mayor que el rango máximo de todos sus predecesores.

Todos los nodos de un ciclo se consideran de igual rango. (La mayoría de los gráficos son acíclicos, pero se producen ciclos simplemente porque los archivos BUILD contienen ciclos erróneos).

Estos formatos de salida son útiles para descubrir la profundidad de un gráfico. Si se usan para el resultado de una consulta deps(x), rdeps(x) o allpaths, el número de clasificación es igual a la longitud de la ruta más corta (con minrank) o más larga (con maxrank) desde x hasta un nodo en esa clasificación. maxrank se puede usar para determinar la secuencia más larga de pasos de compilación necesarios para compilar un destino.

Por ejemplo, el gráfico de la izquierda genera los resultados de la derecha cuando se especifican --output minrank y --output maxrank, respectivamente.

Superada en el ranking
      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

Al igual que label_kind, esta opción imprime, para cada destino del resultado, el tipo y la etiqueta del destino, pero se le antepone una cadena que describe la ubicación de ese destino, como un nombre de archivo y un número de línea. El formato se parece al resultado de grep. Por lo tanto, las herramientas que pueden analizar este último (como Emacs o vi) también pueden usar el resultado de la consulta para recorrer una serie de coincidencias, lo que permite que la herramienta de consultas de Bazel se use como un "grep para archivos BUILD" que reconoce el gráfico de dependencias.

La información de ubicación varía según el tipo de destino (consulta el operador kind). En el caso de las reglas, se imprime la ubicación de la declaración de la regla dentro del archivo BUILD. En el caso de los archivos fuente, se imprime la ubicación de la línea 1 del archivo real. En el caso de un archivo generado, se imprime la ubicación de la regla que lo genera. (La herramienta de consultas no tiene suficiente información para encontrar la ubicación real del archivo generado y, en cualquier caso, es posible que no exista si aún no se realizó una compilación).

--output package

Esta opción imprime el nombre de todos los paquetes a los que pertenece algún destino en el conjunto de resultados. Los nombres se imprimen en orden lexicográfico y se excluyen los duplicados. Formalmente, esto es una proyección del conjunto de etiquetas (paquete, destino) en paquetes.

Los paquetes en repositorios externos tienen el formato @repo//foo/bar, mientras que los paquetes en el repositorio principal tienen el formato foo/bar.

Junto con la consulta deps(...), esta opción de salida se puede usar para encontrar el conjunto de paquetes que se deben extraer para compilar un conjunto determinado de destinos.

Mostrar un gráfico del resultado

--output graph

Esta opción hace que el resultado de la consulta se imprima como un gráfico dirigido en el popular formato GraphViz de AT&T. Por lo general, el resultado se guarda en un archivo, como .png o .svg. (Si el programa dot no está instalado en tu estación de trabajo, puedes instalarlo con el comando sudo apt-get install graphviz). Consulta la sección de ejemplo a continuación para ver una muestra de la invocación.

Este formato de salida es particularmente útil para las búsquedas allpaths, deps o rdeps, en las que el resultado incluye un conjunto de rutas de acceso que no se pueden visualizar fácilmente cuando se renderizan de forma lineal, como con --output label.

De forma predeterminada, el gráfico se renderiza en formato factorizado. Es decir, los nodos topológicamente equivalentes se combinan en un solo nodo con varias etiquetas. Esto hace que el gráfico sea más compacto y legible, ya que los gráficos de resultados típicos contienen patrones muy repetitivos. Por ejemplo, una regla java_library puede depender de cientos de archivos fuente de Java generados por el mismo genrule. En el gráfico factorizado, todos estos archivos se representan con un solo nodo. Este comportamiento se puede inhabilitar con la opción --nograph:factored.

--graph:node_limit n

La opción especifica la longitud máxima de la cadena de etiqueta para un nodo de gráfico en el resultado. Las etiquetas más largas se truncarán. El valor -1 inhabilita el truncamiento. Debido a la forma factorizada en la que suelen imprimirse los gráficos, las etiquetas de los nodos pueden ser muy largas. GraphViz no puede controlar etiquetas que superen los 1,024 caracteres, que es el valor predeterminado de esta opción. Esta opción no tiene ningún efecto a menos que se use --output=graph.

--[no]graph:factored

De forma predeterminada, los gráficos se muestran en formato factorizado, como se explicó anteriormente. Cuando se especifica --nograph:factored, los gráficos se imprimen sin factorización. Esto hace que la visualización con GraphViz sea poco práctica, pero el formato más simple puede facilitar el procesamiento con otras herramientas (como grep). Esta opción no tiene ningún efecto, a menos que se use --output=graph.

XML

--output xml

Esta opción hace que los destinos resultantes se impriman en formato XML. El resultado comienza con un encabezado XML como este:

  <?xml version="1.0" encoding="UTF-8"?>
  <query version="2">

y, luego, continúa con un elemento XML para cada destino en el gráfico de resultados, en orden topológico (a menos que se soliciten resultados no ordenados) y, luego, finaliza con un

</query>

Se emiten entradas simples para los destinos de tipo file:

  <source-file name='//foo:foo_main.cc' .../>
  <generated-file name='//foo:libfoo.so' .../>

Sin embargo, en el caso de las reglas, el XML está estructurado y contiene definiciones de todos los atributos de la regla, incluidos aquellos cuyo valor no se especificó de forma explícita en el archivo BUILD de la regla.

Además, el resultado incluye elementos rule-input y rule-output para que se pueda reconstruir la topología del gráfico de dependencias sin tener que saber que, por ejemplo, los elementos del atributo srcs son dependencias hacia adelante (requisitos previos) y el contenido del atributo outs son dependencias hacia atrás (consumidores).

Los elementos rule-input para las dependencias implícitas se suprimen si se especifica --noimplicit_deps.

  <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 un destino contiene un atributo name, cuyo valor es la etiqueta del destino, y un atributo location, cuyo valor es la ubicación del destino tal como la imprime --output location.

--[no]xml:line_numbers

De forma predeterminada, las ubicaciones que se muestran en el resultado XML contienen números de línea. Cuando se especifica --noxml:line_numbers, no se imprimen los números de línea.

--[no]xml:default_values

De forma predeterminada, la salida XML no incluye el atributo de regla cuyo valor es el valor predeterminado para ese tipo de atributo (por ejemplo, si no se especificó en el archivo BUILD o si el valor predeterminado se proporcionó de forma explícita). Esta opción hace que esos valores de atributos se incluyan en el resultado XML.

Expresiones regulares

Las expresiones regulares en el lenguaje de consultas usan la biblioteca regex de Java, por lo que puedes usar la sintaxis completa para java.util.regex.Pattern.

Consultas con repositorios externos

Si la compilación depende de reglas de repositorios externos (definidas en el archivo WORKSPACE), los resultados de la consulta incluirán estas dependencias. Por ejemplo, si //foo:bar depende de //external:some-lib y //external:some-lib está vinculado a @other-repo//baz:lib, bazel query 'deps(//foo:bar)' incluirá @other-repo//baz:lib y //external:some-lib como dependencias.

Los repositorios externos no son dependencias de una compilación. Es decir, en el ejemplo anterior, //external:other-repo no es una dependencia. Sin embargo, se puede consultar como miembro del paquete //external, por ejemplo:

  # 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