O Bazel oferece suporte a dependências externas, arquivos de origem (texto e binários) usados no seu build que não são do seu espaço de trabalho. Por exemplo, pode ser um conjunto de regras hospedado em um repositório do GitHub, um artefato do Maven ou um diretório na sua 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, focado em repositório, e o sistema MODULE.bazel
mais recente, focado em módulos (codinome Bzlmod, ativado com a flag --enable_bzlmod
). Os dois sistemas podem ser usados juntos, mas o Bzlmod vai substituir o sistema WORKSPACE
em versões futuras do Bazel. Consulte o guia de migração do Bzlmod para saber como migrar.
Este documento explica os conceitos relacionados ao gerenciamento de dependências externas no Bazel antes de entrar em mais detalhes sobre os dois sistemas em ordem.
Conceitos
Repositório
Uma árvore de diretórios com um arquivo marcador de limite na raiz, contendo arquivos de origem que podem ser usados em um build do Bazel. Muitas vezes abreviado para apenas repo.
Um arquivo marcador de limite do repositório pode ser MODULE.bazel
(indicando que este repositório representa um módulo do Bazel), REPO.bazel
(consulte abaixo) ou, em contextos legados, WORKSPACE
ou WORKSPACE.bazel
. Qualquer arquivo marcador de limite de repositório
vai indicar o limite de um repositório. Vários arquivos desse tipo podem coexistir em um
diretório.
Repositório principal
O repositório em que o comando do Bazel atual 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 é executado no mesmo repositório principal. Ele 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" era usado com frequência para se referir ao repositório principal e, às vezes, até como sinônimo de "repositório".
Nome canônico do repositório
O nome canônico pelo qual um repositório pode ser endereçado. No contexto de um
espaço de trabalho, cada repositório tem um único nome canônico. Um destino em um repositório
cujo nome canônico é canonical_name
pode ser abordado 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 aparente do repositório
O nome pelo qual um repositório pode ser acessado no contexto de outro repositório.
Isso pode ser considerado como um "apelido" de um repositório: o repositório com o nome canônico
michael
pode ter o nome aparente mike
no contexto do repositório
alice
, mas pode ter o nome aparente mickey
no contexto do repositório
bob
. Nesse caso, um destino em michael
pode ser abordado 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 do "nome aparente do repositório" para um "nome canônico do repositório".
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 "fazer o download e extrair um arquivo zip de um determinado URL", "buscar um determinado artefato do Maven e disponibilizá-lo como um destino java_import
" ou simplesmente "criar um link simbólico para um diretório local". Cada repositório é definido chamando uma regra de repositório com um número adequado de argumentos.
Consulte Regras de repositório para mais informações sobre como escrever suas próprias regras.
As regras de repositório mais comuns são http_archive
, que baixa e extrai um arquivo de um URL, e local_repository
, que cria um link simbólico para 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 estão 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ó vai buscá-lo novamente se a definição dele tiver mudado.
O comando fetch
pode ser usado para iniciar uma pré-busca de um repositório, um destino ou todos os repositórios necessários para realizar qualquer build. Essa capacidade permite builds off-line usando a opção --nofetch
.
A opção --fetch
serve para gerenciar o acesso à rede. O valor padrão é "true".
No entanto, quando definido como falso (--nofetch
), o comando usa qualquer versão em cache da dependência. Se não houver nenhuma, o comando vai falhar.
Consulte opções de busca para mais informações sobre o controle de busca.
Layout do diretório
Depois de buscado, o repositório pode ser encontrado no subdiretório external
na base de saída, com o nome canônico.
Execute o comando a seguir para conferir 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, 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 à dos arquivos BUILD
, exceto que nenhuma instrução load
é compatível, e apenas uma única função, repo()
, está disponível. repo()
usa os mesmos argumentos da função package()
em arquivos BUILD
. Enquanto package()
especifica atributos comuns para todas as metas de build dentro do pacote, repo()
faz o mesmo para todas as metas de build dentro do repositório.
Por exemplo, é possível especificar uma licença comum para todas as metas no seu repositório
com o seguinte arquivo REPO.bazel
:
repo(
default_package_metadata = ["//:my_license"],
)
Gerenciar dependências externas com o Bzlmod
O 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 repositórios de acordo.
Um módulo do Bazel é um projeto do Bazel que pode ter várias
versões, cada uma delas publicando 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, declarando o nome, a versão, a lista de dependências e outras informações. Confira 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 só pode listar as dependências diretas, que o Bzlmod pesquisa em um registro do Bazel. Por padrão, o Registro central do Bazel. O registro fornece os arquivos MODULE.bazel
das dependências, o que permite que o Bazel descubra todo o gráfico de dependência transitiva antes de realizar a resolução de 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 partes personalizadas de dados chamadas tags, que são consumidas pelas extensões de módulo após a resolução do módulo para definir repositórios adicionais. Essas extensões têm recursos semelhantes às regras de repositório, permitindo que elas 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, respeitando o gráfico de dependência criado com módulos do Bazel.
Links externos no Bzlmod
- Exemplos de uso do Bzlmod em bazelbuild/examples
- Revisão das dependências externas do Bazel (documento de design original do Bzlmod)
- Palestra da BazelCon 2021 sobre Bzlmod
- Palestra do dia da comunidade do Bazel sobre o 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 aos arquivos
BUILD
, usando regras de repositório em vez de regras de build.
O snippet a seguir é um exemplo de uso da 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 cujo nome canônico é foo
. No sistema WORKSPACE
, por padrão, o nome canônico de um repositório também é o nome aparente para todos os outros repositórios.
Confira a lista completa de funções disponíveis em arquivos
WORKSPACE
.
Deficiências do sistema WORKSPACE
Nos anos desde que o sistema WORKSPACE
foi introduzido, os usuários relataram muitos pontos fracos, 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
definem uma macro que, por sua vez, define vários repositórios e pede aos usuários que
chamem essa macro nos arquivos
WORKSPACE
.- Isso tem problemas próprios: as macros não podem
load
outros arquivos.bzl
. Portanto, esses projetos precisam definir as dependências transitivas na macro "deps" ou contornar o 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 problemas próprios: as macros não podem
Devido às limitações do WORKSPACE, o Bzlmod vai substituir o sistema legado do WORKSPACE em versões futuras do Bazel. Leia o guia de migração do Bzlmod (em inglês) para saber como migrar para o Bzlmod.