cquery
es una variante de query
que procesa correctamente los efectos de select()
y de las opciones de compilación en el gráfico de compilación.
Para ello, ejecuta los resultados de la fase de análisis de Bazel, que integra estos efectos. Por el contrario, query
se ejecuta en los resultados de
la fase de carga de Bazel antes de que se evalúen las opciones.
Por ejemplo:
$ cat > tree/BUILD <<EOF sh_library( name = "ash", deps = select({ ":excelsior": [":manna-ash"], ":americana": [":white-ash"], "//conditions:default": [":common-ash"], }), ) sh_library(name = "manna-ash") sh_library(name = "white-ash") sh_library(name = "common-ash") config_setting( name = "excelsior", values = {"define": "species=excelsior"}, ) config_setting( name = "americana", values = {"define": "species=americana"}, ) EOF
# Traditional query: query doesn't know which select() branch you will choose, # so it conservatively lists all of possible choices, including all used config_settings. $ bazel query "deps(//tree:ash)" --noimplicit_deps //tree:americana //tree:ash //tree:common-ash //tree:excelsior //tree:manna-ash //tree:white-ash # cquery: cquery lets you set build options at the command line and chooses # the exact dependencies that implies (and also the config_setting targets). $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (9f87702) //tree:manna-ash (9f87702) //tree:americana (9f87702) //tree:excelsior (9f87702)
Cada resultado incluye un identificador único (9f87702)
de la configuración con la que se compila el destino.
Dado que cquery
se ejecuta en el gráfico de destino configurado, no tiene estadísticas sobre artefactos como las acciones de compilación ni el acceso a las reglas test_suite
, ya que no son objetivos configurados. Para ver el primero, consulta aquery
.
Sintaxis básica
Una llamada cquery
simple se ve de la siguiente manera:
bazel cquery "function(//target)"
La expresión de consulta "function(//target)"
consta de lo siguiente:
function(...)
es la función que se ejecutará en el destino.cquery
admite la mayoría de las funciones dequery
, además de algunas nuevas.//target
es la expresión que se envía a la función. En este ejemplo, la expresión es un objetivo simple. Pero el lenguaje de consulta también permite anidar funciones. Revisa la Guía de consulta para ver ejemplos.
cquery
requiere un destino para ejecutar las fases de carga y análisis. A menos que se especifique lo contrario, cquery
analiza los destinos enumerados en la expresión de la consulta. Consulta --universe_scope
para consultar dependencias de destinos de compilación de nivel superior.
Parámetros de configuración
La línea:
//tree:ash (9f87702)
significa que //tree:ash
se compiló en una configuración con el ID 9f87702
. Para la mayoría de los objetivos, es un hash opaco de los valores de las opciones de compilación que definen la configuración.
Para ver el contenido completo de la configuración, ejecuta el siguiente comando:
$ bazel config 9f87702
9f87702
es un prefijo del ID completo. Esto se debe a que los IDs completos son hash SHA-256, que son largos y difíciles de seguir. cquery
entiende cualquier prefijo válido de un ID completo, de manera similar a los hashes cortos de Git.
Para ver los IDs completos, ejecuta $ bazel config
.
Evaluación del patrón objetivo
//foo
tiene un significado diferente para cquery
y para query
. Esto se debe a que cquery
evalúa los destinos configurados y el gráfico de compilación puede tener varias versiones configuradas de //foo
.
Para cquery
, un patrón de destino en la expresión de consulta se evalúa en cada objetivo configurado con una etiqueta que coincide con ese patrón. El resultado es determinista, pero cquery
no ofrece ninguna garantía de ordenamiento más allá del contrato de pedido de consultas principales.
Esto produce resultados más sutiles para las expresiones de consulta que con query
.
Por ejemplo, lo siguiente puede producir varios resultados:
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on an exec-configured # //foo. So there are two configured target instances of //foo in # the build graph. $ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool //foo (9f87702) //foo (exec)
Si deseas declarar con precisión en qué instancia realizar la consulta, usa la función config
.
Consulta la documentación de patrones de objetivo de query
para obtener más información sobre estos patrones.
Funciones
Del conjunto de funciones compatibles con query
, cquery
admite todos excepto visible
, siblings
, buildfiles
y tests
.
cquery
también incluye las siguientes funciones nuevas:
config
expr ::= config(expr, word)
El operador config
intenta encontrar el objetivo configurado para la etiqueta denotada por el primer argumento y la configuración especificadas por el segundo argumento.
Los valores válidos para el segundo argumento son null
o un hash de configuración personalizado. Los hash se pueden recuperar desde $
bazel config
o desde la salida de cquery
anterior.
Ejemplos:
$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (exec) //baz (exec) $ bazel cquery "config(//baz, 3732cc8)"
Si no se pueden encontrar todos los resultados del primer argumento en la configuración especificada, solo se mostrarán los que se pueden encontrar. Si no se encuentran resultados en la configuración especificada, la consulta falla.
Opciones
Opciones de compilación
cquery
se ejecuta en una compilación normal de Bazel y, por lo tanto, hereda el conjunto de opciones disponibles durante una compilación.
Usa opciones de cquery
--universe_scope
(lista de valores separados por comas)
A menudo, las dependencias de los destinos configurados pasan por transiciones, lo que hace que su configuración difiera de su dependiente Esta marca te permite consultar un destino como si se hubiera compilado como una dependencia o una dependencia transitiva de otro destino. Por ejemplo:
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_binary( name = "tool", srcs = ["tool.cpp"], )
Las genrules configuran sus herramientas en la configuración de ejecución para que las siguientes consultas produzcan los siguientes resultados:
Consulta | Destino creado | Resultado |
---|---|---|
cquery de Bazel "//x:tool" | //x:tool | //x:tool(targetconfig) |
cquery de Bazel "//x:tool" --universe_scope}"x:my_gen" | //x:my_gen | //x:tool(execconfig) |
Si se establece esta marca, se compila su contenido. Si no está configurado, se compilan todos los objetivos mencionados en la expresión de consulta en su lugar. El cierre transitivo de los destinos compilados se usa como el universo de la consulta. De cualquier manera, los destinos que se compilarán deben poder compilarse en el nivel superior (es decir, compatibles con las opciones de nivel superior). cquery
muestra los resultados en el cierre transitivo de estos objetivos de nivel superior.
Incluso si es posible compilar todos los destinos en una expresión de consulta en el nivel superior, puede ser beneficioso no hacerlo. Por ejemplo, configurar de forma explícita --universe_scope
podría evitar compilar destinos varias veces en configuraciones que no te interesan. También puede ayudar a especificar la versión de configuración de un destino que buscas (ya que, por el momento, no es posible especificarlo de otra manera por completo). Debes establecer esta marca si tu expresión de consulta es más compleja que deps(//foo)
.
--implicit_deps
(booleano, predeterminado=verdadero)
Si estableces esta marca como false, se filtrarán todos los resultados que no se configuran de forma explícita en el archivo de COMPILACIÓN y, en su lugar, Bazel configura en otro lugar. Esto incluye filtrar cadenas de herramientas resueltas.
--tool_deps
(booleano, predeterminado=verdadero)
Establecer esta marca como false filtra todos los destinos configurados para los que la ruta de acceso del destino consultado a ellos cruza una transición entre la configuración de destino y las configuraciones que no son del objetivo.
Si el objetivo consultado está en la configuración de destino, establecer --notool_deps
solo mostrará los objetivos que también se encuentren en la configuración de destino. Si el objetivo consultado está en una configuración no objetivo, establecer --notool_deps
solo mostrará objetivos en configuraciones que no sean de destino. Por lo general, esta configuración no afecta el filtrado de las cadenas de herramientas resueltas.
--include_aspects
(booleano, predeterminado=verdadero)
Incluye las dependencias agregadas por aspects.
Si esta marca está inhabilitada, cquery somepath(X, Y)
y cquery deps(X) | grep 'Y'
omiten Y si X solo depende de ella a través de un aspecto.
Formatos de salida
De forma predeterminada, cquery genera resultados en una lista ordenada de dependencias de pares de etiquetas y configuración. También hay otras opciones para exponer los resultados.
Transiciones
--transitions=lite --transitions=full
Las transiciones de configuración se usan para compilar destinos por debajo de los destinos de nivel superior en configuraciones diferentes a los objetivos de nivel superior.
Por ejemplo, un objetivo podría imponer una transición a la configuración de ejecución en todas las dependencias de su atributo tools
. Se conocen como transiciones de atributos. Las reglas también pueden imponer transiciones en sus propias configuraciones, conocidas como transiciones de clases de reglas. Este formato de salida genera información sobre estas transiciones, como qué tipo son y el efecto que tienen en las opciones de compilación.
Este formato de salida se activa con la marca --transitions
que, de forma predeterminada, se configura en NONE
. Se puede configurar en los modos FULL
o LITE
. El modo FULL
genera información sobre las transiciones de clases de reglas y de atributos, incluida una diferencia detallada de las opciones antes y después de la transición. El modo LITE
genera la misma información sin la diferencia de opciones.
Salida del mensaje del protocolo
--output=proto
Esta opción hace que los destinos resultantes se impriman en un formato de búfer de protocolo binario. La definición del búfer de protocolo se puede encontrar en src/main/protobuf/analysis_v2.proto.
CqueryResult
es el mensaje de nivel superior que contiene los resultados de cquery. Tiene una lista de mensajes ConfiguredTarget
y una lista de mensajes Configuration
. Cada ConfiguredTarget
tiene un configuration_id
cuyo valor es igual al del campo id
del mensaje Configuration
correspondiente.
--[no]proto:include_configurations
De forma predeterminada, los resultados de cquery muestran la información de configuración como parte de cada destino configurado. Si deseas omitir esta información y obtener un resultado de proto con un formato idéntico al del resultado de proto de la consulta, configura esta marca como false.
Consulta la documentación de resultados de proto de la consulta para obtener más opciones relacionadas con los resultados de proto.
Resultado del gráfico
--output=graph
Esta opción genera resultados como un archivo .dot compatible con Graphviz. Consulta la documentación de resultados del gráfico de query
para obtener más información. cquery
también admite --graph:node_limit
y --graph:factored
.
Salida de archivos
--output=files
Esta opción imprime una lista de los archivos de salida producidos por cada destino que coincide con la consulta, similar a la lista impresa al final de una invocación bazel build
. El resultado contiene solo los archivos anunciados en los grupos de salida solicitados, según lo determinado por la marca --output_groups
.
Incluye archivos fuente.
Todas las rutas de acceso que emite este formato de salida están relacionadas con execroot, que se puede obtener a través de bazel info execution_root
. Si existe el symlink de conveniencia bazel-out
, las rutas a los archivos en el repositorio principal también se resuelven en relación con el directorio del lugar de trabajo.
Define el formato de salida con Starlark
--output=starlark
Este formato de salida llama a una función Starlark para cada destino configurado en el resultado de la consulta y, luego, imprime el valor que muestra la llamada. La marca --starlark:file
especifica la ubicación de un archivo de Starlark que define una función llamada format
con un solo parámetro, target
. Se llama a esta función para cada Destino
en el resultado de la consulta. Como alternativa, para mayor comodidad, puedes especificar solo el cuerpo de una función declarada como def format(target): return expr
con la marca --starlark:expr
.
Dialecto de Starlark "cquery"
El entorno de Starlark para cquery es diferente de un archivo BUILD o .bzl. Incluye todas las constantes y funciones integradas principales de Starlark, además de algunas específicas de cquery que se describen a continuación, pero no glob
, native
ni rule
(por ejemplo), y no admite sentencias de carga.
build_options(target)
build_options(target)
muestra un mapa cuyas claves son identificadores de opciones de compilación (consulta Configuraciones) y cuyos valores son sus valores de Starlark. Se omiten de este mapa las opciones de compilación cuyos valores no son valores legales de Starlark.
Si el destino es un archivo de entrada, build_options(target)
muestra None, ya que los objetivos del archivo de entrada tienen una configuración nula.
proveedores(objetivo)
providers(target)
muestra un mapa cuyas claves son nombres de proveedores (por ejemplo, "DefaultInfo"
) y cuyos valores son sus valores de Starlark. Se omiten de este mapa los proveedores cuyos valores no son valores legales de Starlark.
Ejemplos
Imprime una lista separada por espacios de los nombres base de todos los archivos producidos por //foo
:
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
Imprime una lista separada por espacios de las rutas de acceso de todos los archivos producidos por los destinos de la regla en //bar
y sus subpaquetes:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
Imprime una lista de los mnemotécnicos de todas las acciones registradas por //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
Imprime una lista de resultados de compilación registradas por un //baz
de cc_library
.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
Imprime el valor de la opción de línea de comandos --javacopt
cuando se compila //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
Imprime la etiqueta de cada destino con exactamente un resultado. En este ejemplo, se usan las funciones de Starlark definidas en un archivo.
$ cat example.cquery def has_one_output(target): return len(target.files.to_list()) == 1 def format(target): if has_one_output(target): return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
Imprime la etiqueta de cada destino, que es estrictamente Python 3. En este ejemplo, se usan las funciones de Starlark definidas en un archivo.
$ cat example.cquery def format(target): p = providers(target) py_info = p.get("PyInfo") if py_info and py_info.has_py3_only_sources: return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
Extrae un valor de un proveedor definido por el usuario.
$ cat some_package/my_rule.bzl MyRuleInfo = provider(fields={"color": "the name of a color"}) def _my_rule_impl(ctx): ... return [MyRuleInfo(color="red")] my_rule = rule( implementation = _my_rule_impl, attrs = {...}, ) $ cat example.cquery def format(target): p = providers(target) my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'") if my_rule_info: return my_rule_info.color return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
cquery y consulta
cquery
y query
se complementan entre sí y se destacan en diferentes nichos. Ten en cuenta lo siguiente para decidir cuál es el adecuado para ti:
cquery
sigue ramas deselect()
específicas para modelar el gráfico exacto que compilas.query
no sabe qué rama elige la compilación, por lo que se acerca demasiado al incluir todas las ramas.- La precisión de
cquery
requiere que compiles más del gráfico quequery
. Específicamente,cquery
evalúa los destinos configurados, mientras quequery
solo evalúa los objetivos. Esto lleva más tiempo y usa más memoria. - La interpretación que hace
cquery
del lenguaje de consulta introduce una ambigüedad quequery
evita. Por ejemplo, si"//foo"
existe en dos configuraciones, ¿cuál debería usarcquery "deps(//foo)"
? La funciónconfig
puede ayudarte con esto. - Como herramienta más reciente,
cquery
carece de compatibilidad para ciertos casos de uso. Consulta la sección Problemas conocidos para obtener más información.
Errores conocidos
Todos los destinos que cquery
"compila" deben tener la misma configuración.
Antes de evaluar las consultas, cquery
activa una compilación justo antes del punto en el que se ejecutarían las acciones de compilación. Los destinos que “compila” se seleccionan de forma predeterminada entre todas las etiquetas que aparecen en la expresión de consulta (esto se puede anular con --universe_scope
). Estos deben tener la misma configuración.
Si bien estas suelen compartir la configuración de "objetivo" de nivel superior, las reglas pueden cambiar su propia configuración con transiciones perimetrales entrantes.
Aquí es donde cquery
falla.
Solución: Si es posible, establece --universe_scope
en un alcance más estricto. Por ejemplo:
# This command attempts to build the transitive closures of both //foo and # //bar. //bar uses an incoming edge transition to change its --cpu flag. $ bazel cquery 'somepath(//foo, //bar)' ERROR: Error doing post analysis query: Top-level targets //foo and //bar have different configurations (top-level targets with different configurations is not supported) # This command only builds the transitive closure of //foo, under which # //bar should exist in the correct configuration. $ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo
--output=xml
no admite asistencia.
Resultado no determinista.
cquery
no borra automáticamente el gráfico de compilación de los comandos anteriores y, por lo tanto, es propenso a recoger resultados de consultas anteriores. Por ejemplo, genrule
ejerce una transición de ejecución en su atributo tools
, es decir, configura sus herramientas en la configuración de ejecución.
A continuación, puedes ver los efectos persistentes de esa transición.
$ cat > foo/BUILD <<<EOF genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", ) EOF $ bazel cquery "//foo:tool" tool(target_config) $ bazel cquery "deps(//foo:my_gen)" my_gen (target_config) tool (exec_config) ... $ bazel cquery "//foo:tool" tool(exec_config)
Solución: Cambia cualquier opción de inicio para forzar un nuevo análisis de los objetivos configurados.
Por ejemplo, agrega --test_arg=<whatever>
a tu comando de compilación.
Solución de problemas
Patrones de objetivos recurrentes (/...
)
Si te encuentras con lo siguiente:
$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)" ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]' because package is not in scope. Check that all target patterns in query expression are within the --universe_scope of this query.
esto sugiere incorrectamente que el paquete //foo
no está dentro del alcance, a pesar de que --universe_scope=//foo:app
lo incluye. Esto se debe a limitaciones de diseño en cquery
. Como solución alternativa, incluye explícitamente //foo/...
en el alcance del universo:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Si eso no funciona (por ejemplo, porque algún destino en //foo/...
no puede
compilarse con las marcas de compilación elegidas), desenvuelve manualmente el patrón en los
paquetes constituyentes con una consulta de procesamiento previo:
# Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into # a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge. # Output looks like "//foo:*+//foo/bar:*+//foo/baz". # $ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/... --output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"