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.