Compila programas con Bazel

Informar un problema Ver código fuente Nightly · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

En esta página, se explica cómo compilar un programa con Bazel, la sintaxis del comando de compilación y la sintaxis del patrón de destino.

Guía de inicio rápido

Para ejecutar Bazel, ve al directorio base workspace. o cualquiera de sus subdirectorios, y escribe bazel. Consulta build si necesitas hacer un nuevo lugar de trabajo.

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

Comandos disponibles:

  • analyze-profile: Analiza los datos del perfil de compilación.
  • aquery: Ejecuta una consulta en el gráfico de acción posterior al análisis.
  • build: Compila los destinos especificados.
  • canonicalize-flags: Convierte en canónicas las marcas de Bazel.
  • clean: Quita los archivos de salida y, de manera opcional, detiene el servidor.
  • cquery: Ejecuta una consulta de grafo de dependencia posterior al análisis.
  • dump: Vuelca el estado interno del proceso del servidor de Bazel.
  • help: Imprime ayuda para los comandos o el índice.
  • info: Muestra información del entorno de ejecución sobre el servidor de Bazel.
  • fetch: Recupera todas las dependencias externas de un destino.
  • mobile-install: Instala apps en dispositivos móviles.
  • query: Ejecuta una consulta de gráfico de dependencia.
  • run: Ejecuta el destino especificado.
  • shutdown: Detiene el servidor de Bazel.
  • test: Compila y ejecuta los destinos de prueba especificados.
  • version: Imprime información de la versión de Bazel.

Cómo obtener ayuda

  • bazel help command: Imprime ayuda y opciones para command.
  • bazel helpstartup_options: Opciones para la JVM que aloja a Bazel
  • bazel helptarget-syntax: Explica la sintaxis para especificar objetivos.
  • bazel help info-keys: Muestra una lista de las teclas que usa el comando info.

La herramienta bazel realiza muchas funciones, llamadas comandos. Los más usados son bazel build y bazel test. Puedes explorar la ayuda en línea mensajes con bazel help.

Cómo compilar un objetivo

Antes de comenzar una compilación, necesitas un lugar de trabajo. Un espacio de trabajo es un árbol de directorios que contiene todos los archivos fuente necesarios para compilar tu aplicación. Bazel te permite compilar a partir de una compilación de solo lectura volumen.

Para compilar un programa con Bazel, escribe bazel build seguido del objetivo que deseas compilar.

bazel build //foo

Después de emitir el comando para compilar //foo, verás un resultado similar al siguiente:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

Primero, Bazel carga todos los paquetes en el gráfico de dependencias de tu destino. Esto incluye las dependencias declaradas, los archivos que se enumeran directamente en el archivo BUILD del destino, y las dependencias transitivas, los archivos que se enumeran en los archivos BUILD de las dependencias del destino. Después de identificar todas las dependencias, Bazel las analiza para verificar su exactitud y crea las acciones de compilación. Por último, Bazel ejecuta. los compiladores y otras herramientas de la compilación.

Durante la fase de ejecución de la compilación, Bazel imprime mensajes de progreso. Los mensajes de progreso incluyen el paso de compilación actual (como el compilador o el vinculador) cuando se inicia y la cantidad completada sobre la cantidad total de acciones de compilación. Cuando comienza la compilación, la cantidad de acciones totales suele aumentar a medida que Bazel descubre todo el gráfico de acciones, pero la cantidad se estabiliza en unos segundos.

Al final de la compilación, Bazel imprime qué destinos se solicitaron, si se compilaron correctamente y, de ser así, dónde se pueden encontrar los archivos de salida. Las secuencias de comandos que ejecutan compilaciones pueden analizar este resultado de forma confiable. Para obtener más información, consulta --show_result.

Si vuelves a escribir el mismo comando, la compilación finalizará mucho más rápido.

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

Esta es una compilación nula. Como no cambió nada, no hay paquetes para volver a cargar ni pasos de compilación para ejecutar. Si algo cambió en "foo" o su dependencias, Bazel volvería a ejecutar algunas acciones de compilación o completaría un compilación incremental.

