Keywords: deal.II
Date: $Date: 2013-12-08 12:12:55 -0500 (Sun, 08 Dec 2013) $

# Build system internals

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 convention

Coding conventions are always a matter of choice. Nevertheless, the following rules should be considered:

- Statements and keywords are written in all caps.
- Indenting is done by two spaces; the usual indenting rules apply.
- The `ELSE()`, `ENDIF()`, `ENDFOREACH()`, etc. statements shall not repeat the corresponding condition in `IF()`, `FOREACH()`, etc.
- To emphasize a comment it may be enclosed by a leading and trailing empty comment line.

An example:

    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()

- Line break is at 78 characters and should be obeyed whenever reasonable.
- Long statements should be broken into several lines at reasonable places. Additional lines for a statement are indented by 2 spaces.
- Multiline statements must end with the closing bracket at a single line:

    LIST(APPEND CONFIG_LIBRARIES
      ${_keyword}
      ${CONFIG_LIBRARIES_${_build}}
    )

    SET_TARGET_PROPERTIES(${DEAL_II_BASE_NAME}${DEAL_II_${build}_SUFFIX}
      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:

- Global (configuration) variables are written in all caps. When introducing a new one, ensure that the name isn't already used somewhere else. Unrelated global variables must never be overwritten.
- Global variables can be prefixed by `DEAL_II_`. (Global variables defined by CMake are usually prefixed by `CMAKE_`.)
- Local variables should always be named in all lowercase with a leading "_". Local variables cannot be assumed to remain valid. The may get overwritten at any time.

## Configuration

### `./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:
      #
      #   CMAKE_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(CMAKE_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(CMAKE_CXX_FLAGS "-march=native")
      #   ENDIF()
      #
      # Checks for compiler features (such as C++11 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_compiler_features.cmake
      #   ./cmake/checks/check_01_cpu_features.cmake
      #   ./cmake/checks/check_01_cxx_features.cmake
      #   ./cmake/checks/check_01_system_features.cmake
      #   ./cmake/checks/check_02_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:

    ./cmake/checks/check_01_compiler_features.cmake
      - Search for support for compiler dependent features such as stack
        trace support, demangler support, etc.

    ./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++11
        support

    ./cmake/checks/check_01_system_features.cmake
      - Checks for specific platform (Linux/Darwin/CYGWIN/Windows..)
        features and support

    ./cmake/checks/check_02_compiler_bugs.cmake
      - Check for compiler bugs

- A check usually consists of a call to one of the macros below that will set up a global variable. Please stick to the naming convention `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.
- A platform check should have a prominent comment explaining what it does and why it is there, and should state author and year.
- There are a number of readily available platform check macros:

      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.

- Necessary compiler flags can easily set in the string variable `CMAKE_REQUIRED_FLAGS`. There are two small macros that do this job nicely:

      PUSH_TEST_FLAG("-Werror")
      CHECK_CXX_SOURCE_COMPILES(...)
      POP_TEST_FLAG()

- Necessary include directories and libraries necessary for linkage can be set in the list variables `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:

- The sole purpose of a find module is to find an external library (no deal.II specific dependency checking, no compatibility checking).
- It should do so by appropriate `FIND_LIBRARY` and `FIND_PATH` calls. The results of this calls should be the only cached variables.
- `FIND_PACKAGE_HANDLE_STANDARD_ARGS` should be used for setting `FEATURE_FOUND` as this already respects the `QUIET` and `REQUIRED` keywords.
- A `WARNING`, `SEND_ERROR` or `FATAL_ERROR` must be avoided (the only exception is the `REQUIRED` keyword).
- If successful, the following uncached variables might be set:

      FEATURE_FOUND
      FEATURE_LIBRARIES
      FEATURE_INCLUDE_DIRS
      FEATURE_LINKER_FLAGS

      FEATURE_VERSION
      FEATURE_VERSION_MAJOR
      FEATURE_VERSION_MINOR
      FEATURE_VERSION_SUBMINOR

  There are obviously valid exceptions from this rule, though.
- Only "local" variables "`_<all lowercase>`" or "global" variables prefixed by `FEATURE_` may be altered. Do not set `DEAL_II_*` or `CMAKE_*` variables directly!
- A hint with `FEATURE_DIR` can be set up for convenience. It is best to start the `Find` module by

      SET_IF_EMPTY(FEATURE_DIR "$ENV{FEATURE_DIR}")

  and use `FEATURE_DIR` as a hint. If the external library could be found, hide it via `MARK_AS_ADVANCED`, if the external library could not be found, set a cache value:

      SET(FEATURE_DIR "" CACHE PATH "An optional hint to a FEATURE directory")

### `./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 variables

    FEATURE_LIBRARIES
    FEATURE_INCLUDE_DIRS
    FEATURE_LINKER_FLAGS

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
- In `./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.) The features must be given with the full option toggle:
          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.

- In `./bundled/CMakeLists.txt`:

      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

- Furthermore, if `FEATURE_<FEATURE>_BUNDLED_CONFIGURED` is set to `TRUE` the file `./bundled/CMakeLists.txt` must compile and install the bundled package appropriately.

### Global variables controlling the build process

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(...)`.)

