Guia de migração do Bzlmod

Informar um problema Ver fonte Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Devido às deficiências do WORKSPACE, o Bzlmod está substituindo o sistema WORKSPACE legado. O arquivo WORKSPACE já está desativado no Bazel 8 (final de 2024) e será removido no Bazel 9 (final de 2025). Este guia ajuda você a migrar seu projeto para o Bzlmod e remover o WORKSPACE para gerenciar dependências externas.

Por que migrar para o Bzlmod?

  • Há muitas vantagens em comparação com o sistema WORKSPACE legado, o que ajuda a garantir um crescimento saudável do ecossistema do Bazel.

  • Se o projeto for uma dependência de outros projetos, a migração para o Bzlmod vai desbloquear a migração deles e facilitar a dependência do seu projeto.

  • A migração para o Bzlmod é uma etapa necessária para usar versões futuras do Bazel (obrigatório no Bazel 9).

Como migrar para o Bzlmod?

Processo de migração recomendado:

  1. Use a ferramenta de migração para simplificar ao máximo o processo. Confira as seções ferramenta de migração e como usar a ferramenta.
  2. Se ainda houver erros depois de usar a ferramenta de migração, resolva-os manualmente. Para entender as principais diferenças entre os conceitos nos arquivos WORKSPACE e MODULE.bazel, consulte a seção WORKSPACE versus Bzlmod.

Ferramenta de migração

Para simplificar o processo, muitas vezes complexo, de migração do WORKSPACE para o Bzlmod, é altamente recomendável usar o script de migração. Essa ferramenta auxiliar automatiza muitas das etapas envolvidas na migração do seu sistema externo de gerenciamento de dependências.

Funcionalidade principal

As principais funções do script são:

  • Coleta de informações de dependência:analisa o arquivo WORKSPACE do projeto para identificar repositórios externos usados por destinos de build especificados. Ele usa a flag experimental_repository_resolved_file do Bazel para gerar um arquivo resolved_deps.py com essas informações.
  • Identificação de dependência direta:usa bazel query para determinar quais repositórios são dependências diretas para os destinos especificados.
  • Migração do Bzlmod:traduz as dependências WORKSPACE relevantes para os equivalentes do Bzlmod. Esse processo é realizado em duas etapas:
    1. Tenta introduzir todas as dependências diretas identificadas no arquivo MODULE.bazel.
    2. Tenta criar os destinos especificados com o Bzlmod ativado e, em seguida, identifica e corrige erros reconhecíveis de forma iterativa. Essa etapa é necessária porque algumas dependências podem estar faltando na primeira etapa.
  • Geração de relatórios de migração:cria um arquivo migration_info.md que documenta o processo de migração. Esse relatório inclui uma lista de dependências diretas, as declarações Bzlmod geradas e as etapas manuais que podem ser necessárias para concluir a migração.

A ferramenta de migração é compatível com:

  • Dependências disponíveis no registro central do Bazel
  • Regras personalizadas do repositório definidas pelo usuário
  • [Em breve] Dependências do gerenciador de pacotes

Observação importante: a ferramenta de migração é um utilitário que faz o melhor possível. Sempre verifique se as recomendações estão corretas.

Como usar a ferramenta de migração

Antes de começar:

  • Faça upgrade para a versão mais recente do Bazel 7, que oferece suporte robusto para WORKSPACE e Bzlmod.
  • Verifique se o seguinte comando é executado corretamente para os principais destinos de build do projeto:

    bazel build --nobuild --enable_workspace --noenable_bzlmod <targets>
    

Depois que os pré-requisitos forem atendidos, execute os comandos a seguir para usar a ferramenta de migração:

# Clone the Bazel Central Registry repository
git clone https://github.com/bazelbuild/bazel-central-registry.git
cd bazel-central-registry

# Build the migration tool
bazel build //tools:migrate_to_bzlmod

