Esta página es el manual de referencia para el lenguaje de consulta de Bazel que se usa
cuando usas bazel query
a fin de analizar las dependencias de compilación. También se describen los formatos de salida que admite bazel query
.
Para casos de uso prácticos, consulta el instructivo de consulta de Bazel.
Referencia de consulta adicional
Además de query
, que se ejecuta en el gráfico de destino de la fase posterior a la carga,
Bazel incluye la consulta de grafo de acción y la consulta configurable.
Consulta del gráfico de acción
La consulta del gráfico de acción (aquery
) funciona en el grafo de destino configurado del análisis posterior y expone información sobre Acciones, Artefactos y sus relaciones. aquery
es útil cuando te interesan las propiedades de las acciones/artefactos generados del grafo de destino configurado.
Por ejemplo, se ejecutan los comandos reales y sus entradas, salidas y valores mnemotécnicos.
Para obtener más detalles, consulta la referencia de consulta.
Consulta configurable
La consulta de Bazel tradicional se ejecuta en el gráfico de destino de la fase de carga y, por lo tanto,
no tiene un concepto de configuración y sus conceptos relacionados. En particular, no resuelve correctamente las sentencias de selección y, en su lugar, muestra todas las resoluciones posibles. Sin embargo, el entorno de consulta configurable, cquery
, controla correctamente las configuraciones, pero no proporciona todas las funciones de esta consulta original.
Para obtener más información, consulta la referencia de BigQuery.
Ejemplos
¿Cómo usan las personas bazel query
? Estos son ejemplos típicos:
¿Por qué el árbol //foo
depende de //bar/baz
?
Muestra una ruta:
somepath(foo/..., //bar/baz:all)
¿Qué bibliotecas de C++ hacen que todas las pruebas de foo
dependan del objeto foo_bin
de destino?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
Tokens: la sintaxis léxica
Las expresiones del lenguaje de consulta se componen de los siguientes tokens:
Palabras clave, como
let
Las palabras clave son palabras reservadas del idioma y cada una se describe a continuación. El conjunto completo de palabras clave es:Palabras, como "
foo/...
", ".*test rule
" o "//bar/baz:all
". Si una secuencia de caracteres está "entrecomillada" (comienza y termina con una 'comilla simple' o comienza y termina con una comilla doble), es una palabra. Aunque una secuencia de caracteres no esté entre comillas, puede analizarse como una palabra. Las palabras sin comillas son secuencias de caracteres dibujados de los caracteres alfabéticos A-Za-z, los números del 0 al 9 y los caracteres especiales*/@.-_:$~[]
(asterisco, barra diagonal, en el punto, guion, guion bajo, dos puntos, dólar, tilde, llave cuadrada izquierda, llave cuadrada derecha). Sin embargo, es posible que las palabras sin comillas no comiencen con un guion-
o asterisco*
, aunque los [nombres de destino][(/concepts/labels#target-names) relativos puedan comenzar con esos caracteres.Las palabras sin comillas tampoco pueden incluir los caracteres más el signo
+
o el signo igual=
, aunque esos caracteres estén permitidos en los nombres de destino. Cuando escribes código que genera expresiones de consulta, los nombres de destino deben estar entre comillas.Las comillas es necesaria 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 esta cotización se suma a cualquier cotización que tu shell pueda requerir, como las siguientes:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
Las palabras clave y los operadores, cuando se citan, se tratan como palabras comunes. Por ejemplo,
some
es una palabra clave, pero "un poco" es una palabra. Tantofoo
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 o todas las comillas dobles).
Los siguientes son ejemplos de la string 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 la mayoría de los casos no necesiten comillas. El ejemplo
".*test rule"
(inusual) necesita comillas: comienza con un punto y contiene un espacio. Citar"cc_library"
es innecesario, pero inofensivo.Puntuación, como los paréntesis
()
, el punto.
y la coma,
. Las palabras que contienen signos de puntuación (además de las excepciones mencionadas anteriormente) deben estar entre comillas.
Los caracteres de espacio en blanco fuera de una palabra entre comillas se ignoran.
Conceptos del lenguaje de consultas de Bazel
El lenguaje de consulta de Bazel es un idioma de expresiones. Cada expresión se evalúa como un conjunto ordenado de objetivos de forma parcial, o un gráfico (DAG) de destinos. Este es el único tipo de datos.
Set y gráfico hacen referencia al mismo tipo de datos, pero enfatizan diferentes aspectos, por ejemplo:
- Establecer: 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 dependencia de compilación deben ser acíclicos.
Los algoritmos que usa el lenguaje de consulta están diseñados para usarse en grafos acíclicos, pero son resistentes contra los ciclos. No se especifican los detalles de cómo se tratan los ciclos y no se debe confiar en ellos.
Dependencias implícitas
Además de compilar dependencias que se definen de forma explícita en archivos BUILD
, Bazel agrega dependencias implícitas adicionales a las reglas. Por ejemplo, cada regla de Java depende implícitamente de JavaBuilder. Las dependencias implícitas se establecen con atributos que comienzan con $
y no se pueden anular en archivos BUILD
.
De forma predeterminada, bazel query
tiene en cuenta las dependencias implícitas cuando se calcula el resultado de la consulta. Este comportamiento se puede cambiar con la opción --[no]implicit_deps
. Ten en cuenta que, como la consulta no tiene en cuenta la
configuración, nunca se consideran las cadenas de herramientas potenciales.
Calidad
Las expresiones del lenguaje de consultas de Bazel operan sobre el gráfico de dependencia
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 grafo es 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 la evaluación de una expresión en el lenguaje de consulta de Bazel es verdadero para todas las configuraciones, lo que significa que puede ser una aproximación conservadora y no precisa. Si usas la Herramienta de consultas para calcular el conjunto de todos los archivos de origen necesarios durante una compilación, esta puede generar informes que superen la cantidad necesaria, ya que, por ejemplo, la Herramienta de consultas incluirá todos los archivos necesarios para admitir la traducción de mensajes, aunque no quieras utilizar esa función en tu compilación.
Conservación del orden de los gráficos
Las operaciones conservan las restricciones de orden heredadas de sus subexpresiones. Puedes considerar esto como “la ley de conservación del orden parcial”. Considera un ejemplo: si realizas una consulta para determinar el cierre transitivo de las dependencias de un objetivo en particular, el conjunto resultante se ordena según el gráfico de dependencias. Si filtras la configuración para incluir solo los objetivos del tipo file
, se mantiene la misma relación de orden parcial transitiva entre cada par de destinos en el subconjunto resultante, aunque ninguno de estos pares esté directamente conectado en el gráfico original.
(No hay bordes en el gráfico de dependencia de la compilación).
Sin embargo, aunque todos los operadores conservan el orden, algunas operaciones, como las operaciones de configuración, no presentan restricciones de orden propias. Considera esta expresión:
deps(x) union y
Se garantiza el orden del conjunto de resultados final para preservar todas las restricciones de orden de sus subexpresiones, es decir, que todas las dependencias transitivas de x
estén ordenadas correctamente una respecto de la otra. Sin embargo, la consulta no garantiza nada sobre el orden de los destinos en y
ni el orden de los destinos en deps(x)
en relación con los de y
(excepto los destinos en y
que también están en deps(x)
).
Entre los operadores que introducen restricciones de ordenamiento se incluyen: allpaths
, deps
, rdeps
, somepath
y los comodines del patrón de destino package:*
, dir/...
, etcétera.
Búsqueda en Sky
Sky Query es un modo de consulta que opera en un alcance universal especificado.
Funciones especiales disponibles solo en SkyQuery
El modo de consulta de Sky tiene las funciones de consulta adicionales allrdeps
y rbuildfiles
. Estas funciones operan en todo el alcance del universo (por eso, no tienen sentido para una consulta normal).
Cómo especificar el 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>
le indica a la consulta que cargue previamente el cierre transitivo del patrón objetivo especificado por los patrones objetivo, que puede ser aditivo y subtractivo. Luego, todas las consultas se evalúan en este “alcance”. En particular, los operadores allrdeps
y rbuildfiles
solo muestran resultados de este alcance.
--infer_universe_scope
le dice 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 consulta, pero es posible que esto 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 destinos en algunos directorios que dependen de forma transitiva de los destinos cuya definición usa un archivo .bzl
determinado. Aquí, --infer_universe_scope
es conveniente, especialmente en el caso en que la elección de --universe_scope
requeriría que analices la expresión de consulta por tu cuenta.
Por lo tanto, para las expresiones de consulta que usan operadores con alcance universal, 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 consulta predeterminada. La principal desventaja es que no se puede ordenar el resultado según el orden de los gráficos y, por lo tanto, no se permiten 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 hace su trabajo mediante la introspección del grafo de Skyframe, en lugar de crear un grafo 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 consulta de Bazel, expresado 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 de objetivo es solo una palabra. Se interpreta como un conjunto (desordenado) de destinos. El patrón de destino más simple es una etiqueta, que
identifica un solo objetivo (archivo o regla). Por ejemplo, el patrón de destino //foo:bar
se evalúa como un conjunto que contiene un elemento, el objetivo y la regla bar
.
Los patrones de destino generalizan las etiquetas para incluir comodines sobre 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 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.
De manera similar, foo/...:*
es un patrón de destino que se evalúa como un conjunto que contiene todos los destinos (reglas y archivos) de cada paquete que se encuentra debajo del directorio foo
. bar/baz:*
se evalúa como un conjunto que contiene todos los destinos del paquete bar/baz
, pero no sus subpaquetes.
Debido a que el comodín :*
coincide con los archivos y con las reglas, suele ser más útil que :all
para las consultas. Por el contrario, el comodín :all
(implícito en
patrones de destino como foo/...
) suele ser más útil para las compilaciones.
Los patrones de destino de bazel query
funcionan igual que los objetivos de compilación de 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), un conjunto que contiene muchos elementos (como en el caso de foo/...
, que tiene miles de elementos) o el conjunto vacío, si el patrón de destino no coincide con ningún objetivo.
Todos los nodos que se obtienen como resultado de una expresión de patrón de destino se ordenan de manera correcta en relación con los demás según la relación de dependencia. Por lo tanto, el resultado de
foo:*
no es solo el conjunto de destinos del paquete foo
, sino también el
gráfico sobre esos destinos. No se garantiza el orden relativo de los nodos de resultado en comparación con otros nodos. Para obtener más información, consulta la sección Orden de gráficos.
Variables
expr ::= let name = expr1 in expr2
| $name
El lenguaje de consulta de Bazel permite definiciones de referencias
y referencias a ellas. El resultado de la evaluación de una expresión let
es el mismo que el de expr2, con todos los casos gratuitos de la variable name reemplazados por el valor de expr1.
Por ejemplo, let v = foo/... in allpaths($v, //common) intersect $v
es equivalente a allpaths(foo/...,//common) intersect foo/...
.
Un caso de una referencia de variable name
que no sea una expresión let name = ...
delimitante 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 palabra, pero con la restricción adicional de que es un identificador legal en el lenguaje de programación C. Las referencias a la variable deben estar precedidas por el carácter "$".
Cada expresión let
define una sola variable, pero puedes anidarlas.
Tanto los patrones de destino como las referencias 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 legales no está relacionado con el subconjunto de palabras que son patrones de segmentación legal.
Técnicamente, las expresiones let
no aumentan la expresividad del lenguaje de consulta: cualquier consulta que se pueda expresar en el idioma también se puede expresar sin ellos. Sin embargo, mejoran la concisión de muchas consultas y también pueden generar una evaluación más eficiente.
Expresiones entre paréntesis
expr ::= (expr)
Los paréntesis asocian las subexpresiones para forzar un orden de evaluación. Una expresión entre paréntesis evalúa el valor de su argumento.
Operaciones de conjuntos algebraicas: intersección, unión, diferencia de conjunto
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 en sus argumentos.
Cada operador tiene dos formatos: uno nominal (por ejemplo, intersect
) y uno simbólico (como ^
). Ambas formas son equivalentes; las simbólicas son más rápidas. (Para mayor claridad, el resto de esta página utiliza formas nominales).
Por ejemplo:
foo/... except foo/bar/...
se evalúa con 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 prioridad, por lo que te recomendamos 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)
Leer destinos desde una fuente externa: establecido
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 la shell Bourne, 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 herramientas de shell UNIX estándar) y, luego, volver a ingresar el resultado en la herramienta de consulta como 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 mediante el filtrado de los valores 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 comandos de shell que no sean cat
, como el comando awk
anterior.
Funciones
expr ::= word '(' int | word | expr ... ')'
El lenguaje de consulta define varias funciones. El nombre de la función determina la cantidad y el tipo de argumentos que requiere. Están disponibles las siguientes funciones:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
Cierre transitivo de dependencias: dependencias
expr ::= deps(expr)
| deps(expr, depth)
El operador deps(x)
evalúa el grafo formado por el cierre transitivo de las dependencias del conjunto de argumentos x. Por ejemplo, el valor de deps(//foo)
es el gráfico de dependencias con permisos de administrador en el único nodo foo
, incluidas todas sus dependencias. El valor de deps(foo/...)
son los gráficos de dependencias cuyas raíces son todas reglas en cada paquete debajo del directorio foo
. En este contexto, "dependencias" significa que solo se incluyen objetivos de reglas y archivos, por lo que no se incluyen aquí los archivos BUILD
y Starlark necesarios para crear estos destinos. Para eso, debes usar el operador buildfiles
.
El grafo resultante se ordena según la relación de dependencia. Para obtener más información, consulta la sección sobre el orden de gráficos.
El operador deps
acepta un segundo argumento opcional, que es un literal de número entero que especifica un límite superior en la profundidad de la búsqueda. Por lo tanto, deps(foo:*, 0)
muestra todos los destinos del paquete foo
, mientras que deps(foo:*, 1)
incluye los requisitos directos de cualquier destino del paquete foo
, deps(foo:*, 2)
incluye los nodos a los que se puede acceder directamente desde deps(foo:*, 1)
, etcétera. (Estos números corresponden a las clasificaciones que se muestran en el formato de salida minrank
).
Si se omite el parámetro depth, la búsqueda no está delimitada: calcula el cierre transitivo reflexivo de los requisitos previos.
Cierre transitivo de 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 de universos u.
El grafo resultante se ordena según la relación de dependencia. Consulta la sección sobre el orden de gráficos para obtener más detalles.
El operador rdeps
acepta un tercer argumento opcional, que es un literal de número entero que especifica un límite superior en la profundidad de la búsqueda. El grafo resultante solo incluye nodos ubicados a una distancia cercana a la profundidad especificada de cualquier nodo del conjunto de argumentos. Por lo tanto, rdeps(//foo, //common, 1)
se evalúa como todos los nodos del cierre transitivo de //foo
que dependen directamente de //common
. (Estos números corresponden a las clasificaciones que se muestran en el formato de salida minrank
). Si se omite el parámetro depth, la búsqueda no está delimitada.
Cierre transitivo de todas las dependencias inversas: allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
El operador allrdeps
se comporta como el operador rdeps
, con la excepción de que el “conjunto universal” es cualquiera que se evalúe con 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)
.
Inversiones directas directas en el mismo paquete: same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
El operador same_pkg_direct_rdeps(x)
evalúa el conjunto completo de destinos que se encuentran en el mismo paquete que un objetivo en el conjunto de argumentos y que dependen directamente de él.
Cómo trabajar con el paquete de un destino: elementos del mismo nivel
expr ::= siblings(expr)
El operador siblings(x)
evalúa el conjunto completo de destinos que se encuentran
en el mismo paquete que un objetivo del conjunto de argumentos.
Elección arbitraria: algunas
expr ::= some(expr)
| some(expr, count )
El operador some(x, k)
selecciona, como máximo, k destinos de forma arbitraria a partir de su conjunto de argumentos x y evalúa a 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 destino seleccionado de forma arbitraria. Si el tamaño del conjunto de argumentos x es menor que k, se mostrará 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 esté definido. La expresión some(//foo:main union //bar:baz, 2)
o some(//foo:main union //bar:baz, 3)
muestra //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 de acceso entre dos conjuntos de destinos. Ambas consultas aceptan dos argumentos: un conjunto S de puntos de partida y un conjunto E de puntos finales. somepath
muestra el gráfico de nodos en alguna ruta arbitraria de un objetivo en S a un objetivo en E; allpaths
muestra el gráfico de nodos en todos los destinos de cualquier destino en S a cualquier destino en E.
Los gráficos resultantes se ordenan según la relación de dependencia. Consulta la sección sobre el orden de los gráficos para obtener más detalles.
somepath(S1 + S2, E) , un resultado posible. |
somepath(S1 + S2, E) , otro resultado posible. |
allpaths(S1 + S2, E) |
Filtrado de categorías de destino: tipo
expr ::= kind(word, expr)
El operador kind(pattern, input)
aplica un filtro a un conjunto de destinos y descarta los objetivos que no son del tipo esperado. El parámetro pattern
especifica con qué tipo de objetivo debe coincidir.
Por ejemplo, en la tabla, se muestran los tipos de los cuatro destinos definidos por el archivo BUILD
(para el paquete p
) que se muestran a continuación:
Programa | Diana | Tipo |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
regla de genrule |
//p:a.in |
archivo de origen | |
//p:a.out |
archivo generado | |
//p:BUILD |
archivo de origen |
Por lo tanto, kind("cc_.* rule", foo/...)
evalúa el conjunto de todos los destinos cc_library
, cc_binary
, etc., que están por debajo de foo
, y kind("source file", deps(//foo))
evalúa el conjunto de todos los archivos de origen en el cierre transitivo de las dependencias del destino //foo
.
Las comillas del argumento pattern a menudo son necesarias porque, sin él, muchas expresiones regulares, como source
file
y .*_test
, no se consideran palabras.
Cuando se establece una coincidencia para package group
, es posible que los objetivos que terminan en :all
no generen ningún resultado. Utiliza :all-targets
en lugar de esta función.
Filtro de nombre de destino: filtro
expr ::= filter(word, expr)
El operador filter(pattern, input)
aplica un filtro a un conjunto de destinos y descarta los objetivos cuyas etiquetas (en forma absoluta) no coinciden con el patrón; evalúa un subconjunto de sus entradas.
El primer argumento, pattern, es una palabra que contiene una expresión regular sobre los nombres de los destinos. Una expresión filter
se evalúa como un conjunto que contiene todos los destinos x, de modo que x es miembro del conjunto input, y la etiqueta (en forma absoluta, como //foo:bar
) de x contiene una coincidencia (no anclada) para la expresión regular pattern. Dado que todos los nombres de destino comienzan con //
, se puede usar como alternativa al ancla de expresión regular ^
.
Este operador a menudo proporciona 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.
deps(//foo) intersect //bar/...
Sin embargo, esta declaració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:
filter(//bar, deps(//foo))
que primero calcularía el conjunto de dependencias //foo
y,
luego, filtraría solo los destinos que coincidan con el patrón proporcionado; en otras palabras,
los objetivos con nombres que contengan //bar
como substring.
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 usan para compilar //foo
.
Filtrado de atributos de reglas: attr
expr ::= attr(word, word, expr)
El operador attr(name, pattern, input)
aplica un filtro a un conjunto de destinos y descarta los objetivos que no son reglas, los objetivos de reglas que no tienen definidos el atributo name o los objetivos de regla en los que el valor del atributo no coincide con la expresión regular pattern; 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 un conjunto que contiene todos los destinos x, de modo que x es miembro del conjunto input, es una regla con el atributo definido name y el valor del atributo contiene una coincidencia (no anclada) 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 del atributo predeterminado para la comparación. Por ejemplo:
attr(linkshared, 0, deps(//foo))
seleccionará todas las dependencias de //foo
que puedan tener un atributo
vínculo compartido (por ejemplo, la regla cc_binary
) y lo establecerá
de forma explícita en 0 o no lo establecerá, pero el valor predeterminado será 0 (como
las reglas cc_binary
).
Los atributos de tipo de lista (como srcs
, data
, etc.) se convierten en strings con el formato [value<sub>1</sub>, ..., value<sub>n</sub>]
, que comienzan con un corchete [
, terminan con un corchete ]
y usan “,
” (coma, espacio) para delimitar varios valores.
Las etiquetas se convierten en strings mediante la forma absoluta de la etiqueta. Por ejemplo, un atributo deps=[":foo",
"//otherpkg:bar", "wiz"]
se convertiría en la string [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
.
Los corchetes siempre están presentes, por lo que la lista vacía usaría el valor de string []
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
(todas las etiquetas tienen al menos 3 caracteres debido a //
y :
).
Para seleccionar todas las reglas entre dependencias de //foo
con un value
particular en un atributo de tipo de lista, usa lo siguiente:
attr("tags", "[\[ ]value[,\]]", deps(//foo))
Esto funciona porque el carácter antes de value
será [
o un espacio, y el carácter después de value
será una coma o ]
.
Filtrado de visibilidad de reglas: visible
expr ::= visible(expr, expr)
El operador visible(predicate, input)
aplica un filtro a un conjunto de destinos y los descarta sin la visibilidad requerida.
El primer argumento, predicate, es un conjunto de destinos para los que todos los objetivos deben ser visibles. Una expresión visible se evalúa como un conjunto que contiene todos los destinos x, de modo que x es miembro del conjunto input, y y es visible para todos los destinos y de predicate.x Por ejemplo:
visible(//foo, //bar:*)
seleccionará todos los destinos del paquete //bar
del que //foo
puede depender sin infringir las restricciones de visibilidad.
Evaluación de los atributos de las reglas de la etiqueta de tipo: etiquetas
expr ::= labels(word, expr)
El operador labels(attr_name, inputs)
muestra el conjunto de destinos especificados en el atributo attr_name del tipo "label" o "list of label" en alguna regla del conjunto inputs.
Por ejemplo, labels(srcs, //foo)
muestra 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 muestra la unión de su srcs
.
Expande y filtra test_suites: pruebas
expr ::= tests(expr)
El operador tests(x)
muestra el conjunto de todas las reglas de prueba del conjunto x, expande las reglas test_suite
al conjunto de pruebas individuales a las que hacen referencia y aplica el filtrado por tag
y size
.
De forma predeterminada, la evaluación de las consultas ignora cualquier objetivo que no sea de prueba en todas las reglas de 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
en el paquete foo
. Todos los resultados son (por definición) miembros del paquete foo
. Por el contrario, la consulta tests(foo:*)
mostrará todas las pruebas individuales que ejecutaría bazel test
foo:*
: esto puede incluir pruebas que pertenezcan a otros paquetes a los que se hace referencia de forma directa o indirecta mediante las reglas test_suite
.
Archivos de definición de paquetes: buildfiles
expr ::= buildfiles(expr)
El operador buildfiles(x)
muestra el conjunto
de archivos que define 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 muestra los archivos BUILD
de los paquetes que contienen estos archivos load
.
Por lo general, este operador se usa a fin de determinar qué archivos o paquetes se requieren para compilar un destino específico, a menudo junto con la opción --output package
a continuación. Por ejemplo:
bazel query 'buildfiles(deps(//foo))' --output package
muestra 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 muestra el conjunto de archivos BUILD
que dependen de forma transitiva de estos fragmentos. Por ejemplo, si //foo
es un paquete, entonces rbuildfiles(foo/BUILD)
mostrará el destino //foo:BUILD
. Si el archivo foo/BUILD
tiene load('//bar:file.bzl'...
, rbuildfiles(bar/file.bzl)
mostrará el destino //foo:BUILD
, así como los objetivos para cualquier otro archivo BUILD
que cargue //bar:file.bzl
.
El alcance del operador --universe_scope
. Los archivos que no corresponden directamente a los archivos BUILD
y los archivos .bzl
no afectan los resultados. Por ejemplo, los archivos de origen (como foo.cc
) se ignoran, incluso si se mencionan de forma explícita en el archivo BUILD
. Sin embargo, se respetan los vínculos simbólicos, de manera que, si foo/BUILD
es un symlink a bar/BUILD
, rbuildfiles(bar/BUILD)
incluirá //foo:BUILD
en sus resultados.
El operador rbuildfiles
es casi moralmente lo inverso del operador buildfiles
. Sin embargo, esta inversión moral se mantiene más fuerte en una dirección: los resultados de rbuildfiles
son como las entradas de buildfiles
; el primero solo contendrá objetivos de archivo BUILD
en paquetes y el segundo puede contener esos objetivos. En la otra dirección, la correspondencia es más débil. Los resultados del operador buildfiles
son objetivos correspondientes a todos los paquetes y archivosArchivos bzl
necesarios para una entrada determinada. Sin embargo, las entradas del operador rbuildfiles
no son esos destinos, sino los fragmentos de rutas de acceso que corresponden a esos destinos.
Archivos de definición de paquetes: loadfiles
expr ::= loadfiles(expr)
El operador loadfiles(x)
muestra el conjunto de archivos de Starlark necesarios para cargar los paquetes de cada destino en el conjunto x. En otras palabras, para cada paquete, muestra los archivos .bzl a los que se hace referencia desde sus archivos BUILD
.
Formatos de salida
bazel query
genera un gráfico.
Especifica el contenido, el formato y el orden por el que bazel query
presenta este grafo mediante 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 resultados desordenados. En particular, se prohíben los formatos de resultado graph
, minrank
y maxrank
.
Algunos de los formatos de salida aceptan opciones adicionales. El nombre de cada opción de salida tiene un prefijo con el formato de salida al que se aplica, por lo que --graph:factored
solo se aplica cuando se usa --output=graph
. No tiene efecto si se usa un formato de salida que no es graph
. Del mismo modo, --xml:line_numbers
solo se aplica cuando se usa --output=xml
.
Orden de los resultados
Aunque las expresiones de consulta siempre siguen la "ley de conservación del orden de los gráficos", presentar los resultados puede realizarse de forma ordenada o no. Esto no
influye en los objetivos del conjunto de resultados ni en la forma en que se calcula la consulta. 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 o no estar ordenados alfabéticamente.
La marca --order_output
se puede usar para controlar este comportamiento.
(La marca --[no]order_results
tiene un subconjunto de la funcionalidad de la marca --order_output
y está obsoleta).
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 imprimen en el orden deps
.
Cuando esta marca es no
y --output
es uno de build
, label
, label_kind
, location
, package
, proto
o xml
, los resultados se imprimirán en orden arbitrario. Por lo general, esta es la opción más rápida. Sin embargo, no es compatible cuando --output
es uno de graph
, minrank
o maxrank
: con estos formatos, Bazel siempre imprime los resultados ordenados por orden o dependencia de dependencia.
Cuando esta marca es deps
, Bazel imprime el orden topográfico, es decir,
las dependencias primero. Sin embargo, los nodos que están desordenados según el orden de la dependencia (porque no hay una ruta de uno a la otra) pueden imprimirse en cualquier orden.
Cuando esta marca es full
, Bazel imprime los nodos en un orden completamente determinista (total).
En primer lugar, todos los nodos están ordenados alfabéticamente. Luego, cada nodo de la lista se usa como comienzo de una búsqueda de primer orden con profundidad posterior al pedido en la que los bordes salientes a los nodos no visitados se desvían en orden alfabético de los nodos sucesores. Por último, los nodos se imprimen al revés del orden en el que se visitaron.
La impresión de nodos en este orden puede ser más lenta, por lo que se debe usar solo cuando el determinismo es importante.
Imprime el formato de origen de los destinos tal como aparecería en BUILD.
--output build
Con esta opción, la representación de cada destino es como si estuviera escrita a mano en el lenguaje de COMPILACIÓN. Todas las variables y llamadas a funciones (como glob y macros) están expandidas, lo que es útil para ver el efecto de las macros de Starlark. Además, cada regla vigente informa un valor generator_name
o generator_function
, lo que da el nombre de la macro que se evaluó para producir la regla efectiva.
Aunque el resultado usa la misma sintaxis que los archivos BUILD
, no se garantiza que se produzca un archivo BUILD
válido.
Imprime la etiqueta de cada destino
--output label
Con esta opción, se imprime un conjunto de nombres (o etiquetas) de cada destino en el grafo resultante, una etiqueta por línea, en orden topológico (a menos que se especifique --noorder_results
, consulta notas sobre el orden de los resultados).
(un orden topológico es aquel en el que un nodo del grafo aparece antes que todos sus sucesores). Por supuesto, hay muchos ordenamientos topológicos posibles en un gráfico (orden inverso es solo uno); no se especifica el que se elija.
Cuando imprimes el resultado de una consulta somepath
, el orden en el que se imprimen los nodos es el orden de la ruta de acceso.
Advertencia: En algunos casos de esquina, puede haber dos destinos distintos con la misma etiqueta. Por ejemplo, una regla sh_binary
y su archivo srcs
único (implícito) pueden llamarse foo.sh
. Si el resultado de una consulta contiene ambos destinos, el resultado (en formato label
) aparecerá como un duplicado. Cuando se usa el formato label_kind
(consulta a continuación), la distinción queda clara: los dos destinos tienen el mismo nombre, pero uno tiene el tipo sh_binary rule
y el otro source file
.
Imprime la etiqueta y el tipo de cada destino
--output label_kind
Al igual que label
, este formato de salida imprime las etiquetas de cada destino en el grafo resultante, en orden topográfico, pero también precede a la etiqueta por el kind del destino.
Imprime la etiqueta de cada destino, en orden de clasificación
--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 rango. Estos no se ven afectados por la marca --[no]order_results
de ordenamiento de resultados (consulta las notas sobre el orden de los resultados).
Hay dos variantes de este formato: minrank
clasifica cada nodo según la longitud de la ruta más corta desde el nodo raíz hasta él.
Los nodos "raíz" (aquellos que no tienen bordes entrantes) son de rango 0, sus sucesores son de rango 1, etc. (Como siempre, los perímetros apuntan de un objetivo a sus requisitos previos: los destinos 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 una clasificación 0; todos los demás nodos tienen una clasificación que es superior a la clasificación máxima 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 los ciclos solo ocurren porque los archivos BUILD
contienen ciclos erróneos).
Estos formatos de resultado son útiles para descubrir qué tan profundo es un grafo. Si se usa para el resultado de una consulta deps(x)
, rdeps(x)
o allpaths
, el número de rango es igual a la longitud de la ruta más corta (con minrank
) o más larga (con maxrank
) de x
a un nodo en esa clasificación. Se puede usar maxrank
a fin de determinar la secuencia más larga de pasos de compilación necesarios para compilar un destino.
Por ejemplo, el gráfico de la izquierda produce los resultados de la derecha cuando se especifican --output minrank
y --output maxrank
, respectivamente.
minrank 0 //c:c 1 //b:b 1 //a:a 2 //b:b.cc 2 //a:a.cc |
maxrank 0 //c:c 1 //b:b 2 //a:a 2 //b:b.cc 3 //a:a.cc |
Imprimir la ubicación de cada destino
--output location
Al igual que label_kind
, esta opción imprime, para cada destino en el resultado, el tipo y la etiqueta del destino, pero tiene el prefijo de una string que describe la ubicación de ese destino, como nombre de archivo y número de línea. El formato es similar al resultado de grep
. Por lo tanto, las herramientas que pueden analizar estas últimas (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 consulta de Bazel se use como un "grep" de reconocimiento de grafos para archivos BUILD.
La información de la ubicación varía según el tipo de destino (consulta el operador de tipo). Para las reglas, se imprime la ubicación de la declaración de la regla dentro del archivo BUILD
.
Para los archivos de origen, se imprime la ubicación de la línea 1 del archivo real. Para un archivo generado, se imprime la ubicación de la regla que lo genera. (La herramienta de consulta 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).
Imprime el conjunto de paquetes.
--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; se excluyen los duplicados. De manera formal, esta es una proyección del conjunto de etiquetas (paquete, objetivo) en paquetes.
Los paquetes de los repositorios externos tienen el formato @repo//foo/bar
, mientras que los del repositorio principal tienen el formato foo/bar
.
Junto con la consulta deps(...)
, esta opción de salida se puede usar para buscar el conjunto de paquetes que se debe pagar para compilar un conjunto determinado de destinos.
Cómo mostrar un gráfico del resultado
--output graph
Esta opción hace que el resultado de la consulta se imprima como un grafo dirigido en el formato popular de AT&T GraphViz. 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 que aparece a continuación para ver una invocación de muestra.
Este formato de salida es particularmente útil para las consultas allpaths
, deps
o rdeps
, en las que el resultado incluye un conjunto de rutas de acceso que no se pueden visualizar con facilidad cuando se renderizan de forma lineal, como con --output label
.
De forma predeterminada, el grafo se renderiza de forma factorizada. Es decir, los nodos topológicamente equivalentes se combinan en un solo nodo con varias etiquetas. Esto hace que el grafo 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 Java generados por el mismo genrule
. En el grafo factorizado, todos estos archivos están representados por 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 string de etiqueta para un nodo del gráfico en el resultado. Las etiquetas más largas se truncarán; -1 inhabilita el truncamiento. Debido a la forma factorizada en la que se imprimen los grafos, las etiquetas de nodo pueden ser muy largas. GraphViz no puede procesar etiquetas que superen los 1,024 caracteres, que es el valor predeterminado de esta opción. Esta opción no tiene efecto, a menos que se use --output=graph
.
--[no]graph:factored
De forma predeterminada, los gráficos se muestran de forma factorizada, como se explica anteriormente.
Cuando se especifica --nograph:factored
, los gráficos se imprimen sin factorizar. Esto hace que la visualización mediante GraphViz no sea práctica, pero el formato más simple puede facilitar el procesamiento de otras herramientas (como grep). Esta opción no tiene 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, con un elemento XML para cada objetivo del gráfico de resultados, en orden topográfico (a menos que se soliciten resultados sin orden) y, por último, finaliza con una
</query>
Se emiten entradas simples para objetivos de la categoría file
:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
Sin embargo, para 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 los elementos rule-input
y rule-output
, de modo que la topología del gráfico de dependencias se pueda reconstruir sin tener que saber que, por ejemplo, los elementos del atributo srcs
son dependencias directa (requisitos previos) y el contenido del atributo outs
es una dependencia inversa (consumidor).
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 según su impresión por --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
, los números de línea no se imprimen.
--[no]xml:default_values
De forma predeterminada, la salida XML no incluye el atributo de la regla cuyo valor es el predeterminado para ese tipo de atributo (por ejemplo, si no se especificó en el archivo BUILD
, o el valor predeterminado se proporcionó de manera explícita). Esta opción hace que dichos valores de atributos se incluyan en el resultado XML.
Expresiones regulares
Las expresiones regulares en el lenguaje de consulta usan la biblioteca de regex de Java, por lo que puedes usar la sintaxis completa para java.util.regex.Pattern
.
Realiza consultas con repositorios externos
Si la compilación depende de reglas de repositorios externos (definidos 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
, entonces bazel query 'deps(//foo:bar)'
mostrará @other-repo//baz:lib
y //external:some-lib
como dependencias.
Los repositorios externos en sí 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