Cómo compilar varios destinos

Bazel permite varias formas de especificar los destinos que se compilarán. En conjunto, estos se conocen como patrones del objetivo. Esta sintaxis se usa en comandos como build, test o query.

Por su parte, las etiquetas se usan para especificar objetivos, como la declaración de dependencias en archivos BUILD, el destino de Bazel los patrones especifican varios destinos. Los patrones de destino son una generalización de la sintaxis de etiquetas para conjuntos de destinos con comodines. En el caso más simple, cualquier etiqueta válida también es un patrón de destino válido, que identifica un conjunto de exactamente un objetivo.

Todos los patrones de destino que comienzan con // se resuelven en relación con el valor actual Workspace.

//foo/bar:wiz Solo el //foo/bar:wiz de destino único.
//foo/bar Equivale a //foo/bar:bar.
//foo/bar:all Todos los objetivos de regla en el paquete foo/bar.
//foo/... Todos los destinos de reglas en todos los paquetes debajo del directorio foo
//foo/...:all Todas las reglas objetivo en todos los paquetes debajo del directorio foo
//foo/...:* Todos los destinos (reglas y archivos) en todos los paquetes debajo del directorio foo.
//foo/...:all-targets Todos los objetivos (reglas y archivos) de todos los paquetes del directorio foo
//... Todos los destinos en paquetes del lugar de trabajo. Esto no incluye objetivos desde repositorios externos.
//:all Todos los destinos del paquete de nivel superior, si hay un archivo "BUILD" en la raíz del espacio de trabajo

Los patrones de destino que no comienzan con // se resuelven en relación con el directorio de trabajo actual. En estos ejemplos, se supone que el directorio de trabajo es foo:

:foo Equivale a //foo:foo.
bar:wiz Equivale a //foo/bar:wiz.
bar/wiz Equivale a:
  • //foo/bar/wiz:wiz si foo/bar/wiz es un paquete
  • //foo/bar:wiz si foo/bar es un paquete
  • De lo contrario, //foo:bar/wiz
bar:all Equivale a //foo/bar:all.
:all Equivale a //foo:all.
...:all Equivale a //foo/...:all.
... Equivale a //foo/...:all.
bar/...:all Equivale a //foo/bar/...:all.

De forma predeterminada, se siguen los symlinks de directorio para los patrones de destino recursivos, excepto aquellos que apuntan a la base de salida, como los symlinks de conveniencia que se crean en el directorio raíz del espacio de trabajo.

Además, Bazel no sigue los symlinks cuando evalúa patrones de destino recursivos en cualquier directorio que contenga un archivo con el siguiente nombre: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... es un comodín sobre packages (paquetes) que indica todos los paquetes de manera recursiva. en el directorio foo (para todas las raíces de la ruta del paquete). :all es un comodín sobre destinos que coincide con todas las reglas de un paquete. Estos dos se pueden combinar, como en foo/...:all, y cuando se usan ambos comodines, se puede abreviar a foo/....

Además, :* (o :all-targets) es un comodín que coincide con todos los destinos. en los paquetes coincidentes, incluidos los archivos que normalmente no se compilan mediante ninguna regla, como los archivos _deploy.jar asociados con las reglas java_binary.

Esto implica que :* denota un superconjunto de :all. y, posiblemente, confusa, esta sintaxis permite usar el comodín :all conocido para compilaciones típicas en las que no se desea compilar objetivos como _deploy.jar.

Además, Bazel permite usar una barra en lugar de los dos puntos requeridos por la sintaxis de las etiquetas; Esto suele ser conveniente cuando se usa la expansión de nombre de archivo Bash. Por ejemplo, foo/bar/wiz es equivalente a //foo/bar:wiz (si hay un paquete foo/bar) o a //foo:bar/wiz (si hay un paquete foo).

