A formatação de arquivos BUILD
segue a mesma abordagem que o Go, em que uma ferramenta padronizada
cuida da maioria dos problemas de formatação.
O Buildifier é uma ferramenta que analisa e
emite o código-fonte em um estilo padrão. Portanto, todos os arquivos BUILD
são
formatados da mesma forma automatizada, o que torna a formatação de não problema durante
as revisões de código. Ele também facilita o entendimento, a edição e
a geração de arquivos BUILD
pelas ferramentas.
A formatação do arquivo BUILD
precisa corresponder à saída de buildifier
.
Exemplo de formatação
# Test code implementing the Foo controller.
package(default_testonly = True)
py_test(
name = "foo_test",
srcs = glob(["*.py"]),
data = [
"//data/production/foo:startfoo",
"//foo",
"//third_party/java/jdk:jdk-k8",
],
flaky = True,
deps = [
":check_bar_lib",
":foo_data_check",
":pick_foo_port",
"//pyglib",
"//testing/pybase",
],
)
Estrutura do arquivo
Recomendação: use a seguinte ordem (todos os elementos são opcionais):
Descrição do pacote (um comentário)
Todas as instruções
load()
A função
package()
.Chamadas para regras e macros
O builder faz uma distinção entre um comentário independente e um comentário anexado a um elemento. Se um comentário não estiver anexado a um elemento específico, use uma linha vazia depois dele. Essa distinção é importante ao fazer alterações automatizadas, por exemplo, para manter ou remover um comentário ao excluir uma regra.
# Standalone comment (such as to make a section in a file)
# Comment for the cc_library below
cc_library(name = "cc")
Referências a destinos no pacote atual
Os arquivos precisam ser referenciados pelos caminhos deles em relação ao diretório do pacote,
sem usar referências acima, como ..
. Os arquivos gerados precisam ter
o prefixo ":
" para indicar que não são origens. Os arquivos de origem
não podem ter o prefixo :
. As regras precisam ser prefixadas com :
. Por
exemplo, supondo que x.cc
seja um arquivo de origem:
cc_library(
name = "lib",
srcs = ["x.cc"],
hdrs = [":gen_header"],
)
genrule(
name = "gen_header",
srcs = [],
outs = ["x.h"],
cmd = "echo 'int x();' > $@",
)
Nomeação de destinos
Os nomes de destino precisam ser descritivos. Se um destino contiver um arquivo de origem,
o destino geralmente terá um nome derivado dessa origem. Por exemplo, um
cc_library
para chat.cc
pode ser nomeado chat
ou um java_library
para
DirectMessage.java
pode ser chamado de direct_message
.
O destino homônimo de um pacote (o destino com o mesmo nome do diretório contido) precisa fornecer a funcionalidade descrita pelo nome do diretório. Caso contrário, não crie um destino de mesmo nome.
Use o nome curto ao se referir a um destino homônimo (//x
em vez de //x:x
). Se você estiver no mesmo pacote, prefira a referência
local (:x
em vez de //x
).
Evite usar nomes de destinos "reservados" que tenham um significado especial. Isso inclui
all
, __pkg__
e __subpackages__
, esses nomes têm semântica
especial e podem causar confusão e comportamentos inesperados quando são usados.
Na ausência de uma convenção de equipe prevalecente, estas são algumas recomendações não vinculativas usadas amplamente no Google:
- Em geral, use "snake_case"
- Para uma
java_library
com umsrc
, isso significa usar um nome diferente do nome do arquivo sem a extensão. - Para as regras
*_binary
e*_test
do Java, use "CamaleCase superior". Isso permite que o nome de destino corresponda a um dossrc
s. Parajava_test
, isso possibilita que o atributotest_class
seja inferido do nome do destino.
- Para uma
- Se houver várias variantes de um destino específico, adicione um sufixo para
remover a ambiguidade (como
:foo_dev
,:foo_prod
ou:bar_x86
,:bar_x64
) - Objetivos de sufixo
_test
com_test
,_unittest
,Test
ouTests
- Evite sufixos sem sentido, como
_lib
ou_library
, a menos que seja necessário para evitar conflitos entre um destino_library
e o_binary
correspondente. - Para destinos relacionados a proto:
proto_library
destinos precisam ter nomes terminados em_proto
- As regras
*_proto_library
específicas dos idiomas precisam corresponder ao proto subjacente, mas substitua_proto
por um sufixo específico da linguagem, como:cc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
Visibilidade
O escopo da visibilidade precisa ser o mais restrito possível, permitindo acesso a testes e dependências reversas. Use __pkg__
e __subpackages__
conforme
adequado.
Evite definir o pacote default_visibility
como //visibility:public
.
//visibility:public
precisa ser definido individualmente apenas para destinos na
API pública do projeto. Podem ser bibliotecas projetadas para depender de projetos externos ou binários que podem ser usados pelo processo de compilação de um projeto externo.
Dependências
As dependências precisam ser restritas a dependências diretas (dependências necessárias pelas fontes listadas na regra). Não liste dependências transitivas.
As dependências de pacote local precisam ser listadas primeiro e mencionadas de maneira compatível com a seção Referências aos destinos no pacote atual acima (não pelo nome absoluto do pacote).
Prefira listar as dependências diretamente como uma única lista. Colocar as dependências "comuns" de vários destinos em uma variável reduz a manutenção, impossibilita que as ferramentas mudem as dependências de um destino e pode levar a dependências não usadas.
Globs
Indique "nenhum destino" com []
. Não use um glob que não corresponda a nada: ele é mais propenso a erros e menos óbvio do que uma lista vazia.
Recursivo
Não use globs recursivos para corresponder a arquivos de origem (por exemplo,
glob(["**/*.java"])
).
Os globs recursivos dificultam a compreensão dos arquivos BUILD
porque pulam
subdiretórios contendo arquivos BUILD
.
Os globs recursivos geralmente são menos eficientes do que ter um arquivo BUILD
por diretório com um gráfico de dependência definido entre eles, porque isso melhora o armazenamento em cache remoto e o paralelismo.
Recomendamos criar um arquivo BUILD
em cada diretório e definir um
gráfico de dependência entre eles.
Não recursivo
Geralmente, os globs não recursivos são aceitáveis.
Outras convenções
Use letras maiúsculas e sublinhados para declarar constantes (como
GLOBAL_CONSTANT
) e use letras minúsculas e sublinhados para declarar variáveis (comomy_variable
).Os rótulos nunca devem ser divididos, mesmo que tenham mais de 79 caracteres. Os rótulos precisam ser literais de string sempre que possível. Justificativa: isso facilita a localização e a substituição. Isso também melhora a legibilidade.
O valor do atributo "name" precisa ser uma string constante literal (exceto em macros). Justificativa: as ferramentas externas usam o atributo de nome para indicar uma regra. Eles precisam encontrar regras sem precisar interpretar códigos.
Ao definir atributos do tipo booleano, use valores booleanos, não valores inteiros. Por motivos legados, as regras ainda convertem números inteiros em booleanos conforme necessário, mas essa ação não é recomendada. Lógica:
flaky = 1
pode ser entendido incorretamente como "diminuir este destino novamente executando-o uma vez".flaky = True
indica claramente que esse teste é instável.
Diferenças com o guia de estilo do Python
Embora a compatibilidade com o guia de estilo do Python seja um objetivo, existem algumas diferenças:
Sem limite de comprimento da linha. Comentários longos e strings longas geralmente são divididos em 79 colunas, mas isso não é necessário. Ele não pode ser aplicado em revisões de código ou scripts de pré-envio. Lógica: os rótulos podem ser longos e exceder esse limite. É comum que arquivos
BUILD
sejam gerados ou editados por ferramentas, o que não funciona bem com um limite de comprimento de linha.A concatenação de strings implícitas não é compatível. Use o operador
+
. Lógica: arquivosBUILD
contêm muitas listas de strings. É fácil esquecer uma vírgula, o que leva a um resultado completamente diferente. Isso criou muitos bugs no passado. Veja também esta discussão.Use espaços ao redor do sinal
=
para argumentos de palavras-chave nas regras. Lógica: argumentos nomeados são muito mais frequentes do que em Python e estão sempre em uma linha separada. Os espaços melhoram a legibilidade. Essa convenção já existe há muito tempo e não vale a pena modificar todos os arquivosBUILD
existentes.Por padrão, use aspas duplas para strings. Lógica: isso não é especificado no guia de estilo do Python, mas recomenda consistência. Por isso, decidimos usar apenas strings entre aspas duplas. Muitas linguagens usam aspas duplas para literais de string.
Use uma única linha em branco entre duas definições de nível superior. Lógica: a estrutura de um arquivo
BUILD
não é como um arquivo Python típico. Ela tem apenas instruções de nível superior. Usar uma linha em branco torna os arquivosBUILD
mais curtos.