Criar programas com o Bazel

Informar um problema Ver código-fonte Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Esta página aborda como criar um programa com o Bazel, a sintaxe do comando de build e a sintaxe do padrão de destino.

Guia de início rápido

Para executar o Bazel, acesse o diretório base workspace. ou qualquer um dos subdiretórios e digite bazel. Consulte criar se você precisar criar um novo espaço de trabalho.

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

Comandos disponíveis

  • analyze-profile: analisa os dados do perfil do build.
  • aquery: executa uma consulta no gráfico de ações pós-análise.
  • build: cria os destinos especificados.
  • canonicalize-flags: canoniza flags do Bazel.
  • clean: remove os arquivos de saída e, opcionalmente, interrompe o servidor.
  • cquery: executa uma consulta de gráfico de dependência de pós-análise.
  • dump: despeja o estado interno do processo do servidor do Bazel.
  • help: mostra a ajuda de comandos ou o índice.
  • info: mostra informações de tempo de execução sobre o servidor do Bazel.
  • fetch: busca todas as dependências externas de um destino.
  • mobile-install: instala apps em dispositivos móveis.
  • query: executa uma consulta de gráfico de dependência.
  • run: executa o destino especificado.
  • shutdown: interrompe o servidor do Bazel.
  • test: cria e executa os destinos de teste especificados.
  • version: imprime informações da versão do Bazel.

Receber ajuda

  • bazel help command: mostra ajuda e opções para command.
  • bazel helpstartup_options: opções para a JVM que hospeda o Bazel.
  • bazel helptarget-syntax: explica a sintaxe para especificar destinos.
  • bazel help info-keys: exibe uma lista de chaves usadas pelo comando info.

A ferramenta bazel executa muitas funções, chamadas comandos. Os métodos as mais usadas são bazel build e bazel test. É possível navegar pelas mensagens de ajuda on-line usando bazel help.

Criando um destino

Antes de iniciar um build, você precisa de um espaço de trabalho. Um espaço de trabalho é uma árvore de diretórios que contém todos os arquivos de origem necessários para criar seu aplicativo. Ele permite executar um build de um modelo volume

Para criar um programa com o Bazel, digite bazel build seguido do target que você quer criar.

bazel build //foo

Depois de emitir o comando para criar //foo, você vai ver uma saída semelhante a esta:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

Primeiro, o Bazel carrega todos os pacotes no gráfico de dependências do destino. Isso inclui dependências declaradas, arquivos listados diretamente no arquivo BUILD do destino. e dependências transitivas, os arquivos listados nos arquivos BUILD da sua de destino. Depois de identificar todas as dependências, o Bazel analisa para fins de correção e cria as ações de build. Por fim, o Bazel executa os compiladores e outras ferramentas do build.

Durante a fase de execução do build, o Bazel imprime mensagens de progresso. O progresso As mensagens incluem a etapa de build atual (como compilador ou vinculador), já que o início e o número de ações concluídas sobre o número total de ações de compilação. À medida que o build começa, o número total de ações geralmente aumenta à medida que o Bazel descobre todo o gráfico de ações, mas o número se estabiliza em alguns segundos.

No final da compilação, o Bazel imprime os destinos solicitados, se isso ocorreu. Os arquivos de saída podem ser encontradas. Os scripts que executam builds podem analisar essa saída de forma confiável. Consulte --show_result para mais detalhes.

Se você digitar o mesmo comando novamente, o build terminará muito mais rápido.

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

Essa é uma versão nula. Como nada mudou, não há pacotes para recarregar e nenhuma etapa de build para executar. Se algo mudar em "foo" ou nas dependências, o Bazel vai executar novamente algumas ações de build ou concluir um build incremental.

Como criar vários destinos

O Bazel permite várias maneiras de especificar os destinos a serem criados. Coletivamente, eles são conhecidos como padrões de destino. Essa sintaxe é usada em comandos como build, test ou query.

Enquanto os rótulos são usados para especificar destinos individuais, como para declarar dependências em arquivos BUILD, os padrões de destino do Bazel especificam vários destinos. Os padrões de segmentação são uma generalização a sintaxe do rótulo para conjuntos de destinos, usando caracteres curinga. No caso mais simples, rótulo válido também é um padrão-alvo válido, identificando um conjunto alvo.

Todos os padrões de destino que começam com // são resolvidos em relação ao atual espaço de trabalho.

