Practical CMake Configuration Techniques

Configuring RPATH in CMake

First, disable the automatic addition of build-time paths to RPATH at the beginning of your CMake configuration:

set(CMAKE_SKIP_RPATH TRUE)

After declaring a library with add_library but before linking with target_link_libraries, set these properties to enable dependency lookup in relative ../lib or ./lib directories. This facilitates deployment by allowing all shared libraries to reside in a lib directory and executables in a bin directory. The --disable-new-dtags flag ensures consistent use of RPATH instead of RUNPATH.

set_target_properties(my_library PROPERTIES LINK_FLAGS "-Wl,--disable-new-dtags")
set_target_properties(my_library PROPERTIES LINK_FLAGS "-Wl,-rpath=../lib:./lib")

Setting RPATH with Configure Scripts

For projects using autotools configure scripts, embed RPATH settings during confiugration to ensure both the primary library and its dependencies use relative paths:

./configure --prefix=${PWD}/build LDFLAGS=-Wl,-rpath=../lib:./lib

This approach ensures deployed libraries function correctly when placed in a lib directory.

Managing Dependency Propagation

Use PUBLIC visibility to transitively propagate a submodule's dependencies to the current module, eliminating the need to manually include secondary dependencies. However, prefer PRIVATE visibility to prevent dependency pollution when possible.

target_include_directories(core_module PUBLIC
    ${CMAKE_SOURCE_DIR}/src/core
    ${CMAKE_SOURCE_DIR}/src/utils
    ${CMAKE_SOURCE_DIR}/external
    ${CMAKE_SOURCE_DIR}/external/single_include)

target_link_libraries(core_module PUBLIC
    Qt${QT_VERSION_MAJOR}::Widgets
    Qt${QT_VERSION_MAJOR}::Sql
    utility_lib
    helper_lib)

Including Current Directory

Enable automatic inclusion of the current source and binary directories:

set(CMAKE_INCLUDE_CURRENT_DIR ON)

Recursive File Discovery

Collect header and source files recursively from a directory structure:

file(GLOB_RECURSE Headers "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
file(GLOB_RECURSE Sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")

Defining Custom Preprocessor Macros

1. Command-Line Definition with Value:

cmake -DBUFFER_SIZE=256 ...

In CMakeLists.txt:

if(DEFINED BUFFER_SIZE)
    message(STATUS "BUFFER_SIZE: ${BUFFER_SIZE}")
    add_definitions(-DBUFFER_SIZE=${BUFFER_SIZE})
endif()

In source code:

#ifdef BUFFER_SIZE
    int buffer = BUFFER_SIZE;
#else
    int buffer = 128;
#endif

2. Command-Line Definition without Value:

cmake -DDEBUG_MODE=ON ...

In CMakeLists.txt:

if(DEBUG_MODE)
    add_definitions(-DDEBUG_ENABLED)
endif()

In source code:

#ifdef DEBUG_ENABLED
    // Debug code here
#endif

Specifying Output Directories

Control where built artiafcts are placed:

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/bin)

Executing Custom Scripts

Run external scripts during configuration:

execute_process(COMMAND bash setup.sh "${CMAKE_SOURCE_DIR}/build"
                WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/scripts
                RESULT_VARIABLE EXIT_CODE
                OUTPUT_VARIABLE SCRIPT_OUTPUT)

message(STATUS "Script output: ${SCRIPT_OUTPUT}")
message(STATUS "Exit code: ${EXIT_CODE}")

This executes setup.sh from the scripts directory, passing the build directory as an argument, and captures both output and exit status.

Tags: CMake build-systems cplusplus rpath dependency-management

Posted on Mon, 06 Jul 2026 16:04:05 +0000 by songwind