Include file downloaded by Bazel http_file

4.1k views Asked by At

I'm using Bazel to build my project. I'd like to use the single-header test framework, Catch v2. I decided to use the http_file rule to make Bazel download the catch header. My WORKSPACE file looks like this:

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

http_file(
  name = "catch",
  downloaded_file_path = "catch.hpp",
  sha256 = "cc6cc272cf84d8e10fb28f66f52584dedbb80d1234aae69e6a1027af4f31ae6f",
  urls = ["https://github.com/catchorg/Catch2/releases/download/v2.4.2/catch.hpp"],
)

According to the doc, the test depends on the generated package like this:

cc_test(
  name = "my_test",
  srcs = ["@catch//file", "my_test.cc"]
)

The test file my_test.cc can't get any simpler:

#include "catch.hpp"

However, I get the following error:

$ bazel test --config=opt -s //...
WARNING: [...]/BUILD:25:10: in srcs attribute of cc_test rule //test:my_test: please do not import '@catch//file:catch.hpp' directly. You should either move the file to this package or depend on an appropriate rule there
SUBCOMMAND: # //test:my_test [action 'Compiling test/my_test.cc']
(cd [...] && \
  exec env - [...] \
  /usr/bin/gcc
 -U_FORTIFY_SOURCE -fstack-protector -Wall -B/usr/bin -B/usr/bin -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer '-std=c++0x' -MD -MF [...].d '-frandom-seed=[...].o' -fPIC
 -iquote .
 -iquote bazel-out/k8-fastbuild/genfiles
 -iquote bazel-out/k8-fastbuild/bin
 -iquote external/bazel_tools
 -iquote bazel-out/k8-fastbuild/genfiles/external/bazel_tools
 -iquote bazel-out/k8-fastbuild/bin/external/bazel_tools
 -fno-canonical-system-headers -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -c test/my_test.cc
 -o [...].o)
ERROR: [...]/BUILD:23:1: C++ compilation of rule '//test:my_test' failed (Exit 1)
test/my_test.cc:1:28: fatal error: catch.hpp: No such file or directory
compilation terminated.
[...]
FAILED: Build did NOT complete successfully

Creating a cc_library wrapper, or including catch/catch.hpp, catch/file/catch.hpp produces the same error.

1

There are 1 answers

0
erenon On

By default, files downloaded by http_file can be included as:

#include "external/<name>/file/<file_name>"

In this specific case:

#include "external/catch/file/catch.hpp"

However, this include path is ugly, it should be wrapped by a cc_library. Furthermore, compiling the full catch header file for each test will make the build slow. According to the catch docs, the implementation part of the catch header should be compiled separately. Like this:

test/BUILD:

cc_library(
  name = "catch",
  hdrs = ["@catch//file"],
  srcs = ["catch.cpp"],
  visibility = ["//visibility:public"],
  strip_include_prefix = "/external/catch/file",
  include_prefix = "catch",
  linkstatic = True,   # otherwise main() will could end up in a .so
)

cc_test(
  name = "my_test",
  deps = ["//test:catch"],
  srcs = ["my_test.cc"],
)

test/catch.cpp:

#define CATCH_CONFIG_MAIN
#include "catch/catch.hpp"

test/my_test.cc:

#include "catch/catch.hpp"

TEST_CASE("my_test", "[main]") { /* ... */ }

This way catch.cpp will not be re-compiled if only my_test.cc changes, saving precious seconds.