# Create a convenient alias for the tool
alias migrate2bzlmod=$(realpath ./bazel-bin/tools/migrate_to_bzlmod)

# Navigate to your project's root directory and run the tool
cd <your workspace root>
migrate2bzlmod -t <your build targets>

WORKSPACE x Bzlmod

O WORKSPACE e o Bzlmod do Bazel oferecem recursos semelhantes com sintaxes diferentes. Esta seção explica como migrar de funcionalidades específicas do WORKSPACE para o Bzlmod.

Definir a raiz de um espaço de trabalho do Bazel

O arquivo WORKSPACE marca a raiz de origem de um projeto do Bazel. Essa responsabilidade é substituída por MODULE.bazel na versão 6.3 e mais recentes do Bazel. Com versões do Bazel anteriores à 6.3, ainda deve haver um arquivo WORKSPACE ou WORKSPACE.bazel na raiz do espaço de trabalho, talvez com comentários como:

  • WORKSPACE

    # This file marks the root of the Bazel workspace.
    # See MODULE.bazel for external dependencies setup.
    

Ativar o Bzlmod no seu bazelrc

Com .bazelrc, é possível definir flags que são aplicadas sempre que você executa o Bazel. Para ativar o Bzlmod, use a flag --enable_bzlmod e aplique-a ao comando common para que ela seja aplicada a todos os comandos:

  • .bazelrc

    # Enable Bzlmod for every Bazel command
    common --enable_bzlmod
    

Especificar o nome do repositório para seu espaço de trabalho

  • WORKSPACE

    A função workspace é usada para especificar um nome de repositório para seu espaço de trabalho. Isso permite que um //foo:bar de destino no espaço de trabalho seja referenciado como @<workspace name>//foo:bar. Se não for especificado, o nome padrão do repositório para seu espaço de trabalho será __main__.

    ## WORKSPACE
    workspace(name = "com_foo_bar")
    
  • Bzlmod

    Recomendamos referenciar destinos no mesmo espaço de trabalho com a sintaxe //foo:bar sem @<repo name>. Mas, se você precisar da sintaxe antiga , use o nome do módulo especificado pela função module como o nome do repositório. Se o nome do módulo for diferente do nome do repositório necessário, use o atributo repo_name da função module para substituir o nome do repositório.

    ## MODULE.bazel
    module(
        name = "bar",
        repo_name = "com_foo_bar",
    )
    

Buscar dependências externas como módulos do Bazel

Se a sua dependência for um projeto do Bazel, você poderá depender dela como um módulo do Bazel quando ela também adotar o Bzlmod.

  • WORKSPACE

    Com o WORKSPACE, é comum usar as regras de repositório http_archive ou git_repository para baixar as fontes do projeto Bazel.

    ## WORKSPACE
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    
    http_archive(
        name = "bazel_skylib",
        urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz"],
        sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa",
    )
    load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
    bazel_skylib_workspace()
    
    http_archive(
        name = "rules_java",
        urls = ["https://github.com/bazelbuild/rules_java/releases/download/6.1.1/rules_java-6.1.1.tar.gz"],
        sha256 = "76402a50ae6859d50bd7aed8c1b8ef09dae5c1035bb3ca7d276f7f3ce659818a",
    )
    load("@rules_java//java:repositories.bzl", "rules_java_dependencies", "rules_java_toolchains")
    rules_java_dependencies()
    rules_java_toolchains()
    

    Como você pode ver, é um padrão comum que os usuários precisem carregar dependências transitivas de uma macro da dependência. Suponha que bazel_skylib e rules_java dependam de platform. A versão exata da dependência platform é determinada pela ordem das macros.

  • Bzlmod

    Com o Bzlmod, desde que sua dependência esteja disponível no Registro central do Bazel ou no registro do Bazel personalizado, basta depender dela com uma diretiva bazel_dep.

    ## MODULE.bazel
    bazel_dep(name = "bazel_skylib", version = "1.4.2")
    bazel_dep(name = "rules_java", version = "6.1.1")
    

    O Bzlmod resolve as dependências de módulos do Bazel de maneira transitiva usando o algoritmo MVS. Portanto, a versão máxima necessária de platform é selecionada automaticamente.

