本页介绍了 Starlark 的基本样式准则,还包含有关宏和规则的信息。
Starlark 是一个 定义软件构建方式的语言, 一种编程语言
您将使用 Starlark 编写 BUILD
文件、宏和构建规则。宏和
规则本质上属于元语言,它们定义了 BUILD
文件的写入方式。
BUILD
文件应简单明了且重复。
所有软件的读取频率都高于写入频率。对于
Starlark,工程师会阅读 BUILD
文件来了解其依赖项,
及其 build 的详细信息。这种阅读通常是顺便、匆忙或在完成其他任务的同时进行的。因此,
简洁性和可读性非常重要
快速理解 BUILD
文件。
当用户打开 BUILD
文件时,他们会很快想知道
文件;或查看该 C++ 库的源代码列表;或移除
依赖项。每次添加抽象层时,
让用户更难完成这些任务
许多不同的工具也会分析和更新 BUILD
文件。工具可能无法
能够修改使用抽象的 BUILD
文件。保持 BUILD
文件的简单性有助于您获得更好的工具。随着代码库规模的扩大
会越来越频繁地在多个 BUILD
文件中进行更改,
更新库或执行清理操作
总体建议
- 将 Buildifier 用作格式设置工具和 lint 工具。
- 遵循测试指南。
样式
Python 样式
如有疑问,请遵循 尽可能遵循 PEP 8 风格指南。 具体而言,请使用四个空格(而非两个空格)进行缩进,以遵循 Python 惯例。
由于 Starlark 不是 Python,因此 Python 编程风格的某些方面不适用。例如,PEP 8 建议使用 is
与单例进行比较,但 is
在 Starlark 中不是运算符。
Docstring
使用文档字符串记录文件和函数。
在每个 .bzl
文件的顶部使用 docstring,并为每个公共函数使用 docstring。
文档规则和方面
规则和方面及其属性,以及提供商及其
字段,应使用 doc
参数进行记录。
命名惯例
- 变量和函数名称均使用小写字母,单词由
下划线 (
[a-z][a-z0-9_]*
),例如cc_library
。 - 顶级不公开值以一条下划线开头。Bazel 会强制执行私有值不能从其他文件中使用。本地变量不应 请使用下划线前缀。
行长
与 BUILD
文件一样,由于标签可以很长,因此没有严格的行长限制。尽可能每行使用最多 79 个字符(遵循 Python 的
风格指南,PEP 8)。不应严格执行此准则:编辑器应显示超过 80 列,自动更改会经常导致行更长,而人类不应花时间拆分已经可读的行。
关键字参数
在关键字参数中,最好在等号两边加空格:
def fct(name, srcs):
filtered_srcs = my_filter(source = srcs)
native.cc_library(
name = name,
srcs = filtered_srcs,
testonly = True,
)
布尔值
首选值 True
和 False
(而不是 1
和 0
)作为布尔值
(例如,在规则中使用布尔值属性时)。
仅将 print 用于调试
请勿在正式版代码中使用 print()
函数;该函数仅用于调试,并且会向 .bzl
文件的所有直接和间接用户发送垃圾邮件。唯一的例外情况是,如果 print()
默认处于停用状态且只能通过修改源代码才能启用,您可以提交使用 print()
的代码。例如,如果 print()
的所有用法都由 if DEBUG:
保护,其中 DEBUG
已硬编码为 False
。请注意,这些声明是否足够实用,以便证明它们对可读性的影响。
宏
宏是在加载过程中将一条或多条规则实例化的函数 阶段。一般来说,请尽可能使用规则,而不是宏。build 图表不是在测试期间 build - 在 Bazel 进行任何构建图分析之前会展开宏。
因此,如果出现问题,用户需要了解宏的实现才能排查构建问题。此外,由于结果中显示的目标来自宏展开,因此 bazel
query
结果可能难以解读。最后,aspect 不知道宏,因此依赖于 aspect 的工具(IDE 等)可能会失败。
宏的安全用法是用于定义要直接在 Bazel CLI 或 BUILD 文件中引用的其他目标:在这种情况下,只有这些目标的最终用户需要了解它们,并且宏引入的任何构建问题都与其用法密切相关。
对于用于定义生成的目标的宏(宏的实现详情) 不应在 CLI 中引用或受目标依赖 不会由该宏实例化),请遵循以下最佳做法:
- 宏应采用
name
参数并使用该名称定义目标。 该目标将成为该宏的主要目标。 - 生成的目标(即由宏定义的所有其他目标)应满足以下条件:
- 以
<name>
或_<name>
为前缀,例如,使用name = '%s_bar' % (name)
。 - 公开范围受限 (
//visibility:private
),并且 - 使用
manual
标记以避免在通配符目标(:all
、...
、:*
等)。
- 以
name
应仅用于派生宏定义的目标的名称,而不能用于任何其他用途。例如,不要使用名称派生 并非由宏本身生成的依赖项或输入文件。- 在宏中创建的所有目标都应以某种方式与主目标相关联。
- 请确保宏中的参数名称保持一致。如果将参数作为属性值传递给主目标,请保持其名称不变。如果宏参数的用途与常规规则属性(例如
deps
)相同,请使用与该属性相同的命名方式(见下文)。 - 调用宏时,请仅使用关键字参数。这与 并大大提高可读性。
工程师通常会编写宏,因为相关规则的 Starlark API 无论规则是否 例如,在原生代码中的 Bazel 或 Starlark 中定义。如果您遇到这种情况 请询问规则制定者是否可以扩展该 API 以完成您的 目标。
一般来讲,与规则类似的宏越多越好。
另请参阅宏。
规则
- 规则、切面及其属性应使用小写名称(“蛇形” 案例”)。
- 规则名称是名词,用于描述
从其依赖项的角度来看(对于叶规则,
用户)。这不一定是文件后缀。例如,一条规则
会生成 C++ 工件,这些工件将用作 Python 扩展,
py_extension
。对于大多数语言,典型规则包括:*_library
- 编译单元或“模块”。*_binary
- 用于生成可执行文件或部署单元的目标。*_test
- 测试目标。这可能包含多个测试。期待所有 测试在*_test
目标中是同一主题的变体, 测试单个库*_import
:用于封装预编译工件(例如.jar
,或在编译期间使用的.dll
。
- 为属性使用一致的名称和类型。某些普遍适用的
属性包括:
srcs
:label_list
,允许的文件:源文件,通常由人编写。deps
:label_list
,通常不允许文件:编译 依赖项data
:label_list
,允许文件:数据文件,如测试数据等。runtime_deps
:label_list
:不需要的运行时依赖项 以进行编译。
- 对于任何具有不明显行为的属性(例如,字符串模板)
以特定替代参数或以特定参数的形式调用工具,
要求),请使用
doc
关键字参数提供相关文档, 属性的声明(attr.label_list()
或类似值)。 - 规则实现函数几乎总是应为不公开函数(以下划线开头)。常见的做法是将
myrule
的实现函数命名为_myrule_impl
。 - 使用定义良好的提供程序接口在规则之间传递信息。声明和记录提供程序字段。
- 设计规则时应考虑可扩展性。请注意,其他规则可能需要与您的规则交互、访问您的提供程序,以及重复使用您创建的操作。
- 在规则中遵循效果指南。