O Bazel pode depender de destinos de outros projetos. As dependências desses outros projetos são chamadas de dependências externas.
O arquivo WORKSPACE
(ou WORKSPACE.bazel
) no
diretório do espaço de trabalho
informa ao Bazel como conseguir as origens de outros projetos. Esses outros projetos podem
conter um ou mais arquivos BUILD
com os próprios destinos. Os arquivos BUILD
no
projeto principal podem depender desses destinos externos usando os nomes deles
do arquivo WORKSPACE
.
Por exemplo, suponha que haja dois projetos em um sistema:
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
Se project1
quisesse depender de um destino, :foo
, definido em
/home/user/project2/BUILD
, poderia especificar que um repositório chamado
project2
poderia ser encontrado em /home/user/project2
. Então, os destinos em
/home/user/project1/BUILD
podem depender de @project2//:foo
.
O arquivo WORKSPACE
permite que os usuários dependam de destinos de outras partes do
sistema de arquivos ou transferidos por download da Internet. Ele usa a mesma sintaxe dos arquivos BUILD
, mas permite um conjunto diferente de regras chamadas regras de repositório (às vezes
também conhecidas como regras do espaço de trabalho). Ele vem com algumas regras de repositório
integradas e um conjunto de regras de repositório
do Starlark incorporadas. Os usuários também podem escrever regras de repositório
personalizadas para conseguir comportamentos mais complexos.
Tipos com suporte de dependências externas
Alguns tipos básicos de dependências externas podem ser usados:
- Dependências de outros projetos do Bazel
- Dependências de projetos que não são do Bazel
- Dependências de pacotes externos
Dependendo de outros projetos do Bazel
Se você quiser usar destinos de um segundo projeto do Bazel, use
local_repository
,
git_repository
ou http_archive
para fazer um link simbólico no sistema de arquivos local, faça referência a um repositório git ou faça o
download dele (respectivamente).
Por exemplo, suponha que você esteja trabalhando em um projeto, my-project/
, e queira
depender dos destinos do projeto do seu colega de trabalho, coworkers-project/
. Ambos os projetos usam o Bazel, para que você possa adicionar o projeto do seu colega de trabalho como uma dependência externa e, em seguida, usar os destinos definidos por ele nos próprios arquivos BUILD. Você adicionaria o seguinte a my_project/WORKSPACE
:
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
Se seu colega de trabalho tiver um //foo:bar
de destino, seu projeto poderá se referir a ele como @coworkers_project//foo:bar
. Os nomes de projetos externos precisam ser
nomes de espaço de trabalho válidos.
Dependendo de projetos que não são do Bazel
As regras prefixadas com new_
, como
new_local_repository
,
permitem criar destinos de projetos que não usam o Bazel.
Por exemplo, suponha que você esteja trabalhando em um projeto, my-project/
, e queira
depender do projeto do seu colega de trabalho, coworkers-project/
. O projeto do seu colega de trabalho usa make
para criar, mas você gostaria de depender de um dos arquivos .so que ele gera. Para fazer isso, adicione o seguinte a my_project/WORKSPACE
:
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file
especifica um arquivo BUILD
para sobrepor no projeto atual, por
exemplo:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
Você pode depender de @coworkers_project//:some-lib
dos arquivos
BUILD
do seu projeto.
Dependendo de pacotes externos
Artefatos e repositórios do Maven
Use o conjunto de regras rules_jvm_external
para fazer o download de artefatos de repositórios Maven e os disponibilizar como dependências
Java.
Como buscar dependências
Por padrão, as dependências externas são buscadas conforme necessário durante bazel build
. Se
você quiser pré-buscar as dependências necessárias para um conjunto específico de destinos, use
bazel fetch
.
Para buscar incondicionalmente todas as dependências externas, use
bazel sync
.
Conforme os repositórios buscados são armazenados na base de saída, a busca
ocorre por espaço de trabalho.
Acompanhamento de dependências
Sempre que possível, é recomendável ter uma única política de versão no seu projeto. Isso é necessário para dependências que você compila e termina no binário final. Mas, nos casos em que isso não é verdade, é possível ocultar as dependências. Pense no seguinte cenário:
meu projeto/espaço de trabalho
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 = "...",
)
ESPAÇO DE TRABALHO
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 = "..."
)
As dependências A
e B
dependem de testrunner
, mas dependem de
versões diferentes de testrunner
. Não há motivo para que esses executores de teste
não coexistam pacificamente dentro do myproject
. No entanto, eles entrarão em conflito,
já que têm o mesmo nome. Para declarar as duas dependências, atualize o 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 também pode ser usado para unir diamantes. Por exemplo, se A
e B
tiverem a mesma dependência, mas forem chamados por nomes diferentes, essas dependências poderão ser agrupadas em myproject/WORKSPACE.
Como substituir repositórios pela linha de comando
Para substituir um repositório declarado por um repositório local na linha de comando,
use a
sinalização
--override_repository
. O uso dessa flag muda o conteúdo de repositórios externos sem
alterar o código-fonte.
Por exemplo, para substituir @foo
pelo diretório local /path/to/local/foo
,
transmita a sinalização --override_repository=foo=/path/to/local/foo
.
Alguns dos casos de uso incluem:
- Problemas de depuração. Por exemplo, é possível substituir um repositório
http_archive
por um diretório local em que seja possível fazer alterações com mais facilidade. - Fornecimento. Se você estiver em um ambiente em que não é possível fazer chamadas de rede, substitua as regras do repositório baseado em rede para apontar para diretórios locais.
Como usar proxies
O Bazel coleta os endereços de proxy das variáveis de ambiente HTTPS_PROXY
e HTTP_PROXY
e os usa para fazer o download de arquivos HTTP/HTTPS (se especificados).
Suporte para IPv6
Em máquinas somente IPv6, o Bazel poderá fazer o download de dependências
sem alterações. No entanto, em máquinas IPv4/IPv6 de pilha dupla, o Bazel segue a mesma
convenção do Java: se o IPv4 estiver ativado, o IPv4 é o preferencial. Em algumas situações,
por exemplo, quando a rede IPv4 não consegue resolver/alcançar endereços externos,
isso pode causar exceções Network unreachable
e falhas na criação.
Nesses casos, é possível substituir o comportamento do Bazel para preferir o IPv6
usando a propriedade do sistema java.net.preferIPv6Addresses=true
(link em inglês).
Especificamente:
Use a opção de inicialização
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
, por exemplo, adicionando a seguinte linha ao arquivo.bazelrc
:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
Se você estiver executando destinos de build em Java que também precisem se conectar à Internet (às vezes, os testes de integração precisam disso), use também a sinalização de ferramenta
--jvmopt=-Djava.net.preferIPv6Addresses=true
, por exemplo, com a seguinte linha no arquivo.bazelrc
:build --jvmopt=-Djava.net.preferIPv6Addresses
Se você estiver usando rules_jvm_external, por exemplo, para resolução da versão de dependência, adicione também
-Djava.net.preferIPv6Addresses=true
à variável de ambienteCOURSIER_OPTS
para fornecer opções da JVM para o Coursier.
Dependências transitivas
O Bazel só lê as dependências listadas no arquivo WORKSPACE
. Se o projeto
(A
) depender de outro (B
) que lista uma dependência de um terceiro
projeto (C
) no arquivo WORKSPACE
, será necessário adicionar B
e C
ao arquivo WORKSPACE
do projeto. Esse requisito pode aumentar o
tamanho do arquivo WORKSPACE
, mas limita as chances de uma biblioteca
incluir C
na versão 1.0 e outra incluir C
na versão 2.0.
Armazenamento em cache de dependências externas
Por padrão, o Bazel só vai fazer o download novamente das dependências externas se a
definição delas mudar. As mudanças nos arquivos referenciados na definição (como patches
ou arquivos BUILD
) também são consideradas pelo Bazel.
Para forçar um novo download, use bazel sync
.
Layout
Todas as dependências externas são transferidas por download para um diretório no subdiretório
external
na base de saída. No caso de um
repositório local, um link simbólico é criado
nele, em vez de um novo diretório.
Veja o diretório external
executando:
ls $(bazel info output_base)/external
Observe que executar bazel clean
não exclui o diretório externo. Para remover todos os artefatos externos, use bazel clean --expunge
.
Builds off-line
Às vezes, é desejável ou necessário executar uma compilação off-line. Para
casos de uso simples, como viajar de avião,
a pré-busca dos repositórios
necessários com bazel fetch
ou bazel sync
pode ser suficiente. Além disso, com
a opção --nofetch
e a opção --nofetch
, a busca de mais repositórios pode ser desativada
durante a criação.
Para builds off-line reais, em que o fornecimento dos arquivos necessários deve ser feito
por uma entidade diferente do bazel, o bazel oferece suporte à opção
--distdir
. Sempre que uma regra de repositório solicitar que o bazel busque um arquivo via
ctx.download
ou
ctx.download_and_extract
e forneça uma soma de hash do arquivo
necessário, o Bazel primeiro verificará os diretórios especificados por essa opção para
um arquivo correspondente ao nome de base do primeiro URL fornecido e usará essa cópia local
se o hash corresponder.
O próprio Bazel usa essa técnica para fazer a inicialização off-line do artefato
de distribuição.
Isso é feito coletando todas as dependências externas necessárias em um distdir_tar
interno.
No entanto, o Bazel permite a execução de comandos arbitrários nas regras do repositório, sem saber se eles chamam a rede. Portanto, o Bazel não tem a opção de exigir que os builds sejam totalmente off-line. Portanto, para testar se um build funciona corretamente off-line, é necessário bloquear externamente a rede, como o Bazel faz no teste de bootstrap.
Práticas recomendadas
Regras de repositório
Uma regra de repositório geralmente é responsável por:
- Detectar configurações do sistema e gravá-las em arquivos.
- Encontrar recursos em outro lugar no sistema.
- Fazendo o download de recursos a partir de URLs.
- Geração ou vinculação simbólica de arquivos BUILD no diretório do repositório externo.
Evite usar repository_ctx.execute
sempre que possível. Por exemplo, ao usar uma biblioteca C++
que não seja Bazel e que tenha um build usando o Make, é preferível usar repository_ctx.download()
e
gravar um arquivo BUILD que a crie, em vez de executar ctx.execute(["make"])
.
Prefira http_archive
a git_repository
e
new_git_repository
. Estes são os motivos:
- As regras do repositório Git dependem do sistema
git(1)
, enquanto a ferramenta de download HTTP é incorporada ao Bazel e não tem dependências do sistema. http_archive
aceita uma lista deurls
como espelhos, egit_repository
aceita apenas um únicoremote
.http_archive
funciona com o cache de repositório, mas não comgit_repository
. Consulte #5116 para mais informações.
Não use bind()
. Consulte "Considere remover o vínculo" para ver uma longa discussão sobre os problemas e alternativas dele.