Substituir uma dependência como um módulo do Bazel

Como módulo raiz, é possível substituir as dependências do módulo do Bazel de diferentes maneiras.

Leia a seção Substituições para mais informações.

Confira alguns exemplos de uso no repositório examples.

Buscar dependências externas com extensões de módulo

Se a dependência não for um projeto do Bazel ou ainda não estiver disponível em nenhum registro do Bazel, use use_repo_rule ou extensões de módulo.

  • WORKSPACE

    Faça o download de um arquivo usando a regra de repositório http_file.

    ## WORKSPACE
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
    
    http_file(
        name = "data_file",
        url = "http://example.com/file",
        sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    )
    
  • Bzlmod

    Com o Bzlmod, é possível usar a diretiva use_repo_rule no arquivo MODULE.bazel para instanciar repositórios diretamente:

    ## MODULE.bazel
    http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
    http_file(
        name = "data_file",
        url = "http://example.com/file",
        sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    )
    

    Em segundo plano, isso é implementado usando uma extensão de módulo. Se você precisar realizar uma lógica mais complexa do que simplesmente invocar uma regra de repositório, também poderá implementar uma extensão de módulo por conta própria. Você precisará mover a definição para um arquivo .bzl, que também permite compartilhar a definição entre WORKSPACE e Bzlmod durante o período de migração.

    ## repositories.bzl
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
    def my_data_dependency():
        http_file(
            name = "data_file",
            url = "http://example.com/file",
            sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        )
    

    Implemente uma extensão de módulo para carregar a macro de dependências. É possível definir no mesmo arquivo .bzl da macro, mas para manter a compatibilidade com versões mais antigas do Bazel, é melhor definir em um arquivo .bzl separado.

    ## extensions.bzl
    load("//:repositories.bzl", "my_data_dependency")
    def _non_module_dependencies_impl(_ctx):
        my_data_dependency()
    
    non_module_dependencies = module_extension(
        implementation = _non_module_dependencies_impl,
    )
    

    Para tornar o repositório visível ao projeto raiz, declare os usos da extensão do módulo e do repositório no arquivo MODULE.bazel.

    ## MODULE.bazel
    non_module_dependencies = use_extension("//:extensions.bzl", "non_module_dependencies")
    use_repo(non_module_dependencies, "data_file")
    

Resolver conflitos de dependências externas com extensão de módulo

Um projeto pode fornecer uma macro que introduz repositórios externos com base em entradas dos chamadores. Mas e se houver vários chamadores no gráfico de dependência e eles causarem um conflito?

Suponha que o projeto foo forneça a seguinte macro, que usa version como argumento.

