3

I'm working on a C++ project and I need Numpy like arrays and functionalities in C++. I found some alternatives like xtensor, NumCpp etc. These are header only libraries. The problem is I'm experimenting with Bazel for the first time so, I don't have any idea about how do I add header only library to Bazel workspace. There are some suggestions like genrule-environment, rules-foreign-cc suggested on other questions around Bazel. I've added http_archive to WORKSPACE file, but I'm not sure what to add in BUILD file.

WORKSPACE file

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])"""

http_archive(
    name = "xtensor",
    build_file_content = all_content,
    strip_prefix = "xtensor-master",
    urls = ["https://github.com/xtensor-stack/xtensor/archive/refs/heads/master.zip"],
)

http_archive(
    name = "NumCpp",
    build_file_content = all_content,
    strip_prefix = "NumCpp-master",
    urls = ["https://github.com/dpilger26/NumCpp/archive/refs/heads/master.zip"],
)

http_archive(
    name = "rules_foreign_cc",
    sha256 = "c2cdcf55ffaf49366725639e45dedd449b8c3fe22b54e31625eb80ce3a240f1e",
    strip_prefix = "rules_foreign_cc-0.1.0",
    url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.1.0.zip",
)

load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies")

rules_foreign_cc_dependencies()

I've tried to follow documentation, but failed every time. Some help would be appreciated.

Jema
  • 65
  • 1
  • 9

1 Answers1

4

For simple things like header-only libraries, I would write BUILD files yourself, without using rules_foreign_cc. Just write a cc_library with no srcs. Something like this:

http_archive(
    name = "xtensor",
    build_file_content = all_content,
    strip_prefix = "xtensor-master",
    urls = ["https://github.com/xtensor-stack/xtensor/archive/refs/heads/master.zip"],
    build_file_content = """
cc_library(
    name = "xtensor",
    visibility = ["//visibility:public"],
    hdrs = glob(["xtensor/*.hpp"]),
    defines = [
        "XTENSOR_ENABLE_ASSERT",
    ],
    deps = [
        "@tbb",
    ],
)
""",
)

@xtensor will be your Bazel repository. The build_file_content will be used to create a BUILD.bazel file in it. That means your code can depend on it via @xtensor//:xtensor, which can be shortened to just @xtensor. You can also put that in a separate file (say build/BUILD.xtensor.bazel) and then use build_file = "@build//:BUILD.xtensor.bazel" instead of putting it inline in WORKSPACE via build_file_content.

rules_foreign_cc is going to generate something equivalent if you get it set up, but that seems like a lot more trouble to me than just writing it yourself. I set defines and deps based on a scan through the CMakeLists.txt, you'll want to customize based on how you want it configured.

The only other thing I see that CMakeLists doing (beyond finding dependencies and setting some -D flags, which translate as shown above) is generating a single file that #includes all the others. If you want to do that, I'd do something like this (in the BUILD file for @xtensor):

genrule(
    name = "gen_single_include",
    outs = ["xtensor.hpp"],
    cmd = "\n".join([
        "cat > $@ <<'END'",
        "#ifndef XTENSOR",
        "#define XTENSOR",
    ] + ["#include \"%s\"" % h[len("xtensor/"):]
         for h in glob(["xtensor/*.hpp"])
         if h not in [
             "xtensor/xexpression_holder.hpp",
             "xtensor/xjson.hpp",
             "xtensor/xmime.hpp",
             "xtensor/xnpy.hpp",
          ]] + [
        "#endif",
        "END",
    ]),

I may not have gotten everything perfect here, but the idea is to build up the file using cat to copy stdin to it, a bash here document to feed the content in, and Python-style list comprehensions to actually build up the content.

Brian Silverman
  • 3,085
  • 11
  • 13
  • Thanks @Brian Silverman. Following your example above I successfully added NummCpp. But with xtensor, I got the following error. `no such package '@tbb//': The repository '@tbb' could not be resolved: Repository '@tbb' is not defined and referenced by '@xtensor'` – Jema Feb 09 '22 at 06:53
  • 2
    Yes, if you want to use tbb, you'll need to get it building. You could also just skip that part, from the CMakeLists.txt it looks optional. I added it as an example of how to add dependencies. Some options if you want to use it: * write a BUILD file for tbb (like this answer) * use rules_foreign_cc on it and get that working * find a precompiled tbb and write a BUILD file for it (just put a .a file in cc_library.srcs) * find somebody else's BUILD file for it – Brian Silverman Feb 09 '22 at 08:07
  • 1
    Thanks @Brian Silverman for the informative answer, I think I'm going to omit tbb for now. – Jema Feb 11 '22 at 06:14