Bazel admite dependencias externas, archivos de origen (de texto y binarios) que se usan en la compilación y que no son de tu lugar de trabajo. Por ejemplo, podrían ser un conjunto de reglas alojado en un repositorio de GitHub, un artefacto de Maven o un directorio en tu máquina local fuera de tu lugar de trabajo actual.
A partir de Bazel 6.0, existen dos formas de administrar dependencias externas con Bazel:
el sistema WORKSPACE
tradicional y centrado en el repositorio y
el sistema MODULE.bazel
más nuevo centrado en el módulo (con el nombre interno Bzlmod,
y habilitado con la marca --enable_bzlmod
). Los dos sistemas se pueden usar juntos, pero Bzlmod reemplaza el sistema WORKSPACE
en futuras versiones de Bazel} para la migración de Bzlmod.{/1.
En este documento, se explican los conceptos relacionados con la administración de dependencias externas en Bazel antes de entrar en más detalle sobre los dos sistemas en orden.
Conceptos
Repositorio
Un árbol de directorios con un archivo de marcador de límite en la raíz, que contiene archivos de origen que se pueden usar en una compilación de Bazel. A menudo, se abrevia como solo repo.
Un archivo de marcador de límite de repositorio puede ser MODULE.bazel
(que indica que este repositorio representa un módulo de Bazel), REPO.bazel
(consulta a continuación) o, en contextos heredados, WORKSPACE
o WORKSPACE.bazel
. Cualquier archivo de marcador de límite de repositorio significará el límite de un repositorio. Es posible que varios archivos de este tipo coexistan en un directorio.
Repositorio principal
El repositorio en el que se ejecuta el comando actual de Bazel.
La raíz del repositorio principal también se conoce como raíz del lugar de trabajo.
Espacio de trabajo
El entorno que comparten todos los comandos de Bazel se ejecuta en el mismo repositorio principal. Abarca el repositorio principal y el conjunto de todos los repositorios externos definidos.
Ten en cuenta que, históricamente, los conceptos de "repositorio" y "lugar de trabajo" se han combinado. El término "lugar de trabajo" se suele usar para referirse al repositorio principal y, a veces, se usa como sinónimo de "repositorio".
Nombre del repositorio canónico
Es el nombre canónico mediante el que se puede acceder a un repositorio. En el contexto de un lugar de trabajo, cada repositorio tiene un solo nombre canónico. Un destino dentro de un repositorio cuyo nombre canónico es canonical_name
se puede identificar con la etiqueta @@canonical_name//pac/kage:target
(ten en cuenta la @
doble).
El nombre canónico del repositorio principal siempre tiene la cadena vacía.
Nombre aparente del repositorio
Es el nombre que se usa para acceder a un repositorio en el contexto de otro repositorio.
Esto se puede considerar como el "apodo" de un repositorio: el repositorio con el nombre canónico michael
puede tener el nombre aparente mike
en el contexto del repositorio alice
, pero puede tener el nombre aparente mickey
en el contexto del repositorio bob
. En este caso, un destino dentro de michael
se puede abordar con la etiqueta @mike//pac/kage:target
en el contexto de alice
(ten en cuenta la @
única).
Por el contrario, esto se puede comprender como una asignación de repositorio: cada repositorio mantiene una asignación de “nombre aparente del repositorio” a un “nombre de repositorio canónico”.
Regla del repositorio
Un esquema para definiciones de repositorio que le indica a Bazel cómo materializar un repositorio Por ejemplo, podría ser “descargar un archivo ZIP de una URL determinada y extraerlo” o “recuperar un artefacto de Maven determinado y hacer que esté disponible como un destino java_import
”, o simplemente “symlink a un directorio local”. Cada repositorio se define mediante una llamada a una regla de repositorio con una cantidad adecuada de argumentos.
Consulta Reglas del repositorio para obtener más información sobre cómo escribir tus propias reglas del repositorio.
Las reglas del repositorio más comunes son
http_archive
, que descarga un archivo
de una URL y lo extrae, y
local_repository
, que vincula simbólicos a un
directorio local que ya es un repositorio de Bazel.
Recupera un repositorio
Es la acción de hacer que un repositorio esté disponible en un disco local mediante la ejecución de su regla de repositorio asociada. Los repositorios definidos en un lugar de trabajo no están disponibles en el disco local antes de que se recuperen.
Por lo general, Bazel solo recupera un repositorio cuando necesita algo del repositorio, y este aún no se recuperó. Si el repositorio ya se recuperó antes, Bazel solo lo vuelve a recuperar si su definición cambió.
El comando fetch
se puede usar para iniciar una recuperación previa de un repositorio, un destino o todos los repositorios necesarios a fin de realizar cualquier compilación. Esta función permite compilaciones sin conexión con la opción --nofetch
.
La opción --fetch
sirve para administrar el acceso a la red. Su valor predeterminado es true.
Sin embargo, cuando se configura como falsa (--nofetch
), el comando usará cualquier versión almacenada en caché de la dependencia. Si no existe ninguna, el comando generará una falla.
Consulta las opciones de recuperación para obtener más información sobre cómo controlar la recuperación.
Diseño del directorio
Una vez recuperado, el repositorio se puede encontrar en el subdirectorio external
en la base de salida, debajo de su nombre canónico.
Puedes ejecutar el siguiente comando para ver el contenido del repositorio con el nombre canónico canonical_name
:
ls $(bazel info output_base)/external/ canonical_name
Archivo REPO.bazel
El archivo REPO.bazel
se usa para marcar el límite superior del árbol de directorios que constituye un repositorio. No es necesario que contenga nada para que funcione como un archivo de límites de repositorio. Sin embargo, también se puede usar con el objetivo de especificar algunos atributos comunes para todos los destinos de compilación dentro del repositorio.
La sintaxis de un archivo REPO.bazel
es similar a la de los archivos BUILD
, con la excepción de que no se admiten declaraciones load
y solo está disponible una función única, repo()
. repo()
toma los mismos argumentos que la función package()
en los archivos BUILD
; mientras que package()
especifica atributos comunes para todos los destinos de compilación dentro del paquete, repo()
lo hace de forma análoga para todos los destinos de compilación dentro del repositorio.
Por ejemplo, puedes especificar una licencia común para todos los destinos de tu repositorio con el siguiente archivo REPO.bazel
:
repo(
default_package_metadata = ["//:my_license"],
)
Administra dependencias externas con Bzlmod
Bzlmod, el nuevo subsistema de dependencia externo, no funciona directamente con las definiciones de repositorios. En cambio, compila un gráfico de dependencia a partir de módulos, ejecuta extensiones en el gráfico y define los repositorios según corresponda.
Un módulo de Bazel es un proyecto de Bazel que puede tener varias
versiones, cada una de las cuales publica metadatos sobre otros módulos de los que depende. Un módulo debe tener un archivo MODULE.bazel
en la raíz del repositorio, junto al archivo WORKSPACE
. Este archivo es el manifiesto del módulo, en el que se declara su nombre, versión y lista de dependencias, entre otros datos. El siguiente es un ejemplo básico:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
Un módulo solo debe enumerar sus dependencias directas, que Bzlmod busca en un registro de Bazel (de forma predeterminada, el registro central de Bazel). El registro proporciona los archivos MODULE.bazel
de las dependencias, lo que permite que Bazel descubra el gráfico de dependencias transitivas completo antes de realizar la resolución de la versión.
Después de la resolución de la versión, en la que se selecciona una versión para cada módulo, Bazel vuelve a consultar el registro a fin de aprender a definir un repositorio para cada módulo (en la mayoría de los casos, con http_archive
).
Los módulos también pueden especificar datos personalizados llamados etiquetas, que consumen las extensiones de módulo después de la resolución del módulo para definir repositorios adicionales. Estas extensiones tienen capacidades similares a las reglas del repositorio, lo que les permite realizar acciones como la E/S de archivos y el envío de solicitudes de red. Entre otras cosas, permiten que Bazel interactúe con otros sistemas de administración de paquetes y, al mismo tiempo, respetan el gráfico de dependencias compilado a partir de módulos de Bazel.
Vínculos externos en Bzlmod
- Ejemplos de uso de Bzlmod en bazelbuild/ejemplos
- Revisión de dependencias externas de Bazel (documento de diseño original de Bzlmod)
- Charla de BazelCon 2021 sobre Bzlmod
- Charla del Día de la Comunidad de Bazel en Bzlmod
Define repositorios con WORKSPACE
.
Históricamente, se pueden administrar dependencias externas mediante la definición de repositorios en el archivo WORKSPACE
(o WORKSPACE.bazel
). Este archivo tiene una sintaxis similar a la de los archivos BUILD
, que emplea reglas de repositorio en lugar de reglas de compilación.
El siguiente fragmento es un ejemplo para usar la regla de repositorio http_archive
en el archivo WORKSPACE
:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "foo",
urls = ["https://example.com/foo.zip"],
sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)
El fragmento define un repositorio cuyo nombre canónico es foo
. De forma predeterminada, en el sistema WORKSPACE
, el nombre canónico de un repositorio es el nombre aparente que se muestra en todos los demás repositorios.
Consulta la lista completa de funciones disponibles en los archivos WORKSPACE
.
Deficiencias del sistema WORKSPACE
En los años transcurridos desde que se introdujo el sistema WORKSPACE
, los usuarios informaron muchos problemas, entre los que se incluyen los siguientes:
- Bazel no evalúa los archivos
WORKSPACE
de ninguna dependencia, por lo que todas las dependencias transitivas deben definirse en el archivoWORKSPACE
del repositorio principal, además de las dependencias directas. - Para solucionar este problema, los proyectos adoptaron el patrón "deps.bzl", en el que definen una macro que, a su vez, define varios repositorios y solicitan a los usuarios que la llamen en sus archivos
WORKSPACE
.- Esto tiene sus propios problemas: las macros no pueden
load
otros archivos.bzl
, por lo que estos proyectos deben definir sus dependencias transitivas en la macro "deps" o solucionar este problema si el usuario llama a varias macros "deps" en varias capas. - Bazel evalúa el archivo
WORKSPACE
de forma secuencial. Además, las dependencias se especifican mediantehttp_archive
con URLs, sin información de la versión. Esto significa que no hay una manera confiable de realizar la resolución de la versión en el caso de dependencias diamante (A
depende deB
yC
;B
yC
dependen de versiones diferentes deD
).
- Esto tiene sus propios problemas: las macros no pueden
Debido a las deficiencias de WORKSPACE, Bzlmod reemplazará el sistema WORKSPACE heredado en versiones futuras de Bazel. Consulta la guía de migración de Bzlmod para saber cómo migrar a Bzlmod.