//foo/bar:wiz Apenas o //foo/bar:wiz de destino.
//foo/bar É equivalente a //foo/bar:bar.
//foo/bar:all Todos os destinos de regra no pacote foo/bar.
//foo/... Todos os destinos de regras em todos os pacotes abaixo do diretório foo.
//foo/...:all Todos os destinos de regras em todos os pacotes abaixo do diretório foo.
//foo/...:* Todos os destinos (regras e arquivos) em todos os pacotes abaixo do diretório foo.
//foo/...:all-targets Todos os destinos (regras e arquivos) em todos os pacotes abaixo do diretório foo.
//... Todas as segmentações em pacotes no espaço de trabalho. Isso não inclui destinos de repositórios externos.
//:all Todos os destinos no pacote de nível superior, se houver um arquivo `BUILD` no raiz do espaço de trabalho.

Os padrões de destino que não começam com // são resolvidos em relação ao diretório de trabalho atual. Estes exemplos assumem um diretório de trabalho de foo:

:foo Equivalente a //foo:foo.
bar:wiz É equivalente a //foo/bar:wiz.
bar/wiz Equivale a:
  • //foo/bar/wiz:wiz se foo/bar/wiz for um pacote
  • //foo/bar:wiz, se foo/bar for um pacote
  • Caso contrário, //foo:bar/wiz.
bar:all É equivalente a //foo/bar:all.
:all Equivalente a //foo:all.
...:all Equivalente a //foo/...:all.
... É equivalente a //foo/...:all.
bar/...:all Equivalente a //foo/bar/...:all.

Por padrão, os links simbólicos de diretório são seguidos para padrões de destino recursivos, exceto aqueles que apontam para a base de saída, como os links criado no diretório raiz do espaço de trabalho.

Além disso, o Bazel não segue links simbólicos ao avaliar padrões de destino recursivos em qualquer diretório que contenha um arquivo com o seguinte nome: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... é um caractere curinga sobre pacotes, indicando todos os pacotes recursivamente abaixo do diretório foo (para todas as raízes do caminho do pacote). :all é um curinga em alvos, correspondendo a todas as regras em um pacote. Eles podem ser combinados, como em foo/...:all, e quando ambos os caracteres curinga são usados, isso pode ser abreviado para foo/....

Além disso, :* (ou :all-targets) é um caractere curinga que corresponde a cada destino. nos pacotes correspondentes, incluindo arquivos que normalmente não são criados por nenhuma regra, como arquivos _deploy.jar associados a regras java_binary.

Isso implica que :* denota um superconjunto de :all. e possivelmente confusa, essa sintaxe permite que o conhecido caractere curinga :all seja usado para builds típicos, em que a criação de destinos como _deploy.jar não é o ideal.

Além disso, o Bazel permite que uma barra seja usada em vez do dois-pontos necessário pela sintaxe do rótulo. Isso é conveniente ao usar a expansão de nome de arquivo do Bash. Por exemplo, foo/bar/wiz é equivalente a //foo/bar:wiz (se houver um pacote foo/bar) ou a //foo:bar/wiz (se houver um pacote foo).

Muitos comandos do Bazel aceitam uma lista de padrões de destino como argumentos, e todos respeitam o operador de negação de prefixo -. Isso pode ser usado para subtrair um conjunto de destinos do conjunto especificado pelos argumentos anteriores. Isso significa a ordem é importante. Por exemplo,

bazel build foo/... bar/...

significa "criar todos os destinos abaixo de foo e todos os destinos abaixo de bar", enquanto

bazel build -- foo/... -foo/bar/...

significa "criar todos os destinos abaixo de foo exceto aqueles abaixo de foo/bar". O argumento -- é necessário para evitar que os argumentos subsequentes que começam com - sejam interpretados como opções adicionais.

No entanto, é importante ressaltar que subtrair destinos dessa forma não garante que eles não sejam criados, já que podem ser dependências de destinos que não foram subtraídos. Por exemplo, se houver um //foo:all-apis de destino que, entre outros, dependiam de //foo/bar:api, este último seria criado conforme parte da construção do primeiro.

Os destinos com tags = ["manual"] não estão incluídos nos padrões de destino com caracteres curinga (..., :*, :all etc.) quando especificado em comandos como bazel build e bazel test (mas estão incluídos em caracteres curinga negativos, ou seja, serão subtraídos). Você deve especifique esses destinos de teste com padrões explícitos de destino na linha de comando se você quer que o Bazel as compile/teste. Por outro lado, bazel query não realiza essa filtragem automaticamente (isso anularia o propósito de bazel query).

Como buscar dependências externas

