CMake CTest single command build and test

Many CMake users, from end-users to developers have muscle memory for the three-stanza configure, build, test with CMake:

cmake -B build  # configure CMake and generate build files

cmake --build build  # compile and link binaries

cd build
ctest  # run program self-tests

However, this can be reduced to a single command for many programs:

ctest -S setup.cmake

where file “setup.cmake” contains

# --- Project-specific -Doptions
# these will be used if the project isn't already configured.
set(_opts)

# --- default build type
if(NOT DEFINED CTEST_BUILD_CONFIGURATION)
  set(CTEST_BUILD_CONFIGURATION "Release")
endif()

# --- verify minimum cmake version as CTest doesn't report otherwise if cmake_minimum_required(VERSION ...) is errored
set(_cmake_min_version 3.14)  # same as top-level CMakeLists.txt
if(CMAKE_VERSION VERSION_LESS ${_cmake_min_version})
  message(FATAL_ERROR "Need CMake >= ${_cmake_min_version}")
endif()

# --- choose source and build directories
set(CTEST_SOURCE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
if(NOT DEFINED CTEST_BINARY_DIRECTORY)
  set(CTEST_BINARY_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/build)
endif()

# --- [optional] tries to find Ninja, otherwise fallback to GNU Make
if(NOT DEFINED CTEST_CMAKE_GENERATOR)
  find_program(_gen NAMES ninja ninja-build samu)
  if(_gen)
    set(CTEST_CMAKE_GENERATOR "Ninja")
  elseif(WIN32)
    set(CTEST_CMAKE_GENERATOR "MinGW Makefiles")
    set(CTEST_BUILD_FLAGS -j)
  else()
    set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
    set(CTEST_BUILD_FLAGS -j)
  endif()
endif()

# --- configure, build, test
ctest_start("Experimental" ${CTEST_SOURCE_DIRECTORY} ${CTEST_BINARY_DIRECTORY})

if(NOT EXISTS ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt)
  ctest_configure(BUILD ${CTEST_BINARY_DIRECTORY} SOURCE ${CTEST_SOURCE_DIRECTORY} OPTIONS "${_opts}")
endif()

ctest_build(BUILD ${CTEST_BINARY_DIRECTORY} CONFIGURATION ${CTEST_BUILD_CONFIGURATION})

ctest_test(BUILD ${CTEST_BINARY_DIRECTORY})

The optional build generator selection avoids the default Visual Studio on Windows, which isn’t appropriate for many modern projects.

Option selection

If you need to specify command-line build options -Dfoo then either specify them in setup.cmake by _opts variable, or do like:

cmake -B build -Dfoo

ctest -S setup.cmake