This page provides details about the CMake build system. Files
processed by the top level CMakeLists.txt
script are
listed in the TOC in chronological order.
Coding conventions are always a matter of choice. Nevertheless, the following rules should be considered:
else()
, endif()
,
endforeach()
, etc. statements shall not repeat the
corresponding condition in if()
,
foreach()
, etc.
foreach(_build ${DEAL_II_BUILD_TYPES}) # # Set an appropriate keyword depending on target and build type: # if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "DebugRelease") set(_keyword "general") else() if(_build MATCHES DEBUG) set(_keyword "debug") else() set(_keyword "optimized") endif() endif() endforeach()
list(APPEND CONFIG_LIBRARIES ${_keyword} ${CONFIG_LIBRARIES_${_build}} ) set_target_properties(${DEAL_II_TARGET_NAME}_${build_lowercase} PROPERTIES VERSION ${VERSION} SOVERSION ${VERSION} LINK_FLAGS "${DEAL_II_LINKER_FLAGS_${build}}" COMPILE_DEFINITIONS "${DEAL_II_DEFINITIONS};${DEAL_II_DEFINITIONS_${build}}" COMPILE_FLAGS "${DEAL_II_CXX_FLAGS_${build}}" )
CMake operates almost always with variables in global state. To guard against accidental overwrite of variables the following naming conventions must be followed at all times:
DEAL_II_
.
(Global variables defined by CMake are usually prefixed by
CMAKE_
.)
./CMakeLists.txt
and ./cmake/setup_*.cmake
The very first configuration steps after some initial setup in
./CMakeLists.txt
takes place in some
./cmake/setup_*.cmake
files:
setup_cached_variables.cmake
:
This sets up all cached variables prior to the call to
project(deal.II)
. For details see the comment at the
top. Furthermore, some bookkeeping for compiler and linker flags
takes place, see the section
about compile flags.
setup_deal_ii.cmake
:
This file is included immediately after the call to
project(deal.II)
and will set up all magic
numbers such as names, definitions, relative and absolute
paths used in the build system. Most of the definitions are
guarded with the help of the SET_IF_EMPTY
macro so
that it is possible to override the values from the command line.
setup_compiler_flags.cmake
sets up a suitable set of default compile flag for a known
compiler by including the appropriate
setup_compiler_flags_*.cmake
file. When adding new
flags or compiler support, please respect the following note
# # (./cmake/setup_compiler_flags.cmake) # # #################### # # FAT NOTE: # # #################### # # All configuration in setup_compiler_flags.cmake and # setup_compiler_flags_.cmake shall ONLY modify: # # DEAL_II_CXX_FLAGS # DEAL_II_CXX_FLAGS_DEBUG # DEAL_II_CXX_FLAGS_RELEASE # DEAL_II_LINKER_FLAGS # DEAL_II_LINKER_FLAGS_DEBUG # DEAL_II_LINKER_FLAGS_RELEASE # # All modifications shall be guarded with the ENABLE_IF_SUPPORTED # or ENABLE_IF_LINKS macro, e.g. # # enable_if_supported(DEAL_II_CXX_FLAGS "-fpic") # enable_if_links(DEAL_II_LINKER_FLAGS "-Wl,--as-needed") # # Compiler flags for platform dependent optimization (such as # -march=native) must always be guarded with # DEAL_II_ALLOW_PLATFORM_INTROSPECTION: # # IF(DEAL_II_ALLOW_PLATFORM_INTROSPECTION) # enable_if_supported(DEAL_II_CXX_FLAGS "-march=native") # ENDIF() # # Checks for compiler features (such as C++17 support) and compiler # specific bugs that # - usually set up further configuration (such as preprocessor # definitions) # - disable a specific flag for a specific compiler version. # # belong the corresponding file: # # ./cmake/checks/check_01_cpu_features.cmake # ./cmake/checks/check_01_cxx_features.cmake # ./cmake/checks/check_02_compiler_features.cmake # ./cmake/checks/check_02_system_features.cmake # ./cmake/checks/check_03_compiler_bugs.cmake #
./cmake/checks/check_*.cmake
The next step in the configuration process is to include all
checks residing under ./cmake/checks
. Currently
there are (included and executed in alphabetical order):
./cmake/checks/check_01_cpu_features.cmake - Platform introspection for CPU features goes here and must be guarded with DEAL_II_ALLOW_PLATFORM_INTROSPECTION ./cmake/checks/check_01_cxx_features.cmake - Check for supported C++ language features such as sufficient C++17 support ./cmake/checks/check_02_compiler_features.cmake - Search for support for compiler dependent features such as stack trace support, demangler support, etc. ./cmake/checks/check_02_system_features.cmake - Checks for specific platform (Linux/Darwin/CYGWIN/Windows..) features and support ./cmake/checks/check_03_compiler_bugs.cmake - Check for compiler bugs
HAVE_<..>
, resp.
DEAL_II_(HAVE|USE)_<..>
. It is forbidden to
use a variable name starting with
DEAL_II_WITH_<..>
because this prefix is
exclusively reserved for the feature mechanism described
below. For some tests it might be necessary to manipulate
global variables.
check_cxx_source_compiles(source variable) - Checks whether it is possible to compile _and_ link the code snippet <source>. If successful, variable is set to 1. check_cxx_source_runs(source variable) - variable is set to 1 if <source> could be successfully compiled and linked and the resulting program ran and exited without error. Avoid this macro outside of a DEAL_II_ALLOW_PLATFORM_INTROSPECTION guard. A sensible fallback should be provided if the check cannot be run (e.g. when cross compiling). check_cxx_compiler_bug(source variable) - Inverts the logic of CHECK_CXX_SOURCE_COMPILES(), i.e. variable is set to 1 if it was not possible to compile and link <source>. check_include_file_cxx(header variable) - Check whether it is possible to compile and link a dummy program including <header>. check_function_exists(function variable) - Check for the existence of a function prototype with name <function>. (Don't forget to specify the link libraries, see below.) Use CHECK_CXX_SYMBOL_EXISTS to search for C++ function definitions instead, if possible. check_cxx_symbol_exists(symbol header_file variable) - Check for the existence of a symbol definition in the header_file as well as for the presence in the current link interface (Don't forget to specify the link libraries, see below.) check_cxx_compiler_flag(flag variable) - Sets the variable to 1 if the compiler understands the flag.
CMAKE_REQUIRED_FLAGS
. There is a small macro that does this
job nicely:
add_flags(CMAKE_REQUIRED_FLAGS "-Werror") check_cxx_source_compiles(...) reset_cmake_required()
CMAKE_REQUIRED_INCLUDES
and
CMAKE_REQUIRED_LIBRARIES
. It is best to append these
lists and later on reset CMAKE_REQUIRED_*
(including
CMAKE_REQUIRED_FLAGS
) to their default values:
list(APPEND CMAKE_REQUIRED_INCLUDES <a list of includes>) list(APPEND CMAKE_REQUIRED_LIBRARIES <a list of libraries>) check_cxx_source_compiles(...) reset_cmake_required()
./cmake/modules/Find*.cmake
These are find modules for the configure_*.cmake
files
and the CONFIGURE_FEATURE
macro as will explained later.
It is crucial that a find module behaves correctly. Therefore, the
following rules are mandatory:
deal_ii_find_library
,
deal_ii_find_path
and deal_ii_find_file
calls (same syntax as the native CMake functions; just a small
wrapper to provide some useful output). The results of this calls
should be the only cached variables.
WARNING
, SEND_ERROR
or
FATAL_ERROR
must be avoided (the only exception is
the REQUIRED
keyword).
FEATURE_FOUND FEATURE_LIBRARIES (with optimized, debug, release keywords) FEATURE_LIBRARIES(_DEBUG|_RELEASE) FEATURE_INCLUDE_DIRS FEATURE_LINKER_FLAGS(|_DEBUG|_RELEASE) FEATURE_CXX_FLAGS(|_DEBUG|_RELEASE) FEATURE_DEFINITIONS(|_DEBUG|_RELEASE) FEATURE_VERSION FEATURE_VERSION(_MAJOR|_MINOR|_SUBMINOR)The
process_feature
macro should be exclusively
used for setting up these variables (except the version variants). An
example invocation is
process_feature(UMFPACK LIBRARIES REQUIRED UMFPACK_LIBRARY OPTIONAL CHOLMOD_LIBRARY CCOLAMD_LIBRARY COLAMD_LIBRARY CAMD_LIBRARY ${_suitesparse_config} REQUIRED AMD_LIBRARY OPTIONAL METIS_LIBRARIES LAPACK_LIBRARIES rt_LIBRARY INCLUDE_DIRS REQUIRED UMFPACK_INCLUDE_DIR AMD_INCLUDE_DIR OPTIONAL SuiteSparse_config_INCLUDE_DIR LINKER_FLAGS OPTIONAL LAPACK_LINKER_FLAGS CLEAR UMFPACK_LIBRARY CHOLMOD_LIBRARY CCOLAMD_LIBRARY COLAMD_LIBRARY CAMD_LIBRARY SuiteSparse_config_LIBRARY AMD_LIBRARY UMFPACK_INCLUDE_DIR AMD_INCLUDE_DIR SuiteSparse_config_INCLUDE_DIR )The macro concatenates all specified variables into the final
FEATURE_SUFFIX
variable. Hereby, a feature is
successfully found if all REQUIRED
variables are
non-empty and not set to "-NOTFOUND"
.
OPTIONAL
variables are just filtered out in this case.
As a last set of parameters the full list of cached search result
variables must be specified after the CLEAR
keyword -
this is used to provide a possibility to undo a feature search.
_<all lowercase>
" or
"global" variables prefixed by FEATURE_
may be
altered. Do not set DEAL_II_*
or CMAKE_*
variables directly!
FEATURE_DIR
can be set up for
convenience. It is best to start the Find
module by
set(FEATURE_DIR "" CACHE PATH "short description") set_if_empty(FEATURE_DIR "$ENV{FEATURE_DIR}")and use
FEATURE_DIR
as a hint.
./cmake/configure/configure_*.cmake
The final step in the configuration phase is the setup of features (which refer to external or bundled libraries deal.II can optionally interface with.)
At bare minimum configure_<feature>.cmake
file for a feature just consists of a call to the
configure_feature(<FEATURE>)
macro which is
implemented in
./cmake/macros/macro_configure_feature.cmake
.
In this case the corresponding Find<FEATURE>.cmake
module is used to determine whether an external dependency can be
resolved or not. Depending on the current state of
DEAL_II_WITH_<FEATURE>
(see
here) the
configuration variables
FEATURE_LIBRARIES FEATURE_LIBRARIES(|_DEBUG|_RELEASE) FEATURE_(|BUNDLED_)INCLUDE_DIRS FEATURE_LINKER_FLAGS(|_DEBUG|_RELEASE) FEATURE_CXX_FLAGS(|_DEBUG|_RELEASE) FEATURE_DEFINITIONS(|_DEBUG|_RELEASE)are appended to the set of global variables and
DEAL_II_WITH_<FEATURE>
is set to
TRUE
.
It is possible to override this default behaviour with the following variables and macros (all of them are optional and will be replaced by an appropriate default action if unset):
<FEATURE>
means all caps,
<feature>
means all lowercase
./cmake/configure/configure_<feature>.cmake
:
FEATURE_<FEATURE>_DEPENDS (a variable) - a variable which contains an optional list of other features this feature depends on (and which have to be enabled for this feature to work.) Features must be given with short name, i.e. without DEAL_II_WITH_ FEATURE_<FEATURE>_AFTER (a variable) - a variable which contains an optional list of other features that have to be configured prior to this feature Features must be given with short name, i.e. without DEAL_II_WITH_ FEATURE_<FEATURE>_FIND_EXTERNAL(var) (a macro) - which should set var to TRUE if all dependencies for the feature are fulfilled. In this case all necessary variables for FEATURE_<FEATURE>_CONFIGURE_EXTERNAL must be set. Otherwise var should remain unset. If this macro is undefined, FIND_PACKAGE(<FEATURES>) is called directly instead. FEATURE_<FEATURE>_CONFIGURE_EXTERNAL() (a macro) - which should setup all necessary configuration for the feature with external dependencies. If something goes wrong this macro must issue a FATAL_ERROR. If this macro is undefined, the information provided in <FEATURES>_LIBRARIES, <FEATURES>_INCLUDE_DIRS and <FEATURES>_LINKER_FLAGS is used for the build. FEATURE_<FEATURE>_CONFIGURE_BUNDLED() (a macro) - which should setup all necessary configuration for the feature with bundled source dependencies. If something goes wrong this macro must issue a FATAL_ERROR. FEATURE_<FEATURE>_ERROR_MESSAGE() (macro) - which should print a meaningful error message (with FATAL_ERROR) for the case that no external library was found (and bundled is not allowed to be used.) If not defined, a suitable default error message will be printed.
./bundled/configure_bundled.cmake
:
FEATURE_<FEATURE>_HAVE_BUNDLED (a boolean) - which should either be set to TRUE if all necessary libraries of the features comes bundled with deal.II and hence can be supported without external dependencies, or unset. DEAL_II_FORCE_BUNDLED_<FEATURE> (an option) - If <feature> can be set up by bundled libraries, this configuration option must be present to force a use of bundled dependencies
DEAL_II_FEATURE_<FEATURE>_BUNDLED_CONFIGURED
is set to
TRUE
the file ./bundled/CMakeLists.txt
must compile and install the bundled package appropriately.
The following list describes all global variables controlling the
build process and the visibility associated with it (internal use for
compiling deal.Ii, externally used variables will get exported in
deal.IIConfig.cmake). Lists should be manipulated with
LIST(APPEND ...)
, flags with ADD_FLAGS(...)
(or if it is necessary to guard them with
ENABLE_IF_SUPPORTED(...)
.)
Feature configuration must not be added directly to this variables but
to corresponding <FEATURE>_*
variables, instead.
Feature configuration variables get appended to the below list of global
configuration variables automatically.
_DEBUG
or
_RELEASE
: Used for all targets
<...>_DEBUG
: additionally used for debug targets
<...>_RELEASE
: additionally used for release targets
DEAL_II_LIBRARIES
DEAL_II_LIBRARIES_DEBUG
DEAL_II_LIBRARIES_RELEASE
DEAL_II_INCLUDE_DIRS
DEAL_II_BUNDLED_INCLUDE_DIRS
-D<...>
) for the compilation of the deal.II
library:
DEAL_II_DEFINITIONS
DEAL_II_DEFINITIONS_DEBUG
DEAL_II_DEFINITIONS_RELEASE
-std=c++20
(if available):
DEAL_II_CXX_FLAGS
DEAL_II_CXX_FLAGS_DEBUG
DEAL_II_CXX_FLAGS_RELEASE
DEAL_II_LINKER_FLAGS
DEAL_II_LINKER_FLAGS_DEBUG
DEAL_II_LINKER_FLAGS_RELEASE
For a general description of this feature see
the deal.II Readme
entry. Many of the various CMakeLists.txt
files split their
source files into two lists: one list of files that are relatively cheap to
compile, which are concatenated into the unity build files, and a list of
files that are more expensive to compile, which are not included in the unity
files. For example: most of the finite element classes take about 5-10 seconds
to compile while the FEValues
instantiation files each take about
60 seconds. In addition, many CMakeLists.txt
files define a
variable _n_includes_per_unity_file
which specifies how many
files should be concatenated into each unity file.
A disadvantage to this approach is that it requires profiling the build in two
places: the time and memory usage of all source files must be measured and the
variable _n_includes_per_unity_file
should be set so that the
unity build files are not overly expensive in terms of memory and wall
time. The current values were chosen so that the unity files, with GCC,
require about 30 to 60 seconds of wall time and about 2 GB of memory.
If you want to add a new file to one of the CMakeLists.txt
files
then you should place it in either the _unity_include_src
or
the _separate_src
list (not both). If the new file only takes a
few seconds to compile then it should be placed in the former category (so
that it may be built in a unity file) and otherwise it should be in the
latter. If you are not sure where a new file belongs then placing it in
the _separate_src
list is the conservative choice.
./include/deal.II/base/config.h.in
config.h.in
should only contain a minimum of
necessary compile definitions to avoid unnecessary recompilation if
configuration changes.
config.h.in
should have a
prominent comment explaining it and should be grouped by file
exporting the definition.
./source/CMakeLists.txt
All parts of the library are organized into logical object libraries
with their respective sources lying under
./source/<foo>
, or
./bundled/<foo>/<...>
. The actual setup of an object
library happens within that subdirectories with the help of a few macros. More
documentation on the unity build subsystem is
available here.
# # A list of source files that, if DEAL_II_UNITY_BUILD=ON, will be concatenated # into a few unity files: # set(_unity_include_src block_info.cc dof_faces.cc ... ) # # A list of source files that are always compiled individually: # set(_separate_src dof_accessor.cc dof_accessor_get.cc ... ) # # The number of files, if DEAL_II_UNITY_BUILD=ON, to include in each unity # file. This number is determined empirically by timing the build. The macro # SETUP_SOURCE_LIST calls the macro SETUP_UNITY_TARGET which will generate unity # files that each contain no more than _n_includes_per_unity_file files. If # DEAL_II_UNITY_BUILD=OFF then this variable is never read. # set(_n_includes_per_unity_file 15) # # A macro that handles setting up the list of source files to compile in the # _src variable and handles the unity build logic: # setup_source_list("${_unity_include_src}" "${_separate_src}" ${_n_includes_per_unity_file} _src ) # # A list of instantiations that must be expanded: # set(_inst block_info.inst.in ... ) # # The following macro will set up an obj_dofs_debug and # obj_dofs_release targets with appropriate compile flags and # definitions. # # Header files and instantiation files (${_header}, ${_inst}) are added # for cosmetic reasons, so that they show up in IDEs. # file(GLOB _header ${CMAKE_SOURCE_DIR}/include/deal.II/dofs/*.h ) deal_ii_add_library(obj_dofs OBJECT ${_src} ${_header} ${_inst}) # # This macro will set up a target for each of the files listed in # ${_inst}. Appropriate target dependencies will be added to obj_dofs_debug and # obj_dofs_release. # expand_instantiations(obj_dofs "${_inst}")
Later, all object targets are collected in
./source/CMakeLists.txt
to define the actual debug and
releases libraries. For further details, see
./source/CMakelists.txt
and
./cmake/macros/macro_deal_ii_add_library.cmake
.
./cmake/config/CMakeLists.txt
The final bits of configuration happens in
./cmake/config/CMakeLists.txt
where the templates for the
project configuration deal.IIConfig.cmake
gets expanded.
Furthermore, the configuration for the template expansion mechanism
resides under ./cmake/config/template_arguments.in
.