Por padrão, o Bazel faz o download e vincula dependências externas de dependências externas durante a ser construído. No entanto, isso pode ser indesejável, porque você deseja saber quando novas dependências externas são adicionadas ou porque você quer "pré-busca" dependências (por exemplo, antes de um voo em que você vai estar off-line). Se você quiser evitar que novas dependências sejam adicionadas durante a criação, é possível especificar a sinalização --fetch=false. Essa flag só se aplica a regras de repositório que não apontam para um diretório no sistema de arquivos local. Mudanças, por exemplo, para local_repository, new_local_repository e regras do repositório do SDK do Android e do NDK sempre vão entrar em vigor, independentemente do valor --fetch.

Se você não permitir a busca durante os builds e o Bazel encontrar novas dependências externas, o build vai falhar.

É possível buscar dependências manualmente executando bazel fetch. Se você não permitir a busca durante a criação, será necessário executar bazel fetch:

  • Antes de criar pela primeira vez.
  • Depois de adicionar uma nova dependência externa.

Depois disso, não será necessário executá-lo novamente até que o espaço de trabalho alterações no arquivo.

fetch recebe uma lista de destinos para os quais buscar dependências. Para exemplo, isso buscaria as dependências necessárias para criar //foo:bar e //bar:baz:

bazel fetch //foo:bar //bar:baz

Para buscar todas as dependências externas de um espaço de trabalho, execute:

bazel fetch //...

Não é necessário executar o bazel fetch se você tiver todas as ferramentas que está usando (de jars de biblioteca ao próprio JDK) na raiz do espaço de trabalho. No entanto, se você estiver usando algo fora do diretório do espaço de trabalho, o Bazel executará automaticamente bazel fetch antes da execução; bazel build.

O cache do repositório

O Bazel tenta evitar a busca do mesmo arquivo várias vezes, mesmo que o mesmo arquivo seja necessário em diferentes espaços de trabalho ou se a definição de um repositório externo mudou, mas ainda precisa do mesmo arquivo para fazer o download. Para fazer isso, o bazel armazena em cache todos os arquivos transferidos por download no cache do repositório, que, por padrão, está localizado em ~/.cache/bazel/_bazel_$USER/cache/repos/v1/. O local pode ser alterado pela opção --repository_cache. O o cache é compartilhado entre todos os espaços de trabalho e versões instaladas do Bazel. Uma entrada é retirada do cache se O Bazel tem certeza de que tem uma cópia do arquivo correto, ou seja, se o de download tem uma soma SHA256 do arquivo especificado e um arquivo com essa está no cache. Portanto, especificar um hash para cada arquivo externo não apenas uma boa ideia do ponto de vista da segurança, também ajuda a evitar desnecessários.

Em cada acerto de cache, o tempo de modificação do arquivo no cache é atualizado. Dessa forma, o último uso de um arquivo no diretório de cache pode ser facilmente determinado, por exemplo, para limpar o cache manualmente. O cache nunca é limpo automaticamente, porque pode conter uma cópia de um arquivo que não está mais disponível upstream.

Diretórios de arquivos de distribuição

O diretório de distribuição é outro mecanismo do Bazel para evitar downloads. O Bazel pesquisa diretórios de distribuição antes do cache do repositório. A principal diferença é que o diretório de distribuição requer preparação manual.

Usar o --distdir=/path/to-directory especifique mais diretórios somente leitura para procurar arquivos em vez de buscá-los. Um arquivo é retirado de um diretório se o nome do arquivo for igual ao nome base do URL e, além disso, o hash do arquivo for igual ao especificado na solicitação de download. Isso só funciona se o hash de arquivo é especificado na declaração WORKSPACE.

Embora a condição no nome do arquivo não seja necessária para a correção, ela reduz o número de arquivos candidatos a um por diretório especificado. Dessa forma, a especificação de diretórios de arquivos de distribuição continua eficiente, mesmo que o número de arquivos em um diretório aumente muito.

Como executar o Bazel em um ambiente com isolamento físico

Para manter o tamanho do binário do Bazel pequeno, as dependências implícitas dele são buscadas. na rede durante a execução pela primeira vez. Essas dependências implícitas conter conjuntos de ferramentas e regras que podem não ser necessárias para todos. Por exemplo, as ferramentas do Android são desempacotadas e buscadas apenas ao criar projetos Android.

No entanto, essas dependências implícitas podem causar problemas ao executar o Bazel em um ambiente com isolamento físico, mesmo que você tenha disponibilizado todas as do WORKSPACE. Para resolver isso, prepare um diretório de distribuição que contenha essas dependências em uma máquina com acesso à rede e, em seguida, transfira-as para o ambiente isolado com uma abordagem off-line.