## repositories.bzl in foo {:#repositories.bzl-foo}
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
def data_deps(version = "1.0"):
    http_file(
        name = "data_file",
        url = "http://example.com/file-%s" % version,
        # Omitting the "sha256" attribute for simplicity
    )
  • WORKSPACE

    Com o WORKSPACE, é possível carregar a macro de @foo e especificar a versão da dependência de dados necessária. Suponha que você tenha outra dependência @bar, que também depende de @foo, mas exige uma versão diferente da dependência de dados.

    ## WORKSPACE
    
    # Introduce @foo and @bar.
    ...
    
    load("@foo//:repositories.bzl", "data_deps")
    data_deps(version = "2.0")
    
    load("@bar//:repositories.bzl", "bar_deps")
    bar_deps() # -> which calls data_deps(version = "3.0")
    

    Nesse caso, o usuário final precisa ajustar cuidadosamente a ordem das macros no WORKSPACE para receber a versão necessária. Esse é um dos maiores problemas do WORKSPACE, já que ele não oferece uma maneira sensata de resolver dependências.

  • Bzlmod

    Com o Bzlmod, o autor do projeto foo pode usar a extensão do módulo para resolver conflitos. Por exemplo, suponha que sempre faça sentido selecionar a versão máxima necessária da dependência de dados entre todos os módulos do Bazel.

    ## extensions.bzl in foo
    load("//:repositories.bzl", "data_deps")
    
    data = tag_class(attrs={"version": attr.string()})
    
    def _data_deps_extension_impl(module_ctx):
        # Select the maximal required version in the dependency graph.
        version = "1.0"
        for mod in module_ctx.modules:
            for data in mod.tags.data:
                version = max(version, data.version)
        data_deps(version)
    
    data_deps_extension = module_extension(
        implementation = _data_deps_extension_impl,
        tag_classes = {"data": data},
    )
    
    ## MODULE.bazel in bar
    bazel_dep(name = "foo", version = "1.0")
    
    foo_data_deps = use_extension("@foo//:extensions.bzl", "data_deps_extension")
    foo_data_deps.data(version = "3.0")
    use_repo(foo_data_deps, "data_file")
    
    ## MODULE.bazel in root module
    bazel_dep(name = "foo", version = "1.0")
    bazel_dep(name = "bar", version = "1.0")
    
    foo_data_deps = use_extension("@foo//:extensions.bzl", "data_deps_extension")
    foo_data_deps.data(version = "2.0")
    use_repo(foo_data_deps, "data_file")
    

    Nesse caso, o módulo raiz exige a versão 2.0 dos dados, enquanto a dependência bar exige 3.0. A extensão do módulo em foo pode resolver esse conflito corretamente e selecionar automaticamente a versão 3.0 para a dependência de dados.

Integrar um gerenciador de pacotes de terceiros

Seguindo a última seção, como a extensão do módulo oferece uma maneira de coletar informações do gráfico de dependências, execute uma lógica personalizada para resolver dependências e chame regras de repositório para introduzir repositórios externos. Isso oferece uma ótima maneira para os autores de regras aprimorarem os conjuntos de regras que integram gerenciadores de pacotes para linguagens específicas.

Leia a página extensões de módulo para saber mais sobre como usar extensões de módulo.

Confira uma lista dos conjuntos de regras que já adotaram o Bzlmod para buscar dependências de diferentes gerenciadores de pacotes:

Um exemplo mínimo que integra um gerenciador de pseudopacotes está disponível no repositório examples.

Detectar toolchains na máquina host

Quando as regras de build do Bazel precisam detectar quais toolchains estão disponíveis na sua máquina host, elas usam regras de repositório para inspecionar a máquina host e gerar informações de toolchain como repositórios externos.

  • WORKSPACE

    Considere a seguinte regra de repositório para detectar um conjunto de ferramentas de shell.

    ## local_config_sh.bzl
    def _sh_config_rule_impl(repository_ctx):
        sh_path = get_sh_path_from_env("SH_BIN_PATH")
    
        if not sh_path:
            sh_path = detect_sh_from_path()
    
        if not sh_path:
            sh_path = "/shell/binary/not/found"
    
        repository_ctx.file("BUILD", """
    load("@bazel_tools//tools/sh:sh_toolchain.bzl", "sh_toolchain")
    sh_toolchain(
        name = "local_sh",
        path = "{sh_path}",
        visibility = ["//visibility:public"],
    )
    toolchain(
        name = "local_sh_toolchain",
        toolchain = ":local_sh",
        toolchain_type = "@bazel_tools//tools/sh:toolchain_type",
    )
    """.format(sh_path = sh_path))
    
    sh_config_rule = repository_rule(
        environ = ["SH_BIN_PATH"],
        local = True,
        implementation = _sh_config_rule_impl,
    )
    

    Você pode carregar a regra do repositório no WORKSPACE.

    ## WORKSPACE
    load("//:local_config_sh.bzl", "sh_config_rule")
    sh_config_rule(name = "local_config_sh")
    
  • Bzlmod

    Com o Bzlmod, é possível introduzir o mesmo repositório usando uma extensão de módulo, que é semelhante à introdução do repositório @data_file na última seção.

    ## local_config_sh_extension.bzl
    load("//:local_config_sh.bzl", "sh_config_rule")
    
    sh_config_extension = module_extension(
        implementation = lambda ctx: sh_config_rule(name = "local_config_sh"),
    )
    

    Em seguida, use a extensão no arquivo MODULE.bazel.

    ## MODULE.bazel
    sh_config_ext = use_extension("//:local_config_sh_extension.bzl", "sh_config_extension")
    use_repo(sh_config_ext, "local_config_sh")
    

