Esta página aborda as diretrizes de estilo básicas para o Starlark e também inclui informações sobre macros e regras.
O Starlark é uma linguagem que define o modo como o software é criado. Assim, ele é uma linguagem de programação e configuração.
Você usará o Starlark para criar arquivos BUILD
, macros e regras de build. Macros e regras são basicamente linguagens meta. Elas definem como os arquivos BUILD
são gravados.
Os arquivos BUILD
devem ser simples e repetitivos.
Todo software é lido com mais frequência do que é escrito. Isso é especialmente verdadeiro para
o Starlark, já que os engenheiros leem arquivos BUILD
para entender as dependências dos
destinos e detalhes dos builds. Essa leitura geralmente acontece ao passar,
com pressa ou em paralelo à realização de alguma outra tarefa. Consequentemente,
a simplicidade e a legibilidade são muito importantes para que os usuários possam analisar e
apreciar arquivos BUILD
rapidamente.
Quando um usuário abre um arquivo BUILD
, ele quer rapidamente saber a lista de destinos no
arquivo, analisar a lista de origens dessa biblioteca C++ ou remover uma
dependência desse binário Java. Cada vez que você adiciona uma camada de abstração, dificulta o trabalho do usuário com essas tarefas.
Os arquivos BUILD
também são analisados e atualizados por muitas ferramentas diferentes. Talvez as ferramentas não consigam
editar o arquivo BUILD
se ele usar abstrações. Manter os arquivos BUILD
simples permite que você tenha ferramentas melhores. À medida que uma base de código cresce, cada vez mais frequente fazer mudanças em muitos arquivos BUILD
para
atualizar uma biblioteca ou fazer uma limpeza.
Recomendações gerais
- Usar o Buildifier como formatador e linter.
- Siga as diretrizes de teste.
Estilo
Estilo Python
Em caso de dúvida, siga o guia de estilo PEP 8 sempre que possível. Use especificamente quatro em vez de dois espaços para recuo para seguir a convenção do Python.
Como o
Starlark não é Python,
alguns aspectos do estilo Python não se aplicam. Por exemplo, o PEP 8 aconselha que
comparações com singletons sejam feitas com is
, que não é um operador no
Starlark.
String do documento
Documente arquivos e funções usando docstrings.
Use um docstring na parte superior de cada arquivo .bzl
e um docstring para cada função
pública.
Regras e aspectos do documento
As regras e os aspectos, além dos atributos, além de provedores e campos, devem ser documentados usando o argumento doc
.
Convenção de nomenclatura
- Os nomes de variáveis e funções usam letras minúsculas com palavras separadas por sublinhados (
[a-z][a-z0-9_]*
), comocc_library
. - Os valores particulares de nível superior começam com um sublinhado. O Bazel determina que os valores particulares não podem ser usados de outros arquivos. As variáveis locais não podem usar o prefixo de sublinhado.
Comprimento da linha
Como nos arquivos BUILD
, não há um limite rigoroso para o tamanho das linhas, porque os rótulos podem ser longos.
Sempre que possível, tente usar no máximo 79 caracteres por linha (seguindo o guia de estilo
do Python, PEP 8). Essa diretriz
não deve ser aplicada de forma rigorosa: os editores precisam exibir mais de 80 colunas,
as mudanças automatizadas introduzirão linhas mais longas com frequência, e os humanos não devem
passar tempo dividindo linhas que já são legíveis.
Argumentos de palavra-chave
Em argumentos de palavra-chave, é melhor usar espaços ao redor do sinal de igual:
def fct(name, srcs):
filtered_srcs = my_filter(source = srcs)
native.cc_library(
name = name,
srcs = filtered_srcs,
testonly = True,
)
Valores booleanos
Prefira os valores True
e False
(em vez de 1
e 0
) para valores booleanos
(como ao usar um atributo booleano em uma regra).
Usar somente impressão para depuração
Não use a função print()
no código de produção. Ela se destina apenas à depuração e vai enviar spam para todos os usuários diretos e indiretos do seu arquivo .bzl
. A única exceção é que você poderá enviar um código que use print()
se ele estiver desativado por padrão e só puder ser ativado editando a origem. Por exemplo, se todos os usos de print()
forem protegidos por if DEBUG:
, em que DEBUG
é fixado no código para False
. Verifique se essas declarações são úteis o suficiente para justificar o impacto delas na legibilidade.
Macros
Uma macro é uma função que instancia uma ou mais regras durante a fase de carregamento. Em geral, use regras sempre que possível em vez de macros. O gráfico do build visto pelo usuário não é o mesmo usado pelo Bazel durante a criação. As macros são expandidas antes do Bazel fazer qualquer análise do gráfico do build.
Por isso, quando algo dá errado, o usuário precisa entender
a implementação da macro para resolver problemas de build. Além disso, os resultados do bazel
query
podem ser difíceis de interpretar, porque os destinos mostrados nos resultados
vêm da expansão da macro. Por fim, os aspectos não estão cientes de macros. Portanto, as ferramentas
dependendo de aspectos (IDEs e outros) podem falhar.
O uso seguro de macros é definido para outros destinos a serem referenciados diretamente na CLI do Bazel ou em arquivos BUILD. Nesse caso, basta que os usuários finais desses destinos tenham conhecimento sobre eles, e os problemas de compilação introduzidos por macros nunca estão longe do uso.
Para macros que definem destinos gerados (detalhes de implementação da macro que não devem ser referidos na CLI ou dependentes de destinos não instanciados por essa macro), siga estas práticas recomendadas:
- Uma macro precisa usar um argumento
name
e definir um destino com esse nome. Esse destino se torna o destino principal dessa macro. - Os destinos gerados, que são todos os outros destinos definidos por uma macro, precisam:
- Use
<name>
ou_<name>
como prefixo dos nomes. Por exemplo, usandoname = '%s_bar' % (name)
. - têm visibilidade restrita (
//visibility:private
); - Use uma tag
manual
para evitar a expansão em destinos de caracteres curinga (:all
,...
,:*
etc.).
- Use
- O
name
só deve ser usado para derivar nomes de destinos definidos pela macro, e não para mais nada. Por exemplo, não use o nome para derivar uma dependência ou um arquivo de entrada que não seja gerado pela própria macro. - Todos os destinos criados na macro precisam ser vinculados de alguma forma ao destino principal.
- Mantenha os nomes dos parâmetros consistentes na macro. Se um parâmetro for transmitido
como um valor de atributo para o destino principal, mantenha o nome dele. Se um parâmetro
macro tiver a mesma finalidade de um atributo de regra comum, como
deps
, dê um nome para ele (veja abaixo). - Ao chamar uma macro, use somente argumentos de palavras-chave. Isso é consistente com as regras e melhora muito a legibilidade.
Os engenheiros costumam gravar macros quando a API Starlark de regras relevantes é suficiente para o caso de uso específico, independentemente de a regra estar definida no Bazel em código nativo ou no Starlark. Se você estiver enfrentando esse problema, pergunte ao autor da regra se ele pode estender a API para alcançar suas metas.
Como regra geral, quanto mais macros se assemelharem às regras, melhor.
Veja também macros.
Regras
- Regras, aspectos e os atributos delas precisam usar nomes com letras minúsculas ("caso snake").
- Nomes de regras são substantivos que descrevem o tipo principal de artefato produzido pela regra, do ponto de vista das dependências dela (ou, para regras de folha, o usuário). Isso não é necessariamente um sufixo de arquivo. Por exemplo, uma regra que
produz artefatos C++ que serão usados como extensões do Python pode ser chamada
py_extension
. Para a maioria dos idiomas, as regras comuns são:*_library
: uma unidade de compilação ou "módulo".*_binary
: um destino que produz um executável ou uma unidade de implantação.*_test
: um destino de teste. Isso pode incluir vários testes. Todos os testes em um destino*_test
precisam ser variações do mesmo tema, por exemplo, testando uma única biblioteca.*_import
: um destino que encapsula um artefato pré-compilado, como um.jar
ou.dll
usado durante a compilação.
- Use nomes e tipos consistentes para os atributos. Estes são alguns dos atributos
geralmente aplicáveis:
srcs
:label_list
, permitindo arquivos: arquivos de origem, normalmente criados por humanos.deps
:label_list
, normalmente não permitindo arquivos: dependências de compilação.data
:label_list
, permitindo arquivos: arquivos de dados, como dados de teste etc.runtime_deps
:label_list
: dependências de execução que não são necessárias para compilação.
- Para atributos com comportamento não óbvio, como modelos de string
com substituições especiais ou ferramentas que são invocadas com requisitos
específicos, forneça a documentação usando o argumento de palavra-chave
doc
na declaração do atributo (attr.label_list()
ou semelhante). - As funções de implementação de regras precisam ser quase sempre funções privadas
(com um sublinhado no início). Um estilo comum é dar à
função de implementação do
myrule
o nome_myrule_impl
. - Transmita informações entre suas regras usando uma interface de provedor bem definida. Declare e documente os campos do provedor.
- Crie sua regra com a extensibilidade em mente. Considere que outras regras podem interagir com ela, acessar seus provedores e reutilizar as ações criadas.
- Siga as diretrizes de desempenho nas suas regras.