- The general (internal) logic for variables applies:
  - A variable name without `_DEBUG` or `_RELEASE`: Used for all targets
  - `<...>_DEBUG`: additionally used for debug targets
  - `<...>_RELEASE`: additionally used for release targets
- For internal use, for setting necessary linker flags for the deal.II library:
  - `DEAL_II_LINKER_FLAGS`
  - `DEAL_II_LINKER_FLAGS_DEBUG`
  - `DEAL_II_LINKER_FLAGS_RELEASE`
- For internal use, for setting necessary compiler flags, e.g. `-std=c++11` (if available):
  - `CMAKE_CXX_FLAGS`
  - `DEAL_II_CXX_FLAGS_DEBUG`
  - `DEAL_II_CXX_FLAGS_RELEASE`
- For internal use, for setting necessary include dirs for the compilation of the deal.II library:
  - `INCLUDE_DIRECTORIES(...)`
- For internal use, for setting necessary preprocessor definitions (`-D<...>`) for the compilation of the deal.II library:
  - `DEAL_II_DEFINITIONS`
  - `DEAL_II_DEFINITIONS_DEBUG`
  - `DEAL_II_DEFINITIONS_RELEASE`
- For internal and external use, used to keep track of external libraries, the deal.II library and user programs have to be linked against:
  - `DEAL_II_EXTERNAL_LIBRARIES`
  - `DEAL_II_EXTERNAL_LIBRARIES_DEBUG`
  - `DEAL_II_EXTERNAL_LIBRARIES_RELEASE`
- For external use, used to keep track of external preprocessor definitions, necessary for the compilation of user programs:
  - `DEAL_II_USER_DEFINITIONS`
  - `DEAL_II_USER_DEFINITIONS_DEBUG`
  - `DEAL_II_USER_DEFINITIONS_RELEASE`
- Used to keep track of external include dirs, necessary for the compilation of user programs:
  - `DEAL_II_USER_INCLUDE_DIRS`

## Target definition and installation

### `./include/deal.II/base/config.h.in`

In contrast to autoconf there is no intermediate step any more that automatically generates config.h.in. The setup in this file has to be done by hand. Please note:

- `config.h.in` should only contain a minimum of necessary compile definitions to avoid unnecessary recompilation if configuration changes.
- Definition toggles in `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 two macros:

    #
    # Glob for all header files associated with the object target:
    # As this list is only for cosmetic reasons, so that associated header
    # files show up in IDEs, we don't manage an explicit list (with the
    # trade-off to have to run "make rebuild_cache" when a new header file
    # emerges...)
    #
    FILE(GLOB _header
      ${CMAKE_SOURCE_DIR}/include/deal.II/dofs/*.h
      )

    #
    # A list of source files forming the object target:
    #
    SET(_src
      ...
      dof_tools.cc
      )

    #
    # A list of instantiations that must be expanded:
    #
    SET(_inst
      ...
      dof_tools.inst.in
      )

    #
    # The following macro will set up an obj_dofs.debug and
    # obj_dofs.release target  with appropriate compile flags and
    # definitions for a simultaneous build of debug and release library.
    # Furthermore, the object name will be stored in
    #   ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/deal_ii_objects_(debug/release)
    # so that it is available in global scope.
    #
    # Header files and instatiation files (${_header}, ${_inst}) are added
    # for cosmetic reasons, so that they show up in IDEs.
    #
    DEAL_II_ADD_LIBRARY(obj_dofs OBJECT ${_src} ${_header} ${_inst})

    #
    # This macro will set up an obj_dofs.inst target for expanding all
    # files listed in ${inst_in_files}. Appropriate target dependencies
    # will be added to obj_dofs.debug and obj_dofs.release.
    #
    EXPAND_INSTANTIATIONS(obj_dofs "${inst_in_files}")

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` and the compatibility file `Make.global_options` get expanded. Furthermore, the configuration for the template expansion mechanism resides under `./cmake/config/template_arguments.in`.