Esta página aborda as diretrizes básicas de estilo para o Starlark e também inclui informações sobre macros e regras.
Starlark é uma linguagem que define como o software é criado e, portanto, é uma linguagem de programação e de configuração.
Você vai usar o Starlark para gravar arquivos BUILD, macros e regras de build. Macros e
regras são essencialmente metalinguagens: elas definem como os arquivos BUILD são gravados.
BUILD arquivos são simples e repetitivos.
Todos os softwares são lidos com mais frequência do que são gravados. Isso é especialmente verdadeiro para
Starlark, já que os engenheiros leem BUILD arquivos para entender as dependências dos
destinos e os detalhes dos builds. Essa leitura geralmente acontece rapidamente,
com pressa ou em paralelo à realização de outra tarefa. Consequentemente,
a simplicidade e a legibilidade são muito importantes para que os usuários possam analisar e
compreender BUILD arquivos rapidamente.
Quando um usuário abre um arquivo BUILD, ele quer saber rapidamente a lista de destinos em
o arquivo, revisar a lista de fontes dessa biblioteca C++ ou remover uma
dependência desse binário Java. Cada vez que você adiciona uma camada de abstração, você
torna mais difícil para um usuário realizar essas tarefas.
Os arquivos BUILD também são analisados e atualizados por muitas ferramentas diferentes. As ferramentas podem não
conseguir editar o arquivo BUILD se ele usar abstrações. Manter os BUILD
arquivos simples permite que você tenha melhores ferramentas. À medida que uma base de código cresce, torna-se mais frequente fazer mudanças em muitos arquivos BUILD para atualizar uma biblioteca ou fazer uma limpeza.
Recomendações gerais
- Use 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, quando possível. Em particular, use quatro espaços em vez de dois para o recuo, seguindo 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.
Docstring
Documente arquivos e funções usando docstrings.
Use uma docstring na parte de cima de cada arquivo .bzl e uma docstring para cada função pública.
Documentar regras e aspectos
As regras e os aspectos, juntamente com os atributos, bem como os provedores e os
campos, precisam ser documentados usando o doc argumento.
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 exige que os valores particulares não possam ser usados em outros arquivos. As variáveis locais não podem usar o prefixo de sublinhado.
Comprimento da linha
Assim como nos arquivos BUILD, não há limite de comprimento de linha, já que os rótulos podem ser longos.
Quando possível, tente usar no máximo 79 caracteres por linha (seguindo o guia de estilo do Python, PEP 8). Essa diretriz
não precisa ser aplicada de forma estrita: os editores precisam mostrar mais de 80 colunas,
as mudanças automatizadas geralmente introduzem linhas mais longas e as pessoas não precisam
gastar tempo dividindo linhas que já são legíveis.
Argumentos de palavra-chave
Em argumentos de palavra-chave, os espaços ao redor do sinal de igual são preferidos:
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 a impressão apenas para depuração
Não use a função print() no código de produção. Ela é destinada apenas à
depuração e vai enviar spam para todos os usuários diretos e indiretos do arquivo .bzl. A
única exceção é que você pode enviar um código que usa 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 é codificado como
False. Considere se essas declarações são úteis o suficiente para justificar
o impacto 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 de build visto pelo usuário não é o mesmo usado pelo Bazel durante o build. As macros são expandidas antes que o Bazel faça qualquer análise de gráfico de build.
Por isso, quando algo dá errado, o usuário precisa entender
a implementação da macro para solucionar problemas de build. Além disso, os resultados de bazel
query podem ser difíceis de interpretar porque os destinos mostrados nos resultados
vêm da expansão de macros. Por fim, os aspectos não reconhecem macros, então as ferramentas
que dependem de aspectos (IDEs e outras) podem falhar.
Um uso seguro para macros é definir destinos adicionais destinados a serem referenciados diretamente na CLI do Bazel ou em arquivos BUILD. Nesse caso, apenas os usuários finais desses destinos precisam conhecê-los, e todos os problemas de build 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 referenciados na CLI ou dependentes de destinos não instanciados por essa macro), siga estas práticas recomendadas:
- Uma macro precisa receber um argumento
namee definir um destino com esse nome. Esse destino se torna o destino principal da macro. - Os destinos gerados, ou seja, todos os outros destinos definidos por uma macro, precisam:
- Ter os nomes prefixados por
<name>ou_<name>. Por exemplo, usandoname = '%s_bar' % (name). - Ter visibilidade restrita (
//visibility:private) e - Ter uma tag
manualpara evitar a expansão em destinos curinga (:all,...,:*, etc.).
- Ter os nomes prefixados por
- O
namesó pode 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 estar acoplados de alguma forma ao destino principal.
- Convencionalmente,
nameprecisa ser o primeiro argumento ao definir uma macro. - Mantenha os nomes dos parâmetros na macro consistentes. Se um parâmetro for transmitido
como um valor de atributo para o destino principal, mantenha o nome dele. Se um macro
parâmetro tiver a mesma finalidade que um atributo de regra comum, como
deps, nomeie-o como o atributo (confira abaixo). - Ao chamar uma macro, use apenas argumentos de palavra-chave. Isso é consistente com as regras e melhora muito a legibilidade.
Os engenheiros geralmente gravam macros quando a API Starlark de regras relevantes é insuficiente para o caso de uso específico, independentemente de a regra ser definida no Bazel em código nativo ou no Starlark. Se você estiver enfrentando este problema, pergunte ao autor da regra se ele pode estender a API para alcançar seus objetivos.
Como regra geral, quanto mais as macros se assemelharem às regras, melhor.
Consulte também macros.
Regras
- As regras, os aspectos e os atributos precisam usar nomes em letras minúsculas ("snake case").
- Os nomes das regras são substantivos que descrevem o tipo principal de artefato produzido pela
regra, do ponto de vista das dependências (ou, para regras de folha, do
usuário). Isso não é necessariamente um sufixo de arquivo. Por exemplo, uma regra que
produz artefatos C++ destinados a serem usados como extensões Python pode ser chamada de
py_extension. Para a maioria das linguagens, as regras típicas incluem:*_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. Espere que todos os testes em um*_testdestino sejam variações do mesmo tema, por exemplo, testar uma única biblioteca.*_import: um destino que encapsula um artefato pré-compilado, como um.jarou um.dllusado durante a compilação.
- Use nomes e tipos consistentes para atributos. Alguns atributos geralmente aplicáveis
incluem:
srcs:label_list, que permite arquivos: arquivos de origem, normalmente criados por humanos.deps:label_list, geralmente não permite arquivos: dependências de compilação.data:label_list, que permite arquivos: arquivos de dados, como dados de teste etc.runtime_deps:label_list: dependências de ambiente de execução que não são necessárias para a compilação.
- Para atributos com comportamento não óbvio (por exemplo, modelos de string
com substituições especiais ou ferramentas que são invocadas com requisitos
específicos), forneça documentação usando o argumento de palavra-chave
docpara a declaração do atributo (attr.label_list()ou semelhante). - As funções de implementação de regras quase sempre precisam ser funções particulares
(nomeadas com um sublinhado à esquerda). Um estilo comum é dar à
função de implementação de
myruleo nome_myrule_impl. - Transmita informações entre as regras usando uma interface de provedor bem definida. Declare e documente os campos do provedor.
- Projete sua regra com extensibilidade em mente. Considere que outras regras podem querer interagir com sua regra, acessar seus provedores e reutilizar as ações criadas.
- Siga as diretrizes de performance nas regras.