Muchos comandos de Bazel aceptan una lista de patrones de destino como argumentos y todos respetan el operador de negación de prefijo -. Esto se puede usar para restar un conjunto de objetivos del conjunto especificado por los argumentos anteriores. Ten en cuenta que esto significa y el orden es importante. Por ejemplo:

bazel build foo/... bar/...

significa "compilar todos los destinos debajo de foo y todos los destinos debajo de bar", mientras que

bazel build -- foo/... -foo/bar/...

significa "crear todas las segmentaciones inferiores a foo, excepto aquellas inferiores a foo/bar". (El Se requiere el argumento -- para evitar que los argumentos posteriores comiencen con -. se interpreten como opciones adicionales).

Es importante señalar que restar objetivos de esta manera no garantizar que no se compilen, ya que pueden ser dependencias de objetivos que no se restaron. Por ejemplo, si hubiera un //foo:all-apis objetivo que, entre otros, dependiera de //foo/bar:api, este último se compilaría como parte de la compilación del primero.

Los destinos con tags = ["manual"] no se incluyen en los patrones de destino con comodines. (..., :*, :all, etc.) cuando se especifica en comandos como bazel build y bazel test; debes especificar prueba destinos con patrones de destino explícitos en la línea de comandos si quieres para compilarlos o probarlos. En cambio, bazel query no realiza ningún tipo de filtrado automáticamente (eso anularía el propósito de bazel query).

Recupera dependencias externas

De forma predeterminada, Bazel descargará y creará symlinks de dependencias externas durante la compilación. Sin embargo, esto puede no ser deseable, ya sea porque deseas saber cuando se agregan nuevas dependencias externas o porque deseas “obtener previamente” las dependencias (por ejemplo, antes de un vuelo en el que no tendrás conexión). Si y deseas evitar que se agreguen nuevas dependencias durante las compilaciones, puede especificar la marca --fetch=false. Ten en cuenta que esta marca solo se aplica a las reglas del repositorio que no apuntan a un directorio en el un sistema de archivos completo. Los cambios, por ejemplo, en local_repository, new_local_repository y las reglas del repositorio de Android SDK y NDK siempre se aplicarán independientemente del valor de --fetch.

Si no permites la recuperación durante las compilaciones y Bazel encuentra dependencias externas nuevas, la compilación fallará.

Para recuperar dependencias de forma manual, ejecuta bazel fetch. Si no permites la recuperación durante la compilación, deberás ejecutar bazel fetch:

  • Antes de compilar por primera vez.
  • Después de agregar una dependencia externa nueva

Una vez ejecutado, no deberías necesitar ejecutarlo de nuevo hasta que aparezca cambios en el archivo.

fetch toma una lista de destinos para los que se recuperarán las dependencias. Para ejemplo, esto recuperaría las dependencias necesarias para compilar //foo:bar y //bar:baz:

bazel fetch //foo:bar //bar:baz

Para recuperar todas las dependencias externas de un lugar de trabajo, ejecuta lo siguiente:

bazel fetch //...

No es necesario que ejecutes bazel fetch si tienes todas las herramientas que usas (desde los archivos JAR de la biblioteca hasta el JDK) en la raíz de tu lugar de trabajo. Sin embargo, si usas algo fuera del directorio del lugar de trabajo, entonces Bazel se ejecutará automáticamente bazel fetch antes de ejecutarse bazel build

La caché del repositorio

Bazel intenta evitar recuperar el mismo archivo varias veces, incluso si se trata de un archivo en diferentes lugares de trabajo o si la definición de una repositorio cambió, pero aún necesita el mismo archivo para descargar. Para ello, sigue estos pasos: bazel almacena en caché todos los archivos descargados en la caché del repositorio que, de forma predeterminada, está en ~/.cache/bazel/_bazel_$USER/cache/repos/v1/. La ubicación se puede cambiar con la opción --repository_cache. La caché se comparte entre todos los lugares de trabajo y las versiones instaladas de bazel. Se toma una entrada de la caché si Bazel sabe con seguridad que tiene una copia del archivo correcto, es decir, si tiene una suma SHA256 del archivo especificado y un archivo con ese el hash en la memoria caché. Por lo tanto, especificar un hash para cada archivo externo no solo es una buena idea desde una perspectiva de seguridad, sino que también ayuda a evitar descargas innecesarias.

