如何使用 Bazel Build 从生成的源文件构建静态库
How to build static library from the Generated source files using Bazel Build
我正在尝试使用 Bazel 进行以下设置 运行。通过调用“bazel build”,一个 Python 脚本应该生成未知数量的随机名称的 *.cc 文件,然后将它们编译成单个静态库(.a 文件),所有这些都在一次 Bazel 调用中完成。我试过以下方法:一个生成的文件有固定的名称,这个文件在 genrule() 和 srcs of cc_library 规则中被引用。问题是我需要将所有生成的文件构建为库,而不仅仅是具有固定名称的文件。任何想法如何做到这一点?
我的构建文件:
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"
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"],
)
[大修改,因为我找到了让它工作的方法:)]
如果您确实需要发出在分析阶段未知的文件,您唯一的方法就是我们内部称为树工件的方法。您可以将其视为包含仅在执行阶段检查的文件的目录。您可以使用 ctx.actions.declare_directory.
从 Skylark 声明一个树工件
这是一个工作示例。注意 3 件事:
- 我们需要在目录名中添加“.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"),
)
}
)
构建:
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;
}
我正在尝试使用 Bazel 进行以下设置 运行。通过调用“bazel build”,一个 Python 脚本应该生成未知数量的随机名称的 *.cc 文件,然后将它们编译成单个静态库(.a 文件),所有这些都在一次 Bazel 调用中完成。我试过以下方法:一个生成的文件有固定的名称,这个文件在 genrule() 和 srcs of cc_library 规则中被引用。问题是我需要将所有生成的文件构建为库,而不仅仅是具有固定名称的文件。任何想法如何做到这一点? 我的构建文件:
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"
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"],
)
[大修改,因为我找到了让它工作的方法:)]
如果您确实需要发出在分析阶段未知的文件,您唯一的方法就是我们内部称为树工件的方法。您可以将其视为包含仅在执行阶段检查的文件的目录。您可以使用 ctx.actions.declare_directory.
从 Skylark 声明一个树工件这是一个工作示例。注意 3 件事:
- 我们需要在目录名中添加“.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"),
)
}
)
构建:
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;
}