CMake:Example
lastmod 2021-01-03created 2016-02-2416 edits
A collection of CMake usage examples.
Install preefix
You can set the directory where the program or library is installed, applied at the make install step.
Print verbose
To see detailed information (command lines, etc.) during the build, add the VERBOSE option as shown below.
The important point is that it is applied at the make step, not cmake.
Print variables
Running the following prints a list of all variables available in CMakeLists.txt.
CMake Script Mode
To use CMake per script rather than for a build, apply the -P option as shown below.
Check directory exists
Global property
You can 'simulate' GLOBAL variable behavior, by using properties with GLOBAL scope :
Then you can extract your global property by using
Target property
I've tried GET_TARGET_PROPERTY but it does not work. The SUFFIX property returns NOTFOUND unless we explicitly set it by calling SET_TARGET_PROPERTIES. Take the following CMakeLists.txt as an example:
PROJECT(hello)
ADD_LIBRARY(hello SHARED hello.c)
GET_TARGET_PROPERTY(suffix hello SUFFIX)
MESSAGE("suffix = ${suffix}")
SET_TARGET_PROPERTIES(hello PROPERTIES SUFFIX .so)
GET_TARGET_PROPERTY(suffix hello SUFFIX)
MESSAGE("suffix = ${suffix}")
Library version
Custom Command
- CMake » 3.0.2 Documentation » cmake-commands(7) » add_custom_command
- CMake » 3.0.2 Documentation » cmake-commands(7) » add_custom_target
- Stackoverflow: cmake, add_custom_command with dependencies from a different directory
- Stackoverflow: How to make CMake target executed whether specified file was changed?
cmake_minimum_required(VERSION 2.8 )
project(part)
# ...
add_custom_command(OUTPUT part.out
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/part.src part.out
DEPENDS part.src)
add_custom_target(part_out
DEPENDS part.out)
Check machine
The machine architecture (32bit or 64bit) can be checked as shown below.
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set (BOOST_LIBRARY "/boost/win64/lib")
else ()
set (BOOST_LIBRARY "/boost/win32/lib")
endif ()
set (CMAKE_EXE_LINKER_FLAGS ${BOOST_LIBRARY})
Linker flags
whole-archive
- Adding the --whole-archive option to a CMAKE project
- CMake: Linking static libraries into shared libs?
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set (MAIN_LINK -Wl,-force_load ${MAIN_STATIC})
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set (MAIN_LINK -Wl,--whole-archive ${MAIN_STATIC} -Wl,--no-whole-archive)
endif ()
# ...
target_link_libraries (${MAIN_SHARED} ${MAIN_LINK})
CMake RPATH handling
- See also: rpath, install_name
- [Recommended] CMake RPATH handling 1
- Stackoverflow: How can LD_LIBRARY_PATH be changed within CMake?
- [Recommended] RPATH handling 2
- Stackoverflow: CMAKE RPATH not working - could not find shared object file
Apply it as shown below.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_library(heart SHARED ${HEART_FILES})
add_executable(run ${RUN_FILES})
target_link_libraries(run heart)
install(
TARGETS heart run
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
)
However, it must be called before the point where targets are created, such as with add_library or add_executable. (Need to check whether functions like target_link_libraries are also included)
Static & Shared library
- Make Both Static and Shared Libraries in One Build with CMake
- Stackoverflow: Is it possible to get CMake to build both a static and shared version of the same library?
- Stackoverflow: CMake: how create a single shared library from all static libraries of subprojects?
- Build shared and static in one build
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
# On Linux, it will build MyLib.a and MyLib.so
CUDA Example
- CMake » 3.0.2 Documentation » cmake-modules(7) » FindCUDA
- Example of CMake File for CUDA+CPP Code
- How to build CUDA programs using CMake
- [Recommended] Compiling .cu with Mpi, Gcc and Cmake
google-protocol-buffers custom target example
A custom build method for using Protobuf.
## CMake google-protocol-buffers build script.
exists_define_or_die (THIRD_PREFIX)
set (PROTOBUF_TARGET_NAME "protobuf")
project (${PROTOBUF_TARGET_NAME})
set (PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set (PROTOBUF_DIR "${PARENT_DIR}/protobuf")
#set (PROTOBUF_AUTOGEN "${PROTOBUF_DIR}/autogen.sh")
set (PROTOBUF_CONFIG "${PROTOBUF_DIR}/configure")
set (PROTOBUF_MAKE "${PROTOBUF_DIR}/Makefile")
set (PROTOBUF_LIB_TARGET "${THIRD_PREFIX}/lib/libprotobuf.a")
set (PROTOBUF_EXE_TARGET "${THIRD_PREFIX}/bin/protoc")
add_custom_command (OUTPUT ${PROTOBUF_DIR}
COMMAND git clone --depth=1 https://github.com/google/protobuf.git
WORKING_DIRECTORY ${PARENT_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_CONFIG}
COMMAND ./autogen.sh
DEPENDS ${PROTOBUF_DIR}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_MAKE}
COMMAND ./configure --prefix=${THIRD_PREFIX}
DEPENDS ${PROTOBUF_CONFIG}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_LIB_TARGET} ${PROTOBUF_EXE_TARGET}
COMMAND make && make install
DEPENDS ${PROTOBUF_MAKE}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_target (${PROTOBUF_TARGET_NAME}
DEPENDS ${PROTOBUF_LIB_TARGET} ${PROTOBUF_EXE_TARGET}
)
# ...
add_dependencies (MAIN_PROJ protobuf)
Script mode example
Script mode example:
## CMake third-party library generator.
cmake_minimum_required (VERSION 2.8.8)
set (THIRD_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/libthird.a")
set (THIRD_OBJS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/objs")
if (EXISTS ${THIRD_OBJS_DIR})
file (REMOVE_RECURSE ${THIRD_OBJS_DIR})
endif ()
if (NOT EXISTS ${THIRD_OBJS_DIR})
file (MAKE_DIRECTORY ${THIRD_OBJS_DIR})
endif ()
# Extract object in the archive.
foreach (LIB_CURSOR ${THIRD_LIBS})
execute_process (
COMMAND ar xv "${LIB_CURSOR}"
WORKING_DIRECTORY "${THIRD_OBJS_DIR}"
)
endforeach ()
execute_process (
COMMAND ar cr "${THIRD_ARCHIVE}" *.o
WORKING_DIRECTORY "${THIRD_OBJS_DIR}"
)
Run it as shown below.
Print all properties
I have had limited success with the following work-around to the apparent lack of ability to dynamically query for the properties of a target.
I invoke the cmake command to list all properties, and then try each one on the target.
# Get all propreties that cmake supports
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
# Convert command output into a CMake list
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
function(print_properties)
message ("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}")
endfunction(print_properties)
function(print_target_properties tgt)
if(NOT TARGET ${tgt})
message("There is no target named '${tgt}'")
return()
endif()
foreach (prop ${CMAKE_PROPERTY_LIST})
string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
# message ("Checking ${prop}")
get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
if (propval)
get_target_property(propval ${tgt} ${prop})
message ("${tgt} ${prop} = ${propval}")
endif()
endforeach(prop)
endfunction(print_target_properties)
Removing the main function from a static library
How to remove the main of dwm and add your own main function. Use the strip utility.
cmake_minimum_required (VERSION 3.3)
project (opwm)
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
set (DWM_NAME dwm)
set (DWM_VERSION 6.2)
set (DWM_SOURCE_FILES
dwm/drw.c
dwm/dwm.c
dwm/util.c)
set (OPWM_NAME opwm)
set (OPWM_VERSION 6.2)
set (OPWM_SOURCE_FILES
main.c)
set (DWM_NOMAIN_NAME dwm-nomain)
set (DWM_NOMAIN_PATH
"${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}dwm-nomain${CMAKE_STATIC_LIBRARY_SUFFIX}")
set (COMMON_COMPILE_DEFINITIONS
_DEFAULT_SOURCE
_BSD_SOURCE
_POSIX_C_SOURCE=2
XINERAMA)
set (COMMON_INCLUDE_DIRECTORIES
/usr/X11R6/include
/usr/include/freetype2
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/dwm)
set (COMMON_COMPILE_OPTIONS
-std=c99
-pedantic
-Wall
-Wno-deprecated-declarations)
set (COMMON_LINK_LIBRARIES
-L/usr/X11R6/lib
-lX11
-lXinerama
-lfontconfig
-lXft)
add_library (${DWM_NAME} STATIC ${DWM_SOURCE_FILES})
target_compile_definitions (${DWM_NAME} PRIVATE ${COMMON_COMPILE_DEFINITIONS} VERSION=\"${DWM_VERSION}\")
target_include_directories (${DWM_NAME} PRIVATE ${COMMON_INCLUDE_DIRECTORIES})
target_compile_options (${DWM_NAME} PRIVATE ${COMMON_COMPILE_OPTIONS})
add_custom_target (
${DWM_NOMAIN_NAME}
ALL
DEPENDS ${DWM_NOMAIN_PATH})
add_custom_command (
OUTPUT ${DWM_NOMAIN_PATH}
COMMAND strip --strip-symbol=main -o "${DWM_NOMAIN_PATH}" "$<TARGET_FILE:${DWM_NAME}>"
DEPENDS ${DWM_NAME}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_executable (${OPWM_NAME} ${OPWM_SOURCE_FILES})
add_dependencies (${OPWM_NAME} ${DWM_NOMAIN_NAME})
target_compile_definitions (${OPWM_NAME} PRIVATE ${COMMON_COMPILE_DEFINITIONS})
target_include_directories (${OPWM_NAME} PRIVATE ${COMMON_INCLUDE_DIRECTORIES})
target_compile_options (${OPWM_NAME} PRIVATE ${COMMON_COMPILE_OPTIONS})
target_link_libraries (${OPWM_NAME} PRIVATE ${DWM_NOMAIN_PATH} ${COMMON_LINK_LIBRARIES})
set (COMPILE_COMMANDS_NAME cc)
set (COMPILE_COMMANDS_SRC "${CMAKE_BINARY_DIR}/compile_commands.json")
set (COMPILE_COMMANDS_DEST "${CMAKE_SOURCE_DIR}/compile_commands.json")
add_custom_target (${COMPILE_COMMANDS_NAME} DEPENDS ${COMPILE_COMMANDS_DEST})
add_custom_command (
OUTPUT ${COMPILE_COMMANDS_DEST}
COMMAND ${CMAKE_COMMAND} -E copy "${COMPILE_COMMANDS_SRC}" "${COMPILE_COMMANDS_DEST}"
DEPENDS ${OPWM_NAME} ${COMPILE_COMMANDS_SRC}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
install (TARGETS ${OPWM_NAME})