将C ++生成的文件分派到srcs和hdrs中

时间:2017-06-04 07:30:26

标签: bazel

在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是几十。

我的问题/问题是:如何编写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让它真实。

3 个答案:

答案 0 :(得分:3)

Globs只有在传入规则时才会得到扩展,因此您需要编写一个简单的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
  )

这就是我的demo BUILD文件的样子(我更改了globs,因此它们都包含* .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 ++源/标头扩展,这似乎是一个好主意。

答案 1 :(得分:2)

Depending on the genrule by name (:gen_cpp_srcs) will give you all of the outputs of the genrule, as you have noted. Instead, you can depend on the individual outputs of the genrule (e.g. hdrs = [:myFile.hpp] and srcs = [:myFile.cpp]).

See also the answer to Bazel & automatically generated cpp / hpp files.

答案 2 :(得分:2)

看起来您知道应该生成的文件总数。你能把它们放在自己的变量中,然后在两个目标中重复使用它们。您的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
)