glob模式
glob模式也被常称之为shell通配符,是一种特殊的模式匹配,通常用于匹配目录以及文件,而非文本。
# 匹配任意长度任意字符
*
# 匹配任意单个字符
?
# 匹配指定范围内的单个字符
[list]
# 匹配指定范围外的单个字符
[^list] [!list] 匹配指定范围外的任意单个字符或字符集合
# 匹配str1或者集合
{str1,[list]}
# 递归的任意目录
**
glob函数
def glob(include, exclude=[], exclude_directories=1, allow_empty=True)
Bazel中的glob函数是对glob模式匹配实现的简化版,它在当前包中(不包括子包)匹配所有文件列表。一般地,文件路径由/
分割为多个路径段组成;其中,*
匹配路径段中的零个或多个任意字符,**
匹配任意的路径段。
目前,Bazel实现的glob函数依旧不够完善,它仅支持*
和**
的模式匹配,而不支持?
,字符集合,及其大括号等模式。
只能匹配源文件,而不匹配派生文件
java_library(
name = "mylib",
srcs = glob(["*.java"]) + [":gen_java_srcs"],
)
genrule(
name = "gen_java_srcs",
outs = [
"Foo.java",
"Bar.java",
],
}
排除法
在当前包中,匹配testdata
目录下所有扩展名为txt
的文本文件列表,但排除testdata/experimental.txt
文件。注意,该规则不匹配testdata
子目录中的文件列表。
sh_test(
name = "mytest",
srcs = ["mytest.sh"],
data = glob(
["testdata/*.txt"],
exclude = ["testdata/experimental.txt"],
),
)
递归
在当前包中,匹配testdata
目录及子目录中扩展名为txt
的文本文件列表。
sh_test(
name = "mytest",
srcs = ["mytest.sh"],
data = glob(["testdata/**/*.txt"]),
)
如果要匹配当前目录,及其所有子目录,则以**
开头。例如,当前目录及其子目录下所有java
文件,当排除路径名中包括testing
的文件列表。
java_library(
name = "mylib",
srcs = glob(
["**/*.java"],
exclude = ["**/testing/**"],
),
)
动态规则
如下代码,可动态生成统计测试文件代码行的规则列表。
# Conveniently, the build language supports list comprehensions.
[genrule(
name = "count_lines_" + f[:-3], # strip ".cc"
srcs = [f],
outs = ["%s-linecount.txt" % f[:-3]],
cmd = "wc -l $< >$@",
) for f in glob(["*_test.cc"])]
此时,通过bazel query
可查询出动态生成的规则列表。此处,//foo:all
表示foo
包下的所有规则,不包括文件。
$ bazel query '//foo:all' | sort
//foo:count_lines_a_test
//foo:count_lines_b_test
//foo:count_lines_c_test
可构建任意目标。执行如下命令,将统计a_test.cc
文件的代码行,并将结果重定向至a_test-linecount.txt
之中。
$ bazel build //foo:count_lines_a_test
查看结果,显示22行。
$ cat bazel-bin/foo/a_test-linecount.txt
22 foo/a_test.cc
Bazel的动态性,再加持Shell
,可扩展的空间特别大,且语法是类Python的,相对Makefile非常易读。CMake在可扩展性和可读性,Bazel技高一筹。