Arquivos BUILD

As seções anteriores descreveram pacotes, destinos e rótulos, e o gráfico de dependência do build de forma 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 o uso de 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 build, e a ordem relativa dessas instruções é irrelevante. O que importa é quais regras foram declaradas e com quais valores, até o momento em que a avaliação do pacote foi concluída.

Quando uma função de regra de build, como cc_library, é executada, ela cria um novo destino no gráfico. Mais tarde, é possível referenciar esse destino usando um rótulo.

Em arquivos BUILD simples, as declarações de regras podem ser reordenadas livremente sem mudar o comportamento.

Para incentivar uma separação limpa 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 compreensões de lista e expressões if são permitidas. 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.

É importante destacar que os programas no Starlark não podem realizar E/S arbitrárias. Essa invariante torna a interpretação de arquivos BUILD hermética, dependente apenas de um conjunto conhecido de entradas, o que é essencial para garantir que os builds sejam reproduzíveis. Para mais detalhes, consulte Hermeticidade.

Os arquivos BUILD precisam ser gravados usando apenas caracteres ASCII, embora tecnicamente sejam 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 fazer comentários livres para documentar o papel de cada destino de build, seja para uso público ou não, e para documentar o papel do próprio pacote.

Carregar uma extensão

As 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 de load. Os argumentos precisam ser literais de string (sem variável) e as instruções load precisam aparecer no nível superior. Eles 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, ele será resolvido em relação ao pacote (não ao diretório) que contém o arquivo bzl atual. Rótulos relativos em instruções load precisam usar um : no início.

load também oferece suporte a aliases. Portanto, você pode atribuir nomes diferentes para os símbolos importados.

load("//foo/bar:file.bzl", library_alias = "some_library")

Você pode 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.

Use a visibilidade de carregamento para restringir quem pode carregar um arquivo .bzl.

Tipos de regras de build

A maioria das regras de build vem em famílias, agrupadas por idioma. Por exemplo, cc_binary, cc_library e cc_test são as regras de build para binários, bibliotecas e testes do 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 de build, mas é possível que qualquer pessoa crie novas regras.

  • As regras *_binary criam programas executáveis em uma determinada linguagem. Após um build, o executável residirá na árvore de saída binária da ferramenta de build no nome correspondente do rótulo da regra, de modo que //my:program apareceria (por exemplo) em $(BINDIR)/my/program.

    Em algumas linguagens, essas regras também criam um diretório de arquivos de execução que contém 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. Testes são simplesmente programas que retornam zero em caso de sucesso.

    Como os binários, os testes também têm árvores de arquivos de execução, e os arquivos abaixo deles são os únicos arquivos que um teste pode abrir legitimamente durante a 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 não observação da regra fará com que o teste falhe quando 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 de bibliotecas, com o comportamento de compilação separada esperado.

Rótulos Dependências