Visão geral das dependências externas

Informar um problema Ver código-fonte

O Bazel é compatível com dependências externas, arquivos de origem (de texto e binários) usados na sua versão 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 tradicional sistema WORKSPACE com foco no repositório e o sistema MODULE.bazel mais recente com foco no módulo (com o codinome Bzlmod e ativado com a sinalização --enable_bzlmod). Os dois sistemas podem ser usados juntos, mas o Bzlmod está substituindo o WORKSPACE em versões futuras do Bazel. Consulte o guia de migração do Bzlmod.

Neste documento, explicamos os conceitos relacionados ao gerenciamento de dependências externas no Bazel antes de falar um pouco mais sobre os dois sistemas em ordem.

conceitos

Repositório

Um diretório com um arquivo WORKSPACE ou WORKSPACE.bazel, contendo arquivos de origem a serem usados em uma versão do Bazel. Geralmente reduzido para apenas repo.

Repositório principal

O repositório em que o comando atual do Bazel está sendo executado.

Espaço de trabalho

O ambiente compartilhado por todos os comandos do Bazel é executado no mesmo repositório principal.

Historicamente, os conceitos de "repositório" e "espaço de trabalho" foram confundidos. O termo "espaço de trabalho" tem sido frequentemente usado para se referir ao repositório principal e, às vezes, até mesmo como sinônimo de "repositório".

Nome do repositório canônico

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 dentro de 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 o nome canônico.

Nome do repositório aparente

O nome pelo qual um repositório pode ser endereçado no contexto de um determinado outro repositório. Isso pode ser considerado um "apelido" de um repositório: o repo 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 repo bob. Nesse caso, um destino dentro de 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 de "nome do repositório aparente" para um "nome do 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 "fazer o download de um arquivo ZIP de um determinado URL e extraí-lo", "buscar um determinado artefato Maven e disponibilizá-lo como um destino java_import" ou simplesmente "vincular um diretório local". Cada repo é definido chamando uma regra de repo com um número apropriado de argumentos.

Consulte Regras de repositório para mais informações sobre como escrever suas próprias regras de repositório.

As regras de repositório mais comuns são http_archive, que faz o download de um arquivo de um URL e o extrai, e local_repository, que vincula um diretório local que já é um repositório do Bazel.

Buscar um repositório

A ação de disponibilizar um repo no disco local executando a regra de repo associada a ele. 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 repo quando precisa de algo do repo, e o repo 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.

Layout do diretório

Depois de ser buscado, o repo pode ser encontrado no subdiretório external na base de saída, sob seu nome canônico.

É possível executar o seguinte comando para ver o conteúdo do repo com o nome canônico canonical_name:

ls $(bazel info output_base)/external/ canonical_name 

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 de módulos, executa extensões sobre o gráfico e define os repositórios de acordo.

Um módulo do Bazel é um projeto do Bazel que pode ter várias versões, cada uma publicando metadados sobre outros módulos dos quais 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. Veja 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 do Bazel (por padrão, o Bazel Central Registry). O registro fornece os arquivos MODULE.bazel das dependências, permitindo que o Bazel descubra todo o gráfico de dependências transitivas antes de executar 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 dados personalizados chamados de tags, que são consumidos por 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 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ências criado a partir de módulos do Bazel.

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, empregando regras de repositório em vez de regras de criação.

O snippet a seguir é um exemplo para 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 o nome canônico foo. No sistema WORKSPACE, por padrão, o nome canônico de um repo também é seu nome aparente para todos os outros repositórios.

Veja a lista completa das funções disponíveis nos arquivos WORKSPACE.

Falhas do sistema WORKSPACE

Nos anos seguintes à introdução do sistema WORKSPACE, os usuários relataram muitas dificuldades, incluindo:

  • O Bazel não avalia os arquivos WORKSPACE de nenhuma dependência. Portanto, todas as dependências transitivas precisam ser definidas no arquivo WORKSPACE do repo principal, além das dependências diretas.
  • Para contornar esse problema, os projetos adotaram o padrão "deps.bzl", em que definem uma macro que, por sua vez, define vários repositórios, e pedem aos usuários que chamem essa macro nos arquivos WORKSPACE.
    • Isso tem seus próprios problemas: as macros não podem usar load em outros arquivos .bzl. Portanto, esses projetos precisam definir as dependências transitivas nessa macro "deps" ou solucionar esse problema fazendo com que o usuário chame macros "deps" de várias camadas.
    • O Bazel avalia o arquivo WORKSPACE sequencialmente. Além disso, as dependências são especificadas usando http_archive com URLs, sem informações de versão. Isso significa que não há uma maneira confiável de executar a resolução de versão no caso de dependências de diamante (A depende de B e C; B e C dependem de versões diferentes de D).

Devido às limitações do WORKSPACE, o Bzlmod substituirá o sistema legado WORKSPACE nas próximas versões do Bazel. Leia o guia de migração do Bzlmod (em inglês) para saber como migrar para o Bzlmod.