Psirus
Psirus

Reputation: 1483

Unit tests with CMake without duplicate compilation

I'm trying to write unit tests for classes in a library. Building the lib and the tests is done with CMake.

├── CMakeLists.txt
├── src
│   ├── Bar.cpp
│   ├── CMakeLists.txt
│   └── Foo.cpp
└── test
    ├── BarTest.cpp
    ├── CMakeLists.txt
    └── FooTest.cpp

The src/CMakeLists.txt is simply add_library(Example Foo.cpp Bar.cpp). And because I'd like to build the unit tests without building the library (i.e. if I make a change to say Foo I can run its unit test without having the interaction with Bar to work already. So the test/CMakeLists.txt looks like this:

add_executable(FooTest FooTest.cpp ${CMAKE_SOURCE_DIR}/src/Foo.cpp)
add_test(bla::FooTest ${CMAKE_CURRENT_BINARY_DIR}/FooTest)

add_executable(BarTest BarTest.cpp ${CMAKE_SOURCE_DIR}/src/Bar.cpp)
add_test(bla::BarTest ${CMAKE_CURRENT_BINARY_DIR}/BarTest)

However, this results in every source file being build twice:

[ 11%] Building CXX object src/CMakeFiles/Example.dir/Foo.o
[ 22%] Building CXX object src/CMakeFiles/Example.dir/Bar.o
[ 33%] Linking CXX static library libExample.a
[ 33%] Built target Example
[ 44%] Building CXX object test/CMakeFiles/FooTest.dir/FooTest.o
[ 55%] Building CXX object test/CMakeFiles/FooTest.dir/__/src/Foo.o
[ 66%] Linking CXX executable FooTest
[ 66%] Built target FooTest
[ 77%] Building CXX object test/CMakeFiles/BarTest.dir/BarTest.o
[ 88%] Building CXX object test/CMakeFiles/BarTest.dir/__/src/Bar.o
[100%] Linking CXX executable BarTest
[100%] Built target BarTest

Is it possible to avoid this? I.e. if I have build src/Foo.cpp before for a unit test, don't build it again for a library? All flags are the same.

Upvotes: 3

Views: 656

Answers (1)

Florian
Florian

Reputation: 43058

If you don't mind the additional targets, that's what CMake's object libraries are for:

add_library(Foo OBJECT Foo.cpp)
add_library(Bar OBJECT Bar.cpp)
add_executable(Example $<TARGET_OBJECTS:Foo> $<TARGET_OBJECTS:Bar>)

And then

add_executable(FooTest FooTest.cpp $<TARGET_OBJECTS:Foo>)
add_executable(BarTest BarTest.cpp $<TARGET_OBJECTS:Bar>)

Upvotes: 1

Related Questions