如何使用Bazel Build从生成的源文件构建静态库

时间:2018-01-24 08:18:05

标签: build bazel

我正在尝试使用Bazel进行以下设置。通过调用“bazel build”,Python脚本应生成具有随机名称的未知数量的* .cc文件,然后将这些文件编译为单个静态库(.a文件),所有这些都在一个Bazel调用中。我试过以下:一个生成的文件有固定名称,这个在genrule()和cc_library规则的srcs中引用。问题是我需要将所有生成的文件构建为库,而不仅仅是具有固定名称的文件。任何想法如何做到这一点? 我的BUILD文件:

py_binary(
    name = "sample_script",
    srcs = ["sample_script.py"],
)
genrule(
    name = "sample_genrule",
    tools = [":sample_script"],
    cmd = "$(location :sample_script)",
    outs = ["cpp_output_fixed.cc"], #or shall also the files with random names be defined here?
)
cc_library(
    name = "autolib",
    srcs = ["cpp_output_fixed.cc"],
    #srcs = glob([ #here should all generated .cc files be named
    #    "./*.cc",
    #    "./**/*.cc",
    #    ])+["cpp_output_fixed.cc"], 
)

Python文件sample_script.py:

#!/usr/bin/env python
import hashlib
import time

time_stamp = time.time()

time_1 = str(time_stamp)
time_2 = str(time_stamp + 1)

random_part_1 = hashlib.sha1(time_1).hexdigest()[-4:]
random_part_2 = hashlib.sha1(time_1).hexdigest()[-4:]

fixed_file = "cpp_output_fixed" + ".cc"
file_1 = "cpp_output_" + random_part_1 + ".cc"
file_2 = "cpp_output3_" + random_part_2 + ".cc"

with open(fixed_file, "w") as outfile:
    outfile.write("#include <iostream>"
                   "int main() {"
                   "  std::cout <<'''Hello_world'''    <<std::endl;"
                   "  return 0"
                   "}")

with open(file_1, "w") as outfile:
    outfile.write("#include <iostream>"
                   "int main() {"
                   "  std::cout <<'''Hello_world'''    <<std::endl;"
                   "  return 0"
                   "}")

with open(file_2, "w") as outfile_new:
    outfile_new.write("#include <iostream>"
                   "int main() {"
                   "  std::cout <<'''Hello_world''' <<std::endl;"
                   "  return 0"
                   "}")

print ".cc generation DONE"

2 个答案:

答案 0 :(得分:4)

[大编辑,因为我找到了一种让它起作用的方法:)]

如果您确实需要在分析阶段发出未知的文件,那么您唯一的方法就是我们内部调用树形工件。您可以将其视为包含仅在执行阶段检查的文件的目录。您可以使用ctx.actions.declare_directory从Skylark声明一个树形工件。

这是一个工作示例。注意事项:

  • 我们需要在目录名称中添加“.cc”来欺骗C ++规则这是有效的输入
  • 生成器需要创建bazel告诉它的目录
  • 你需要使用bazel @HEAD(或bazel 0.11.0及更高版本)

genccs.bzl:

def _impl(ctx):
  tree = ctx.actions.declare_directory(ctx.attr.name + ".cc")
  ctx.actions.run(
    inputs = [],
    outputs = [ tree ],
    arguments = [ tree.path ],
    progress_message = "Generating cc files into '%s'" % tree.path,
    executable = ctx.executable._tool,
  )

  return [ DefaultInfo(files = depset([ tree ])) ]

genccs = rule(
  implementation = _impl,
  attrs = {
    "_tool": attr.label(
      executable = True,
      cfg = "host",
      allow_files = True,
      default = Label("//:genccs"),
    )
  }
)

BUILD:

load(":genccs.bzl", "genccs")

genccs(
    name = "gen_tree",
)

cc_library(
    name = "main",
    srcs = [ "gen_tree" ]
)

cc_binary(
    name = "genccs",
    srcs = [ "genccs.cpp" ],
)

genccs.cpp

#include <fstream>
#include <sys/stat.h>
using namespace std;

int main (int argc, char *argv[]) {
  mkdir(argv[1], S_IRWXU);
  ofstream myfile;
  myfile.open(string(argv[1]) + string("/foo.cpp"));
  myfile << "int main() { return 42; }";
  return 0;
}

答案 1 :(得分:2)

1)列出所有输出文件。 2)使用genrule作为库的依赖。

genrule(
    name = "sample_genrule",
    tools = [":sample_script"],
    cmd = "$(location :sample_script)",
    outs = ["cpp_output_fixed.cc", "cpp_output_0.cc", ...]
)

cc_library(
    name = "autolib",
    srcs = [":sample_genrule"],
)