本页简要介绍了 Starlark(以前称为 Skylark),这是 Bazel 中使用的语言。如需查看函数和类型的完整列表,请参阅 Bazel API 参考文档。
如需详细了解该语言,请参阅 Starlark 的 GitHub 代码库。
如需查看 Starlark 语法和行为的权威规范,请参阅 Starlark 语言规范。
语法
Starlark 的语法灵感源自 Python3。以下是 Starlark 中的有效语法:
def fizz_buzz(n):
"""Print Fizz Buzz numbers from 1 to n."""
for i in range(1, n + 1):
s = ""
if i % 3 == 0:
s += "Fizz"
if i % 5 == 0:
s += "Buzz"
print(s if s else i)
fizz_buzz(20)
Starlark 的语义可能与 Python 不同,但行为差异很少见,除非 Starlark 引发错误。支持以下 Python 类型:
可变性
Starlark 倾向于不可变性。有两种可变数据结构:列表和字典。对可变数据结构(例如向列表附加值或删除字典中的条目)所做的更改仅对在当前上下文中创建的对象有效。上下文结束后,其值将变为不可变。
这是因为 Bazel 构建使用并行执行。在 build 期间,每个 .bzl
文件和每个 BUILD
文件都有自己的执行上下文。每条规则也会在各自的上下文中进行分析。
我们以文件 foo.bzl
为例:
# `foo.bzl`
var = [] # declare a list
def fct(): # declare a function
var.append(5) # append a value to the list
fct() # execute the fct function
当 foo.bzl
加载时,Bazel 会创建 var
。因此,var
是 foo.bzl
上下文的一部分。当 fct()
运行时,它会在 foo.bzl
的上下文中运行。在完成对 foo.bzl
的评估后,环境包含一个不可变条目 var
,其值为 [5]
。
当另一个 bar.bzl
从 foo.bzl
加载符号时,加载的值保持不变。因此,bar.bzl
中的以下代码是违规的:
# `bar.bzl`
load(":foo.bzl", "var", "fct") # loads `var`, and `fct` from `./foo.bzl`
var.append(6) # runtime error, the list stored in var is frozen
fct() # runtime error, fct() attempts to modify a frozen list
在 bzl
文件中定义的全局变量无法在定义它们的 bzl
文件之外进行更改。与上面使用 bzl
文件的示例一样,规则返回的值是不可变的。
BUILD 文件与 .bzl 文件之间的区别
BUILD
文件通过调用规则来注册目标。.bzl
文件提供常量、规则、宏和函数的定义。
原生函数和原生规则是 BUILD
文件中的全局符号。bzl
文件需要使用 native
模块加载这些文件。
BUILD
文件存在两项语法限制:1) 不允许声明函数;2) 不允许使用 *args
和 **kwargs
实参。
与 Python 的区别
全局变量是不可变的。
不允许在顶层使用
for
语句。请在函数中使用这些变量。在BUILD
文件中,您可以使用列表推导式。不允许在顶层使用
if
语句。不过,可以使用if
表达式:first = data[0] if len(data) > 0 else None
。用于迭代字典的确定性顺序。
不允许递归。
Int 类型仅限于 32 位有符号整数。如果发生溢出,系统会抛出错误。
在迭代期间修改集合会出错。
除了等值测试之外,比较运算符
<
、<=
、>=
、>
等未跨值类型定义。简而言之:5 < 'foo'
会抛出错误,而5 == "5"
会返回 false。在元组中,只有当元组位于圆括号之间时,尾随逗号才有效,即您应编写
(1,)
而不是1,
。字典字面值不能包含重复的键。例如,以下代码会出错:
{"a": 4, "b": 7, "a": 1}
。字符串用双引号表示(例如,当您调用 repr 时)。
字符串不可迭代。
不支持以下 Python 功能: