Bazel puede depender de los destinos de otros proyectos. Las dependencias de estos otros proyectos se denominan dependencias externas.
El archivo WORKSPACE
(o el archivo WORKSPACE.bazel
) del
directorio de lugar de trabajo
le indica a Bazel cómo obtener las fuentes de otros proyectos. Estos otros proyectos pueden contener uno o más archivos BUILD
con sus propios destinos. Los archivos BUILD
dentro del proyecto principal pueden depender de estos destinos externos si se usa su nombre del archivo WORKSPACE
.
Por ejemplo, supongamos que hay dos proyectos en un sistema:
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
Si project1
quisiera depender de un destino, :foo
, definido en /home/user/project2/BUILD
, podría especificar que se podría encontrar un repositorio llamado project2
en /home/user/project2
. Luego, los objetivos en /home/user/project1/BUILD
podrían depender de @project2//:foo
.
El archivo WORKSPACE
permite que los usuarios dependan de destinos de otras partes del sistema de archivos o que se descarguen de Internet. Usa la misma sintaxis que los archivos BUILD
, pero permite un conjunto diferente de reglas llamado reglas del repositorio (a veces también conocidas como reglas del lugar de trabajo). Bazel incluye algunas reglas de repositorio integradas y un conjunto de reglas del repositorio incorporadas de Starlark. Los usuarios también pueden escribir reglas de repositorio personalizadas para obtener un comportamiento más complejo.
Tipos de dependencias externas compatibles
Se pueden usar algunos tipos básicos de dependencias externas:
- Dependencias en otros proyectos de Bazel
- Dependencias en proyectos que no son de Bazel
- Dependencias en paquetes externos
Según otros proyectos de Bazel
Si deseas usar destinos de un segundo proyecto de Bazel, puedes
usar
local_repository
,
git_repository
o http_archive
para vincularlo con el sistema de archivos local, hacer referencia a un repositorio de Git o descargarlo (respectivamente).
Por ejemplo, supongamos que trabajas en un proyecto, my-project/
, y deseas depender de los objetivos del proyecto de tu compañero de trabajo, coworkers-project/
. Ambos
proyectos usan Bazel, por lo que puedes agregar el proyecto de tu compañero de trabajo como una dependencia
externa y, luego, usar cualquier destino que tu compañero de trabajo haya definido desde tus propios
archivos de BUILD. Deberías agregar lo siguiente a my_project/WORKSPACE
:
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
Si tu compañero de trabajo tiene un //foo:bar
objetivo, tu proyecto puede referirse a él como @coworkers_project//foo:bar
. Los nombres de proyectos externos deben ser nombres de lugares de trabajo válidos.
Según proyectos que no sean de Bazel
Las reglas con el prefijo new_
, como
new_local_repository
,
te permiten crear destinos a partir de proyectos que no usan Bazel.
Por ejemplo, supongamos que trabajas en un proyecto, my-project/
, y deseas depender del proyecto de tu compañero de trabajo, coworkers-project/
. El proyecto de tu compañero de trabajo usa make
para compilar, pero te gustaría depender de uno de los archivos .so que genera. Para ello, agrega lo siguiente a my_project/WORKSPACE
:
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file
especifica un archivo BUILD
que se superpondrá en el proyecto existente, por ejemplo:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
Luego, puedes depender de @coworkers_project//:some-lib
desde los archivos BUILD
de tu proyecto.
Según paquetes externos
Artefactos y repositorios de Maven
Usa el conjunto de reglas rules_jvm_external
para descargar artefactos de repositorios de Maven y hacer que estén disponibles como dependencias de Java.
Recupera dependencias
De forma predeterminada, las dependencias externas se recuperan según sea necesario durante bazel build
. Si quieres realizar una carga previa de las dependencias necesarias para un conjunto específico de destinos, usa bazel fetch
.
Para recuperar incondicionalmente todas las dependencias externas, usa bazel sync
.
Como los repositorios recuperados se almacenan en la base de salida, la recuperación se produce por lugar de trabajo.
Dependencias que generan el bloqueo
Siempre que sea posible, se recomienda tener una sola política de versiones en el proyecto. Esto es necesario para las dependencias con las que compilas y terminas en tu objeto binario final. Sin embargo, para los casos en los que esto no sea así, es posible ocultar las dependencias. Considera la siguiente situación:
miproyecto/WORKSPACE
workspace(name = "myproject")
local_repository(
name = "A",
path = "../A",
)
local_repository(
name = "B",
path = "../B",
)
A/WORKSPACE
workspace(name = "A")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "...",
)
B/ESPACIO DE TRABAJO
workspace(name = "B")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
Ambas dependencias, A
y B
, dependen de testrunner
, pero dependen de diferentes versiones de testrunner
. No hay motivo para que estos ejecutores de pruebas
no coexistan de manera pacífica dentro de myproject
; sin embargo, competirán entre sí
ya que tienen el mismo nombre. Para declarar ambas dependencias, actualiza myproject/WORKSPACE:
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner-v1",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "..."
)
http_archive(
name = "testrunner-v2",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
local_repository(
name = "A",
path = "../A",
repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
name = "B",
path = "../B",
repo_mapping = {"@testrunner" : "@testrunner-v2"}
)
Este mecanismo también se puede usar para unir diamantes. Por ejemplo, si A
y B
tenían la misma dependencia, pero la llamaron con nombres diferentes, esas dependencias se pueden unir en myproject/WORKSPACE.
Anula repositorios desde la línea de comandos
Para anular un repositorio declarado con un repositorio local desde la línea de comandos, usa la marca --override_repository
. Usar esta marca cambia el contenido de los repositorios externos sin cambiar el código fuente.
Por ejemplo, para anular @foo
en el directorio local /path/to/local/foo
, pasa la marca --override_repository=foo=/path/to/local/foo
.
A continuación, se presentan algunos de los casos prácticos:
- Problemas de depuración Por ejemplo, puedes anular un repositorio
http_archive
para un directorio local en el que puedas realizar cambios con mayor facilidad. - Proveedores. Si te encuentras en un entorno en el que no puedes realizar llamadas de red, anula las reglas del repositorio basado en la red para que apunten a directorios locales.
Usa proxies
Bazel recopilará direcciones de proxy de las variables de entorno HTTPS_PROXY
y HTTP_PROXY
y las usará para descargar archivos HTTP/HTTPS (si se especifica).
Compatibilidad con IPv6
En máquinas que solo usan IPv6, Bazel podrá descargar dependencias sin
cambios. Sin embargo, en las máquinas IPv4/IPv6 de doble pila, Bazel sigue la misma
convención que Java: si IPv4 está habilitado, se prefiere IPv4. En algunas situaciones, por ejemplo, cuando la red IPv4 no puede resolver o llegar a direcciones externas, esto puede causar excepciones Network unreachable
y fallas de compilación.
En estos casos, puedes anular el comportamiento de Bazel para priorizar IPv6 mediante la propiedad del sistema java.net.preferIPv6Addresses=true
.
En particular, haz lo siguiente:
Usa la opción de inicio
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
, por ejemplo, agregando la siguiente línea en tu archivo.bazelrc
:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
Si ejecutas objetivos de compilación de Java que también necesitan conectarse a Internet (las pruebas de integración a veces lo necesitan), también usa la marca de herramienta
--jvmopt=-Djava.net.preferIPv6Addresses=true
, por ejemplo, incluyendo la siguiente línea en tu archivo.bazelrc
:build --jvmopt=-Djava.net.preferIPv6Addresses
Si usas rules_jvm_external, por ejemplo, para la resolución de versión de dependencia, también agrega
-Djava.net.preferIPv6Addresses=true
a la variable de entornoCOURSIER_OPTS
a fin de proporcionar opciones de JVM para Coursier
Dependencias transitivas
Bazel solo lee las dependencias enumeradas en el archivo WORKSPACE
. Si tu proyecto (A
) depende de otro proyecto (B
), que enumera una dependencia en un tercer proyecto (C
) en su archivo WORKSPACE
, deberás agregar B
y C
al archivo WORKSPACE
de tu proyecto. Este requisito puede aumentar el tamaño del archivo WORKSPACE
, pero limita las posibilidades de que una biblioteca incluya C
en la versión 1.0 y otra que incluya C
en 2.0.
Almacenamiento en caché de dependencias externas
De forma predeterminada, Bazel solo volverá a descargar dependencias externas si
cambia su definición. Bazel también tiene en cuenta los cambios en los archivos a los que se hace referencia en la definición (como los parches o los archivos BUILD
).
Para forzar una nueva descarga, usa bazel sync
.
Diseño
Las dependencias externas se descargan en un directorio dentro del subdirectorio external
en la base de salida. En el caso de un repositorio local, allí se crea un symlink, en lugar de crear un directorio nuevo.
Para ver el directorio external
, ejecuta lo siguiente:
ls $(bazel info output_base)/external
Ten en cuenta que ejecutar bazel clean
en realidad no borrará el directorio
externo. Para quitar todos los artefactos externos, usa bazel clean --expunge
.
Compilaciones sin conexión
A veces, resulta conveniente o necesario ejecutar una compilación sin conexión. Para casos de uso simples, como viajar en un avión, la carga previa de los repositorios necesarios con bazel fetch
o bazel sync
puede ser suficiente. Además, con el uso de la opción --nofetch
, se puede inhabilitar la recuperación de otros repositorios durante la compilación.
Para compilaciones reales sin conexión, en las que una entidad diferente de Bazel realiza el suministro de los archivos necesarios, Bazel admite la opción --distdir
. Cada vez que una regla de repositorio le solicite a Bazel que recupere un archivo a través de
ctx.download
o
ctx.download_and_extract
y proporcione una suma de hash del archivo
necesario, Bazel primero buscará en los directorios que especifica esa opción un archivo que coincida con el nombre base de la primera URL proporcionada y usará esa copia local
si el hash coincide.
Bazel usa esta técnica para realizar un arranque sin conexión del artefacto de distribución.
Para ello, recopila todas las dependencias externas necesarias en una distdir_tar
interna.
Sin embargo, Bazel permite ejecutar comandos arbitrarios en las reglas del repositorio sin saber si llaman a la red. Por lo tanto, Bazel no tiene la opción de aplicar compilaciones completamente sin conexión. Por lo tanto, probar si una compilación funciona correctamente sin conexión requiere el bloqueo externo de la red, como lo hace Bazel en su prueba de arranque.
Prácticas recomendadas
Reglas del repositorio
En general, una regla de repositorio debe ser responsable de lo siguiente:
- Detecta la configuración del sistema y la escribe en archivos.
- Buscar recursos en otra parte del sistema.
- Descargando recursos de las URLs
- Generar o vincular symlink archivos BUILD en el directorio del repositorio externo
Evita usar repository_ctx.execute
cuando sea posible. Por ejemplo, cuando usas una biblioteca de C++
que no es de Bazel y que tiene una compilación con Make, es preferible usar repository_ctx.download()
y, luego,
escribir un archivo BUILD que lo compile, en lugar de ejecutar ctx.execute(["make"])
.
Prefiere http_archive
en lugar de git_repository
y new_git_repository
. Estos son los motivos:
- Las reglas del repositorio de Git dependen del sistema
git(1)
, mientras que el software de descarga de HTTP está integrado en Bazel y no tiene dependencias del sistema. http_archive
admite una lista deurls
como duplicaciones, ygit_repository
admite solo unaremote
.http_archive
funciona con la caché del repositorio, pero no congit_repository
. Consulta #5116 para obtener más información.
No uses bind()
. Consulta "Considera quitar vínculos" para ver un debate largo de sus problemas y alternativas.