Para preparar o diretório de distribuição, use o --distdir . Você precisará fazer isso uma vez para cada nova versão binária do Bazel, já que as dependências implícitas podem ser diferentes para cada versão.

Para criar essas dependências fora do ambiente com isolamento térmico, primeiro Confira a árvore de origem do Bazel na versão correta:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

Depois, crie o tarball contendo as dependências implícitas de ambiente de execução para esse versão específica do Bazel:

bazel build @additional_distfiles//:archives.tar

Exporte esse tarball para um diretório que possa ser copiado para o ambiente airgapped. Observe a flag --strip-components, porque --distdir pode ser bastante complicada com o nível de aninhamento do diretório:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

Por fim, quando você usar o Bazel no ambiente com isolamento físico, transmita o --distdir que aponta para o diretório. Para facilitar, adicione como .bazelrc. entrada:

build --distdir=path/to/directory

Configurações do build e compilação cruzada

Todas as entradas que especificam o comportamento e o resultado de um determinado build podem ser divididos em duas categorias distintas. O primeiro tipo é o intrínseco, informações armazenadas nos arquivos BUILD do seu projeto: a regra de build, o valores dos atributos e o conjunto completo de suas dependências transitivas. O segundo tipo são os dados externos ou ambientais, fornecidos pelo usuário ou pela ferramenta de build: a escolha da arquitetura de destino, opções de compilação e vinculação e outras opções de configuração do conjunto de ferramentas. Nos referimos a um conjunto completo de dados ambientais como uma configuração.

Em qualquer build, pode haver mais de uma configuração. Considere uma compilação cruzada, em que você cria um executável //foo:bin para uma arquitetura de 64 bits, mas sua estação de trabalho é uma máquina de 32 bits. Claramente, o build vai exigem a criação de //foo:bin usando um conjunto de ferramentas capaz de criar Os executáveis, mas o sistema de compilação também deve compilar várias ferramentas usadas durante a por conta própria — por exemplo, ferramentas criadas a partir da origem e depois usadas em uma regra geral e precisam ser criados para serem executados na estação de trabalho. Assim, podemos identificar duas configurações: a configuração "exec", usada para criar ferramentas que são executadas durante o build e a configuração de destino (ou solicitar configuração, mas dizemos "configuração de destino" com mais frequência) embora essa palavra já tenha muitos significados), o que é usado para criar que você acabou de solicitar.

