2

I have a project (with main.cpp and some headers. Yes, it is a Catch2 test project as described in this blog). It compiles and runs.

My problem is: This project does nothing useful unless I add some more source files (my test cases). These source files use one header from the project and bring in some other dependencies as well (my library that I want to test).

The simple solution would be to copy this project, add the needed files and we are done.

Is there a better way? Currently with qmake I have the project defined in a catch.pri file. By including this in an project I have everything for the qt and catch2 setup, and only have to define the files with the testcases by modifying the SOURCES-Variable and the dependencies for the code to test.

Mapping this to CMake makes me ask questions:

First: when I include have a line like:

add_executable(tests main.cpp ${SOURCES})

Can I define SOURCES in a later line?

Second and more important: Is it a good idea to do it this way?

arved
  • 4,401
  • 4
  • 30
  • 53

3 Answers3

1

Can I define SOURCES in a later line?

Yes, but not the way you've done it. You can define your executable target tests with a few sources or no sources, but you can always append more sources later using the target_sources command.

add_executable(tests main.cpp)

...

# Later in the CMake file (or in another CMake file added via 'add_subdirectory').
target_sources(tests PRIVATE
    MyTestClass1.cpp
    MyTestClass2.cpp
    ...
)

You can similarly add compilation flags to this tests target later using target_compile_options, and add dependencies to link to tests using target_link_libraries.

Kevin
  • 16,549
  • 8
  • 60
  • 74
  • This way I could define my test target (the part of the test that is the same for all test projects) in a subdir; load it with `add_subdirectory` into my current test-project and add my test files, dependencies and furhter flags? This looks like the way to go for me. –  Jun 08 '20 at 12:28
  • @generic_opto_guy Yes, you can always append sources and additional compile flags/dependencies, even for a target defined in an earlier subdirectory of your CMake project. – Kevin Jun 08 '20 at 13:56
  • But I can not `target_link_libraries` since I run into [this](https://stackoverflow.com/questions/26838367/cmake-attempted-to-add-link-library-to-target-which-is-not-built-in-this-direct) problem. –  Jun 09 '20 at 09:19
  • @generic_opto_guy Yes, prior to CMake 3.13, you had to place the `target_link_libraries()` call in the same directory where the target was created. Upgrade your CMake to 3.13 or greater. – Kevin Jun 09 '20 at 13:34
0

Is there a better way?

No, this is how usually things are done. Any library / subproject is included using a .pri file. You can, of course, make the subproject a git-submodule.

Can I define SOURCES in a later line?

Short answer: No

Example:

Lets say we have a small project with a single file a.cpp and a CMakeLists.txt as follows:

cmake_minimum_required(VERSION 3.12)
project(testing)
add_executable(testing ${sources})
#defining ${sources} later
set(sources a.cpp)

if you try to build this, it will result in an error:

No SOURCES given to target: testing

I assume you want to separate the definition of sources variable to a separate file. In that case we can solve this as following. Assuming we have a dir structure as follows:

src/
|--lib/
|--tests/
|---- CMakeLists.txt
CMakeLists.txt
main.cpp

Our cmake file will be same as before with these additional changes before add_executable:

add_subdirectory(tests)

In the CMakeLists.txt file inside tests/ you can define the ${SOURCES} variable:

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp
    PARENT_SCOPE
)

Note that you need PARENT_SCOPE here to make this SOURCES variable visible to the parent directory, which in our case is src/

Now in our main CMakeLists.txt we can use this variable:

add_executable(tests ${SOURCES})

Second and more important: Is it a good idea to do it this way?

It depends. If you have a simple single directory project then it's not necessary. If you have multiple directories then of course, each directory should have its own CMake file which defines it's own variables. CMake files are code, they should be treated as code meaning they should be clean, modular and readable.

Waqar
  • 8,558
  • 4
  • 35
  • 43
  • So in the `tests/CMakeLists.txt` I can place all modifications to the test project? Like adding dependencies to the `tests` executable. Or setting flags for the compilation? –  Jun 08 '20 at 07:29
  • You can add files only. But you can't add dependencies(external libraries) or flags because your target i.e., `tests` is in the main cmake file and is not defined yet. You can instead move the target to `tests/` directory and then set flags/add dependencies. – Waqar Jun 08 '20 at 07:34
0

There is nothing wrong with defining the test_template as an static lib, which provides the main.cpp.

This way I define my tests as new executable, with test-files, library-dependencies and whatever, and only have to link to the static lib.