O Bazel é compatível com dependências externas, arquivos de origem (texto e binários) usados no build que não são do seu espaço de trabalho. Por exemplo, eles podem ser um conjunto de regras hospedado em um repositório do GitHub, um artefato Maven ou um diretório na máquina local fora do espaço de trabalho atual.
A partir do Bazel 6.0, há duas maneiras de gerenciar dependências externas com o Bazel:
o sistema WORKSPACE
tradicional, com foco em repositório, e
o mais novo sistema MODULE.bazel
focado em módulo (chamado Bzlmod
e ativado com a flag --enable_bzlmod
). Os dois sistemas podem ser usados
juntos, mas o Bzlmod está substituindo o sistema WORKSPACE
em versões futuras do
Bzlmod. Confira o guia de migração Bzlmod para
migração do Bazel{/1.
Este documento explica os conceitos relacionados ao gerenciamento de dependências externas no Bazel, antes de entrar em mais detalhes sobre os dois sistemas na ordem.
conceitos
Repositório
Uma árvore de diretórios com um arquivo de marcador de limite na raiz, contendo arquivos de origem que podem ser usados em um build do Bazel. Geralmente encurtado para apenas repo.
Um arquivo de marcador de limite do repo pode ser MODULE.bazel
, o que indica que ele representa um módulo do Bazel, REPO.bazel
(consulte abaixo) ou WORKSPACE
ou WORKSPACE.bazel
em contextos legados. Qualquer arquivo de marcador de limite do repositório representará o limite de um repositório. Vários desses arquivos podem coexistir em um diretório.
Repositório principal
O repositório em que o comando atual do Bazel está sendo executado.
A raiz do repositório principal também é conhecida como raiz do espaço de trabalho.
Espaço de trabalho
O ambiente compartilhado por todos os comandos do Bazel são executados no mesmo repositório principal. Ela abrange o repositório principal e o conjunto de todos os repositórios externos definidos.
Historicamente, os conceitos de "repositório" e "espaço de trabalho" foram confundidos. O termo "espaço de trabalho" é frequentemente usado para se referir ao repositório principal e, às vezes, até como sinônimo de "repositório".
Nome do repositório canônico
O nome canônico pelo qual um repositório é endereçável. Dentro do contexto de um
espaço de trabalho, cada repositório tem um único nome canônico. Um destino dentro de um repositório
com um nome canônico é canonical_name
pode ser endereçado pelo rótulo
@@canonical_name//pac/kage:target
(observe o @
duplo).
O repositório principal sempre tem a string vazia como nome canônico.
Nome do repositório aparente
O nome de um repositório é endereçável no contexto de um determinado outro repositório.
Isso pode ser considerado como o "apelido" de um repositório: o repositório com o nome canônico
michael
pode ter o nome aparente mike
no contexto do repo
alice
, mas pode ter o nome aparente mickey
no contexto do
bob
. Nesse caso, um destino dentro de michael
pode ser endereçado pelo rótulo
@mike//pac/kage:target
no contexto de alice
(observe o único @
).
Por outro lado, isso pode ser entendido como um mapeamento de repositório: cada repositório mantém um mapeamento de "nome do repositório aparente" para um "nome de repositório canônico".
Regra de repositório
Um esquema para definições de repositório que informa ao Bazel como materializar um
repositório. Por exemplo, pode ser "faça o download de um arquivo ZIP de um determinado URL
e extraia-o", "buscar um determinado artefato Maven e o disponibilizar como um
destino java_import
" ou simplesmente "link simbólico de um diretório local". Cada repositório é
definido chamando uma regra de repositório com um número apropriado de argumentos.
Consulte Regras de repositório para mais informações sobre como gravar suas próprias regras de repositório.
As regras de repositório mais comuns são, de longe,
http_archive
, que faz o download de um arquivo
de um URL e o extrai, e
local_repository
, que vincula simbolicamente um
diretório local que já é um repositório do Bazel.
Buscar um repositório
A ação de disponibilizar um repositório no disco local executando a regra de repositório associada. Os repositórios definidos em um espaço de trabalho não ficam disponíveis no disco local antes de serem buscados.
Normalmente, o Bazel só busca um repositório quando precisa de algo dele e ele ainda não foi buscado. Se o repositório já tiver sido buscado antes, o Bazel só o buscará novamente se a definição tiver sido alterada.
O comando fetch
pode ser usado para iniciar uma pré-busca de um repositório,
destino ou todos os repositórios necessários para executar qualquer build. Esse recurso
permite builds off-line usando a opção --nofetch
.
A opção --fetch
serve para gerenciar o acesso à rede. O valor padrão é verdadeiro.
No entanto, quando definido como falso (--nofetch
), o comando vai usar qualquer versão armazenada
em cache da dependência e, se nenhuma existir, o comando vai resultar em
falha.
Consulte opções de busca para mais informações sobre como controlar a busca.
Layout do diretório
Depois de ser buscado, o repositório pode ser encontrado no subdiretório external
na
base de saída, abaixo do nome canônico dele.
Execute o seguinte comando para ver o conteúdo do repositório com o
nome canônico canonical_name
:
ls $(bazel info output_base)/external/ canonical_name
Arquivo REPO.bazel
O arquivo REPO.bazel
é usado para marcar o limite superior da árvore de diretórios
que constitui um repositório. Ele não precisa conter nada para servir como um arquivo
de limite do repositório. No entanto, ele também pode ser usado para especificar alguns atributos comuns
para todos os destinos de build dentro do repositório.
A sintaxe de um arquivo REPO.bazel
é semelhante à BUILD
. A diferença é que não há suporte para nenhuma instrução load
e apenas uma função, repo()
, está disponível. repo()
usa os mesmos argumentos que a função package()
em arquivos BUILD
. Enquanto package()
especifica atributos comuns para todos os destinos de build dentro do pacote, repo()
faz isso de forma analógica para todos os destinos de build dentro do repositório.
Por exemplo, é possível especificar uma licença comum para todos os destinos em seu repositório
tendo o seguinte arquivo REPO.bazel
:
repo(
default_package_metadata = ["//:my_license"],
)
Gerenciar dependências externas com o Bzlmod
Bzlmod, o novo subsistema de dependência externa, não funciona diretamente com definições de repositório. Em vez disso, ele cria um gráfico de dependência com base em módulos, executa extensões sobre o gráfico e define os repositórios de acordo com isso.
Um módulo do Bazel é um projeto que pode ter várias
versões. Cada uma delas publica metadados sobre outros módulos de que depende. Um módulo precisa ter um arquivo MODULE.bazel
na raiz do repositório, ao lado do
arquivo WORKSPACE
. Esse arquivo é o manifesto do módulo, que declara o nome,
a versão, a lista de dependências, entre outras informações. Confira a seguir um exemplo 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")
Um módulo precisa listar apenas as dependências diretas, que o Bzlmod procura em um
registro Bazel (por padrão, o Registro
Bazel Central). O registro fornece os
arquivos MODULE.bazel
das dependências, que permitem que o Bazel descubra todo o
gráfico de dependências transitiva antes de realizar a resolução da versão.
Após a resolução da versão, em que uma versão é selecionada para cada módulo,
o Bazel consulta o registro novamente para saber como definir um repositório para cada módulo
(na maioria dos casos, usando http_archive
).
Os módulos também podem especificar dados personalizados, chamados de tags, que são consumidos pelas extensões de módulo após a resolução para definir outros repositórios. Essas extensões têm recursos semelhantes às regras de repositório, permitindo que executem ações como E/S de arquivos e envio de solicitações de rede. Entre outras coisas, eles permitem que o Bazel interaja com outros sistemas de gerenciamento de pacotes ao mesmo tempo em que respeita o gráfico de dependências criado a partir dos módulos do Bazel.
Links externos no Bzlmod
- Exemplos de uso do Bzlmod em bazelbuild/examples
- Revisão de dependências externas do Bazel (documento de design original do Bzlmod)
- Palestra na BazelCon 2021 sobre a Bzlmod
- Palestra do Dia da Comunidade do Bazel sobre Bzlmod
Definir repositórios com WORKSPACE
Historicamente, é possível gerenciar dependências externas definindo repositórios no arquivo
WORKSPACE
(ou WORKSPACE.bazel
). Esse arquivo tem uma sintaxe semelhante à
BUILD
, empregando regras de repositório em vez de regras de build.
O snippet a seguir é um exemplo de como usar a regra de repositório http_archive
no
arquivo WORKSPACE
:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "foo",
urls = ["https://example.com/foo.zip"],
sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)
O snippet define um repositório com um nome canônico que é foo
. No sistema
WORKSPACE
, por padrão, o nome canônico de um repositório também é o nome aparente
de todos os outros.
Veja a lista completa das funções disponíveis nos
arquivos WORKSPACE
.
Falhas do sistema do WORKSPACE
Desde que o sistema WORKSPACE
foi introduzido, os usuários relataram
vários pontos problemáticos, incluindo:
- O Bazel não avalia os arquivos
WORKSPACE
de nenhuma dependência. Portanto, todas as dependências transitivas precisam ser definidas no arquivoWORKSPACE
do repositório principal, além das dependências diretas. - Para contornar isso, os projetos adotaram o padrão "deps.bzl", em que
eles definem uma macro que, por sua vez, define vários repositórios e pedem que os usuários
chamem essa macro nos arquivos
WORKSPACE
.- Isso tem os próprios problemas: as macros não podem
load
outros arquivos.bzl
. Portanto, esses projetos precisam definir as dependências transitivas nessa macro "deps" ou contornar esse problema fazendo com que o usuário chame várias macros "deps" em camadas. - O Bazel avalia o arquivo
WORKSPACE
sequencialmente. Além disso, as dependências são especificadas usandohttp_archive
com URLs, sem informações de versão. Isso significa que não há uma maneira confiável de realizar a resolução de versão no caso de dependências de diamante (A
depende deB
eC
,B
eC
dependem de versões diferentes deD
).
- Isso tem os próprios problemas: as macros não podem
Devido às deficiências do ESPAÇO DE TRABALHO, o Bzlmod vai substituir o sistema legado do ESPAÇO DE TRABALHO em versões futuras do Bazel. Leia o Guia de migração do Bzlmod sobre como migrar para o Bzlmod.