Cada vez que se produce un hit de caché, se actualiza la hora de modificación del archivo en la caché. De esta manera, se puede determinar fácilmente el último uso de un archivo en el directorio de caché, por ejemplo, para limpiar la caché de forma manual. La caché nunca se limpia automáticamente, ya que podría contener una copia de un archivo que ya no está disponible en la fuente.

Directorios de archivos de distribución

El directorio de distribución es otro mecanismo de Bazel para evitar descargas. Bazel busca directorios de distribución antes de la caché del repositorio. La diferencia principal es que el directorio de distribución requiere preparación manual.

Con el --distdir=/path/to-directory puedes especificar directorios de solo lectura adicionales para buscar archivos en lugar de recuperarlos. Se toma un archivo de ese directorio si el nombre del archivo es igual al nombre base de la URL y, además, el hash del archivo es igual al especificado en la solicitud de descarga. Esto solo funciona si el hash de archivo se especifica en la declaración WORKSPACE.

Si bien la condición del nombre del archivo no es necesaria para que sea correcta, reduce la cantidad de archivos candidatos a uno por directorio especificado. De esta manera, especificar directorios de archivos de distribución sigue siendo eficiente, incluso si la cantidad de archivos en un directorio de este tipo aumenta.

Ejecución de Bazel en un entorno aislado

Para mantener el tamaño binario de Bazel pequeño, las dependencias implícitas de Bazel se recuperan a través de la red mientras se ejecutan por primera vez. Estas dependencias implícitas contienen cadenas de herramientas y reglas que pueden no ser necesarias para todos. Para Por ejemplo, las herramientas de Android se desagrupan y se recuperan solo cuando se compila Android. proyectos.

Sin embargo, estas dependencias implícitas pueden causar problemas cuando se ejecuta Bazel en un entorno de aislamiento, incluso si vendiste todas tus dependencias de WORKSPACE. Para resolverlo, puedes preparar un directorio de distribución que contiene estas dependencias en una máquina con acceso a la red y, luego, y transferirlos al entorno aislado con un enfoque sin conexión.

Para preparar el directorio de distribución, usa la --distdir marca. Deberás hacerlo una vez por cada versión binaria nueva de Bazel, ya que las dependencias implícitas pueden ser diferentes para cada versión.

Para compilar estas dependencias fuera de tu entorno de aislamiento, primero revisa el árbol de fuentes de Bazel en la versión correcta:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

Luego, compila el archivo tar que contiene las dependencias implícitas del entorno de ejecución para esa versión específica de Bazel:

bazel build @additional_distfiles//:archives.tar

Exporta este archivo tar a un directorio que se pueda copiar en tu entorno sin conexión a Internet. Observa la marca --strip-components, ya que --distdir puede ser bastante complejo con el nivel de anidamiento de directorios:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

Por último, cuando uses Bazel en tu entorno de aislamiento, pasa la marca --distdir que apunte al directorio. Para mayor comodidad, puedes agregarlo como una entrada .bazelrc:

build --distdir=path/to/directory

Parámetros de configuración de compilación y compilación cruzada

Todas las entradas que especifican el comportamiento y el resultado de una compilación determinada pueden dividirse en dos categorías distintas. El primer tipo es el de almacenada en los archivos BUILD de tu proyecto: la regla de compilación, valores de sus atributos y el conjunto completo de sus dependencias transitivas. El segundo tipo son los datos externos o del entorno, que proporciona el usuario o la herramienta de compilación: la elección de la arquitectura de destino, las opciones de compilación y vinculación, y otras opciones de configuración de la cadena de herramientas. Nos referimos a un conjunto completo de datos del entorno como una configuración.

