192

I am trying to structure my project to include the production sources (in src subfolder) and tests (in test subfolder). I am using CMake to build this. As a minimal example I have the following files:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src/CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src/sqr.h

#ifndef SQR_H
#define SQR_H
double sqr(double);    
#endif // SQR_H

src/sqr.cpp

#include "sqr.h"
double sqr(double x) { return x*x; }

src/main.cpp - uses sqr, doesn't really matter

test/CMakeLists.txt:

find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

include_directories (${TEST_SOURCE_DIR}/src) 

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp) 

target_link_libraries(test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )

enable_testing()
add_test(MyTest test)

test/test.cpp:

#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>

#include "sqr.h"

BOOST_AUTO_TEST_CASE(FailTest)
{
    BOOST_CHECK_EQUAL(5, sqr(2));
}

BOOST_AUTO_TEST_CASE(PassTest)
{
    BOOST_CHECK_EQUAL(4, sqr(2));
}

A few questions:

  1. Does this structure make sense? What are the best practises when structuring this code? (I am coming from C# and java, and there it is easier in a sense)
  2. I don't like the fact that I have to list all the files from the src folder in the test/CMakeLists.txt file. If this was a library project, I would just link the library. Is there a way to avoid listing all the cpp files from the other project?
  3. What are the lines enable_testing() and add_test(MyTest test) doing? I haven't seen any effect. How can I run the tests from CMake (or CTest)?
  4. So far I just ran cmake . in the root folder, but this created a mess with temporary files everywhere. How can I get the compilation results in a reasonable structure?
1
  • I consider myself a CMake novice, so I don't know what the accepted best practices are, but FWIW I'd make a "sqr" library* that both main and test depended on. (* or the moral equivalent thereof)
    – user786653
    Commented Jan 21, 2013 at 20:42

2 Answers 2

168

For questions 1 & 2, I would recommend making a library from your non-test files excluding main.cpp (in this case just src/sqr.cpp and src/sqr.h), and then you can avoid listing (and more importantly re-compiling) all the sources twice.

For question 3, these commands add a test called "MyTest" which invokes your executable "test" without any arguments. However, since you've added these commands to test/CMakeLists.txt and not your top-level CMakeLists.txt, you can only invoke the test from within the "test" subdirectory of your build tree (try cd test && ctest -N). If you want the test to be runnable from your top-level build directory, you'd need to call add_test from the top-level CMakeLists.txt. This also means you have to use the more verbose form of add_test since your test exe isn't defined in the same CMakeLists.txt

In your case, since you're running cmake in the root folder, your build tree and your source tree are one and the same. This is known as an in-source build and isn't ideal, which leads to question 4.

The preferred method for generating the build tree is to do an out-of-source build, i.e. create a directory somewhere outside of your source tree and execute cmake from there. Even creating a "build" directory in the root of your project and executing cmake .. would provide a clean structure which won't interfere with your source tree.

One final point is to avoid calling executables "test" (case-sensitive). For reasons why, see this answer.

To achieve these changes, I'd do the following:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src) 
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)

src/CMakeLists.txt:
add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

test/CMakeLists.txt:
find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
8
  • 4
    I just noticed that you also added the .h files to CMakeLists.txt files accordingly. Is it required? And what would happen if I leave them out?
    – Grzenio
    Commented Jan 22, 2013 at 14:29
  • 4
    @Grzenio This is just a convenience feature - they appear in IDE's like MSVC as part of the target, but otherwise this has no effect.
    – Fraser
    Commented Jan 22, 2013 at 14:44
  • 2
    Where is TEST_SOURCE_DIR set?
    – aggsol
    Commented Jul 21, 2016 at 9:41
  • 7
    It's automatically set by CMake when calling project (TEST) - see cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
    – Fraser
    Commented Jul 22, 2016 at 14:08
  • 2
    If I have many test cases within test folder, how to add them efficiently without calling many add_test manully ?
    – Lewis Chan
    Commented Apr 11, 2019 at 2:04
67

I like the example of @Fraser but would use the add_test command in the test/CMakeLists.txt and use enable_testing before add_subdirectory(test).

This way you can run your tests from the top-level build directory while specifying your tests in the test/CMakeLists.txt.

The result would look like this (I reused the example of @Fraser):

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)

enable_testing ()
add_subdirectory (test)

src/CMakeLists.txt

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

test/CMakeLists.txt

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
add_test (NAME MyTest COMMAND Test)
5
  • 3
    Thanks, I showed no tests via ctest -N until your the tip about enabling testing before adding the subdir.
    – alaferg
    Commented May 20, 2016 at 16:51
  • @alaferg: they would otherwise end up in the test subdir inside the build dir.
    – gauteh
    Commented Nov 13, 2017 at 14:09
  • 16
    I wish CMake had something that resembled structure.
    – ruipacheco
    Commented Jan 11, 2019 at 18:55
  • @ruipacheco It's up to you to split the CMakeLists by responsibilities into different subfolders. Each of them should remain short.
    – Sandburg
    Commented Nov 5, 2021 at 11:01
  • add_definitions (-DBOOST_TEST_DYN_LINK) doesn't work for me; it never adds any defines in my project.. using vscode + cmake extensions.
    – Avrdan
    Commented Nov 8, 2022 at 15:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.