CMake Macros, Linking, and Other Notes
Previously I described using CMake for multi-platform builds; developing this kind of support makes CMake scripting more complex. To help manage this we can use macros and other techniques, described below.
Macros
You can write macros in CMake, store them in a directory with other .cmake
macro files and access them like this:
# Specify directory to find macro files
set(CMAKE_MODULE_PATH ...)
# Include macro file, .cmake extension not required
include(...)
Create macros like so, save the code in a file with .cmake
extension:
macro(name PARAM1 ...)
# Parameters can be accessed by name
message("${PARAM1}")
# Or find them in ${ARGV}, which is read-only.
# To access and modify them, we first have to make a copy,
# then we can operate on the copy like any other list.
set(PARAMS ${ARGV})
# For example, pop the first value off.
list(REMOVE_AT PARAMS 0)
# Then you can add any other commands
...
endmacro(name)
Variable String Matching
The following block is executed if x86
appears anywhere in the value stored in $ENV{MACHINE}
:
if( $ENV{MACHINE} MATCHES "x86" )
endif()
File Operations
To create directories:
file(MAKE_DIRECTORY name)
Copy directory structure, using a custom target:
add_custom_target(... ALL
COMMAND $(CMAKE_COMMAND) -E copy_directory source destination
)
Where ...
is a target name, so you can set dependencies (other targets that your copy target depends on will need to be built first), source
and destination
are the source and destination directories for the copy operation. Using cmake
to perform the copy so that you won't have to deal with different copy commands under different operating systems.
Linking
To link libraries A, B, and C (for example, libA.so
, libB.so
, and libC.so
on Linux) to your build_target:
add_executable(build_target ...)
target_link_libraries(build_target A B C)
CMake will take care of proper switches required to link. Library names can be build targets from previous add_library()
entries also.
Imported Static Library
From time to time you need to statically link a library or archive that is built by someone else. You can rename it so that it may get picked up as part of library search. Alternatively, you can define it as a library:
add_library(... STATIC IMPORTED)
set_target_properties(... PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/file.a
)
Where ...
is the target name that you can use to link against, and ${CMAKE_CURRENT_SOURCE_DIR}/file.a
is path to the archive (in above example it lives within the source tree).
Output Target Properties
Define library version and output directory:
add_library(... SHARED ${SOURCES})
set_target_properties(... PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}
VERSION ${VERSION_STRING}
SOVERSION ${VERSION_MAJOR_NUMBER}
)
Define executable output directory and specific link options:
add_executable(... ${SOURCES})
set_target_properties(... PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}
LINK_FLAGS ${LINK_OPTIONS}
)
Temporary Objects
You can group several source files together as a single unit and reference them later. This is useful if you want to apply different set of compile flags to just a subset of your source tree.
add_library(build_target OBJECT ...)
Once this is done, you can reference build_target just like another source with $<TARGET_OBJECTS: ...>
:
set(SOURCES
A.cpp
B.cpp
$<TARGET_OBJECTS:build_target>
)
add_executable(build_output ${SOURCES})