Как собрать статическую библиотеку из сгенерированных исходных файлов с помощью Bazel Build
Я пытаюсь выполнить следующую настройку с помощью Bazel. При вызове "bazel build" скрипт Python должен сгенерировать неизвестное количество файлов *.cc со случайными именами, а затем скомпилировать их в одну статическую библиотеку (файл.a), все в рамках одного вызова Bazel. Я попробовал следующее: один сгенерированный файл имеет фиксированное имя, на него ссылаются выходы genrule() и srcs правила cc_library. Проблема в том, что мне нужно, чтобы все сгенерированные файлы были собраны в виде библиотеки, а не только файл с фиксированным именем. Есть идеи, как это сделать? Мой файл 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 ответа
[большое редактирование, так как я нашел способ заставить это работать:)]
Если вам действительно нужно испустить файлы, которые неизвестны на этапе анализа, ваш единственный путь - это то, что мы внутренне называем древовидными артефактами. Вы можете рассматривать его как каталог, содержащий файлы, которые будут проверяться только на этапе выполнения. Вы можете объявить древовидный артефакт из Skylark, используя ctx.actions.declare_directory.
Вот рабочий пример. Обратите внимание на 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"),
)
}
)
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) Используйте 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"],
)