函数

目录

package

package(default_deprecation, default_package_metadata, default_testonly, default_visibility, features)

此函数声明适用于软件包中每条规则的元数据。它在软件包(BUILD 文件)中最多使用一次。

如需使用对应函数声明适用于整个 代码库中每条规则的元数据,请使用代码库根目录下的 repo() 函数在 REPO.bazel 文件中。repo() 函数接受的实参与 package() 完全相同。

package() 函数应在文件顶部的所有 load() 语句之后、任何规则之前调用。

实参

属性 说明
default_applicable_licenses

default_package_metadata. 的别名。

default_visibility

标签列表;默认值为 []

此软件包中顶级规则目标和符号 宏的默认可见性,即未在符号宏内声明的目标和符号宏 。如果目标或宏指定了 visibility 值,则系统会忽略此属性。

如需详细了解此属性的语法,请参阅 visibility 的文档。软件包的默认可见性不适用于 exports_files,后者默认处于公开状态。

default_deprecation

字符串;默认值为 ""

为此软件包中的所有规则设置默认 deprecation 消息。

default_package_metadata

标签列表;默认值为 []

设置适用于软件包中所有其他目标的默认元数据目标列表。 这些目标通常与 OSS 软件包和许可声明相关。 如需查看示例,请参阅 rules_license

default_testonly

布尔值;默认值为 False,另有说明的情况除外

为此软件包中的所有规则设置默认 testonly 属性。

javatests 下的软件包中,默认值为 True

features

字符串列表;默认值为 []

设置影响此 BUILD 文件的语义的各种标志。

此功能主要供构建系统开发者使用,用于 标记需要某种特殊处理的软件包。除非构建系统开发者 明确要求,否则请勿使用此功能。

示例

以下声明声明此软件包中的规则仅对软件包组 //foo:target 的成员可见。规则的单独可见性声明(如果存在)会替换此规范。
package(default_visibility = ["//foo:target"])

package_group

package_group(name, packages, includes)

此函数定义一组 软件包 ,并将标签与该组相关联。该标签可在 visibility 属性中引用。

软件包组主要用于控制可见性。公开可见的目标可以从源树中的每个软件包引用。私下可见的目标只能在其自己的软件包(而非子软件包)中引用。 在这两种极端情况之间,目标可以允许访问其自己的软件包,以及一个或多个软件包组描述的任何软件包。如需详细了解可见性系统,请参阅 visibility 属性。

如果给定的软件包与 packages 属性匹配,或者已包含在 includes 属性中提及的其他软件包组之一中,则该软件包被视为属于该组。

软件包组在技术上是目标,但不是由规则创建的,并且本身没有任何可见性保护。

实参

属性 说明
name

名称;必需

此目标的唯一名称。

packages

字符串列表;默认值为 []

零个或多个软件包规范的列表。

每个软件包规范字符串可以采用以下 形式之一:

  1. 软件包的完整名称,不包含其代码库,以 双斜杠开头。例如,//foo/bar 指定具有该名称且与软件包组位于同一代码库中的软件包组。
  2. 与上文相同,但带有尾随 /...。例如, //foo/... 指定 //foo 及其所有 子软件包的集合。//... 指定当前代码库中的所有软件包。
  3. 字符串 publicprivate,分别指定每个软件包或没有软件包。(此形式需要 设置标志 --incompatible_package_group_has_public_syntax。)

此外,前两种软件包规范还可以 带有前缀 -,以表示它们被否定。

