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 arquivo WORKSPACE.bazel) no
diretório do espaço de trabalho
informa ao Bazel como acessar as origens de outros projetos. Esses outros projetos podem
conter um ou mais BUILD arquivos com os próprios destinos. Os arquivos BUILD no
projeto principal podem depender desses destinos externos usando o nome deles no
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, ele poderia especificar que um repositório chamado
project2 poderia ser encontrado em /home/user/project2. Em seguida, os destinos em
/home/user/project1/BUILD poderiam depender de @project2//:foo.
O arquivo WORKSPACE permite que os usuários dependam de destinos de outras partes do
sistema de arquivos ou baixados da Internet. Ele usa a mesma sintaxe dos BUILD
arquivos, mas permite um conjunto diferente de regras chamadas regras de repositório (às vezes
também conhecidas como regras de espaço de trabalho). O Bazel vem com algumas regras de repositório integradas e um conjunto de regras de repositório Starlark incorporadas. Os usuários também podem criar regras de repositório personalizadas para ter um comportamento mais complexo.
Tipos de dependências externas compatíveis
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
Depender de outros projetos do Bazel
Se você quiser usar destinos de um segundo projeto do Bazel, pode
usar
local_repository,
git_repository
ou http_archive
para criar um link simbólico no sistema de arquivos local, referenciar um repositório Git ou fazer o download
dele (respectivamente).
Por exemplo, suponha que você esteja trabalhando em um projeto, my-project/, e queira
depender de destinos do projeto do seu colega de trabalho, coworkers-project/. Como os dois
projetos usam o Bazel, você pode adicionar o projeto do seu colega de trabalho como uma dependência
externa e usar qualquer destino definido pelo seu colega de trabalho nos seus próprios arquivos
BUILD. Adicione o seguinte a my_project/WORKSPACE:
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
Se o colega de trabalho tiver um destino //foo:bar, seu projeto poderá se referir a ele como
@coworkers_project//foo:bar. Os nomes de projetos externos precisam ser
nomes de espaços de trabalho válidos.
Depender 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 a ser sobreposto no projeto atual, por
exemplo:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
Em seguida, você pode depender de @coworkers_project//:some-lib dos arquivos
BUILD do seu projeto.
Depender 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 do Maven e disponibilizá-los 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 buscar as dependências necessárias para um conjunto específico de destinos, use
bazel fetch.
Para buscar todas as dependências externas incondicionalmente, use
bazel sync.
Como os repositórios buscados são armazenados na base de saída, a busca
acontece por espaço de trabalho.
Dependências de sombreamento
Sempre que possível, recomendamos ter uma política de versão única no seu projeto. Isso é necessário para dependências que você compila e que acabam no seu binário final. No entanto, para casos em que isso não é verdade, é possível sombrear dependências. Pense no seguinte cenário:
myproject/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/WORKSPACE
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 em myproject, mas eles vão entrar em conflito porque têm o mesmo nome. Para declarar as duas dependências,
atualize 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"}
)
Esse mecanismo também pode ser usado para unir diamantes. Por exemplo, se A e B
tiverem a mesma dependência, mas a chamarem por nomes diferentes, essas dependências podem
ser unidas em myproject/WORKSPACE.
Substituir repositórios na linha de comando
Para substituir um repositório declarado por um repositório local na linha de comando,
use a
--override_repository
flag. 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 flag --override_repository=foo=/path/to/local/foo.
Alguns dos casos de uso incluem:
- Depuração de problemas. Por exemplo, você pode substituir um
http_archiverepositório por um diretório local em que é possível fazer mudanças com mais facilidade. - Fornecimento. Se você estiver em um ambiente em que não é possível fazer chamadas de rede, substitua as regras de repositório baseadas em rede para apontar para diretórios locais em vez disso.
Uso de proxies
O Bazel vai coletar endereços de proxy das HTTPS_PROXY e HTTP_PROXY
variáveis de ambiente e usá-los para fazer o download de arquivos HTTP/HTTPS (se especificado).
Suporte ao IPv6
Em máquinas somente IPv6, o Bazel poderá fazer o download de dependências com
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, ele será preferido. Em algumas situações,
por exemplo, quando a rede IPv4 não consegue resolver/alcançar endereços externos,
isso pode causar Network unreachable exceções e falhas de build.
Nesses casos, é possível substituir o comportamento do Bazel para preferir o IPv6
usando a propriedade do sistema java.net.preferIPv6Addresses=true.
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=trueSe você estiver executando destinos de build Java que também precisam se conectar à Internet (os testes de integração às vezes precisam disso), use também
--jvmopt=-Djava.net.preferIPv6Addresses=trueflag de ferramenta, por exemplo, incluindo a seguinte linha no arquivo.bazelrc:build --jvmopt=-Djava.net.preferIPv6AddressesSe você estiver usando rules_jvm_external, por exemplo, para resolução de versão de dependência, adicione também
-Djava.net.preferIPv6Addresses=trueàCOURSIER_OPTSvariável de ambiente para fornecer opções de 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 projeto (B) que liste uma dependência em um terceiro
projeto (C) no arquivo WORKSPACE, você precisará adicionar B
e C ao arquivo WORKSPACE do seu projeto. Esse requisito pode aumentar o
WORKSPACE tamanho do arquivo, mas limita as chances de uma biblioteca
incluir C na versão 1.0 e outra incluir C na 2.0.
Armazenamento em cache de dependências externas
Por padrão, o Bazel só vai fazer o download de dependências externas novamente se a
definição delas mudar. As mudanças nos arquivos referenciados na definição (como patches
ou BUILD arquivos) também são consideradas pelo Bazel.
Para forçar um novo download, use bazel sync.
Layout
Todas as dependências externas são baixadas 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
em vez de um novo diretório.
Para conferir o diretório external, execute:
ls $(bazel info output_base)/externalA execução de 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 um build off-line. Para
casos de uso simples, como viajar de avião,
prefetching os repositórios necessários com bazel fetch ou bazel sync pode ser suficiente. Além disso, usando a opção --nofetch, a busca de outros repositórios pode ser desativada
durante o build.
Para builds off-line verdadeiros, em que o fornecimento dos arquivos necessários é feito
por uma entidade diferente do Bazel, o Bazel oferece suporte à opção
--distdir. Sempre que uma regra de repositório pede ao Bazel para buscar um arquivo usando
ctx.download ou
ctx.download_and_extract
e fornece uma soma de hash do arquivo
necessário, o Bazel primeiro procura nos diretórios especificados por essa opção um arquivo que corresponda ao nome base do primeiro URL fornecido e usa essa cópia local
se o hash corresponder.
O próprio Bazel usa essa técnica para inicializar off-line a partir do artefato
de distribuição.
Ele faz isso 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 em regras de repositório, sem saber se eles fazem chamadas para a rede. Portanto, o Bazel não tem uma opção para forçar builds totalmente off-line. Assim, testar se um build funciona corretamente off-line exige o bloqueio externo da rede, como o Bazel faz no teste de inicialização.
Práticas recomendadas
Regras do repositório
Uma regra de repositório geralmente é responsável por:
- Detectar configurações do sistema e gravá-las em arquivos.
- Encontrar recursos em outros lugares do sistema.
- Fazer o download de recursos de URLs.
- Gerar ou criar links simbólicos 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 do Bazel e que tenha um build usando Make, é preferível usar repository_ctx.download() e, em seguida,
gravar um arquivo BUILD que o 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 o downloader HTTP é integrado ao Bazel e não tem dependências do sistema. http_archiveoferece suporte a uma lista deurlscomo espelhos, egit_repositoryoferece suporte apenas a um únicoremote.http_archivefunciona com o cache do repositório, mas nãogit_repository. Consulte #5116 para mais informações.
Não use bind(). Consulte "Considerar a remoção de
bind" para uma discussão longa
sobre os problemas e alternativas.