Share targets between src and tests subdirectory

How can I make use of already compiled targets in another subdirectory? Do I necessarily need to build a library?

Suppose I have a (mini) finite element code and have structured the project as follows

│── CMakeLists.txt
│── unit-tests
│ └── CMakeLists.txt
│ └── test_mesh.cpp
│ └── test_element.cpp
│ └── test_solver.cpp
│── src
└── CMakeLists.txt
└── mesh.cpp/.hpp
└── element.cpp/.hpp
└── solver.cpp/.hpp
└── main.cpp

The src/CMakeLists.txt files will have a main target composed of mesh.cpp, node.cpp, solver.cpp, element.cpp. I also have a unit-test/CMakeLists.txt that unit tests the mesh, element and solver components. How to avoid having to recompile the same mesh.cpp, node.cpp, solver.cpp, element.cpp also in the unit-test subdirectory? I do not want to define them as targets again but rather be able to use the targets already defined in src/CMakeLists.txt

The simplest solution is to make a STATIC library that your executable links.

# src/CMakeLists.txt
add_library(foo STATIC)
target_sources(foo PRIVATE
target_include_directories(foo PUBLIC .)

target_sources(bar PRIVATE main.cpp)

target_link_libraries(bar PRIVATE foo)
# unit-tests/CMakeLists.txt
target_sources(tests PRIVATE

target_link_libraries(tests PRIVATE foo)
1 Like

Ok, thank you. I have two follow up questions:

  • Should I make them imported targets or imported targets should left only for dependencies?
  • What would be a non-simplest solution?

Should I make them imported targets or imported targets should left only for dependencies?

None of what you are showing requires imported targets at all.

What would be a non-simplest solution?

I’d just encourage looking into using ctest for running your unit tests.

This blog gives a good introduction to ctest: Using CMake’s CTest and add_test To Run All Your Tests

1 Like

The blog follows the same approach you mentioned of defining a library. It does not really use an alternative approach. It only adds the use of CTest and GTest to the mix but that I am already doing.

Thus, in essence it seems the approach is to define a library