After a lot of hard work and research, I've managed to make multiple cmake targets to separate running my program from running tests on the code. But I don't like what I've made because I see redundancy in the CMakeList.txt files.
Currently I have to add every new source file to both targets so that the source target can build using that file and the test target can build since they need to test that file. I can't throw the entire source target into the test target because then the test target would contain two main files.
My only idea of how to fix the redundancy is to put all of the files in the source target without the main.cpp file into some group, and then attach that group to both targets. That way the source target contains just the main.cpp file and the source file group, and the test target contains all its tests and the source file group. So the file group would basically be all of the overlap between the two targets. I just don't know how to do that.
Research
Here's the other stack overflow questions I found that helped me get to where I am:
- what does target option mean in cmake
- how to use cmake with catch2
- cmake one build directory for multiple projects
Code
Here is my test project I made to experiment with catch2 and cmake that currently works for both build targets "tests" and "catch2Test":
/catch2Test // <-- project folder
|---- /include
| |---- /catch2
| |---- catch.hpp
|---- /src
| |---- /myMath
| | |---- factorial.cpp
| | |---- factorial.h
| |---- main.cpp
| |---- CMakeLists.txt
|---- /test
| |---- test_main.cpp
| |---- test_factorial.cpp
| |---- CMakeLists.txt
|---- CMakeLists.txt
/include/catch2/catch.hpp is the library header file for catch2
/src/myMath/ contains the header file and code file for the factorial implementation, same as used in the catch2 tutorial. This is also where the implementation for the factorial tests come from.
/src/main.cpp is a simple main file that includes factorial.h to do factorial math and then prints it to cout.
Here's explicit code for the remaining files that actually matter:
/test/test_main.cpp
#define CATCH_CONFIG_MAIN
#include "../include/catch2/catch.hpp"
/test/test_factorial.cpp
#include "../include/catch2/catch.hpp"
#include "../src/myMath/factorial.h"
TEST_CASE("Factorials are computed", "[factorial]")
{
REQUIRE(factorial(0) == 1);
REQUIRE(factorial(1) == 1);
REQUIRE(factorial(2) == 2);
REQUIRE(factorial(3) == 6);
REQUIRE(factorial(10) == 3628800);
}
/CmakeLists.txt
cmake_minimum_required(VERSION 3.13)
set(CMAKE_CXX_STANDARD 14)
add_subdirectory(src)
add_subdirectory(test)
/test/CMakeLists.txt
add_executable(tests
../src/myMath/factorial.cpp ../src/myMath/factorial.h
../include/catch2/catch.hpp
test_main.cpp
test_factorial.cpp
)
/src/CMakeLists.txt
add_executable(catch2Test
main.cpp
myMath/factorial.cpp myMath/factorial.h
)
Running
When I run the catch2Test target, I get desired results:
Hello, World!
Factorial 0! = 1
Factorial 1! = 1
Factorial 2! = 2
Factorial 3! = 6
Factorial 6! = 720
Factorial 10! = 3628800
Process finished with exit code 0
And when I run the tests target, I also get desired results:
===============================================================================
All tests passed (5 assertions in 1 test case)
Process finished with exit code 0
It all works, I just don't like my current solution.
How can I make my targets more easily extendable?
Also, side question: what's the more appropriate way to include a header library? I assume it's not supposed to be in the add_executable() like I did in /test/CMakeLists.txt as ../include/catch2/catch.hpp...
I think I found an answer to my question in the list of related questions in the sidebar: cmake project structure with unit tests
Using
add_libraryI can create a list of files with a new target name that doesn't necessarily contain a main file. Here's how I've changed my subdirectoryCMakeList.txtfiles:src/CMakeList.txttest/CMakeList.txtNow all my source files that I add go into the
srclibrary and both of my targets link to it usingtarget_link_libraries([target] src).Now I'm trying to figure out if I can use target_link_libraries to attach the catch2 lib to the tests target.
Edit: I think I found my answer to my second question here: 'cmake os x failure ar no archive members specific' and here: 'how to create a cmake header only library that depends on external header files'.
I tried to make a library out of a single header file and cmake doesn't recognize header files apparently. I now have a
CMakeLists.txtin my/includefolder that looks like:I've added the
/includefolder to the list of added subdirectories in my mainCMakeLists.txtfile.Also my tests target now links the catch2 library by using
target_link_libraries(tests catch2)which I find much nicer than putting a strained directory link inside the list of executable files for the tests target.