Veja nesta página como criar um programa com o Bazel, a sintaxe do comando de compilação 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 build se 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 de build.aquery
: executa uma consulta no gráfico de ações pós-análise.build
: compila os destinos especificados.canonicalize-flags
: canonizar sinalizações do Bazel.clean
: remove os arquivos de saída e, como opção, interrompe o servidor.cquery
: executa uma consulta de gráfico de dependência pós-análise.dump
: despeja o estado interno do processo do servidor do Bazel.help
: exibe a ajuda para comandos ou o índice.info
: exibe informações do ambiente 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
: para o servidor do Bazel.test
: compila e executa os destinos de teste especificados.version
: imprime informações de versão do Bazel.
Receber ajuda
bazel help command
: imprime ajuda e opções paracommand
.bazel help
startup_options
: opções para a JVM que hospeda o Bazel.bazel help
target-syntax
: explica a sintaxe para especificar destinos.bazel help info-keys
: exibe uma lista de chaves usadas pelo comando de informações.
A ferramenta bazel
executa muitas funções, chamadas de comandos. Os mais usados
são bazel build
e bazel test
. É possível navegar pelas mensagens de ajuda on-line usando bazel help
.
Como criar um destino
Para 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. O Bazel permite que você execute uma versão de um volume completamente somente leitura.
Para criar um programa com o Bazel, digite bazel build
seguido pelo destino que você quer criar.
bazel build //foo
Depois de emitir o comando para criar //foo
, você 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 do gráfico de dependência do seu destino. Isso inclui dependências declaradas, arquivos listados diretamente no arquivo BUILD
do destino e dependências transitivas, arquivos listados nos arquivos BUILD
das dependências do destino. Depois de identificar todas as dependências, o Bazel as analisa para correção e cria as ações de versão. 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. As mensagens de progresso incluem a etapa de criação atual (como compilador ou vinculador) quando inicia e o número concluído sobre o número total de ações de versão. À medida que o build é iniciado, o número total de ações geralmente aumenta conforme o Bazel descobre todo o gráfico de ação, mas o número se estabiliza em alguns segundos.
No final da compilação, o Bazel imprime quais destinos foram solicitados, se foram criados com sucesso e, em caso afirmativo, onde os arquivos de saída podem ser encontrados. Os scripts que executam builds podem analisar essa saída de maneira confiável. Consulte
--show_result
para ver mais detalhes.
Se você digitar o mesmo comando novamente, a versão será concluída mais rapidamente.
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
Este é um build nulo. Como nada mudou, não há pacotes para recarregar e nenhuma etapa de build para executar. Se algo mudou em "foo" ou nas dependências, o Bazel executará novamente algumas ações de versão ou concluirá uma compilação incremental.
Como criar vários destinos
O Bazel oferece várias maneiras de especificar os destinos a serem criados. Coletivamente,
elas são conhecidas como padrões de destino. Essa sintaxe é usada em comandos como
build
, test
ou query
.
Enquanto rótulos são usados para especificar destinos individuais, por exemplo, para declarar dependências em arquivos BUILD
, os padrões de destino do Bazel especificam vários destinos. Os padrões de destino são uma generalização da
sintaxe do rótulo para conjuntos de destinos, usando caracteres curinga. No caso mais simples, qualquer
rótulo válido também é um padrão de destino válido, identificando um conjunto de exatamente um
destino.
Todos os padrões de destino começando com //
são resolvidos em relação ao espaço de trabalho
atual.
//foo/bar:wiz |
Apenas o destino //foo/bar:wiz . |
//foo/bar |
É equivalente a //foo/bar:bar . |
//foo/bar:all |
Todos os destinos de regra no pacote foo/bar . |
//foo/... |
Todos os destinos de regra em todos os pacotes abaixo do diretório foo . |
//foo/...:all |
Todos os destinos de regra 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 . |
//... |
Todos os destinos 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` na 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 pressupõem um diretório de trabalho de foo
:
:foo |
É equivalente a //foo:foo . |
bar:wiz |
É equivalente a //foo/bar:wiz . |
bar/wiz |
Equivalente a:
|
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 simbólicos de conveniência criados 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 nomeado da seguinte maneira: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN
foo/...
é um caractere curinga em pacotes, indicando todos os pacotes abaixo do diretório foo
de maneira recursiva (para todas as raízes do caminho do pacote). :all
é um
caractere curinga em destinos, correspondendo a todas as regras em um pacote. Esses dois podem ser
combinados, como em foo/...:all
, e quando os dois caracteres curinga forem usados, eles poderão ser
abreviados como foo/...
.
Além disso, :*
(ou :all-targets
) é um caractere curinga que corresponde a todos os destinos
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 o :*
indica um superconjunto do :all
. Embora potencialmente
confuso, essa sintaxe permite que o caractere curinga :all
seja usado para
builds típicos, em que o destino de builds como o _deploy.jar
não é desejado.
Além disso, ele permite que uma barra seja usada no lugar dos dois-pontos exigidos pela sintaxe do rótulo. Isso costuma ser conveniente ao usar a expansão de nome de arquivo Bash.
Por exemplo, foo/bar/wiz
será equivalente a //foo/bar:wiz
(se houver um
pacote foo/bar
) ou //foo:bar/wiz
(se houver um pacote foo
).
Muitos comandos do Bazel aceitam uma lista de padrões de destino como argumentos e todos seguem 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 que
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 os que estão abaixo de foo/bar
. O argumento --
é necessário para evitar que os argumentos subsequentes que começam com -
sejam interpretados como opções adicionais.
É importante destacar que a subtração de destinos dessa maneira não
garante que eles não serão criados, já que eles podem ser dependências de destinos
que não foram subtraídos. Por exemplo, se houver um //foo:all-apis
de destino que dependia de //foo/bar:api
, este último será criado como
parte do primeiro.
Os destinos com tags = ["manual"]
não são incluídos em padrões de destino de caracteres curinga (...
, :*
, :all
etc.) quando especificados em comandos como bazel build
e bazel test
. No entanto, eles são incluídos em padrões de destino de caracteres curinga negativos, ou seja, serão subtraídos. Especifique esses destinos de teste com padrões de destino explícitos na linha de comando se quiser que eles sejam criados/testados pelo Bazel. Por outro lado, o bazel query
não realiza
essas filtros automaticamente (o que prejudicaria a finalidade de
bazel query
).
Buscando dependências externas
Por padrão, o Bazel fará o download e vinculará dependências externas durante a versão. No entanto, isso pode ser indesejável, porque você quer saber quando novas dependências externas são adicionadas ou porque gostaria de “pré-buscar” dependências (por exemplo, antes de um voo em que você estará off-line). Se você
quiser impedir que novas dependências sejam adicionadas durante os builds, especifique a sinalização --fetch=false
. Observe que essa sinalização só se aplica a regras de repositório que não apontam para um diretório no sistema de arquivos local. Por exemplo, mudanças no local_repository
, new_local_repository
e nas 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 as versões e o Bazel encontrar novas dependências externas, a versão falhará.
É possível buscar dependências manualmente executando bazel fetch
. Se
você proibir a busca durante a compilação, será necessário executar bazel fetch
:
- Antes de criar pela primeira vez,
- Depois de adicionar uma nova dependência externa.
Depois da execução, você não precisará executá-lo novamente até que o arquivo WORKSPACE mude.
fetch
recebe uma lista de destinos para os quais buscar dependências. Por
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 é preciso executar a busca do Bazel 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 vai executar bazel fetch
automaticamente antes de 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 espaços de trabalho diferentes ou se a definição de um repositório externo tiver mudado, mas ainda precisar do mesmo arquivo para 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 cache é compartilhado entre todos os espaços de trabalho e versões instaladas do bazel.
Uma entrada é retirada do cache se o Bazel tiver certeza de que tem uma cópia do arquivo correto, ou seja, se a solicitação de download tiver uma soma SHA256 do arquivo especificado e um arquivo com esse hash estiver no cache. Portanto, especificar um hash para cada arquivo externo
não é apenas uma boa ideia de uma perspectiva de segurança, mas também ajuda a evitar
downloads desnecessários.
O tempo de modificação do arquivo no cache é atualizado em cada ocorrência dele. 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 desnecessários. O Bazel pesquisa nos diretórios de distribuição antes do cache do repositório. A principal diferença é que o diretório de distribuição exige a preparação manual.
Usando a opção
--distdir=/path/to-directory
, é possível especificar outros diretórios somente leitura para procurar arquivos
em vez de buscá-los. Um arquivo é extraído desse diretório se o nome dele é igual ao nome base do URL e, além disso, o hash do arquivo é igual ao especificado na solicitação de download. Isso só funcionará se o hash de arquivo for especificado na declaração WORKSPACE.
Embora a condição no nome do arquivo não seja necessária para correção, ela reduz o número de arquivos candidatos para um por diretório especificado. Dessa forma, a especificação dos diretórios de arquivos de distribuição continua eficiente, mesmo que o número de arquivos seja maior.
Como executar o Bazel em um ambiente com lacunas
Para manter o tamanho binário do Bazel baixo, as dependências implícitas são buscadas na rede durante a execução pela primeira vez. Essas dependências implícitas contêm conjuntos de ferramentas e regras que podem não ser necessários para todos. Por exemplo, as ferramentas do Android são desagrupadas 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 lacunas, mesmo que você tenha fornecido todas as suas dependências do espaço de trabalho. Para resolver isso, você pode preparar um diretório de distribuição contendo essas dependências em uma máquina com acesso à rede e transferi-las para o ambiente de lacunas com uma abordagem off-line.
Para preparar o diretório de distribuição, use a
sinalização --distdir
. É necessário fazer isso uma vez para cada nova versão binária do Bazel, já que
as dependências implícitas podem ser diferentes a cada versão.
Para criar essas dependências fora do ambiente de lacuna, primeiro faça o check-out da á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"
Em seguida, crie o tarball contendo as dependências implícitas do ambiente de execução para essa 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 com lacunas. Observe a sinalização --strip-components
, porque --distdir
pode ser
completamente detalhada 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, ao usar o Bazel no ambiente com intervalo de tempo, transmita a sinalização --distdir
que aponta para o diretório. Por conveniência, é possível adicioná-la como uma entrada
.bazelrc
:
build --distdir=path/to/directory
Configurações de compilação e compilação cruzada
Todas as entradas que especificam o comportamento e o resultado de uma determinada versão podem ser
divididas em duas categorias distintas. O primeiro tipo é a informação intrínseca armazenada nos arquivos BUILD
do projeto: a regra de compilação, os valores dos atributos e o conjunto completo das dependências transitivas dele.
O segundo tipo são os dados externos ou ambientais, fornecidos pelo usuário ou pela ferramenta de compilação: a opção de arquitetura de destino, opções de compilação e vinculação e outras opções de configuração do conjunto de ferramentas. Chamamos um conjunto completo
de dados ambientais uma configuração.
Em qualquer build, pode haver mais de uma configuração. Pense em 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, é necessário
criar //foo:bin
usando um conjunto de ferramentas capaz de executar executáveis de
64 bits, mas o sistema de compilação também precisa criar várias ferramentas usadas durante a
criação. Por exemplo, ferramentas criadas da origem e usadas
em uma regra geral, que precisam ser criadas para execução na estação de trabalho. Assim,
podemos identificar duas configurações: a configuração de execução, usada
para criar ferramentas que são executadas durante o build, e a configuração de destino,
ou a configuração de solicitação, mas dizemos "configuração de destino" com mais frequência,
mesmo que essa palavra já tenha muitos significados, que é usada para criar o
binário solicitado.
Normalmente, há muitas bibliotecas que são pré-requisitos do destino
de compilação solicitado (//foo:bin
) e de uma ou mais ferramentas exec, por exemplo, algumas
bibliotecas base. Essas bibliotecas precisam ser criadas duas vezes, uma para a configuração de execução e outra para a de destino. O Bazel garante que as duas 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 entre si. Se você vir mensagens de progresso
indicando que um determinado destino está sendo criado duas vezes, essa provavelmente é a
explicação.
A configuração de execução é derivada da configuração de destino da seguinte maneira:
- Use a mesma versão do Crosstool (
--crosstool_top
), conforme especificado na configuração da solicitaçã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 configuração
da solicitação:
--compiler
,--use_ijars
. Se--host_crosstool_top
for usado, o valor de--host_cpu
será usado para procurar umdefault_toolchain
na Crosstool (ignorando--compiler
) para a configuração executiva. - Use o valor de
--host_javabase
para--javabase
- Use o valor de
--host_java_toolchain
para--java_toolchain
- Use builds otimizados para o 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 daquele usado por qualquer possível configuração de solicitação.
- Suprimir carimbo de dados binários com dados de build (consulte as opções
--embed_*
). - Todos os outros valores permanecem nos padrões.
Há muitos motivos para preferir uma configuração executiva diferente da configuração de solicitação. Mais importante:
Primeiro, usando binários removidos e otimizados, você reduz o tempo gasto na vinculação e execução das ferramentas, o espaço em disco ocupado pelas ferramentas e o tempo de E/S da rede em builds distribuídos.
Em segundo lugar, ao desacoplar as configurações de execução e de solicitação em todos os builds, você evita recriações muito caras que resultariam de pequenas mudanças na configuração da solicitação (como alterar uma opção do vinculador), conforme descrito anteriormente.
Reconstruções incrementais corretas
Um dos principais objetivos do projeto Bazel é garantir recriações incrementais corretas. As ferramentas de compilação anteriores, especialmente as baseadas no Make, fazem várias suposições sólidas sobre a implementação de builds incrementais.
Primeiro, as marcações de tempo dos arquivos aumentam de maneira uniforme. Embora esse seja o caso típico, é muito fácil cair nessa suposição. Sincronizar com uma revisão anterior de um arquivo diminui o tempo de modificação desse arquivo. Sistemas baseados em marca não serão recriados.
Em geral, embora o Make detecte alterações em arquivos, ele não detecta mudanças
em comandos. Se você alterar as opções transmitidas ao compilador em uma determinada etapa do build,
o Make não executará o compilador novamente 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 dos subprocessos depois que ele começa a ser gravado no arquivo de saída. Embora a execução atual do Make falhe, a invocação seguinte do Make presumirá que o arquivo de saída truncado é válido (porque é mais recente do que as entradas) e não será recriado. Da mesma forma, se o processo do Make for eliminado, uma situação semelhante pode ocorrer.
O Bazel evita essas suposições e outras. O Bazel mantém um banco de dados de todo o trabalho feito anteriormente e só omitirá uma etapa se ele descobrir que o conjunto de arquivos de entrada (e os respectivos carimbos de data/hora) para essa etapa de versão e o comando de compilação dessa etapa de versão correspondem exatamente a um no banco de dados e que o conjunto de arquivos de saída (e seus carimbos de data/hora) para a entrada de banco de dados corresponde exatamente aos carimbos de data/hora dos arquivos no disco. Qualquer alteração nos arquivos de entrada ou de saída, ou no próprio comando, causa uma nova execução da etapa de versão.
O benefício para os usuários de builds incrementais corretos é: menos tempo desperdiçado devido à
confusão. Além disso, há menos tempo gasto esperando por reconstruções causadas pelo uso de make
clean
, seja necessário ou preventivo.
Consistência de build e builds incrementais
De maneira formal, definimos o estado de um build como consistente quando todos os arquivos de saída esperados existem e o conteúdo está correto, conforme especificado pelas etapas ou regras necessárias para criá-los. Quando você edita um arquivo de origem, diz-se que o estado do build é inconsistente e permanece inconsistente até que você execute a ferramenta de compilação novamente. Descrevemos essa situação como inconsistência instável, porque ela é apenas temporária e a consistência é restaurada com a execução da ferramenta de build.
Há outro tipo de inconsistência: inconsistência. Se o build atingir um estado inconsistente e estável, a invocação repetida
da ferramenta de build não restaurará a consistência: o build
está "travado" e as saídas permanecem incorretas. Os estados estáveis
foram o principal motivo dos usuários do Make (e de outras ferramentas de build) do tipo make clean
.
Descobrir que a ferramenta de compilação falhou dessa maneira (e depois se recuperar dela)
pode ser demorado e muito frustrante.
Conceitualmente, a maneira mais simples de ter um build consistente é descartando todas as saídas de build anteriores e recomeçando: tornando cada build um build limpo. Essa abordagem é obviamente demorada demais 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 compilação não fazem bem para evitar estados inconsistentes estáveis durante builds incrementais. Por outro lado, o Bazel oferece a seguinte garantia: após uma invocação bem-sucedida da ferramenta de build em que você não fez edições, a versão estará em um estado consistente. Se você editar os arquivos de origem durante uma criação, o Bazel não garante a consistência do resultado da versão atual. Mas ele garante que os resultados do próximo build vão restaurar a consistência.
Assim como em todas as garantias, há algumas letras pequenas: há algumas maneiras conhecidas de entrar em um estado inconsistente e estável com o Bazel. Não vamos investigar esses problemas decorrentes de tentativas deliberadas de encontrar bugs na análise de dependência incremental. No entanto, vamos investigar e fazer o possível para corrigir todos os estados estáveis e inconsistentes decorrentes do uso normal ou "razoável" da ferramenta de build.
Se você detectar um estado inconsistente e estável no Bazel, informe um bug.
Execução em sandbox
O Bazel usa sandboxes para garantir que as ações sejam executadas de maneira hermética e correta. O Bazel executa spawns (frases: ações) em sandboxes que
contêm apenas o conjunto mínimo de arquivos que a ferramenta exige para fazer o trabalho dele. No momento, 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 imprimir um aviso se o sistema não for compatível com sandbox para alertar você sobre o fato de que as versões não são herméticas e podem afetar o sistema host de maneiras desconhecidas. Para desativar esse aviso, transmita a sinalização --ignore_unsupported_sandboxing
ao Bazel.
Em algumas plataformas, como os nós do cluster do Google Kubernetes
Engine ou o Debian,
os namespaces do usuário são desativados por padrão devido a preocupações de
segurança. Para verificar isso, observe o arquivo
/proc/sys/kernel/unprivileged_userns_clone
: se ele existir e contiver 0,
os namespaces do usuário poderão ser ativados com
sudo sysctl kernel.unprivileged_userns_clone=1
.
Em alguns casos, o sandbox do Bazel não executa regras por causa da configuração do sistema. Geralmente, esse sintoma é 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 gerais com
--strategy=Genrule=standalone
e para outras regras com
--spawn_strategy=standalone
. Além disso, informe um bug no nosso
Issue Tracker e mencione a distribuição do Linux que você está usando para que possamos
investigar e fornecer uma correção em uma versão posterior.
Fases de um build
No Bazel, uma versão ocorre em três fases distintas. Como usuário, entender a diferença entre elas fornece informações sobre as opções que controlam uma versão (veja abaixo).
Carregando fase
O primeiro é carregar durante o qual todos os arquivos BUILD necessários para os destinos iniciais e seu 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 do Bazel, a fase de carregamento normalmente leva muitos segundos à medida que muitos arquivos BUILD são carregados do sistema de arquivos. Em versões subsequentes, especialmente se nenhum arquivo BUILD tiver mudado, o carregamento ocorre muito rapidamente.
Os erros relatados durante essa fase incluem: pacote não encontrado, destino não encontrado, erros léxicos e gramaticais em um arquivo BUILD e erros de avaliação.
Fase de análise
A segunda fase, análise, envolve a análise semântica e validação de cada regra de compilação, a construção de um gráfico de dependência de compilação e a determinação exata do trabalho a ser feito em cada etapa da versão.
Assim como o carregamento, a análise também leva alguns segundos quando calculada de modo completo. No entanto, o Bazel armazena em cache o gráfico de dependência de uma versão para a próxima e só analisa novamente o que ele precisa, o que pode tornar as versões incrementais extremamente rápidas, no caso de os pacotes não terem mudado desde a versão anterior.
Os erros relatados nesta fase incluem: dependências inadequadas, entradas inválidas para uma regra e todas as mensagens de erro específicas da regra.
As fases de carregamento e análise são rápidas porque o Bazel evita a E/S de arquivos desnecessários neste estágio, lendo apenas arquivos BUILD para determinar o trabalho a ser feito. Isso ocorre por design e torna o 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 da compilação é 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/link/etc. conforme necessário. Nesta etapa, a versão passa a maior parte do tempo, variando de alguns segundos a mais de uma hora para uma versão 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 produzir o conjunto esperado de saídas.