Registrar toolchains e plataformas de execução

Seguindo a última seção, depois de apresentar informações sobre uma cadeia de ferramentas de hospedagem de repositório (por exemplo, local_config_sh), provavelmente você vai querer registrar a cadeia de ferramentas.

  • WORKSPACE

    Com WORKSPACE, é possível registrar a cadeia de ferramentas das seguintes maneiras.

    1. É possível registrar o conjunto de ferramentas no arquivo .bzl e carregar a macro no arquivo WORKSPACE.

      ## local_config_sh.bzl
      def sh_configure():
          sh_config_rule(name = "local_config_sh")
          native.register_toolchains("@local_config_sh//:local_sh_toolchain")
      
      ## WORKSPACE
      load("//:local_config_sh.bzl", "sh_configure")
      sh_configure()
      
    2. Ou registre o conjunto de ferramentas diretamente no arquivo WORKSPACE.

      ## WORKSPACE
      load("//:local_config_sh.bzl", "sh_config_rule")
      sh_config_rule(name = "local_config_sh")
      register_toolchains("@local_config_sh//:local_sh_toolchain")
      
  • Bzlmod

    Com o Bzlmod, as APIs register_toolchains e register_execution_platforms estão disponíveis apenas no arquivo MODULE.bazel. Não é possível chamar native.register_toolchains em uma extensão de módulo.

    ## MODULE.bazel
    sh_config_ext = use_extension("//:local_config_sh_extension.bzl", "sh_config_extension")
    use_repo(sh_config_ext, "local_config_sh")
    register_toolchains("@local_config_sh//:local_sh_toolchain")
    

As toolchains e plataformas de execução registradas em WORKSPACE, WORKSPACE.bzlmod e no arquivo MODULE.bazel de cada módulo do Bazel seguem esta ordem de precedência durante a seleção de toolchain (da mais alta à mais baixa):

  1. toolchains e plataformas de execução registradas no arquivo MODULE.bazel do módulo raiz.
  2. toolchains e plataformas de execução registradas no arquivo WORKSPACE ou WORKSPACE.bzlmod.
  3. toolchains e plataformas de execução registradas por módulos que são dependências (transitivas) do módulo raiz.
  4. quando não usar WORKSPACE.bzlmod: toolchains registradas no sufixo de WORKSPACE.

Apresentar repositórios locais

Talvez seja necessário introduzir uma dependência como um repositório local quando você precisar de uma versão local da dependência para depuração ou quiser incorporar um diretório no seu espaço de trabalho como um repositório externo.

  • WORKSPACE

    Com WORKSPACE, isso é feito por duas regras de repositório nativas, local_repository e new_local_repository.

    ## WORKSPACE
    local_repository(
        name = "rules_java",
        path = "/Users/bazel_user/workspace/rules_java",
    )
    
  • Bzlmod

    Com o Bzlmod, é possível usar local_path_override para substituir um módulo por um caminho local.

    ## MODULE.bazel
    bazel_dep(name = "rules_java")
    local_path_override(
        module_name = "rules_java",
        path = "/Users/bazel_user/workspace/rules_java",
    )
    

    Também é possível introduzir um repositório local com extensão de módulo. No entanto, não é possível chamar native.local_repository na extensão do módulo. Há um esforço contínuo para starlarkificar todas as regras de repositório nativas. Confira #18285 para acompanhar o progresso. Em seguida, chame o local_repository correspondente do Starlark em uma extensão de módulo. Também é trivial implementar uma versão personalizada da regra de repositório local_repository se esse for um problema de bloqueio para você.

