将 C++ 生成的文件分派到 srcs 和 hdrs
Dispatching C++ generated files into srcs and hdrs
在 Bazel 官方文档中有一个 example 解释了如何创建一个 Java 库,该库由常规 java 文件和由 :gen_java_srcs 规则生成的文件构建.为了便于阅读,我在这里重写了这段代码:
java_library(
name = "mylib",
srcs = glob(["*.java"]) + [":gen_java_srcs"],
deps = "...",
)
genrule(
name = "gen_java_srcs",
outs = [
"Foo.java",
"Bar.java",
],
...
)
现在从 C++ 的角度来看,我处于 genrule 生成两种文件的场景:.hpp 和 .cpp:
genrule(
name = "gen_cpp_srcs",
outs = [
"myFile_1.hpp","myFile_2.hpp",...,"myFile_N.hpp",
"myFile.cpp","myFile_2.cpp",...,"myFile_N.cpp",
],
...
)
其中 N 是十位。
我的 problem/question 是:如何编写 cc_library 规则,将 hpp 和 cpp 文件自动分派到 hdrs 和 srcs 字段?
我想要这样的东西:
cc_library(
name = "mylib",
srcs = glob(["*.cpp"]) + (howto: .cpp files of [":gen_cpp_srcs"]),
hdrs = glob(["*.hpp"]) + (howto: .hpp files of [":gen_cpp_srcs"]),
...
)
一些魔术,例如:
output_filter(":gen_cpp_srcs","*.cpp")
会很完美,但我对 Bazel 的了解还不够多,无法实现。
根据名称 (:gen_cpp_srcs
) 的类规则,您将获得该类规则的 所有输出 ,如您所指出的。相反,您可以依赖 genrule 的各个输出(例如 hdrs = [:myFile.hpp]
和 srcs = [:myFile.cpp]
)。
另请参阅 的答案。
您似乎知道应该生成的文件总数。你能把它们放在它们自己的变量中,然后在两个目标中重用它们吗?在你的 BUILD 文件中是这样的:
output_cpp_files = [
"myFile_1.cpp",
"myFile_2.cpp",
"myFile_3.cpp"
]
output_hpp_files = [
"myFile_1.hpp",
"myFile_2.hpp",
"myFile_3.hpp"
]
genrule(
name = "gen_cpp_srcs",
outs = output_cpp_files + output_hpp_files,
cmd = """
touch $(OUTS)
"""
)
cc_library(
name = "mylib",
srcs = output_cpp_files,
hdrs = output_hpp_files
)
Glob 只有在传递给规则时才会扩展,因此您需要编写一个简单的 rule。我会像这样打包它(在一个名为 filter.bzl
的文件中):
# The actual rule which does the filtering.
def _do_filter_impl(ctx):
return struct(
files = set([f for f in ctx.files.srcs if f.path.endswith(ctx.attr.suffix)]),
)
_do_filter = rule(
implementation = _do_filter_impl,
attrs = {
"srcs": attr.label_list(
mandatory = True,
allow_files = True,
),
"suffix": attr.string(
mandatory = True,
),
},
)
# A convenient macro to wrap the custom rule and cc_library.
def filtered_cc_library(name, srcs, hdrs, **kwargs):
_do_filter(
name = "%s_hdrs" % name,
visibility = ["//visibility:private"],
srcs = hdrs,
suffix = ".hpp",
)
_do_filter(
name = "%s_srcs" % name,
visibility = ["//visibility:private"],
srcs = srcs,
suffix = ".cpp",
)
native.cc_library(
name = name,
srcs = [ ":%s_srcs" % name ],
hdrs = [ ":%s_hdrs" % name ],
**kwargs
)
这是我的演示 BUILD
文件的样子(我更改了 glob,因此它们都包含 *.cpp 和 *.hpp 文件;使用 genrule 的标签将以相同的方式工作):
load("//:filter.bzl", "filtered_cc_library")
filtered_cc_library(
name = "mylib",
srcs = glob(["*.*pp"]),
hdrs = glob(["*.*pp"]),
)
这很容易通过更改 _do_filter_impl
扩展到更复杂的过滤。特别是,将 suffix
更改为 attr.string_list 以便您可以接受多个 C/C++ source/header 扩展似乎是个好主意。
在 Bazel 官方文档中有一个 example 解释了如何创建一个 Java 库,该库由常规 java 文件和由 :gen_java_srcs 规则生成的文件构建.为了便于阅读,我在这里重写了这段代码:
java_library(
name = "mylib",
srcs = glob(["*.java"]) + [":gen_java_srcs"],
deps = "...",
)
genrule(
name = "gen_java_srcs",
outs = [
"Foo.java",
"Bar.java",
],
...
)
现在从 C++ 的角度来看,我处于 genrule 生成两种文件的场景:.hpp 和 .cpp:
genrule(
name = "gen_cpp_srcs",
outs = [
"myFile_1.hpp","myFile_2.hpp",...,"myFile_N.hpp",
"myFile.cpp","myFile_2.cpp",...,"myFile_N.cpp",
],
...
)
其中 N 是十位。
我的 problem/question 是:如何编写 cc_library 规则,将 hpp 和 cpp 文件自动分派到 hdrs 和 srcs 字段?
我想要这样的东西:
cc_library(
name = "mylib",
srcs = glob(["*.cpp"]) + (howto: .cpp files of [":gen_cpp_srcs"]),
hdrs = glob(["*.hpp"]) + (howto: .hpp files of [":gen_cpp_srcs"]),
...
)
一些魔术,例如:
output_filter(":gen_cpp_srcs","*.cpp")
会很完美,但我对 Bazel 的了解还不够多,无法实现。
根据名称 (:gen_cpp_srcs
) 的类规则,您将获得该类规则的 所有输出 ,如您所指出的。相反,您可以依赖 genrule 的各个输出(例如 hdrs = [:myFile.hpp]
和 srcs = [:myFile.cpp]
)。
另请参阅
您似乎知道应该生成的文件总数。你能把它们放在它们自己的变量中,然后在两个目标中重用它们吗?在你的 BUILD 文件中是这样的:
output_cpp_files = [
"myFile_1.cpp",
"myFile_2.cpp",
"myFile_3.cpp"
]
output_hpp_files = [
"myFile_1.hpp",
"myFile_2.hpp",
"myFile_3.hpp"
]
genrule(
name = "gen_cpp_srcs",
outs = output_cpp_files + output_hpp_files,
cmd = """
touch $(OUTS)
"""
)
cc_library(
name = "mylib",
srcs = output_cpp_files,
hdrs = output_hpp_files
)
Glob 只有在传递给规则时才会扩展,因此您需要编写一个简单的 rule。我会像这样打包它(在一个名为 filter.bzl
的文件中):
# The actual rule which does the filtering.
def _do_filter_impl(ctx):
return struct(
files = set([f for f in ctx.files.srcs if f.path.endswith(ctx.attr.suffix)]),
)
_do_filter = rule(
implementation = _do_filter_impl,
attrs = {
"srcs": attr.label_list(
mandatory = True,
allow_files = True,
),
"suffix": attr.string(
mandatory = True,
),
},
)
# A convenient macro to wrap the custom rule and cc_library.
def filtered_cc_library(name, srcs, hdrs, **kwargs):
_do_filter(
name = "%s_hdrs" % name,
visibility = ["//visibility:private"],
srcs = hdrs,
suffix = ".hpp",
)
_do_filter(
name = "%s_srcs" % name,
visibility = ["//visibility:private"],
srcs = srcs,
suffix = ".cpp",
)
native.cc_library(
name = name,
srcs = [ ":%s_srcs" % name ],
hdrs = [ ":%s_hdrs" % name ],
**kwargs
)
这是我的演示 BUILD
文件的样子(我更改了 glob,因此它们都包含 *.cpp 和 *.hpp 文件;使用 genrule 的标签将以相同的方式工作):
load("//:filter.bzl", "filtered_cc_library")
filtered_cc_library(
name = "mylib",
srcs = glob(["*.*pp"]),
hdrs = glob(["*.*pp"]),
)
这很容易通过更改 _do_filter_impl
扩展到更复杂的过滤。特别是,将 suffix
更改为 attr.string_list 以便您可以接受多个 C/C++ source/header 扩展似乎是个好主意。