Descripción general de las dependencias externas

Bazel admite dependencias externas, archivos fuente (texto y binarios) que se usan en tu compilación y que no provienen de tu espacio 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 espacio de trabajo actual.

A partir de Bazel 6.0, hay dos formas de administrar dependencias externas con Bazel: el sistema tradicional WORKSPACE centrado en el repositorio y el sistema MODULE.bazel más nuevo centrado en el módulo (con nombre en clave Bzlmod, y habilitado con la marca --enable_bzlmod). Los dos sistemas se pueden usar juntos, pero Bzlmod reemplazará el sistema WORKSPACE en futuras versiones de Bazel. Consulta la guía de migración de Bzlmod para saber cómo migrar.

En este documento, se explican los conceptos relacionados con la administración de dependencias externas en Bazel, antes de entrar en más detalles sobre los dos sistemas en orden.

Conceptos

Repositorio

Un directorio con un archivo WORKSPACE o WORKSPACE.bazel, que contiene archivos fuente que se usarán en una compilación de Bazel. A menudo, se abrevia como repo.

Repositorio principal

El repositorio en el que se ejecuta el comando de Bazel actual.

Espacio de trabajo

El entorno compartido por todos los comandos de Bazel que se ejecutan en el mismo repositorio principal.

Ten en cuenta que, históricamente, los conceptos de "repositorio" y "espacio de trabajo" se han combinado; el término "espacio de trabajo" se usó con frecuencia para hacer referencia al repositorio principal y, a veces, incluso como sinónimo de "repositorio".

Nombre canónico del repositorio

El nombre canónico por el que se puede direccionar un repositorio. En el contexto de un espacio de trabajo, cada repositorio tiene un solo nombre canónico. Se puede direccionar un destino dentro de un repositorio cuyo nombre canónico es canonical_name con la etiqueta @@canonical_name//pac/kage:target (observa el doble @).

El repositorio principal siempre tiene la cadena vacía como nombre canónico.

Nombre aparente del repositorio

El nombre por el que se puede direccionar un repositorio en el contexto de otro repositorio determinado. Esto se puede considerar como el "apodo" de un repositorio: el repositorio con el nombre canónico michael podría tener el nombre aparente mike en el contexto del repositorio alice, pero podría tener el nombre aparente mickey en el contexto del repositorio bob. En este caso, se puede direccionar un destino dentro de michael con la etiqueta @mike//pac/kage:target en el contexto de alice (observa el @ único).

Por el contrario, esto se puede entender como una asignación de repositorio: cada repositorio mantiene una asignación de "nombre aparente del repositorio" a un "nombre canónico del repositorio".

Regla de repositorio

Un esquema para las definiciones de repositorio que le indica a Bazel cómo materializar un repositorio. Por ejemplo, podría ser "descargar un archivo ZIP desde una URL determinada y extraerlo", o "recuperar un artefacto de Maven determinado y ponerlo a disposición como un java_import destino", o simplemente "vincular simbólicamente un directorio local". Cada repositorio se define llamando a una regla de repositorio con una cantidad adecuada de argumentos.

Consulta Reglas de repositorio para obtener más información sobre cómo escribir tus propias reglas de repositorio.

Las reglas de repositorio más comunes son http_archive, que descarga un archivo de una URL y lo extrae, y local_repository, que vincula simbólicamente un directorio local que ya es un repositorio de Bazel.

Recuperar un repositorio

La acción de poner un repositorio a disposición en el disco local mediante la ejecución de su regla de repositorio asociada. Los repositorios definidos en un espacio 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 de él, y el repositorio aún no se recuperó. Si el repositorio ya se recuperó antes, Bazel solo lo vuelve a recuperar si cambió su definición.

Diseño del directorio

Después de recuperarse, el repositorio se puede encontrar en el subdirectorio external en la base de salida, con 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 

Administra dependencias externas con Bzlmod

Bzlmod, el nuevo subsistema de dependencias externas, no funciona directamente con las definiciones de repositorio. En cambio, crea un gráfico de dependencias a partir de módulos, ejecuta extensiones sobre el gráfico y define los repositorios en consecuencia.

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 on. Un módulo debe tener un archivo MODULE.bazel en la raíz de su repositorio, junto al WORKSPACE archivo. Este archivo es el manifiesto del módulo, que declara su nombre, versión, lista de dependencias, entre otra información. A continuación, se muestra 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 todo el gráfico de dependencias transitivas antes de realizar la resolución de versiones.

Después de la resolución de versiones, en la que se selecciona una versión para cada módulo, Bazel vuelve a consultar el registro para obtener información sobre cómo definir un repositorio para cada módulo (en la mayoría de los casos, con http_archive).

Los módulos también pueden especificar fragmentos de datos personalizados llamados etiquetas, que son consumidos por 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 de repositorio, lo que les permite realizar acciones como E/S de archivos y enviar solicitudes de red. Entre otras cosas, permiten que Bazel interactúe con otros sistemas de administración de paquetes y, al mismo tiempo, respete el gráfico de dependencias creado a partir de los módulos de Bazel.

Define repositorios con WORKSPACE

Históricamente, puedes administrar dependencias externas definiendo repositorios en el WORKSPACE (o WORKSPACE.bazel) archivo. Este archivo tiene una sintaxis similar a los archivos BUILD, ya 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 WORKSPACE archivo:

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. En el WORKSPACE sistema, de forma predeterminada, el nombre canónico de un repositorio también es su nombre aparente para todos los demás repositorios.

Deficiencias del sistema WORKSPACE

En los años transcurridos desde que se introdujo el sistema WORKSPACE, los usuarios informaron muchas dificultades, incluidas las siguientes:

  • Bazel no evalúa los archivos WORKSPACE de ninguna dependencia, por lo que todas las dependencias transitivas deben definirse en el archivo WORKSPACE 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 les piden a los usuarios que llamen a esta macro en sus archivos WORKSPACE.
    • Esto tiene sus propios problemas: las macros no pueden load otros .bzl archivos, por lo que estos proyectos deben definir sus dependencias transitivas en esta macro "deps" o solucionar este problema haciendo que el usuario llame a varias macros "deps" en capas.
    • Bazel evalúa el archivo WORKSPACE de forma secuencial. Además, las dependencias se especifican con http_archive con URLs, sin información de versión. Esto significa que no hay una forma confiable de realizar la resolución de versiones en el caso de las dependencias de diamante (A depende de B y C; B y C dependen de diferentes versiones de D).

Debido a las deficiencias de WORKSPACE, Bzlmod reemplazará el sistema WORKSPACE heredado en futuras versiones de Bazel. Lee la guía de migración de Bzlmod para saber cómo migrar a Bzlmod.