Normalmente, há muitas bibliotecas que são pré-requisitos do destino de build solicitado (//foo:bin) e de uma ou mais das ferramentas de execução, por exemplo, algumas bibliotecas básicas. Essas bibliotecas precisam ser criadas duas vezes, uma para o comando e outra para a de destino. O Bazel cuida de garantir que ambas as variantes sejam criadas e que os arquivos derivados sejam mantidos separados para evitar interferências. Normalmente, esses destinos podem ser criados simultaneamente, já que são independentes uns dos outros. Se você receber mensagens de progresso indicando que um determinado destino está sendo criado duas vezes, essa é provavelmente a explicação.

A configuração "exec" é derivada da configuração de destino da seguinte maneira:

  • Use a mesma versão do Crosstool (--crosstool_top) conforme especificada no solicitação de configuração, a menos que --host_crosstool_top seja especificado.
  • Use o valor de --host_cpu para --cpu (padrão: k8).
  • Use os mesmos valores dessas opções, conforme especificado na solicitação configuração: --compiler, --use_ijars, e se --host_crosstool_top for usado, o valor de --host_cpu é usado para procurar um default_toolchain no Crosstool (ignorando --compiler) para a execução configuração do Terraform.
  • Use o valor de --host_javabase para --javabase
  • Use o valor de --host_java_toolchain para --java_toolchain
  • Use builds otimizados para código C++ (-c opt).
  • Não gera informações de depuração (--copt=-g0).
  • Remover informações de depuração de executáveis e bibliotecas compartilhadas (--strip=always).
  • Coloque todos os arquivos derivados em um local especial, diferente do usado por qualquer configuração de solicitação possível.
  • Suprimir a marcação de binários com dados de build (consulte as opções de --embed_*).
  • Todos os outros valores permanecem com os valores padrão.

Há muitas razões pelas quais pode ser preferível selecionar um exec diferente da solicitação. Mais importante:

Primeiro, ao usar binários otimizados e simplificados, você reduz o tempo gasto vinculando e executando as ferramentas, o espaço em disco ocupado pelas ferramentas e o tempo de E/S de rede em builds distribuídos.

Segundo, ao desacoplar as configurações "exec" e "request" em todos os builds, você evitar recriações muito caras que resultariam de pequenas alterações no solicitação de configuração (como a alteração de uma opção do vinculador faz), conforme descrito antes.

Correções de reconstruções incrementais

Um dos principais objetivos do projeto do Bazel é garantir recriações. As ferramentas de build anteriores, especialmente as baseadas em Make, criam vários e suposições insatisfatórias na implementação de builds incrementais.

Primeiro, os carimbos de data/hora dos arquivos aumentam de forma monotonicamente. Embora este seja o desse caso típico, é muito fácil cair em desacordo com essa suposição; sincronizando com um revisões anteriores de um arquivo diminui o tempo de modificação desse arquivo; Os sistemas baseados em Make não serão recriados.

De modo geral, embora o Make detecte mudanças em arquivos, ele não detecta mudanças em comandos. Se você mudar as opções passadas ao compilador em um determinado build o Make não vai executar novamente o compilador e será necessário descartar manualmente as saídas inválidas do build anterior usando make clean.

Além disso, o Make não é robusto contra o encerramento malsucedido de um de seus subprocessos depois que aquele subprocesso começou a gravar em seu arquivo de saída. Embora a execução atual do Make falhe, a invocação subsequente do Make vai presumir cegamente que o arquivo de saída truncado é válido (porque é mais recente que as entradas) e não será recriado. Da mesma forma, se o processo Make for morto, uma situação semelhante pode ocorrer.

O Bazel evita essas e outras suposições. O Bazel mantém um banco de dados de todo o trabalho feito anteriormente e só vai omitir uma etapa de build se encontrar que o conjunto de arquivos de entrada (e os carimbos de data/hora deles) para essa etapa de build e o comando de compilação para essa etapa de build correspondem exatamente a um no banco de dados e que o conjunto de arquivos de saída (e os carimbos de data/hora deles) para a entrada do banco de dados correspondem exatamente aos carimbos de data/hora dos arquivos no disco. Qualquer mudança nos arquivos de entrada ou na saída ou ao próprio comando, fará com que a etapa de criação seja reexecutada.

O benefício para os usuários de builds incrementais corretos é: menos tempo desperdiçado devido à confusão. Além disso, menos tempo gasto aguardando recriações causadas pelo uso de make clean, seja ela necessária ou preventiva.

Criar consistência e builds incrementais

Formalmente, definimos o estado de um build como consistente quando todos os arquivos de saída esperados existem e o conteúdo deles está correto, conforme especificado pelas etapas ou regras necessárias para criá-los. Quando você edita um arquivo de origem, o estado do build é considerado inconsistente e permanece assim até a próxima execução da ferramenta de build para conclusão. Descrevemos essa situação como instável inconsistência, porque é apenas temporária e a consistência é restaurada ao executar a ferramenta de build.

Há outro tipo de inconsistência que é perniciosa: a inconsistência estável. Se o build atingir um estado inconsistente estável e, em seguida, invocação bem-sucedida da ferramenta de build não restaura a consistência: o build ficou "travada" e as saídas permanecem incorretas. Estados inconsistentes estáveis são o principal motivo para os usuários do Make (e outras ferramentas de build) digitarem make clean. Descobrir que a ferramenta de build falhou dessa maneira (e depois se recuperar dela) pode ser demorado e muito frustrante.

Conceitualmente, a maneira mais simples de alcançar um build consistente é descartar todas as saídas de build anteriores e começar de novo: faça com que cada build seja um build limpo. Essa abordagem é obviamente muito demorada para ser prática (exceto, talvez, para engenheiros de lançamento). Portanto, para ser útil, a ferramenta de build precisa ser capaz de executar builds incrementais sem comprometer a consistência.

A análise de dependência incremental correta é difícil, e, conforme descrito acima, muitas outras ferramentas de build não conseguem evitar estados instáveis e inconsistentes durante builds incrementais. Por outro lado, o Bazel oferece a seguinte garantia: depois que uma invocação bem-sucedida da ferramenta de compilação durante a qual você não fez edições, o estejam em um estado consistente. Se você editar os arquivos de origem durante uma compilação, o Bazel não garante a consistência do resultado da compilação atual. No entanto, ele garante que os resultados do próximo build vão restaurar a consistência.)

