How to make Cmake build only the test binaries without making the other executables?

Hi, I am about 3 days old to Cmake, lol. I have read the relevant chapters in Professional Cmake book but have not found the answer to my question.

Here is my CMakeList.txt

cmake_minimum_required(VERSION 3.21)

include(cmake/prelude.cmake)
include(cmake/macros.cmake)

message(NOTICE " " CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE})
message(NOTICE " " CMAKE_CURRENT_BINARY_DIR = ${CMAKE_CURRENT_BINARY_DIR})

project(
    c_template_two
    VERSION 0.1.0
    DESCRIPTION "A simple C template made using `cmake-init`."
    HOMEPAGE_URL "https://example.com/"
    LANGUAGES C
)

include(cmake/variables.cmake)

# Find all source files under each subdirectory of source/libs and add each of them as a library named after the name of the directory
# ADD_LIBRARY_FOR_EACH_SUB_DIR("source/libs")

# Use the macro `GET_SUB_DIRS_NAMES` to get a list of Library Directories Names => `SUB_DIR_NAMES` = GCDUtilitiesPrimalityUtilities
GET_SUB_DIRS_NAMES(LIBRARIES_NAMES "source/libs")
MESSAGE(NOTICE "`LIBRARIES_NAMES` = " ${LIBRARIES_NAMES})

FOREACH(libname ${LIBRARIES_NAMES})
  FILE(GLOB library_source_files source/libs/${libname}/*.c)
  add_library(${libname} STATIC ${library_source_files})
  target_include_directories(
    ${libname} ${warning_guard}
    PUBLIC
    "\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source/libs/${libname}>"
  )
  target_compile_features(${libname} PUBLIC c_std_17)
ENDFOREACH()

# target_include_directories(
#     PrimalityUtilities ${warning_guard}
#     PUBLIC
#     "\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source/libs/PrimalityUtilities>"
# )

# target_include_directories(
#   GCDUtilities ${warning_guard}
#     PUBLIC
#     "\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source/libs/GCDUtilities>"
# )


# target_compile_features(PrimalityUtilities PUBLIC c_std_17)
# target_compile_features(GCDUtilities PUBLIC c_std_17)

# ---- Declare executable ----

GET_SUB_DIRS_NAMES(EXECUTABLE_NAMES "source/bin")
MESSAGE(NOTICE "`EXECUTABLE_NAMES` = " ${EXECUTABLE_NAMES})

FOREACH(executable_name ${EXECUTABLE_NAMES})
  FILE(GLOB executable_source_files source/bin/${executable_name}/*.c)
  add_executable(${executable_name} source/bin/${executable_name}/main.c)
  add_executable(${executable_name}::exe ALIAS ${executable_name})

  set_property(TARGET ${executable_name} PROPERTY OUTPUT_NAME ${executable_name})

  target_compile_features(${executable_name} PRIVATE c_std_17)

  FOREACH(libname ${LIBRARIES_NAMES})
    target_link_libraries(${executable_name} PRIVATE ${libname})
  ENDFOREACH()
ENDFOREACH()

# add_executable(primetest source/bin/primetest/main.c)
# add_executable(primetest::exe ALIAS primetest)

# set_property(TARGET primetest PROPERTY OUTPUT_NAME primetest)

# target_compile_features(primetest PRIVATE c_std_17)

# target_link_libraries(primetest PRIVATE PrimalityUtilities)
# target_link_libraries(primetest PRIVATE GCDUtilities)

# ---- Declare executable ----

# add_executable(gcd source/bin/gcd/main.c)
# add_executable(gcd::exe ALIAS gcd)

# set_property(TARGET gcd PROPERTY OUTPUT_NAME gcd)

# target_compile_features(gcd PRIVATE c_std_17)

# target_link_libraries(gcd PRIVATE PrimalityUtilities)
# target_link_libraries(gcd PRIVATE GCDUtilities)

# ---- Tests ----

# https://honeytreelabs.com/posts/cmake-unity-integration/
# use Unity

include(FetchContent)
FetchContent_Declare(
  unity
  URL https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.6.0.zip
)

FetchContent_MakeAvailable(unity)

enable_testing()

add_executable(
  test_isprime
  test/source/test_isprime.c
)

target_link_libraries(
  test_isprime
  unity
  PrimalityUtilities
  GCDUtilities
)

# ---- Install rules ----

if(NOT CMAKE_SKIP_INSTALL_RULES)
  include(cmake/install-rules.cmake)
endif()

# ---- Developer mode ----

if(NOT c_template_two_DEVELOPER_MODE)
  return()
elseif(NOT PROJECT_IS_TOP_LEVEL)
  message(
      AUTHOR_WARNING
      "Developer mode is intended for developers of c_template_two"
  )
endif()

include(cmake/dev-mode.cmake)

Basically, what this project is doing is that it has two executables, gcd (calculate the greatest common divisor) and isprime (calculates if a number is prime or not). I am building the test_isprime binary to do unit testing with the Unity Testing Framework.

The issue is, each time I run to commands

cmake -S . -Bbuild/test
cmake --build build/test

to build the test binary (test_isprime), it also builds the other binaries (gcd and isprime).

What would be the best practice in this situation?

In some situations, perhaps my tests will involve executing the actual release binaries, e.g. ./build/release/isprime 12, but it can also be the case where all I want is to build only the test binaries for unit testing.

Should I create a new Configuration named ‘Test’ and set up a guard (using If() .... ENDIF()) to only build the binaries that I need for testing, e.g. isprime and test_isprime while neglecting say gcd? Again, what would be the best practice?

You can ask to build just specific targets, not all default targets:

cmake --build build/test --target test_isprime

If you have many test targets and you want to build them all, but not the non-test executable targets, you could list each of the test targets after --target like so:

cmake --build build/test --target test_isprime some_other_test another_test

That won’t be efficient with some CMake generators though. You may find the build tool is invoked to build each target one by one instead of passing them all to the build tool to build together. Another option would be to define a custom target that depends on all your test targets, then build that custom target.

add_custom_target(all_tests ALL)
add_dependencies(all_tests test_isprime some_other_test another_test)
cmake --build build/test --target all_tests
1 Like

Thank you for your prompt reply and your second method of adding custom target works perfectly.

Here is now my Cmake for the test directory so that people can reference it in the future.

# ---- Tests ----
# https://honeytreelabs.com/posts/cmake-unity-integration/ use Unity
INCLUDE(CTest)

INCLUDE(FetchContent)
FETCHCONTENT_DECLARE(
    unity
    URL https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.6.0.zip)

FETCHCONTENT_MAKEAVAILABLE(unity)

ENABLE_TESTING()

ADD_EXECUTABLE(test_isprime source/test_isprime.c)
TARGET_LINK_LIBRARIES(test_isprime unity PrimalityUtilities)
TARGET_COMPILE_FEATURES(test_isprime PRIVATE c_std_23)

INCLUDE(${CMAKE_SOURCE_DIR}/cmake/functions.cmake)
CREATE_EXECUTABLE_TARGET(gcd)

ADD_CUSTOM_TARGET(test_binaries ALL)
ADD_DEPENDENCIES(test_binaries test_isprime gcd)

ADD_TEST(test_isprime_one test_isprime)
ADD_TEST(NAME test_gcd COMMAND ${CMAKE_COMMAND} -P
                               ${CMAKE_SOURCE_DIR}/cmake/tests.cmake)