Nas seções anteriores, descrevemos pacotes, destinos e rótulos, além do gráfico de dependência de versão, de maneira abstrata. Nesta seção, descrevemos a sintaxe concreta usada para definir um pacote.
Por definição, cada pacote contém um arquivo BUILD
, que é um programa curto.
Os arquivos BUILD
são avaliados com uma linguagem imperativa,
Starlark.
Elas são interpretadas como uma lista sequencial de instruções.
Em geral, a ordem é importante: as variáveis precisam ser definidas antes de serem usadas, por exemplo. No entanto, a maioria dos arquivos BUILD
consiste apenas em declarações de regras de compilação, e a ordem relativa dessas instruções é irrelevante. O importante é quais regras foram declaradas e com quais valores, até que a avaliação do pacote seja concluída.
Quando uma função de regra de compilação, como cc_library
, é executada, ela cria um novo destino no gráfico. Posteriormente, esse destino poderá ser referenciado usando um rótulo.
Em arquivos BUILD
simples, as declarações de regra podem ser reordenadas sem custo financeiro sem mudar o comportamento.
Para incentivar uma separação clara entre código e dados, os arquivos BUILD
não podem conter definições de função, instruções for
ou instruções if
, mas expressões de lista e expressões if
são permitidas. Em vez disso, as funções podem ser declaradas em arquivos .bzl
. Além disso, os argumentos *args
e **kwargs
não são permitidos em arquivos BUILD
. Em vez disso, liste todos os argumentos explicitamente.
É fundamental que programas em Starlark não possam executar E/S arbitrária. Essa variante torna a interpretação dos arquivos BUILD
hermética, dependendo apenas de um conjunto conhecido de entradas, o que é essencial para garantir que as versões sejam reproduzíveis.
Para mais detalhes, consulte Hermeticidade.
Os arquivos BUILD
precisam ser escritos usando apenas caracteres ASCII, embora eles sejam tecnicamente interpretados usando o conjunto de caracteres Latin-1.
Como os arquivos BUILD
precisam ser atualizados sempre que as dependências do
código subjacente mudam, eles geralmente são mantidos por várias pessoas em uma
equipe. Os autores de arquivos BUILD
precisam comentar livremente para documentar o papel de cada destino de criação, seja ele destinado para uso público ou não, e documentar o papel do próprio pacote.
Carregando uma extensão
Extensões do Bazel são arquivos que terminam em .bzl
. Use a instrução load
para importar
um símbolo de uma extensão.
load("//foo/bar:file.bzl", "some_library")
Esse código carrega o arquivo foo/bar/file.bzl
e adiciona o símbolo some_library
ao ambiente. Isso pode ser usado para carregar novas regras, funções ou constantes (por exemplo, uma string ou uma lista). Vários símbolos podem ser importados usando
outros argumentos para a chamada para load
. Os argumentos precisam ser literais de string (sem variável) e as instruções load
precisam aparecer no nível superior. Elas não podem estar no corpo de uma função.
O primeiro argumento de load
é um rótulo que identifica um arquivo .bzl
. Se for um rótulo relativo, será resolvido em relação ao pacote (não ao diretório) que contém o arquivo bzl
atual. Os rótulos relativos nas instruções load
precisam usar um :
à esquerda.
load
também é compatível com aliases. Portanto, é possível atribuir nomes diferentes aos símbolos importados.
load("//foo/bar:file.bzl", library_alias = "some_library")
É possível definir vários aliases em uma instrução load
. Além disso, a lista de argumentos pode conter aliases e nomes de símbolos regulares. O exemplo a seguir é perfeitamente legal (observe quando usar aspas).
load(":my_rules.bzl", "some_rule", nice_alias = "some_other_rule")
Em um arquivo .bzl
, os símbolos que começam com _
não são exportados e não podem ser carregados de outro arquivo.
É possível usar a visibilidade de carregamento para restringir
quem pode carregar um arquivo .bzl
.
Tipos de regras de compilação
A maioria das regras de criação vem em famílias, agrupadas por linguagem. Por exemplo, cc_binary
, cc_library
e cc_test
são as regras de build para binários,
bibliotecas e testes de C++, respectivamente. Outras linguagens usam o mesmo esquema de nomenclatura, com um prefixo diferente, como java_*
para Java. Algumas dessas funções estão documentadas na Enciclopédia da criação, mas qualquer pessoa pode criar novas regras.
As regras
*_binary
criam programas executáveis em uma determinada linguagem. Depois de uma versão, o executável ficará na árvore de saída binária da ferramenta de criação no nome correspondente para o rótulo da regra. Assim,//my:program
apareceria em (por exemplo)$(BINDIR)/my/program
.Em algumas linguagens, essas regras também criam um diretório de arquivos de execução contendo todos os arquivos mencionados em um atributo
data
pertencente à regra ou qualquer regra no fechamento transitivo de dependências. Esse conjunto de arquivos é reunido em um só lugar para facilitar a implantação na produção.As regras
*_test
são uma especialização de uma regra*_binary
, usada para testes automatizados. Os testes são simplesmente programas que não retornam nenhum sucesso.Assim como os binários, os testes também têm árvores runfiles, e os arquivos abaixo deles são os únicos que um teste pode abrir legitimamente no ambiente de execução. Por exemplo, um programa
cc_test(name='x', data=['//foo:bar'])
pode abrir e ler$TEST_SRCDIR/workspace/foo/bar
durante a execução. Cada linguagem de programação tem a própria função utilitária para acessar o valor de$TEST_SRCDIR
, mas todas são equivalentes a usar a variável de ambiente diretamente. A falha em observar a regra fará com que o teste falhe quando ele for executado em um host de teste remoto.As regras
*_library
especificam módulos compilados separadamente na linguagem de programação especificada. As bibliotecas podem depender de outras, e os binários e testes podem depender das bibliotecas, com o comportamento esperado de compilação separada.
Rótulos | Dependências |