3

I would like to use the test framework Catch2 in a monorepo in which there will be many components, each with their own tests. I'd like to use CMake to define all build targets.

Catch2 provides a simple means to generate a common main() function that will run all tests linked into the application. The source file (which I am calling test_main.cpp) is just these two lines:

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

I'd like to have just one copy of test_main.cpp in my source tree, and refer to it from each component directory that has tests (which will end up being on the order of hundreds of directories).

I can see how to set up CMake to work if I duplicated the test_main.cpp so that a redundant copy existed in each directory with tests, but I haven't figured out how to have just one copy. Is there a simple trick I've overlooked?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
4dan
  • 1,033
  • 10
  • 14
  • [Git can handle symlinks FWIW](https://stackoverflow.com/questions/954560/how-does-git-handle-symbolic-links). – ivan_pozdeev Mar 16 '18 at 02:38
  • I would check the Catch's logic to find out where it looks for test sources. Since they are all plain C code (i.e. Catch seems to only kick in after compilation), I guess it's as simple as adding another compilation unit to a project. – ivan_pozdeev Mar 16 '18 at 02:42
  • Have you tried just adding `test_main.cpp` to each `add_executable` line? You'd probably need the full path to the file, but something like `${PROJECT_SOURCE_DIR}/test_main.cpp` (assuming you have `test_main.cpp` at the top level of your project) should work. – Stephen Newell Mar 16 '18 at 03:02

1 Answers1

2

Try integrating Catch2 as a CMake interface library in the following way:

Add the single header file catch.hpp and test_main.cpp to a directory of their own (e.g., Catch2) along with the following CMakeLists.txt:

add_library(catch INTERFACE)
target_include_directories(catch INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_sources(catch INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/test_main.cpp")

The in your outermost CMakeLists.txt include Catch2 with add_subdirectory:

add_subdirectory(Catch2)

You can then set up test executables anywhere in the project in the following way:

add_executable(
    project_tests EXCLUDE_FROM_ALL
    test_case1.cpp
    test_case2.cpp
    ...
)

target_link_libraries(project_tests catch)

Because test_main.cpp has been added to catch as an interface source file, it will be compiled as part of the test executable.

sakra
  • 62,199
  • 16
  • 168
  • 151
  • This looks good. I'll give it try and approve the answer after I've verified that it works. Thanks. – 4dan Mar 22 '18 at 03:42
  • in fact we do not need to copy catch.hpp and put it to a directory with test_main.cpp, we can just have test_main.cpp in the folder and write CMakeLists.txt like:``` add_library(catch test_main.cpp) target_link_libraries(catch PUBLIC Catch2::Catch2) ``` – BruceSun Jul 25 '20 at 07:16