Como migrar do Xcode para o Bazel

Nesta página, descrevemos como criar ou testar um projeto Xcode com o Bazel. Ele descreve as diferenças entre o Xcode e o Bazel e apresenta as etapas para converter um projeto do Xcode em um projeto do Bazel. Ele também fornece soluções de solução de problemas para resolver erros comuns.

Diferenças entre o Xcode e o Bazel

  • O Bazel exige que você especifique explicitamente cada destino de build e as dependências dele, além das configurações de build correspondentes usando as regras de build.

  • O Bazel exige que todos os arquivos de que o projeto depende estejam presentes no diretório do espaço de trabalho ou sejam especificados como importações no arquivo WORKSPACE.

  • Ao criar projetos do Xcode com o Bazel, os arquivos BUILD se tornam a fonte da verdade. Se você trabalha no projeto no Xcode, é necessário gerar uma nova versão do projeto do Xcode que corresponda aos arquivos BUILD usando rules_xcodeproj sempre que atualizar os arquivos BUILD. Certas mudanças nos arquivos BUILD, como a adição de dependências a um destino, não exigem a regeneração do projeto, o que pode acelerar o desenvolvimento. Se você não estiver usando o Xcode, os comandos bazel build e bazel test vão fornecer recursos de build e teste com algumas limitações descritas mais adiante neste guia.

Antes de começar

Antes de começar, faça o seguinte:

  1. Instale o Bazel se ainda não tiver feito isso.

  2. Se você não conhece o Bazel e os conceitos dele, conclua o tutorial do app iOS. Você precisa entender o espaço de trabalho do Bazel, incluindo os arquivos WORKSPACE e BUILD, bem como os conceitos de destinos, regras de build e pacotes do Bazel.

  3. Analisar e entender as dependências do projeto.

Analisar as dependências do projeto

Ao contrário do Xcode, o Bazel exige que você declare explicitamente todas as dependências de cada destino no arquivo BUILD.

Para mais informações sobre dependências externas, consulte Como trabalhar com dependências externas.

Criar ou testar um projeto do Xcode com o Bazel

Para criar ou testar um projeto do Xcode com o Bazel, faça o seguinte:

  1. Criar o arquivo WORKSPACE

  2. (Experimental) Integrar dependências do SwiftPM

  3. Crie um arquivo BUILD:

    a. Adicionar o aplicativo de destino

    b. (Opcional) Adicionar os destinos do teste

    c) Adicionar destinos da biblioteca

  4. (Opcional) Granularizar o build

  5. Executar o build

  6. Gere o projeto Xcode com rules_xcodeproj

Etapa 1: criar o arquivo WORKSPACE

Crie um arquivo WORKSPACE em um novo diretório. Esse diretório se torna a raiz do espaço de trabalho do Bazel. Se o projeto não usa dependências externas, esse arquivo pode estar vazio. Se o projeto depender de arquivos ou pacotes que não estejam em um dos diretórios do projeto, especifique essas dependências externas no arquivo WORKSPACE.

Etapa 2: (experimental) integrar dependências do SwiftPM

Para integrar dependências do SwiftPM ao espaço de trabalho do Bazel com swift_bazel, você precisa convertê-las em pacotes do Bazel, conforme descrito neste tutorial.

Etapa 3: criar um arquivo BUILD

Depois de definir o espaço de trabalho e as dependências externas, você precisa criar um arquivo BUILD que informe ao Bazel como o projeto está estruturado. Crie o arquivo BUILD na raiz do espaço de trabalho do Bazel e configure-o para fazer um build inicial do projeto da seguinte maneira:

Dica:para saber mais sobre pacotes e outros conceitos do Bazel, consulte Espaços de trabalho, pacotes e destinos.

Etapa 3a: adicionar o aplicativo de destino

Adicione um destino de regra macos_application ou ios_application. Esse destino cria um pacote de aplicativos macOS ou iOS, respectivamente. No destino, especifique pelo menos o seguinte:

  • bundle_id: ID do pacote (caminho do DNS reverso seguido pelo nome do app) do binário.

  • provisioning_profile: perfil de provisionamento da sua conta de desenvolvedor da Apple (se estiver criando para um dispositivo iOS).

  • families (somente iOS): se o aplicativo será criado para iPhone, iPad ou ambos.

  • infoplists: lista de arquivos .plist a serem mesclados no arquivo Info.plist final.

  • minimum_os_version: a versão mínima do macOS ou iOS compatível com o aplicativo. Isso garante que o Bazel crie o aplicativo com os níveis corretos de API.

