参数

报告问题 查看来源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

一种以节省内存的方式封装构建部分或全部命令行所需数据的对象。

有时,某个操作需要一个包含从传递依赖项累积的值的大型命令行。例如,链接器命令行可能会列出所有被链接的库所需的所有对象文件。最佳做法是将此类传递性数据存储在 depset 中,以便多个目标可以共享这些数据。不过,如果规则作者必须将这些 depsets 转换为字符串列表才能构建操作命令行,那么这种内存共享优化就会失效。

因此,操作构建函数除了接受字符串之外,还接受 Args 对象。每个 Args 对象都表示字符串和 depset 的串联,并包含用于操纵数据的可选转换。Args 对象不会处理它们封装的 depsets,直到执行阶段需要计算命令行时才会处理。这有助于将任何开销较大的复制操作推迟到分析阶段完成后再进行。如需了解详情,请参阅优化性能页面。

通过调用 ctx.actions.args() 来构造 Args。它们可以作为 ctx.actions.run()ctx.actions.run_shell()arguments 参数传递。对 Args 对象的每次变异都会将值附加到最终的命令行。

借助 map_each 功能,您可以自定义项目转换为字符串的方式。如果您未提供 map_each 函数,则标准转换如下:

  • 已是字符串的值会保持不变。
  • File 对象会转换为其 File.path 值。
  • Label 对象会转换为字符串表示形式,在主代码库的上下文中解析时,该字符串表示形式会解析回同一对象。如果可能,字符串表示形式会使用代码库的显示名称,而不是代码库的规范名称,这使得该表示形式适合在 BUILD 文件中使用。虽然无法保证表示形式的确切形式,但典型示例包括 //foo:bar@repo//foo:bar@@canonical_name+//foo:bar.bzl
  • 所有其他类型都会以未指定的方式转换为字符串。因此,您应避免将非字符串或 File 类型的值传递给 add(),如果将这些值传递给 add_all()add_joined(),则应提供 map_each 函数。

使用字符串格式设置(add*() 方法的 formatformat_eachformat_joined 参数)时,格式模板的解读方式与字符串上的 % 替换相同,只不过模板必须只有一个替换占位符,并且必须是 %s。文本百分号可以转义为 %%。格式设置是在值转换为字符串后应用的,如上所述。

每个 add*() 方法都有一个替代形式,可接受一个额外的位置形参,即要插入到其余实参之前的“实参名称”字符串。对于 add_alladd_joined,如果序列为空,则不会添加额外的字符串。例如,相同的用法可以向命令行添加 --foo val1 val2 val3 --bar 或仅添加 --bar,具体取决于给定的序列是否包含 val1..val3 或是否为空。

如果命令行的大小可能会超出系统允许的最大大小,则可以将参数溢出到参数文件中。请参阅 use_param_file()set_param_file_format()

示例:假设我们要生成以下命令行:

--foo foo1.txt foo2.txt ... fooN.txt --bar bar1.txt,bar2.txt,...,barM.txt --baz
我们可以使用以下 Args 对象:
# foo_deps and bar_deps are depsets containing
# File objects for the foo and bar .txt files.
args = ctx.actions.args()
args.add_all("--foo", foo_deps)
args.add_joined("--bar", bar_deps, join_with=",")
args.add("--baz")
ctx.actions.run(
  ...
  arguments = [args],
  ...
)

成员

添加

Args Args.add(arg_name_or_value, value=unbound, *, format=None)

向此命令行附加一个实参。

参数

参数 说明
arg_name_or_value 必需
如果传递了两个位置参数,则此参数会被解读为实参名称。在值之前添加了实参名称,但未进行任何处理。如果只传递了一个位置参数,则该参数会被解读为 value(见下文)。
value 默认值为 unbound
要附加的对象。系统将使用上述标准转换将其转换为字符串。由于此函数没有 map_each 参数,因此 value 应该是字符串或 File。必须将列表、元组、depset 或目录 File 传递给 add_all()add_joined(),而不是传递给此方法。
format 字符串;或 None; 默认值为 None
要应用于 value 的字符串化版本的格式字符串模式。

add_all

Args Args.add_all(arg_name_or_values, values=unbound, *, map_each=None, format_each=None, before_each=None, omit_if_empty=True, uniquify=False, expand_directories=True, terminate_with=None, allow_closure=False)

