Bazel - Including all headers from a directory when importing a static library

Viewed 3224

I am a total newbie to Bazel and trying to add a static library to my build.

Lets say as a simple example say I have the following.

cc_import(
  name = "my_test_lib"
  static_library = "lib\my_test_lib\test.lib"
  hdrs = ["lib\my_test_lib\include\headerA.h", 
          "lib\my_test_lib\include\headerB.h"]
  visibility = ["//visibility:public"],
)

Now this works fine.

However, what if I have a huge number of includes and within the include directory there is a number of subdirectories. Do I have to individually enter each one that my main project depends on, or can I do something like the following to essentially make all headers in this directory / subdirectories available?

 hdrs = [ "lib\my_test_lib\include\*"]
2 Answers

[This is a supplement to Sebastian's answer.] Here's a trick I just learned (from a colleague) to use with cc_import:

Suppose you don't want your headers exposed "naked", but want them all in a subdir prefixed by your library name, so that you refer to them like this:

#include <openjpeg/openjpeg.h>

The first step is to have a directory structure that looks like this:

. <library root>
- include
  - openjpeg
    - openjpeg.h
    - <other header files>

But now if you expose these header files via a glob, e.g., glob(["mylib/include/openjpeg/*.h"]) or some variant like glob(["mylib/include/**/*.h"]) (or even by naming them explicitly!) they're not actually exposed as #include <openjpeg/openjpeg.h> but instead as #include "openjpeg.h" or #include <include/openjpeg/openjpeg.h> or something like that.

The problem is that cc_import unaccountably does not support the includes attribute that cc_library does so you can't just name an include directory.

So, use the standard computer science workaround of adding another level of indirection and use this:

cc_library(name = "openjpeg", 
           includes = ["include"],
           deps = ["openjpeg-internal"],
           visibility = ["//visibility:public"],
)
cc_import(name = "openjpeg-internal",
          hdrs = glob(["include/**/*.h"]),
          static_library = ...,
          visibility = ["//visibility:private"],
)

What you need is the glob function.

To use it in your above example, you would do something like this

cc_import(
  name = "my_test_lib"
  static_library = "lib/my_test_lib/test.lib"
  hdrs = glob(["lib/my_test_lib/include/*.h"])
  visibility = ["//visibility:public"],
)

which would find all files ending with .h under lib\my_test_lib\include and put them in the hdrs attribute of your cc_import.

There's more information about glob in the Bazel documentation: https://docs.bazel.build/versions/master/be/functions.html#glob

Note: Always use forward slashes on all platforms in Bazel BUILD files (even on Windows).

Multiple glob patterns

It's sometimes useful to put in more than one pattern in the glob, for example like this

cc_import(
  ...
  hdrs = glob([
    "lib/my_test_lib/include/*.h",
    "lib/my_test_lib/include/*.hpp",
    "lib/my_test_lib/public/*.h",
  ]),
  ...
)

Combining a glob with a hard coded list of files

Another useful thing is combining globs with hard coded paths. You might have a few files you want in there and then a directory you also want to include. You can do this by using the + operator to concatenate the hard coded list of paths with the glob results like this

cc_import(
  ...
  hdrs = [
    "lib/my_test_lib/some_header.h",
  ] + glob([
    "lib/my_test_lib/include/*.h",
  ]),
  ...
)

Globbing a directory hierarchy (beware of massive inclusions)

The glob function also support traversing directories and their sub directories when finding files. This can be done using the ** glob pattern. So, to for example grab all .h files in the my_test_lib directory, use this glob

cc_import(
  ...
  hdrs = glob([
    "lib/my_test_lib/**/*.h",
  ]),
  ...
)

Beware: This will include all files below the specified directory, as expected. This can go out of hand since it's not explicit what files get included. Might be better to stay away from **.

Related