Como em todas as garantias, há alguns detalhes: há algumas formas conhecidas de entrar em um estado inconsistente estável com o Bazel. Não garantimos a investigação desses problemas decorrentes de tentativas deliberadas de encontrar bugs na análise incremental de dependências, mas vamos investigar e fazer o possível para corrigir todos os estados instáveis inconsistentes decorrentes do uso normal ou "razoável" da ferramenta de build.

Se você detectar um estado inconsistente estável com o Bazel, informe um bug.

Execução em sandbox

O Bazel usa sandboxes para garantir que as ações sejam executadas hermeticamente e corretamente. O Bazel executa spawns (em termos gerais: ações) em sandboxes que contêm apenas o conjunto mínimo de arquivos necessários para a ferramenta fazer o trabalho. Atualmente, o sandbox funciona no Linux 3.12 ou mais recente com a opção CONFIG_USER_NS ativada e também no macOS 10.11 ou mais recente.

O Bazel vai mostrar um aviso se o sistema não oferecer suporte ao sandbox para alertar que os builds não têm garantia de serem herméticos e podem afetar o sistema host de maneiras desconhecidas. Para desativar esse aviso, transmita o Sinalização --ignore_unsupported_sandboxing para o Bazel.

Em algumas plataformas, como o Google Kubernetes do Google Kubernetes Engine ou do Debian, os namespaces de usuário são desativados por padrão devido à segurança problemas. Isso pode ser verificado analisando o arquivo /proc/sys/kernel/unprivileged_userns_clone: se ele existir e contiver um 0, os namespaces de usuário poderão ser ativados com sudo sysctl kernel.unprivileged_userns_clone=1.

Em alguns casos, o sandbox do Bazel não executa as regras por causa do sistema configuração da infraestrutura. O sintoma geralmente é uma falha que gera uma mensagem semelhante a namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory. Nesse caso, tente desativar o sandbox para regras geradas com --strategy=Genrule=standalone e para outras regras com --spawn_strategy=standalone. Além disso, informe um bug na rastreador de problemas e mencione qual distribuição Linux você está usando para que possamos investigar e fornecer uma correção em uma versão subsequente.

Fases de um build

No Bazel, um build ocorre em três fases distintas. como usuário, compreender a diferença entre eles fornece informações sobre as opções que controlam um build Confira abaixo.

Fase de carregamento

A primeira é o carregamento, durante o qual todos os arquivos BUILD necessários para o os destinos iniciais e o fechamento transitivo de dependências são carregados, analisados, avaliados e armazenados em cache.

Na primeira compilação após o início de um servidor Bazel, a fase de carregamento normalmente leva muitos segundos, a partir do qual muitos arquivos BUILD são carregados do sistema de arquivos. Em builds subsequentes, especialmente se nenhum arquivo BUILD tiver sido alterado, o carregamento ocorre muito rapidamente.

Os erros relatados durante essa fase incluem: pacote não encontrado, destino não encontrado, erros de gramática e ortografia em um arquivo BUILD e erros de avaliação.

Fase de análise

A segunda fase, análise, envolve a análise e validação semânticas de cada regra de build, a construção de um gráfico de dependência de build e a determinação de exatamente qual trabalho deve ser feito em cada etapa do build.

Assim como o carregamento, a análise também leva vários segundos quando computada por completo. No entanto, o Bazel armazena em cache o gráfico de dependência de um build para o próximo e somente analisa novamente o que precisa ser feito, o que pode tornar as compilações incrementais extremamente rápidas em caso os pacotes não tenham mudado desde o build anterior.

Os erros relatados neste estágio incluem: dependências inadequadas, dependências entradas em uma regra e todas as mensagens de erro específicas dela.

As fases de carregamento e análise são rápidas porque o Bazel evita arquivos desnecessários E/S nesta fase, lendo apenas arquivos BUILD para determinar o trabalho a ser feito. Isso é intencional e faz do Bazel uma boa base para ferramentas de análise, como o comando query do Bazel, que é implementado na fase de carregamento.

Fase de execução

A terceira e última fase do build é a execução. Essa fase garante que as saídas de cada etapa do build sejam consistentes com as entradas, executando novamente ferramentas de compilação/vinculação/etc. conforme necessário. É nessa etapa que o build passa a maior parte do tempo, variando de alguns segundos a mais de uma hora para um build grande. Os erros relatados durante essa fase incluem: arquivos de origem ausentes, erros em uma ferramenta executada por alguma ação de compilação ou falha de uma ferramenta para conjunto esperado de saídas.