Vincular destinos

A regra bind no WORKSPACE foi descontinuada e não é compatível com o Bzlmod. Ele foi introduzido para dar a um destino um alias no pacote especial //external. Todos os usuários que dependem disso precisam migrar.

Por exemplo, se você tiver

## WORKSPACE
bind(
    name = "openssl",
    actual = "@my-ssl//src:openssl-lib",
)

Isso permite que outros destinos dependam de //external:openssl. Para migrar dessa situação, faça o seguinte:

  • Substitua todos os usos de //external:openssl por @my-ssl//src:openssl-lib.

    • Dica: use o comando bazel query --output=build --noenable_bzlmod --enable_workspace [target] para encontrar informações relevantes sobre o destino.
  • Ou use a regra de build alias

    • Defina a seguinte meta em um pacote (por exemplo, //third_party):

      ## third_party/BUILD
      alias(
          name = "openssl",
          actual = "@my-ssl//src:openssl-lib",
      )
      
    • Substitua todos os usos de //external:openssl por //third_party:openssl.

Buscar x sincronizar

Os comandos de busca e sincronização são usados para fazer o download de repositórios externos localmente e mantê-los atualizados. Às vezes, também para permitir a criação off-line usando a flag --nofetch depois de buscar todos os repositórios necessários para uma build.

  • WORKSPACE

    A sincronização faz uma busca forçada de todos os repositórios ou de um conjunto específico de repositórios configurados, enquanto a busca é usada apenas para buscar um destino específico.

  • Bzlmod

    O comando de sincronização não é mais aplicável, mas a busca oferece várias opções. É possível buscar um destino, um repositório, um conjunto de repositórios configurados ou todos os repositórios envolvidos na resolução de dependências e extensões de módulo. O resultado da busca é armazenado em cache. Para forçar uma busca, inclua a opção --force durante o processo.

Migração manual

Esta seção fornece informações e orientações úteis para o processo de migração manual do Bzlmod. Para um processo de migração mais automatizado, consulte a seção processo de migração recomendado.

Conheça suas dependências no WORKSPACE

A primeira etapa da migração é entender quais dependências você tem. Pode ser difícil descobrir quais dependências exatas são introduzidas no arquivo WORKSPACE porque as dependências transitivas geralmente são carregadas com macros *_deps.

Inspecionar dependência externa com arquivo resolvido do espaço de trabalho

Felizmente, a flag --experimental_repository_resolved_file pode ajudar. Essa flag gera essencialmente um "arquivo de bloqueio" de todas as dependências externas buscadas no último comando do Bazel. Confira mais detalhes nesta postagem do blog.

Ele pode ser usado de duas maneiras:

  1. Para buscar informações de dependências externas necessárias para criar determinados destinos.

    bazel clean --expunge
    bazel build --nobuild --experimental_repository_resolved_file=resolved.bzl //foo:bar
    
  2. Para buscar informações de todas as dependências externas definidas no arquivo WORKSPACE.

    bazel clean --expunge
    bazel sync --experimental_repository_resolved_file=resolved.bzl
    

    Com o comando bazel sync, é possível buscar todas as dependências definidas no arquivo WORKSPACE, incluindo:

    • Usos do bind
    • Usos de register_toolchains e register_execution_platforms

    No entanto, se o projeto for multiplataforma, a sincronização do Bazel poderá falhar em determinadas plataformas porque algumas regras de repositório só funcionam corretamente em plataformas compatíveis.

Depois de executar o comando, você terá informações sobre suas dependências externas no arquivo resolved.bzl.

Inspecionar dependência externa com bazel query

Você também pode usar bazel query para inspecionar regras de repositório com

bazel query --output=build //external:<repo name>

Embora seja mais conveniente e muito mais rápido, bazel query pode mentir sobre a versão da dependência externa, então tenha cuidado ao usar! A consulta e a inspeção de dependências externas com o Bzlmod serão feitas com um novo subcomando.

Dependências padrão integradas

Se você verificar o arquivo gerado por --experimental_repository_resolved_file, vai encontrar muitas dependências que não estão definidas no WORKSPACE. Isso acontece porque o Bazel adiciona prefixos e sufixos ao conteúdo do arquivo WORKSPACE do usuário para injetar algumas dependências padrão, que geralmente são exigidas por regras nativas (por exemplo, @bazel_tools, @platforms e @remote_java_tools). Com o Bzlmod, essas dependências são introduzidas com um módulo integrado bazel_tools, que é uma dependência padrão para todos os outros módulos do Bazel.

Modo híbrido para migração gradual

O Bzlmod e o WORKSPACE podem trabalhar lado a lado, o que permite que a migração de dependências do arquivo WORKSPACE para o Bzlmod seja um processo gradual.

WORKSPACE.bzlmod

Durante a migração, os usuários do Bazel talvez precisem alternar entre builds com e sem o Bzlmod ativado. O suporte a WORKSPACE.bzlmod é implementado para facilitar o processo.

WORKSPACE.bzlmod tem exatamente a mesma sintaxe que WORKSPACE. Quando o Bzlmod está ativado, se um arquivo WORKSPACE.bzlmod também existir na raiz do espaço de trabalho:

  • WORKSPACE.bzlmod entra em vigor, e o conteúdo de WORKSPACE é ignorado.
  • Nenhum prefixo ou sufixo é adicionado ao arquivo WORKSPACE.bzlmod.

Usar o arquivo WORKSPACE.bzlmod pode facilitar a migração porque:

  • Quando o Bzlmod está desativado, você volta a buscar dependências do arquivo WORKSPACE original.
  • Quando o Bzlmod está ativado, é possível acompanhar melhor quais dependências ainda precisam ser migradas com WORKSPACE.bzlmod.

Visibilidade do repositório

O Bzlmod pode controlar quais outros repositórios ficam visíveis em um determinado repositório. Confira nomes de repositório e dependências estritas para mais detalhes.

Confira um resumo das visibilidades de repositórios de diferentes tipos de repositórios, considerando também o WORKSPACE.

Do repositório principal Dos repositórios de módulos do Bazel De repositórios de extensão de módulo Dos repositórios do WORKSPACE
O repositório principal Visível Se o módulo raiz for uma dependência direta Se o módulo raiz for uma dependência direta do módulo que hospeda a extensão do módulo Visível
Repositórios de módulos do Bazel Dependências diretas Dependências diretas Dependências diretas do módulo que hospeda a extensão do módulo Dependências diretas do módulo raiz
Repositórios de extensão de módulo Dependências diretas Dependências diretas Dependências diretas do módulo que hospeda a extensão do módulo + todos os repositórios gerados pela mesma extensão do módulo Dependências diretas do módulo raiz
Repositórios do WORKSPACE Todos visíveis Não visível Não visível Todos visíveis

Processo de migração manual

Um processo típico de migração do Bzlmod pode ser assim:

  1. Entenda quais dependências você tem no WORKSPACE.
  2. Adicione um arquivo MODULE.bazel vazio na raiz do projeto.
  3. Adicione um arquivo WORKSPACE.bzlmod vazio para substituir o conteúdo do arquivo WORKSPACE.
  4. Crie seus destinos com o Bzlmod ativado e verifique qual repositório está faltando.
  5. Verifique a definição do repositório ausente no arquivo de dependência resolvido.
  6. Introduza a dependência ausente como um módulo do Bazel, usando uma extensão de módulo, ou deixe-a no WORKSPACE.bzlmod para migração posterior.
  7. Volte para a etapa 4 e repita até que todas as dependências estejam disponíveis.

Publicar módulos do Bazel

Se o projeto do Bazel for uma dependência de outros projetos, você poderá publicá-lo no Registro central do Bazel.

Para fazer check-in do seu projeto no BCR, você precisa de um URL de arquivo de origem do projeto. Ao criar o arquivo de origem, observe alguns pontos:

  • Verifique se o arquivo está apontando para uma versão específica.

    O BCR só pode aceitar arquivos de origem com versão porque o Bzlmod precisa fazer a comparação de versões durante a resolução de dependências.

  • Verifique se o URL do arquivo estável.

    O Bazel verifica o conteúdo do arquivo com um valor de hash. Portanto, verifique se o checksum do arquivo baixado nunca muda. Se o URL for do GitHub, crie e faça upload de um arquivo de lançamento na página de lançamento. O GitHub não garante o checksum dos arquivos de origem gerados sob demanda. Em resumo, URLs no formato https://github.com/<org>/<repo>/releases/download/... são considerados estáveis enquanto https://github.com/<org>/<repo>/archive/... não é. Confira GitHub Archive Checksum Outage para mais contexto.

  • Verifique se a árvore de origem segue o layout do repositório original.

    Se o repositório for muito grande e você quiser criar um arquivo de distribuição com tamanho reduzido removendo fontes desnecessárias, verifique se a árvore de origem removida é um subconjunto da árvore de origem original. Isso facilita a substituição do módulo por uma versão não lançada pelos usuários finais usando archive_override e git_override.

  • Inclua um módulo de teste em um subdiretório que teste suas APIs mais comuns.

    Um módulo de teste é um projeto do Bazel com arquivos WORKSPACE e MODULE.bazel localizados em um subdiretório do arquivo de origem que depende do módulo real a ser publicado. Ele precisa conter exemplos ou alguns testes de integração que abrangem as APIs mais comuns. Consulte o módulo de teste para saber como configurar.

Quando o URL do arquivo de origem estiver pronto, siga as diretrizes de contribuição da BCR para enviar seu módulo à BCR com uma solicitação de pull do GitHub.

É altamente recomendável configurar o app do GitHub Publish to BCR para seu repositório e automatizar o processo de envio do módulo ao BCR.

Práticas recomendadas

Esta seção documenta algumas práticas recomendadas para gerenciar melhor suas dependências externas.

Divida os destinos em pacotes diferentes para evitar buscar dependências desnecessárias.

Confira #12835, em que as dependências de desenvolvimento para testes são buscadas desnecessariamente para criar destinos que não precisam delas. Isso não é específico do Bzlmod, mas seguir essas práticas facilita a especificação correta das dependências de desenvolvimento.

Especificar dependências de desenvolvimento

É possível definir o atributo dev_dependency como verdadeiro para as diretivas bazel_dep e use_extension para que elas não sejam propagadas para projetos dependentes. Como módulo raiz, você pode usar a flag --ignore_dev_dependency para verificar se seus destinos ainda são criados sem dependências de desenvolvimento e substituições.

Progresso da migração da comunidade

Confira o Registro central do Bazel para saber se as dependências já estão disponíveis. Caso contrário, participe desta discussão no GitHub para votar ou postar as dependências que estão bloqueando sua migração.

Informar problemas

Confira a lista de problemas do Bazel no GitHub para ver problemas conhecidos do Bzlmod. Fique à vontade para registrar novos problemas ou solicitações de recursos que possam ajudar a desbloquear sua migração.