我正在尝试为bazel建立一个规则,以模仿CMake * .in模板系统。
这有两个挑战,第一个是生成模板输出。第二个是使输出可用于genrules
,filegroups
和cc_*
规则。第三是使该依赖关系可传递给其他下游规则。
我让它在genfiles(或bazel-bin)中生成输出文件version.hpp
,我可以得到包含它的初始库规则,但似乎无法弄清楚如何制作cc_binary规则,该规则取决于cc_library,并依赖于header_template规则来查找头文件。
我有以下.bzl规则:
def _header_template_impl(ctx):
# this generates the output from the template
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = ctx.attr.vars,
)
return [
# create a provider which says that this
# out file should be made available as a header
CcInfo(compilation_context=cc_common.create_compilation_context(
headers=depset([ctx.outputs.out])
)),
# Also create a provider referencing this header ???
DefaultInfo(files=depset(
[ctx.outputs.out]
))
]
header_template = rule(
implementation = _header_template_impl,
attrs = {
"vars": attr.string_dict(
mandatory = True
),
"extension": attr.string(default=".hpp"),
"template": attr.label(
mandatory = True,
allow_single_file = True,
),
},
outputs = {
"out": "%{name}%{extension}",
},
output_to_genfiles = True,
)
在其他地方我有cc_library规则:
load("//:tools/header_template.bzl", "header_template")
# version control
BONSAI_MAJOR_VERSION = '2'
BONSAI_MINOR_VERSION = '0'
BONSAI_PATCH_VERSION = '9'
BONSAI_VERSION = \
BONSAI_MAJOR_VERSION + '.' + \
BONSAI_MINOR_VERSION + '.' + \
BONSAI_PATCH_VERSION
header_template(
name = "bonsai_version",
extension = ".hpp",
template = "version.hpp.in",
vars = {
"@BONSAI_MAJOR_VERSION@": BONSAI_MAJOR_VERSION,
"@BONSAI_MINOR_VERSION@": BONSAI_MINOR_VERSION,
"@BONSAI_PATCH_VERSION@": BONSAI_PATCH_VERSION,
"@BONSAI_VERSION@": BONSAI_VERSION,
},
)
# ...
private = glob([
"src/**/*.hpp",
"src/**/*.cpp",
"proto/**/*.hpp",
])
public = glob([
"include/*.hpp",
":bonsai_version",
])
cc_library(
# target name matches directory name so you can call:
# bazel build .
name = "bonsai",
srcs = private,
hdrs = public,
# public headers
includes = [
"include",
],
# ...
deps = [
":bonsai_version",
# ...
],
# ...
)
构建时,我的源文件必须能够:
#include "bonsai_version.hpp"
我认为答案涉及CcInfo
,但我对如何构造它一无所知。
我已经尝试将"-I$(GENDIR)/" + package_name()
添加到副本中,但无济于事。生成的标头仍然不可用。
我的期望是,我应该能够返回某种Info对象,该对象将允许我在srcs
中添加依赖项。也许应该是DefaultInfo
。
我已经浏览了bazel规则示例和源代码,但是我缺少一些基本知识,并且找不到有关此特定主题的文档。
我希望能够执行以下操作:
header_template(
name = "some_header",
extension = ".hpp",
template = "some_header.hpp.in",
vars = {
"@SOMEVAR@": "value",
"{ANOTHERVAR}": "another_value",
},
)
cc_library(
name = "foo",
srcs = ["foo.src", ":some_header"],
...
)
cc_binary(
name = "bar",
srcs = ["bar.cpp"],
deps = [":foo"],
)
并包含生成的标头,如下所示:
#include "some_header.hpp"
void bar(){
}
答案 0 :(得分:1)
答案看起来像是
def _header_template_impl(ctx):
# this generates the output from the template
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = ctx.attr.vars,
)
return [
# create a provider which says that this
# out file should be made available as a header
CcInfo(compilation_context=cc_common.create_compilation_context(
# pass out the include path for finding this header
includes=depset([ctx.outputs.out.dirname]),
# and the actual header here.
headers=depset([ctx.outputs.out])
))
]
其他地方:
header_template(
name = "some_header",
extension = ".hpp",
template = "some_header.hpp.in",
vars = {
"@SOMEVAR@": "value",
"{ANOTHERVAR}": "another_value",
},
)
cc_library(
name = "foo",
srcs = ["foo.cpp"],
deps = [":some_header"],
...
)
cc_binary(
name = "bar",
srcs = ["bar.cpp"],
deps = [":foo"],
)
答案 1 :(得分:0)
如果标头具有通用名称(例如config.h),而您希望它是私有的(即srcs
而不是hdrs
),则可能需要其他方法。我已经看到了gflag的问题,它“泄漏”了config.h并影响了依赖它的库(issue)。
当然,在两种情况下,最简单的解决方案是为目标平台生成并提交头文件。
或者,您可以为使用生成的专用标头的copts
规则设置cc_library
:
cc_library(
name = "foo",
srcs = ["foo.cpp", "some_header.hpp"],
copts = ["-I$(GENDIR)/my/package/name"],
...
)
如果您希望在将存储库作为外部存储库包含时工作,那么由于bazel issue #4463,您的工作量将减少。
PS。您可能想查看cc_fix_config中的https://github.com/antonovvk/bazel_rules是否适合您。它只是perl的包装,但我发现它很有用。