假设我有一个创建native.cc_binary目标的宏:
def build_it(name, **kwargs):
native.cc_binary(
name = name + ".out",
linkopts = [
"-Lsomedir",
"-lsomelib"
],
**kwargs)
我也有这个规则需要一些资源,在它们上面运行一个工具,并生成一个值,将该值写入输出文件:
def _write_value_impl:
args = [f.path for f in ctx.files.srcs] + [ctx.outputs.out.path]
ctx.actions.run(
inputs = ctx.files.srcs,
outputs = [ctx.outputs.out],
arguments = args,
executable = ctx.executable._tool
)
write_value = rule(
implementation=_write_value_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"out": attr.output(mandatory = True),
"_tool": attr.label(
executable = True,
allow_files = True,
default = Label("//tools:generate_value")
}
)
好的,我想要做的是修改宏,以便将write_value规则生成的值添加到linkopts。像这样:
def build_it(name, value, **kwargs):
native.cc_binary(
name = name + ".out",
linkopts = [
"-Lsomedir",
"-lsomelib",
"-Wl,--defsym=SOME_SYMBOL={}".format(value)
],
**kwargs)
如何使这项工作?问题是build_it的目标是在分析时间生成的,但它所需的值是在评估时间生成的。此外,该值已放入文件中。如何从文件中获取值并将其提供给宏?
我怀疑代替宏,我需要一个规则,但如何让规则调用native.cc_binary?
答案 0 :(得分:1)
您可以编写repository_rule()
来创建文件并在加载阶段之前生成值,然后在分析期间规则可以访问@external_repo//...
中的文件。 https://docs.bazel.build/versions/master/skylark/repository_rules.html
答案 1 :(得分:-1)
这在Bazel无法做到,正是因为你所提到的。规则的所有输入都需要在分析阶段而不是执行阶段确定。 Bazel希望在执行任何操作之前构建完整的操作图,这需要write_value
规则在build_it
被分析之前运行。
解决方法可能是事先在Bazel之外自己生成BUILD
文件,然后在构建期间使用生成的BUILD
文件。
另一种解决方法是对linkopts
进行硬编码,以将其指定为您期望的内容。然后在write_value
中检查它们是否符合您的预期,如果不是则抛出退出代码。这样Bazel至少会在他们不匹配的时候发出警告,但要更新这两个地方需要花一些时间才能让他们再次对齐。
对于您的具体问题,有linker scripts甚至implicit linker scripts的概念。也许您可以生成一个并将其提供给cc_binary
属性中的srcs
。您可能需要将其命名为.o
文件(即使它不是目标文件)。 GCC链接器文档说:
如果指定链接器无法识别的链接器输入文件 作为目标文件或存档文件,它将尝试将文件读取为 链接器脚本。