将多个实参附加到此命令行。在执行阶段,系统会以延迟方式处理这些项。

大多数处理过程都是针对要附加的实参列表进行的,具体步骤如下:

  1. 每个目录 File 项都会被该目录中以递归方式包含的所有 File 所取代。
  2. 如果指定了 map_each,则将其应用于每个项,并将生成的字符串列表串联起来以形成初始实参列表。否则,初始实参列表就是对每个项应用标准转换后的结果。
  3. 列表中的每个实参(如果存在)都采用 format_each 格式。
  4. 如果 uniquify 为 true,则移除重复的实参。第一个出现的内容会保留。
  5. 如果提供 before_each 字符串,则会将其作为新实参插入到列表中的每个现有实参之前。这实际上使要附加的实参数量增加了一倍。
  6. 除非列表为空且 omit_if_empty 为 true(默认值),否则如果提供了实参名称和 terminate_with,则分别将其作为第一个和最后一个实参插入。
请注意,空字符串是有效的实参,需要经过所有这些处理步骤。

参数

参数 说明
arg_name_or_values 必需
如果传递了两个位置参数,则此参数会被解读为实参名称。实参名称会作为单独的实参添加到 values 之前,而不会经过任何处理。如果 omit_if_empty 为 true(默认值)且未附加任何其他项(如果 values 为空或其所有项都被过滤掉,就会出现这种情况),则不会添加此实参名称。如果只传递了一个位置参数,则该参数会被解读为 values(见下文)。
values 序列;或 depset; 默认值为 unbound
要附加其项的列表、元组或 depset。
map_each 可调用对象;或 None; 默认值为 None
一种函数,可将每个项转换为零个或多个字符串,这些字符串可能会在附加之前进一步处理。如果未提供此参数,则使用标准转化。

该函数会传递一个或两个位置实参:要转换的项,后跟可选的 DirectoryExpander。仅当提供的函数是用户定义的(非内置)且声明了多个形参时,才会传递第二个实参。

返回值的类型取决于要为相应商品生成多少个实参:

  • 在常见情况下,如果每个项都转换为一个字符串,则该函数应返回该字符串。
  • 如果需要完全过滤掉相应商品,该函数应返回 None
  • 如果该项变为多个字符串,则该函数会返回这些字符串的列表。
返回单个字符串或 None 的效果分别与返回长度为 1 或长度为 0 的列表相同。不过,在不需要创建列表的情况下避免创建列表会更高效且更易读。

通常情况下,当 expand_directories=True 设置为 true 时,目录项会自动展开即可显示其内容。不过,此函数不会展开包含在其他值中的目录,例如当项是具有目录作为字段的结构体时。在这种情况下,您可以应用 DirectoryExpander 实参来手动获取指定目录的文件。

为避免在执行阶段意外保留大型分析阶段数据结构,map_each 函数必须通过顶级 def 语句声明;默认情况下,它不能是嵌套的函数闭包。

警告:在调用 map_each 期间执行的 print() 语句不会产生任何可见的输出。

format_each 字符串;或 None; 默认值为 None
一个可选的格式字符串模式,应用于 map_each 函数返回的每个字符串。格式字符串必须有且只有 1 个“%s”占位符。
before_each 字符串;或 None; 默认值为 None
一个可选实参,用于在每个从 values 派生的实参之前附加内容。
omit_if_empty bool; 默认值为 True
如果为 true,则表示如果没有要附加的从 values 派生的实参,则会抑制所有进一步处理,并且命令行将保持不变。如果为 false,则无论是否存在其他实参,系统仍会附加实参名称和 terminate_with(如果已提供)。
uniquify bool; 默认值为 False
如果为 true,则会省略从 values 派生的重复实参。系统只会保留每个实参的第一次出现。通常不需要此功能,因为 depset 已经省略了重复项,但如果 map_each 为多个项发出相同的字符串,此功能可能会很有用。
expand_directories bool; 默认值为 True
如果为 true,则 values 中的任何目录都将展开为扁平的文件列表。此操作会在应用 map_each 之前发生。
terminate_with 字符串;或 None; 默认值为 None
一个可选实参,用于附加到所有其他实参之后。如果 omit_if_empty 为 true(默认值)且未附加任何其他项(如果 values 为空或其所有项都被过滤,则会发生这种情况),则不会添加此实参。
allow_closure bool; 默认值为 False
如果为 true,则允许在函数参数中使用闭包,例如 map_each。通常情况下,这没有必要,并且可能会将大型分析阶段数据结构保留到执行阶段。

add_joined

Args Args.add_joined(arg_name_or_values, values=unbound, *, join_with, map_each=None, format_each=None, format_joined=None, omit_if_empty=True, uniquify=False, expand_directories=True, allow_closure=False)

通过使用分隔符将多个值串联在一起,将实参附加到此命令行。在执行阶段,系统会以延迟方式处理这些项。

处理方式与 add_all() 类似,但从 values 派生的实参列表会像通过 join_with.join(...) 一样合并为单个实参,然后使用给定的 format_joined 字符串模板设置格式。与 add_all() 不同,没有 before_eachterminate_with 参数,因为当将多个项合并为单个实参时,这些参数通常没有用。

如果过滤后没有要连接到实参中的字符串,并且 omit_if_empty 为 true(默认值),则不进行任何处理。否则,如果没有要连接的字符串,但 omit_if_empty 为 false,则连接后的字符串将为空字符串。

参数

参数 说明
arg_name_or_values 必需
如果传递了两个位置参数,则此参数会被解读为实参名称。实参名称会添加到 values 之前,不会进行任何处理。如果 omit_if_empty 为 true(默认值),并且没有从 values 派生的字符串要连接在一起(如果 values 为空或其所有项都被过滤,则可能会出现这种情况),则不会添加此实参。如果只传递了一个位置参数,则该参数会被解读为 values(见下文)。
values 序列;或 depset;默认值为 unbound
要连接的项所在的列表、元组或 depset。
join_with string; 必需
一种分隔符字符串,用于以与 string.join() 相同的方式将应用 map_eachformat_each 后获得的字符串联接在一起。
map_each 可调用对象;或 None; 默认值为 None
add_all 相同。
format_each 字符串;或 None; 默认值为 None
add_all 的相同。
format_joined string;或 None; 默认值为 None
应用于联接字符串的可选格式字符串模式。格式字符串必须有且只有 1 个“%s”占位符。
omit_if_empty bool;默认值为 True
如果为 true,则当没有要连接的字符串(因为 values 为空或其所有项都被过滤掉)时,系统会抑制所有进一步处理,并且命令行将保持不变。如果为 false,即使没有要联接的字符串,也会附加两个实参:实参名称后跟一个空字符串(这是零个字符串的逻辑联接)。
uniquify bool; 默认值为 False
add_all 相同。
expand_directories bool; 默认值为 True
add_all 相同。
allow_closure bool; 默认值为 False
add_all 相同。

set_param_file_format

Args Args.set_param_file_format(format)

设置参数文件的格式(如果使用参数文件)

参数

参数 说明
format string; required
Must be one of:
  • “multiline”:每个项(实参名称或值)都按原样写入参数文件,并在后面添加一个换行符。
  • “shell”:与“multiline”相同,但项会加上 shell 引号
  • “flag_per_line”:与“multiline”相同,但 (1) 只有标志(以“--”开头)会写入参数文件,并且 (2) 标志的值(如果有)会与“=”分隔符一起写入同一行。这是 Abseil 标志库所需的格式。

如果未调用,格式默认为“shell”。

use_param_file

Args Args.use_param_file(param_file_arg, *, use_always=False)

将实参溢出到参数文件,并将其替换为指向参数文件的指针。当您的实参可能过大,超出系统命令长度限制时使用。

为了提高效率,Bazel 可能会选择在执行期间省略将参数文件写入输出树的操作。如果您要调试操作并检查参数文件,请将 --materialize_param_files 传递给 build。

参数

参数 说明
param_file_arg string; 必需
包含单个“%s”的格式字符串。如果实参溢出到参数文件,则会替换为包含此字符串(格式为参数文件的路径)的实参。

例如,如果实参溢出到参数文件“params.txt”,则指定“--file=%s”会导致操作命令行包含“--file=params.txt”。

use_always bool; 默认值为 False
是否始终将实参溢出到参数文件。如果为 false,bazel 将根据您的系统和实参长度来决定是否需要溢出实参。