问:将计算的linkopts传递给cc_binary规则?

时间:2018-01-09 18:50:36

标签: bazel

假设我有一个创建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?

2 个答案:

答案 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链接器文档说:

  

如果指定链接器无法识别的链接器输入文件   作为目标文件或存档文件,它将尝试将文件读取为   链接器脚本。