En cualquier compilación, puede haber más de una configuración. Considera una compilación cruzada, en la que compilas un ejecutable //foo:bin para una arquitectura de 64 bits, pero tu estación de trabajo es una máquina de 32 bits. Claramente, la compilación Es necesario compilar //foo:bin con una cadena de herramientas capaz de crear archivos de 64 bits. ejecutables, pero el sistema de compilación también debe compilar varias herramientas utilizadas durante la compilarse a sí mismo, por ejemplo, herramientas que se compilan a partir del código fuente y, luego, usarse en, por ejemplo, una genrule, que deben compilarse para ejecutarse en tu estación de trabajo. Por lo tanto, podemos identificar dos configuraciones: la exec configuration, que se usa para compilar herramientas que se ejecutan durante la compilación, y la configuración de destino (o la configuración de la solicitud, pero hablamos de "configuración del destino" con más frecuencia, aunque esa palabra ya tiene muchos significados), que se utiliza para construir la binario que finalmente solicitaste.

Por lo general, hay muchas bibliotecas que son requisitos previos del objetivo de compilación solicitado (//foo:bin) y una o más de las herramientas, por ejemplo, algunas bibliotecas básicas. Esas bibliotecas se deben compilar varias veces, para que el comando exec y target parámetros de configuración. Bazel se encarga de garantizar que se compilen todas las variantes. que los archivos derivados se mantengan separados para evitar interferencias por lo general, este los destinos pueden crearse de forma simultánea, ya que son independientes entre sí. Si verás mensajes de progreso que indican que se está compilando un destino determinado muchas veces, esta es, probablemente, la explicación.

La configuración de ejecución se deriva de la configuración de destino de la siguiente manera:

  • La plataforma de ejecución para el destino de la solicitud se convierte en la plataforma de destino para la configuración de ejecución.
  • Usa la misma versión de Crosstool (--crosstool_top) que se especifica en la la configuración de la solicitud, a menos que se especifique --host_crosstool_top.
  • Usa el valor de --host_cpu para --cpu (valor predeterminado: k8).
  • Usa los mismos valores de estas opciones que se especifican en la solicitud. configuración: --compiler, --use_ijars y si --host_crosstool_top es usado, entonces el valor de --host_cpu se usa para buscar un default_toolchain en el Crosstool (ignorando --compiler) para el host configuración.
  • Usa el valor de --host_javabase para --javabase
  • Usa el valor de --host_java_toolchain para --java_toolchain.
  • Usa compilaciones optimizadas para el código C++ (-c opt).
  • No se genera información de depuración (--copt=-g0).
  • Quita la información de depuración de los archivos ejecutables y las bibliotecas compartidas (--strip=always).
  • Colocar todos los archivos derivados en una ubicación especial, distinta de la usada por cualquier configuración de solicitud posible.
  • Suprime el estampado de objetos binarios con datos de compilación (consulta las opciones de --embed_*).
  • Todos los demás valores permanecen en su configuración predeterminada.

Recompilaciones incrementales correctas

Uno de los objetivos principales del proyecto Bazel es garantizar que las recompilaciones incrementadas sean correctas. Las herramientas de compilación anteriores, especialmente las basadas en Make, hacen que varias suposiciones ofensivas en la implementación de compilaciones incrementales.

En primer lugar, las marcas de tiempo de los archivos aumentan de forma monótona. Si bien este es el caso típico, es muy fácil caer en esta suposición. La sincronización con una revisión anterior de un archivo hace que disminuya el tiempo de modificación de ese archivo. Los sistemas basados en Make no se volverán a compilar.

En términos más generales, si bien Make detecta cambios en los archivos, no detecta cambios en los comandos. Si alteras las opciones que se pasan al compilador en un paso de compilación determinado, Make no volverá a ejecutar el compilador y será necesario descartar manualmente los resultados no válidos de la compilación anterior con make clean.

Además, Make no es resistente a la finalización fallida de uno de sus subprocesos después de que ese subproceso comenzó a escribir en su archivo de salida. Mientras que la ejecución actual de Make fallará, la invocación posterior de Make fallará suponer a ciegas que el archivo de salida truncado es válido (porque es más reciente que sus entradas) y no se volverá a compilar. Del mismo modo, si se finaliza el proceso de Make, puede ocurrir una situación similar.

Bazel evita estas suposiciones y otras. Bazel mantiene una base de datos de todos trabajo realizado anteriormente y solo omitirá un paso de compilación si detecta que el conjunto de archivos de entrada (y sus marcas de tiempo) a ese paso de compilación, y la compilación para ese paso de compilación, debe coincidir exactamente con uno de la base de datos y que Un conjunto de archivos de salida (y sus marcas de tiempo) para la entrada de la base de datos debe coincidir exactamente las marcas de tiempo de los archivos en el disco. Cualquier cambio en los archivos de entrada o salida o al comando en sí, causará que se vuelva a ejecutar el paso de compilación.

El beneficio para los usuarios de las compilaciones incrementales correctas es: menos tiempo desperdiciado debido a confusión. Además, se reduce el tiempo de espera de recompilaciones causadas por el uso de make clean, ya sea necesario o preventivo.

Compila compilaciones incrementales y coherencia

De forma formal, definimos el estado de una compilación como coherente cuando existen todos los archivos de salida esperados y su contenido es correcto, según lo especificado por los pasos o las reglas necesarios para crearlos. Cuando editas un archivo fuente, el estado del archivo se dice que la compilación es incoherente y permanece inconsistente hasta la próxima ejecución. la herramienta de compilación hasta que se complete con éxito. Describimos esta situación como una incoherencia inestable, ya que es solo temporal y se restablece la coherencia cuando se ejecuta la herramienta de compilación.

Existe otro tipo de inconsistencia perniciosa: estable incoherencia. Si la compilación alcanza un estado estable incoherente, la invocación correcta y repetida de la herramienta de compilación no restablece la coherencia: la compilación se "bloqueó" y los resultados siguen siendo incorrectos. Los estados inestables y coherentes son el motivo principal por el que los usuarios de Make (y otras herramientas de compilación) escriben make clean. Descubrir que la herramienta de compilación falló de esta manera (y luego recuperarse de ella) puede llevar mucho tiempo y ser muy frustrante.

Conceptualmente, la forma más sencilla de lograr una compilación coherente es descartar todos los resultados de la compilación anterior y comenzar de nuevo: haz que cada compilación sea una compilación limpia. Obviamente, este enfoque requiere demasiado tiempo para ser práctico (excepto quizás para los ingenieros de lanzamiento) y, por lo tanto, para ser útil, la herramienta de compilación debe poder realizar compilaciones incrementales sin comprometer la coherencia.

El análisis de dependencias incrementales correcto es difícil y, como se describió anteriormente, muchas otras herramientas de compilación no evitan los estados inestables y incoherentes durante las compilaciones incrementales. En cambio, Bazel ofrece la siguiente garantía: después de una invocaci￳n correcta de la herramienta de compilaci￳n durante la cual no hiciste ninguna modificaci￳n, la compilaci￳n estar￳ en un estado coherente. (Si editas tus archivos fuente durante una compilación, Bazel no garantiza la coherencia del resultado de la compilación actual. Sin embargo, garantiza que los resultados de la próxima compilación restablecerán la coherencia.

Como sucede con todas las garantías, se incluye la letra chica: hay algunas formas de llegar a un estado incoherente estable con Bazel. No garantizamos que investigaremos esos problemas que surjan de intentos deliberados de encontrar errores en el análisis de dependencias incremental, pero investigaremos y haremos todo lo posible para corregir todos los estados inestables incoherentes que surjan del uso normal o "razonable" de la herramienta de compilación.

Si alguna vez detectas un estado incoherente estable con Bazel, informa un error.

Ejecución en zona de pruebas

Bazel usa zonas de pruebas para garantizar que las acciones se ejecuten de forma hermética y correcta. Bazel ejecuta creaciones (en términos generales, acciones) en zonas de pruebas que solo contienen el conjunto mínimo de archivos que la herramienta requiere para realizar su trabajo. Actualmente La zona de pruebas funciona en Linux 3.12 o versiones posteriores con la opción CONFIG_USER_NS. y también en macOS 10.11 o versiones posteriores.

Bazel imprimirá una advertencia si tu sistema no admite la zona de pruebas para alertarte de que no se garantiza que las compilaciones sean herméticas y que podrían afectar al sistema host de formas desconocidas. Para inhabilitar esta advertencia, puedes pasar la marca --ignore_unsupported_sandboxing a Bazel.

En algunas plataformas, como los nodos de clúster de Google Kubernetes Engine o Debian, los espacios de nombres de usuario se desactivan de forma predeterminada debido a problemas de seguridad. Para verificar esto, consulta el archivo /proc/sys/kernel/unprivileged_userns_clone: si existe y contiene un 0, los espacios de nombres de usuario se pueden activar con sudo sysctl kernel.unprivileged_userns_clone=1.

En algunos casos, la zona de pruebas de Bazel no ejecuta reglas debido a la configuración del sistema. Por lo general, el síntoma es una falla que genera un mensaje similar al siguiente: namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory En ese caso, intenta desactivar la zona de pruebas para genrules con --strategy=Genrule=standalone y para otras reglas con --spawn_strategy=standalone Además, informa un error en nuestro seguimiento de problemas y menciona qué distribución de Linux usas para que podamos investigarlo y proporcionar una solución en una versión posterior.

Fases de una compilación

En Bazel, una compilación se produce en tres fases distintas. Como usuario, comprender la diferencia entre ellas proporciona información sobre las opciones que controlan una compilación (consulta a continuación).

Fase de carga

El primero es la carga, durante la cual se cargan, analizan, evalúan y almacenan en caché todos los archivos BUILD necesarios para los objetivos iniciales y su cierre transitivo de dependencias.

En la primera compilación después de que se inicia un servidor de Bazel, la fase de carga suele llevar muchos segundos, ya que se cargan muchos archivos BUILD desde el sistema de archivos. En las compilaciones posteriores, especialmente si no cambió ningún archivo BUILD, la carga se realiza muy rápido.

Entre los errores informados durante esta fase, se incluyen los siguientes: no se encontró el paquete, no se encontró el destino, errores gramaticales y léxicos en un archivo BUILD y errores de evaluación.

Fase de análisis

La segunda fase, análisis, incluye el análisis semántico y la validación de cada regla de compilación, la construcción de un gráfico de dependencias de compilación y la determinación de qué trabajo se debe realizar exactamente en cada paso de la compilación.

Al igual que la carga, el análisis también tarda varios segundos cuando se calcula en su totalidad. Sin embargo, Bazel almacena en caché el gráfico de dependencias de una compilación a la siguiente y solo vuelve a analizar lo que tiene que hacer, lo que puede hacer que las compilaciones incrementales sean muy rápidas en el caso en el que los paquetes no cambiaron desde la compilación anterior.

Los errores informados en esta etapa incluyen dependencias inapropiadas, no válidas las entradas de una regla y todos los mensajes de error específicos de la regla.

Las fases de carga y análisis son rápidas porque Bazel evita la E/S de archivos innecesaria en esta etapa y solo lee archivos de COMPILACIÓN para determinar el trabajo que se debe realizar. Esto es así por diseño y hace que Bazel sea una buena base para las herramientas de análisis, como el comando query de Bazel, que se implementa en la fase de carga.

Fase de ejecución

La tercera y última fase de la compilación es la ejecución. Esta fase garantiza que que los resultados de cada paso de la compilación sean coherentes con sus entradas, lo que vuelve a ejecutar compilación/vinculación, etcétera. herramientas según sea necesario. En este paso, la compilación pasa la mayor parte del tiempo, que puede variar desde unos segundos hasta más de una hora para una compilación grande. Entre los errores informados durante esta fase, se incluyen los siguientes: archivos fuente faltantes, errores en una herramienta que ejecuta alguna acción de compilación o la falla de una herramienta para producir el conjunto de resultados esperado.