Etapa 3b: adicionar os destinos do teste (opcional)

As regras de build da Apple do Bazel são compatíveis com a execução de testes de unidade e interface em todas as plataformas da Apple. Adicione destinos de teste da seguinte maneira:

  • macos_unit_test para executar testes de unidade baseados em biblioteca e aplicativo em um macOS.

  • ios_unit_test para criar e executar testes de unidade baseados em biblioteca no iOS.

  • ios_ui_test para criar e executar testes de interface do usuário no simulador do iOS.

  • Existem regras de teste semelhantes para tvOS, watchOS e visionOS (todos em inglês).

Especifique no mínimo um valor para o atributo minimum_os_version. Ainda que outros atributos de empacotamento, como bundle_identifier e infoplists, sejam padronizados para os valores mais usados, verifique se esses padrões são compatíveis com o projeto e ajuste-os conforme necessário. Para testes que exigem o simulador de iOS, especifique também o nome de destino ios_application como o valor do atributo test_host.

Etapa 3c: adicionar destinos da biblioteca

Adicione um destino objc_library para cada biblioteca Objective-C e um destino swift_library para cada biblioteca Swift de que o aplicativo e/ou os testes dependem.

Adicione os destinos da biblioteca da seguinte maneira:

  • Adicione os destinos da biblioteca do aplicativo como dependências aos destinos do aplicativo.

  • Adicione os destinos da biblioteca de teste como dependências aos destinos de teste.

  • Liste as origens de implementação no atributo srcs.

  • Liste os cabeçalhos no atributo hdrs.

É possível procurar exemplos atuais de vários tipos de aplicativos diretamente no diretório de exemplos derules_apple. Exemplo:

Para saber mais sobre as regras de build, consulte Regras da Apple para o Bazel.

Neste ponto, é uma boa ideia testar o build:

bazel build //:<application_target>

Etapa 4 (opcional): detalhar o build

Se o projeto for grande ou crescer, considere dividi-lo em vários pacotes do Bazel. Esse aumento de granularidade oferece:

  • Maior incrementabilidade de builds,

  • Maior carregamento em paralelo de tarefas de compilação,

  • Melhor capacidade de manutenção para futuros usuários

  • Melhor controle sobre a visibilidade do código-fonte entre destinos e pacotes. Isso evita que problemas como bibliotecas que contêm detalhes de implementação vazem para APIs públicas.

Dicas para granular o projeto:

  • colocar cada biblioteca no próprio pacote do Bazel. Comece com aqueles que exigem o menor número de dependências e vá subindo na árvore de dependências.

  • À medida que você adicionar arquivos BUILD e especificar destinos, inclua esses novos destinos nos atributos deps dos destinos que dependem deles.

  • A função glob() não ultrapassa os limites dos pacotes. Portanto, conforme o número de pacotes aumenta, os arquivos correspondentes a glob() diminuem.

  • Ao adicionar um arquivo BUILD a um diretório main, adicione também um arquivo BUILD ao diretório test correspondente.

  • Aplique limites de visibilidade íntegros nos pacotes.

  • Crie o projeto após cada alteração importante nos arquivos BUILD e corrija os erros de build à medida que eles forem encontrados.

Etapa 5: executar o build

Execute o build totalmente migrado para garantir que ele seja concluído sem erros ou avisos. Execute cada aplicativo e destino de teste individualmente para encontrar mais facilmente as origens dos erros ocorridos.

Exemplo:

bazel build //:my-target

Etapa 6: gerar o projeto Xcode com rules_xcodeproj

Ao criar com o Bazel, os arquivos WORKSPACE e BUILD se tornam a fonte da verdade sobre o build. Para informar isso ao Xcode, gere um projeto Xcode compatível com o Bazel usando rules_xcodeproj.

Solução de problemas

Os erros do Bazel podem surgir quando ele fica dessincronizado com a versão selecionada do Xcode, como quando você aplica uma atualização. Tente fazer o seguinte se estiver com erros no Xcode. Por exemplo, "A versão do Xcode precisa ser especificada para usar uma CROSSTOOL da Apple".

  • Execute o Xcode manualmente e aceite os Termos e Condições.

  • Use o Xcode select para indicar a versão correta, aceitar a licença e limpar o estado do Bazel.

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license
  bazel sync --configure
  • Se isso não funcionar, tente executar bazel clean --expunge.