软件包组包含与至少一个肯定规范匹配且与任何否定规范都不匹配的任何软件包。例如,值 [//foo/..., -//foo/tests/...] 包含 //foo 的所有子软件包,这些子软件包不是 //foo/tests 的子软件包。(//foo 本身包含在内,而 //foo/tests 本身不包含在内。)

除了公开可见性之外,没有其他方法可以直接指定 当前代码库之外的软件包。

如果缺少此属性,则等同于将其设置为空列表,也等同于将其设置为仅包含 private 的列表。

注意: Prior to Bazel 6.0, the specification //... had a legacy behavior of being the same as public. 在 Bazel 6.0 之前,规范 `//...` 的旧行为与 `public` 相同。此 行为在启用 --incompatible_fix_package_group_reporoot_syntax时得到修复,这是 Bazel 6.0 之后的默认设置。

注意: 在 Bazel 6.0 之前,当此属性序列化为 bazel query --output=proto(或 --output=xml)的一部分时,会省略前导斜杠。__注意:For instance, //pkg/foo/... will output as \"pkg/foo/...\". 在 Bazel 6.0 之后,当 --incompatible_package_group_includes_double_slash 启用时,此行为已修复,这是默认设置。

includes

标签列表;默认为 []

此软件包组中包含的其他软件包组。

标签列表;默认值为 `[]` 此软件包组中包含的其他软件包组。 此属性中的标签必须引用其他软件包组。aabbcc

与否定的软件包规范一起使用时,请注意,首先独立计算每个组的软件包集,然后将结果合并在一起。这意味着一个组中的否定规范对另一个组中的规范没有影响。

当与否定软件包规范一起使用时,请注意,每个组的软件包集首先是独立计算的,然后将结果合并在一起。

以下 package_group 声明指定了一个名为“tropical”的 包组,其中包含热带水果。

package_group(
    name = "tropical",
    packages = [
        "//fruits/mango",
        "//fruits/orange",
        "//fruits/papaya/...",
    ],
)

示例

package_group(
    name = "fooapp",
    includes = [
        ":controller",
        ":model",
        ":view",
    ],
)

package_group(
    name = "model",
    packages = ["//fooapp/database"],
)

package_group(
    name = "view",
    packages = [
        "//fooapp/swingui",
        "//fooapp/webui",
    ],
)

package_group(
    name = "controller",
    packages = ["//fooapp/algorithm"],
)

exports_files

exports_files([label, ...], visibility, licenses)

exports_files() 指定属于此软件包并导出到其他软件包的文件列表。

statementexports_files()`exports_files()` 指定属于此软件包且导出到其他软件包的文件列表。 Read more about visibility of files.

作为旧版行为,规则输入中提及的文件也会以默认可见性导出 ,直到翻转标志 --incompatible_no_implicit_file_export 。然而,不应依赖此行为,而应积极地 迁移。

作为旧版行为,在翻转标志 `--incompatible_no_implicit_file_export` 之前,提及为规则输入的文件也会以默认可见性导出。

不过,不应依赖此行为,而应主动迁移。实参如果未指定可见性,则文件 将对每个软件包可见,即使在package 函数中指定了软件包默认可见性 。还可以指定可见性声明;在这种情况下,文件将对指定的目标可见。

如果未指定可见性,则文件将对每个软件包可见,即使在 `package` 函数中指定了软件包的默认可见性也是如此。

以下示例导出 golden.txt,一个来自 test_data 包的文本文件,以便其他包可以使用它,例如在测试的 data 属性中。

# from //test_data/BUILD

exports_files(["golden.txt"])

示例

glob(include, exclude=[], exclude_directories=1, allow_empty=True)

Glob 是一个辅助函数,用于查找与某些路径模式匹配的所有文件, 并返回其路径的新的、可变的、已排序的列表。glob

源文件的标签包含在结果中,如果文件的包相对 路径与任何 include 模式匹配,并且不与任何 exclude 模式匹配。

includeexclude 列表包含相对于当前软件包的路径模式 。如果源文件的软件包相对路径与任何 `include` 模式匹配,并且与任何 `exclude` 模式都不匹配,则该源文件的标签将包含在结果中。与 Unix 路径一样,这些段由 /分隔。每个模式可以包含一个或多个路径段。与 Unix 路径一样,这些段以 / 分隔。*模式中的段与路径的段进行匹配。此外,** 通配符可以匹配 零个或多个完整路径段,但必须声明为独立 路径段。

此通配符可以在一个路径段中使用多次。
  • foo/bar.txt 与此包中的 foo/bar.txt 文件 完全匹配(除非 foo/ 是子包)
  • 示例:foo/*.txt 匹配 foo/ 目录中的每个文件 如果文件以 .txt 结尾(除非 foo/ 是 子包)
  • foo/a*.htm*foo/ 目录中以 a 开头,后跟任意字符串(可以 为空),再后跟 .htm,并以另一个任意字符串 结尾的每个文件匹配(除非 foo/ 是子软件包);例如 foo/axx.htmfoo/a.htmlfoo/axxx.html
  • foo/*foo/ 目录中的每个文件匹配, (除非 foo/ 是子软件包);即使 exclude_directories 设置为 0,它也不匹配 foo 目录本身
  • foo/** 与软件包第一级子目录 foo/ 下的每个非子软件包子目录中的每个文件匹配;如果 exclude_directories 设置为 0,则 foo 目录本身也与模式匹配;在这种情况下,** 被视为匹配零个路径段
  • **/a.txt 与此软件包的 a.txt 目录中的文件以及非子软件包子目录中的文件匹配。
  • **/bar/**/*.txt 与此软件包的每个非子软件包子目录中的每个 .txt 文件匹配;如果结果路径上至少有一个目录名为 bar,例如 xxx/bar/yyy/zzz/a.txtbar/a.txt(请记住 ** 也匹配零个段)或 bar/zzz/a.txt
  • ** 与此软件包的目录以及非子软件包子目录中的所有文件匹配。
  • foo**/a.txt 是无效模式,因为 ** 必须 独立作为段
  • foo/ 是无效模式,因为在 / 之后定义的第二个段是空字符串

如果启用了 exclude_directories 参数(设置为 1),则会从结果中省略 目录类型的文件(默认为 1)。

如果 allow_empty 参数设置为 False,则 glob 函数将出错,如果结果本来是 空列表。

存在一些重要的限制和注意事项:

  1. 由于 glob() 在 BUILD 文件评估期间运行, glob() 仅匹配源树中的文件,而不匹配 生成的文件。有几个重要的限制和注意事项:请参阅下面的示例 ,其中包含 :mylib:gen_java_srcs

  2. 如果规则与匹配的源文件同名,则该规则将 “遮蔽”该文件。

    要理解这一点,请记住 glob() 返回路径列表,因此在其他规则的属性(例如 srcs = glob(["*.cc"]))中使用 glob() 与明确列出匹配的路径具有相同的效果。如果规则与匹配的源文件同名,则该规则将“遮盖”该文件。glob()glob()["Foo.java", "bar/Baz.java"]有关更多详细信息,请参阅 GitHub 问题 #10395

  3. 例如,如果 `glob()` 生成 `["Foo.java", "bar/Baz.java"]`,但软件包中也有一个名为“Foo.java”的规则(这是允许的,但 Bazel 会发出警告),那么 `glob()` 的使用者将使用“Foo.java”规则(其输出),而不是“Foo.java”文件。 如需了解详情,请参阅 GitHub 问题 #10395。Glob 可能会匹配子目录中的文件。
  4. 并且子目录名称可能会使用通配符。

    例如,包 x中的 glob 表达式**/*.cc不包含x/y/z.cc,如果 x/y作为包存在(无论是作为 x/y/BUILD,还是在包路径上的其他位置)。这意味着 glob 表达式的结果实际上取决于 BUILD 文件的存在 — 也就是说,如果不存在名为 x/y 的软件包,或者使用 --deleted_packages 标志将其标记为已删除,则相同的 glob 表达式将包含 x/y/z.cc

  5. 例如,如果 `x/y` 作为软件包存在(无论是作为 `x/y/BUILD`,还是作为软件包路径上的其他位置),则软件包 `x` 中的 glob 表达式 `**/*.cc` 不包含 `x/y/z.cc`。
  6. . 开头的文件名完全匹配 *** 通配符。如果您想使用复合模式匹配隐藏文件 ,您的模式需要以 . 开头。例如, *.*.txt 将匹配 .foo.txt,但 *.txt 不会。 如果要使用复合模式匹配隐藏文件,则模式需要以 `.` 开头。隐藏目录 可能包含不需要作为输入的文件,并且会增加不必要地 glob 的文件数量和内存消耗。隐藏目录也以相同的方式匹配。
  7. “**” 通配符有一个特殊情况:模式 "**" 不匹配包的目录路径。也就是说,glob(["**"], exclude_directories = 0) 匹配当前软件包目录下的所有文件和目录(当然不包括子软件包的目录 - 请参阅之前的说明)。

”通配符有一个特殊情况:模式 `""` 与软件包的目录路径不匹配。也就是说,`glob(["**"], exclude_directories = 0)` 与当前软件包目录下的所有文件和目录(严格来说是传递性的)匹配(但当然不会进入子软件包的目录 - 请参阅有关该内容的上一条注释)。

一般来说,您应该**尝试为 glob 模式提供适当的扩展名(例如 *.html),而不是使用裸“*”** 。更明确的名称既是自记录的,又可确保您不会意外匹配备份文件或 emacs/vi/... 自动保存文件。请参阅下面的 展开的 glob 示例部分。

这样可以为每个输入生成单独的规则,例如。

从本目录中的所有 Java 文件以及由 :gen_java_srcs 规则生成的所有文件构建 Java 库。

java_library(
    name = "mylib",
    srcs = glob(["*.java"]) + [":gen_java_srcs"],
    deps = "...",
)

genrule(
    name = "gen_java_srcs",
    outs = [
        "Foo.java",
        "Bar.java",
    ],
    ...
)

Glob 示例 创建一个 Java 库,该库由该目录中的所有 Java 文件以及 `:gen_java_srcs` 规则生成的所有文件构建而成。包含 testdata 目录中的所有 txt 文件,但 experimental.txt 除外。

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(
        ["testdata/*.txt"],
        exclude = ["testdata/experimental.txt"],
    ),
)

请注意,testdata 子目录中的文件将不包含在内。

如果您希望包含这些文件,请使用递归 glob (**)。递归 Glob 示例(请参阅上面的限制 和注意事项。)

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(["testdata/**/*.txt"]),
)

包含 BUILD 文件的子目录将被忽略。 应尽可能避免此模式,因为它会降低构建 增量性,从而增加构建时间。

java_library(
    name = "mylib",
    srcs = glob(
        ["**/*.java"],
        exclude = ["**/testing/**"],
    ),
)

创建一个库,该库由该目录中的所有 Java 文件以及所有子目录构建而成,但路径中包含名为 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"])]

如果上面的 BUILD 文件在包 //foo 中,并且该包包含三个 匹配文件 a_test.cc、b_test.cc 和 c_test.cc,则运行 bazel query '//foo:all' 将列出生成的所有规则:

$ bazel query '//foo:all' | sort
//foo:count_lines_a_test
//foo:count_lines_b_test
//foo:count_lines_c_test

为当前目录中的 *_test.cc 创建单独的 genrule,用于统计文件中的行数。

select(
    {conditionA: valuesA, conditionB: valuesB, ...},
    no_match_error = "custom message"
)

select() 是使规则属性 可配置的辅助函数。 select`select()` 是一个辅助函数,用于使规则属性可配置。

它可以替换几乎任何属性赋值的右侧,因此其值取决于命令行 Bazel 标志。 __

sh_binary(
    name = "mytarget",
    srcs = select({
        ":conditionA": ["mytarget_a.sh"],
        ":conditionB": ["mytarget_b.sh"],
        "//conditions:default": ["mytarget_default.sh"]
    })
)

这使得 srcs 属性 的 sh_binary 可配置,方法是将其常规标签 列表分配替换为 select 调用,该调用将 配置条件映射到匹配值。Each condition is a label reference to a config_setting or constraint_value, which "matches" if the target's configuration matches an expected set of values. mytarget#srcs 的值会变成与当前调用匹配的标签列表。

每个条件都是对 `config_setting` 或 `constraint_value` 的标签引用,如果目标的配置与预期的一组值匹配,则该条件将“匹配”。

  • 然后,`mytarget#srcs` 的值将成为与当前调用匹配的任何标签列表。
  • 注意: 在任何调用中,系统都会选择一个条件。这意味着特化解析并非旨在创建如下面示例 2 中所示的顺序。
  • 如果多个条件匹配,并且其中一个不是所有其他条件的特化,则 Bazel 会报错,除非所有条件都解析为相同的值。
  • 特殊的伪标签 //conditions:default 被 视为匹配,如果没有其他条件匹配。如果此条件 被省略,则必须匹配其他规则以避免错误。
  • select 可以嵌入 更大的 属性赋值中。因此,srcs = ["common.sh"] + select({ ":conditionA": ["myrule_a.sh"], ...}) srcs = select({ ":conditionA": ["a.sh"]}) + select({ ":conditionB": ["b.sh"]}) 是有效的表达式。
  • select 可以嵌入到较大的属性赋值中。 __不兼容的 属性在其文档中标记为 nonconfigurable

    `select` 适用于大多数属性,但并非所有属性。

    subpackages(include, exclude=[], allow_empty=True)

    subpackages() 是一个辅助函数,类似于 glob() ,它列出子包而不是文件和目录。subpackagesglob()请参阅 glob,了解 include 和 exclude 模式的详细说明和示例。

    返回的子软件包列表按排序顺序排列,包含与当前加载软件包相关的路径,这些路径与 include 中的给定模式匹配,而不与 exclude 中的模式匹配。

    如需详细了解包含和排除模式并查看相关示例,请参阅 glob。

    返回的子软件包列表按排序顺序排列,并且包含与 foo/BUILD 中给定的模式匹配的相对于当前加载软件包的路径,但不包含与 `exclude` 中的模式匹配的路径。

    # The following BUILD files exist:
    # foo/BUILD
    # foo/bar/baz/BUILD
    # foo/bar/but/bad/BUILD
    # foo/sub/BUILD
    # foo/sub/deeper/BUILD
    #
    # In foo/BUILD a call to
    subs1 = subpackages(include = ["**"])
    
    # results in subs1 == ["sub", "bar/baz", "bar/but/bad"]
    #
    # 'sub/deeper' is not included because it is a subpackage of 'foo/sub' not of
    # 'foo'
    
    subs2 = subpackages(include = ["bar/*"])
    # results in subs2 = ["bar/baz"]
    #
    # Since 'bar' is not a subpackage itself, this looks for any subpackages under
    # all first level subdirectories of 'bar'.
    
    subs3 = subpackages(include = ["bar/**"])
    # results in subs3 = ["bar/baz", "bar/but/bad"]
    #
    # Since bar is not a subpackage itself, this looks for any subpackages which are
    # (1) under all subdirectories of 'bar' which can be at any level, (2) not a
    # subpackage of another subpackages.
    
    subs4 = subpackages(include = ["sub"])
    subs5 = subpackages(include = ["sub/*"])
    subs6 = subpackages(include = ["sub/**"])
    # results in subs4 and subs6 being ["sub"]
    # results in subs5 = [].
    #
    # In subs4, expression "sub" checks whether 'foo/sub' is a package (i.e. is a
    # subpackage of 'foo').
    # In subs5, "sub/*" looks for subpackages under directory 'foo/sub'. Since
    # 'foo/sub' is already a subpackage itself, the subdirectories will not be
    # traversed anymore.
    # In subs6, 'foo/sub' is a subpackage itself and matches pattern "sub/**", so it
    # is returned. But the subdirectories of 'foo/sub' will not be traversed
    # anymore.
    

    通常,建议用户使用 skylib 的“subpackages”模块,而不是直接调用此函数 skylib