BASIS  r3148
ProjectTools.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  ProjectTools.cmake
00003 # @brief Definition of main project tools.
00004 #
00005 # Copyright (c) 2011, 2012, 2013 University of Pennsylvania. All rights reserved.<br />
00006 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00007 #
00008 # Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00009 ##############################################################################
00010 
00011 # ============================================================================
00012 # meta-data
00013 # ============================================================================
00014 
00015 # ----------------------------------------------------------------------------
00016 ## @brief Check meta-data and set defaults.
00017 #
00018 # @sa basis_project()
00019 # @sa basis_slicer_module()
00020 macro (basis_project_check_metadata)
00021   # PROJECT_AUTHOR
00022   if (PROJECT_AUTHORS AND PROJECT_AUTHOR)
00023     message (FATAL_ERROR "Options AUTHOR and AUTHORS are mutually exclusive!")
00024   endif ()
00025   if (PROJECT_AUTHOR)
00026     set (PROJECT_AUTHORS "${PROJECT_AUTHOR}")
00027   endif ()
00028   if (NOT PROJECT_AUTHORS AND PROJECT_IS_MODULE)
00029     set (PROJECT_AUTHORS "${BASIS_PROJECT_AUTHORS}")
00030   endif ()
00031   if (NOT PROJECT_IS_MODULE)
00032     set (BASIS_PROJECT_AUTHORS "${PROJECT_AUTHORS}")
00033   endif ()
00034   # PROJECT_NAME or PROJECT_SUBPROJECT
00035   if (PROJECT_SUBPROJECT AND PROJECT_NAME)
00036     message (FATAL_ERROR "Options SUBPROJECT and NAME are mutually exclusive!")
00037   elseif (PROJECT_SUBPROJECT)
00038     set (PROJECT_NAME "${PROJECT_SUBPROJECT}")
00039     set (PROJECT_IS_SUBPROJECT TRUE)
00040   else ()
00041     set (PROJECT_IS_SUBPROJECT FALSE)
00042   endif ()
00043   unset (PROJECT_SUBPROJECT)
00044   if (NOT PROJECT_NAME)
00045     message (FATAL_ERROR "Project name not specified!")
00046   endif ()
00047   if (NOT PROJECT_NAME MATCHES "^([a-z][a-z0-9]*|[A-Z][a-zA-Z0-9]*)")
00048     message (FATAL_ERROR "Invalid project name: ${PROJECT_NAME}!\n\n"
00049                          "Please choose a project name with either only captial "
00050                          "letters in case of an acronym or a name with mixed case, "
00051                          "but starting with a captial letter.\n\n"
00052                          "Note that numbers are allowed, but not as first character. "
00053                          "Further, do not use characters such as '_' or '-' to "
00054                          "separate parts of the project name. Instead, use the "
00055                          "upper camel case notation "
00056                          "(see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms).")
00057   endif ()
00058   string (TOLOWER "${PROJECT_NAME}" PROJECT_NAME_L)
00059   string (TOUPPER "${PROJECT_NAME}" PROJECT_NAME_U)
00060   if (NOT PROJECT_IS_MODULE)
00061     set (BASIS_PROJECT_NAME   "${PROJECT_NAME}")
00062     set (BASIS_PROJECT_NAME_L "${PROJECT_NAME_L}")
00063     set (BASIS_PROJECT_NAME_U "${PROJECT_NAME_U}")
00064   endif ()
00065   # PROJECT_PACKAGE
00066   if (NOT PROJECT_PACKAGE)
00067     if (PROJECT_IS_MODULE)
00068       set (PROJECT_PACKAGE "${BASIS_PROJECT_PACKAGE}")
00069     else ()
00070       if (PROJECT_IS_SUBPROJECT)
00071         message (FATAL_ERROR "Missing PACKAGE option for SUBPROJECT ${PROJECT_NAME}!"
00072                              " Note that the PACKAGE option is required for subprojects"
00073                              " in order to enable the independent build. It should be"
00074                              " set to the name of the top-level project this subproject"
00075                              " belongs to. Otherwise, the subproject can only be build"
00076                              " as part of the package it belongs to.")
00077       endif ()
00078       set (PROJECT_PACKAGE "${PROJECT_NAME}")
00079     endif ()
00080   endif ()
00081   if (NOT PROJECT_PACKAGE MATCHES "^([a-z][a-z0-9]*|[A-Z][a-zA-Z0-9]*)")
00082     message (FATAL_ERROR "Project ${PROJECT_NAME} declares invalid package name: ${PROJECT_PACKAGE}!\n\n"
00083                          "Please choose a package name with either only captial "
00084                          "letters in case of an acronym or a name with mixed case, "
00085                          "but starting with a captial letter.\n\n"
00086                          "Note that numbers are allowed, but not as first character. "
00087                          "Further, do not use characters such as '_' or '-' to "
00088                          "separate parts of the package name. Instead, use the "
00089                          "upper camel case notation "
00090                          "(see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms).")
00091   endif ()
00092   string (TOLOWER "${PROJECT_PACKAGE}" PROJECT_PACKAGE_L)
00093   string (TOUPPER "${PROJECT_PACKAGE}" PROJECT_PACKAGE_U)
00094   if (NOT PROJECT_IS_MODULE)
00095     set (BASIS_PROJECT_PACKAGE   "${PROJECT_PACKAGE}")
00096     set (BASIS_PROJECT_PACKAGE_L "${PROJECT_PACKAGE_L}")
00097     set (BASIS_PROJECT_PACKAGE_U "${PROJECT_PACKAGE_U}")
00098   endif ()
00099   # PROJECT_PACKAGE_VENDOR
00100   if (PROJECT_PROVIDER AND PROJECT_PACKAGE_VENDOR)
00101     message (FATAL_ERROR "Options PROVIDER and PACKAGE_VENDOR are mutually exclusive!")
00102   endif ()
00103   if (PROJECT_PROVIDER)
00104     set (PROJECT_PACKAGE_VENDOR "${PROJECT_PROVIDER}")
00105   endif ()
00106   if (NOT PROJECT_PACKAGE_VENDOR)
00107     if (PROJECT_IS_MODULE)
00108       set (PROJECT_PACKAGE_VENDOR "${BASIS_PROJECT_PACKAGE_VENDOR}")
00109     else ()
00110       set (PROJECT_PACKAGE_VENDOR "${BASIS_PACKAGE_VENDOR}")
00111     endif ()
00112   endif ()
00113   string (TOLOWER "${PROJECT_PACKAGE_VENDOR}" PROJECT_PACKAGE_VENDOR_L)
00114   string (TOUPPER "${PROJECT_PACKAGE_VENDOR}" PROJECT_PACKAGE_VENDOR_U)
00115   if (NOT PROJECT_IS_MODULE)
00116     set (BASIS_PROJECT_PACKAGE_VENDOR   "${PROJECT_PACKAGE_VENDOR}")
00117     set (BASIS_PROJECT_PACKAGE_VENDOR_L "${PROJECT_PACKAGE_VENDOR_L}")
00118     set (BASIS_PROJECT_PACKAGE_VENDOR_U "${PROJECT_PACKAGE_VENDOR_U}")
00119   endif ()
00120   # PROJECT_VERSION
00121   if (PROJECT_VERSION)
00122     if (NOT PROJECT_VERSION MATCHES "^[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(rc[0-9]+|[a-z])?$")
00123       message (FATAL_ERROR "Project ${PROJECT_NAME} has invalid version: ${PROJECT_VERSION}!")
00124     endif ()
00125     if (PROJECT_IS_MODULE)
00126       if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?$")
00127         set (PROJECT_VERSION "${BASIS_PROJECT_VERSION}")
00128       endif ()
00129     else ()
00130       set (BASIS_PROJECT_VERSION "${PROJECT_VERSION}")
00131     endif ()
00132   else ()
00133     if (PROJECT_IS_MODULE)
00134       set (PROJECT_VERSION "${BASIS_PROJECT_VERSION}")
00135     else ()
00136       message (FATAL_ERROR "Project version not specified!")
00137     endif ()
00138   endif ()
00139   # PROJECT_DESCRIPTION
00140   if (PROJECT_DESCRIPTION)
00141     basis_list_to_string (PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
00142   else ()
00143     set (PROJECT_DESCRIPTION "")
00144   endif ()
00145   # PROJECT_COPYRIGHT
00146   if (NOT PROJECT_COPYRIGHT)
00147     if (PROJECT_IS_MODULE)
00148       set (PROJECT_COPYRIGHT "${BASIS_PROJECT_COPYRIGHT}")
00149     else ()
00150       set (PROJECT_COPYRIGHT "${BASIS_COPYRIGHT}")
00151     endif ()
00152   endif ()
00153   if (NOT PROJECT_IS_MODULE)
00154     set (BASIS_PROJECT_COPYRIGHT "${PROJECT_COPYRIGHT}")
00155   endif ()
00156   # PROJECT_LICENSE
00157   if (NOT PROJECT_LICENSE)
00158     if (PROJECT_IS_MODULE)
00159       set (PROJECT_LICENSE "${BASIS_PROJECT_LICENSE}")
00160     else ()
00161       set (PROJECT_LICENSE "${BASIS_LICENSE}")
00162     endif ()
00163   endif ()
00164   if (NOT PROJECT_IS_MODULE)
00165     set (BASIS_PROJECT_LICENSE "${PROJECT_LICENSE}")
00166   endif ()
00167   # PROJECT_CONTACT
00168   if (NOT PROJECT_CONTACT)
00169     if (PROJECT_IS_MODULE)
00170       set (PROJECT_CONTACT "${BASIS_PROJECT_CONTACT}")
00171     else ()
00172       set (PROJECT_CONTACT "${BASIS_CONTACT}")
00173     endif ()
00174   endif ()
00175   if (NOT PROJECT_IS_MODULE)
00176     set (BASIS_PROJECT_CONTACT "${PROJECT_CONTACT}")
00177   endif ()
00178   # let basis_project_impl() know that basis_project() was called
00179   set (BASIS_basis_project_CALLED TRUE)
00180 endmacro ()
00181 
00182 # ----------------------------------------------------------------------------
00183 ## @brief Define project meta-data, i.e., attributes.
00184 #
00185 # Any BASIS project has to call this macro in the file BasisProject.cmake
00186 # located in the top level directory of the source tree in order to define
00187 # the project attributes required by BASIS to setup the build system.
00188 # Moreover, if the BASIS project is a module of another BASIS project, this
00189 # file and the variables set by this macro are used by the top-level project to
00190 # identify its modules and the dependencies among them.
00191 #
00192 # @par Project version:
00193 # The version number consists of three components: the major version number,
00194 # the minor version number, and the patch number. The format of the version
00195 # string is "<major>.<minor>.<patch>", where the minor version number and patch
00196 # number default to "0" if not given. Only digits are allowed except of the two
00197 # separating dots.
00198 # @n
00199 # - A change of the major version number indicates changes of the softwares
00200 #   @api (and @abi) and/or its behavior and/or the change or addition of major
00201 #   features.
00202 # - A change of the minor version number indicates changes that are not only
00203 #   bug fixes and no major changes. Hence, changes of the @api but not the @abi.
00204 # - A change of the patch number indicates changes only related to bug fixes
00205 #   which did not change the softwares @api. It is the least important component
00206 #   of the version number.
00207 #
00208 # @par Dependencies:
00209 # Dependencies on other BASIS projects, which can be subprojects of the same
00210 # BASIS top-level project, as well as dependencies on external packages such as ITK
00211 # have to be defined here using the @p DEPENDS argument option. This will be used
00212 # by a top-level project to ensure that the dependencies among its subprojects are
00213 # resolved properly. For each external dependency, the BASIS functions
00214 # basis_find_package() and basis_use_package() are invoked by
00215 # basis_project_initialize(). If an external package is not CMake aware and
00216 # additional CMake code shall be executed to include the settings of the external
00217 # package (which is usually done in a so-called <tt>Use&lt;Pkg&gt;.cmake</tt> file
00218 # if the package would be CMake aware), such code should be added to the
00219 # <tt>Settings.cmake</tt> file of the project.
00220 #
00221 # @param [in] ARGN This list is parsed for the following arguments:
00222 # @par
00223 # <table border="0">
00224 #   <tr>
00225 #     @tp @b NAME name @endtp
00226 #     <td>The name of the project.</td>
00227 #   </tr>
00228 #   <tr>
00229 #     @tp @b SUBPROJECT name @endtp
00230 #     <td>Use this option instead of @c NAME to indicate that this project is a
00231 #         subproject of the package @c PACKAGE. This results, for example, in target
00232 #         UIDs such as "<package>.<name>.<target>" instead of "<package>.<target>".
00233 #         Moreover, the libraries and shared files of a subproject are installed
00234 #         in subdirectores whose name equals the name of the subproject. This option
00235 #         should only be used for projects which are modules of another BASIS project,
00236 #         where these modules should reside in their own sub-namespace rather than
00237 #         on the same level as the top-level project.</td>
00238 #   </tr>
00239 #   <tr>
00240 #     @tp @b PACKAGE pkg @endtp
00241 #     <td>Name of the package this project (module) belongs to. Defaults to the
00242 #         name of the (top-level) project. This option can further be used in case
00243 #         of a top-level project to specify a different package name for the installation.
00244 #         In case of a subproject which is a module of another BASIS project, setting
00245 #         the package name explicitly using this option enables the build of the
00246 #         subproject as separate project while preserving the directory structure
00247 #         and other namespace settings. Therefore, this option is required if the
00248 #         @c SUBPROJECT option is given and the project shall be build independently
00249 #         as stand-alone package. (default: name of top-level package)</td>
00250 #   </tr>
00251 #   <tr>
00252 #     @tp @b PACKAGE_VENDOR vendor @endtp
00253 #     <td>The vendor of this package, used for packaging and installation.
00254 #         (default: vendor of top-level project or empty string)</td>
00255 #   </tr>
00256 #   <tr>
00257 #     @tp @b PROVIDER vendor @endtp
00258 #     <td>This option can be used as an alternative to @c PACKAGE_VENDOR.</td>
00259 #   </tr>
00260 #   <tr>
00261 #     @tp @b VERSION major[.minor[.patch]] @endtp
00262 #     <td>Project version string. (default: 1.0.0)</td>
00263 #   </tr>
00264 #   <tr>
00265 #     @tp @b DESCRIPTION description @endtp
00266 #     <td>Package description, used for packing. If multiple arguments are given,
00267 #         they are concatenated using one space character as delimiter.</td>
00268 #   </tr>
00269 #   <tr>
00270 #     @tp @b DEPENDS name[, name] @endtp
00271 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00272 #         or names of external packages.</td>
00273 #   </tr>
00274 #   <tr>
00275 #     @tp @b OPTIONAL_DEPENDS name[, name] @endtp
00276 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00277 #         or names of external packages which are used only if available.</td>
00278 #   </tr>
00279 #   <tr>
00280 #     @tp @b TEST_DEPENDS name[, name] @endtp
00281 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00282 #         or names of external packages which are only required by the tests.</td>
00283 #   </tr>
00284 #   <tr>
00285 #     @tp @b OPTIONAL_TEST_DEPENDS name[, name] @endtp
00286 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00287 #         or names of external packages which are used only by the tests if available.</td>
00288 #   </tr>
00289 # </table>
00290 #
00291 # @returns Sets the following non-cached CMake variables:
00292 # @retval PROJECT_NAME                    @c NAME argument.
00293 # @retval PROJECT_PACKAGE                 @c PACKAGE argument.
00294 # @retval PROJECT_PACKAGE_VENDOR          @c PACKAGE_VENDOR argument.
00295 # @retval PROJECT_VERSION                 @c VERSION argument.
00296 # @retval PROJECT_DESCRIPTION             @c DESCRIPTION argument.
00297 # @retval PROJECT_DEPENDS                 @c DEPENDS arguments.
00298 # @retval PROJECT_OPTIONAL_DEPENDS        @c OPTIONAL_DEPENDS arguments.
00299 # @retval PROJECT_TEST_DEPENDS            @c TEST_DEPENDS arguments.
00300 # @retval PROJECT_OPTIONAL_TEST_DEPENDS   @c OPTIONAL_TEST_DEPENDS arguments.
00301 # @retval PROJECT_IS_SUBPROJECT           @c TRUE if @c IS_SUBPROJECT option given or @c FALSE otherwise.
00302 #
00303 # @ingroup CMakeAPI
00304 macro (basis_project)
00305   CMAKE_PARSE_ARGUMENTS (
00306     PROJECT
00307       "${BASIS_METADATA_LIST_SWITCH}"
00308       "${BASIS_METADATA_LIST_SINGLE}"
00309       "${BASIS_METADATA_LIST_MULTI}"
00310     ${ARGN}
00311   )
00312   basis_project_check_metadata ()
00313 endmacro ()
00314 
00315 
00316 ## @addtogroup CMakeUtilities
00317 # @{
00318 
00319 
00320 # ============================================================================
00321 # initialization
00322 # ============================================================================
00323 
00324 # ----------------------------------------------------------------------------
00325 ## @brief Ensure certain requirements on build tree.
00326 #
00327 # Requirements:
00328 # - Root of build tree must not be root of source tree.
00329 #
00330 # @param [in] ARGN Not used.
00331 #
00332 # @returns Nothing.
00333 function (basis_buildtree_asserts)
00334   string (TOLOWER "${CMAKE_SOURCE_DIR}" SOURCE_ROOT)
00335   string (TOLOWER "${CMAKE_BINARY_DIR}" BUILD_ROOT)
00336   basis_sanitize_for_regex (SOURCE_ROOT_RE "${SOURCE_ROOT}")
00337   if (BUILD_ROOT MATCHES "^${SOURCE_ROOT_RE}$")
00338     message(FATAL_ERROR "This project should not be configured & build in the "
00339                         "source directory:\n"
00340                         "  ${CMAKE_SOURCE_DIR}\n"
00341                         "You must run CMake in a separate build directory.")
00342   endif()
00343 endfunction ()
00344 
00345 # ----------------------------------------------------------------------------
00346 ## @brief Ensure certain requirements on install tree.
00347 #
00348 # Requirements:
00349 # - Prefix must be an absolute path.
00350 # - Install tree must be different from source and build tree.
00351 #
00352 # @param [in] ARGN Not used.
00353 #
00354 # @returns Nothing.
00355 function (basis_installtree_asserts)
00356   if (NOT IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}")
00357     message (FATAL_ERROR "CMAKE_INSTALL_PREFIX must be an absolute path!")
00358   endif ()
00359   string (TOLOWER "${CMAKE_SOURCE_DIR}"     SOURCE_ROOT)
00360   string (TOLOWER "${CMAKE_BINARY_DIR}"     BUILD_ROOT)
00361   string (TOLOWER "${CMAKE_INSTALL_PREFIX}" INSTALL_ROOT)
00362   basis_sanitize_for_regex (INSTALL_ROOT_RE "${INSTALL_ROOT}")
00363   if (BUILD_ROOT MATCHES "^${INSTALL_ROOT_RE}$" OR SOURCE_ROOT MATCHES "^${INSTALL_ROOT_RE}$")
00364     message (FATAL_ERROR "The current CMAKE_INSTALL_PREFIX points at the source or build tree:\n"
00365                          "  ${CMAKE_INSTALL_PREFIX}\n"
00366                          "This is not permitted by this project. "
00367                          "Please choose another installation prefix."
00368     )
00369   endif()
00370 endfunction ()
00371 
00372 # ----------------------------------------------------------------------------
00373 ## @brief Initialize project modules.
00374 #
00375 # Most parts of this macro were copied from the ITK4 project
00376 # (http://www.vtk.org/Wiki/ITK_Release_4), in particular, the top-level
00377 # CMakeLists.txt file. This file does not state any specific license, but
00378 # the ITK package itself is released under the Apache License Version 2.0,
00379 # January 2004 (http://www.apache.org/licenses/).
00380 #
00381 # @attention At this point, the project-specific variables have not been
00382 #            set yet. For example, use @c CMAKE_CURRENT_SOURCE_DIR instead of
00383 #            @c PROJECT_SOURCE_DIR.
00384 macro (basis_project_modules)
00385   # --------------------------------------------------------------------------
00386   # reset variables
00387   set (PROJECT_MODULES)
00388   set (PROJECT_MODULES_ENABLED)
00389   set (PROJECT_MODULES_DISABLED)
00390 
00391   # --------------------------------------------------------------------------
00392   # load module DAG
00393 
00394   # glob BasisProject.cmake files in modules subdirectory
00395   file (
00396     GLOB
00397       MODULE_INFO_FILES
00398     RELATIVE
00399       "${CMAKE_CURRENT_SOURCE_DIR}"
00400     "${CMAKE_CURRENT_SOURCE_DIR}/modules/*/BasisProject.cmake"
00401   )
00402 
00403   # use function scope to avoid overwriting of this project's variables
00404   function (basis_module_info F)
00405     set (PROJECT_IS_MODULE TRUE)
00406     set (BASIS_basis_project_CALLED FALSE)
00407     include ("${CMAKE_CURRENT_SOURCE_DIR}/${F}")
00408     # make sure that basis_project() was called
00409     if (NOT BASIS_basis_project_CALLED)
00410       message (FATAL_ERROR "basis_module_info(): Missing basis_project() command in ${F}!")
00411     endif ()
00412     # remember dependencies
00413     foreach (V IN ITEMS DEPENDS OPTIONAL_DEPENDS TEST_DEPENDS OPTIONAL_TEST_DEPENDS)
00414       set (${V})
00415       foreach (D ${PROJECT_${V}})
00416         basis_tokenize_dependency ("${D}" PKG VER CMP)
00417         list (APPEND ${V} "${PKG}")
00418       endforeach ()
00419     endforeach ()
00420     set (${PROJECT_NAME}_DEPENDS               "${DEPENDS}"               PARENT_SCOPE)
00421     set (${PROJECT_NAME}_OPTIONAL_DEPENDS      "${OPTIONAL_DEPENDS}"      PARENT_SCOPE)
00422     set (${PROJECT_NAME}_TEST_DEPENDS          "${TEST_DEPENDS}"          PARENT_SCOPE)
00423     set (${PROJECT_NAME}_OPTIONAL_TEST_DEPENDS "${OPTIONAL_TEST_DEPENDS}" PARENT_SCOPE)
00424     set (${PROJECT_NAME}_DECLARED              TRUE                       PARENT_SCOPE)
00425     # remember if module depends on Slicer - used by basis_find_packages()
00426     if (PROJECT_IS_SLICER_MODULE)
00427       foreach (_D IN LISTS BASIS_SLICER_METADATA_LIST)
00428           if (DEFINED PROJECT_${_D})
00429             set (${PROJECT_NAME}_${_D} "${PROJECT_${_D}}" PARENT_SCOPE)
00430           endif ()
00431       endforeach ()
00432       set (${PROJECT_NAME}_IS_SLICER_MODULE TRUE PARENT_SCOPE)
00433     else ()
00434       set (${PROJECT_NAME}_IS_SLICER_MODULE FALSE PARENT_SCOPE)
00435     endif ()
00436     # do not use MODULE instead of PROJECT_NAME in this function as it is not
00437     # set in the scope of this function but its parent scope only
00438     set (MODULE "${PROJECT_NAME}" PARENT_SCOPE)
00439   endfunction ()
00440 
00441   set (PROJECT_MODULES)
00442   foreach (F IN LISTS MODULE_INFO_FILES)
00443     basis_module_info (${F})
00444     list (APPEND PROJECT_MODULES ${MODULE})
00445     get_filename_component (${MODULE}_BASE ${F} PATH)
00446     set (MODULE_${MODULE}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${${MODULE}_BASE}")
00447     # use module name as subdirectory name such that the default package
00448     # configuration file knows where to find the module configurations
00449     set (MODULE_${MODULE}_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/modules/${MODULE}")
00450     # help modules to find each other using basis_find_package()
00451     set (${MODULE}_DIR "${MODULE_${MODULE}_BINARY_DIR}")
00452   endforeach()
00453   unset (MODULE)
00454 
00455   # validate the module DAG to identify cyclic dependencies
00456   macro (basis_module_check MODULE NEEDED_BY STACK)
00457     if (${MODULE}_DECLARED)
00458       if (${MODULE}_CHECK_STARTED AND NOT ${MODULE}_CHECK_FINISHED)
00459         # we reached a module while traversing its own dependencies recursively
00460         set (MSG "")
00461         foreach (M ${STACK})
00462           set (MSG " ${M} =>${MSG}")
00463           if ("${M}" STREQUAL "${MODULE}")
00464             break ()
00465           endif ()
00466         endforeach ()
00467         message (FATAL_ERROR "Module dependency cycle detected:\n ${MSG} ${MODULE}")
00468       elseif (NOT ${MODULE}_CHECK_STARTED)
00469         # traverse dependencies of this module
00470         set (${MODULE}_CHECK_STARTED TRUE)
00471         foreach (D IN LISTS ${MODULE}_DEPENDS)
00472           basis_module_check (${D} ${MODULE} "${MODULE};${STACK}")
00473         endforeach ()
00474         set (${MODULE}_CHECK_FINISHED TRUE)
00475       endif ()
00476     endif ()
00477   endmacro ()
00478 
00479   foreach (MODULE ${PROJECT_MODULES})
00480     basis_module_check ("${MODULE}" "" "")
00481   endforeach ()
00482 
00483   # --------------------------------------------------------------------------
00484   # determine list of enabled modules
00485 
00486   # provide an option for all modules
00487   if (PROJECT_MODULES)
00488     option (BUILD_ALL_MODULES "Request to build all modules." OFF)
00489   endif ()
00490 
00491   # provide an option for each module
00492   foreach (MODULE ${PROJECT_MODULES})
00493     option (MODULE_${MODULE} "Request building module ${MODULE}." OFF)
00494     if (${MODULE}_EXCLUDE_FROM_ALL)
00495       set (${MODULE}_IN_ALL FALSE)
00496     else ()
00497       set (${MODULE}_IN_ALL ${BUILD_ALL_MODULES})
00498     endif ()
00499   endforeach ()
00500 
00501   # follow dependencies
00502   macro (basis_module_enable MODULE NEEDED_BY)
00503     if (${MODULE}_DECLARED)
00504       if (NOT "${NEEDED_BY}" STREQUAL "")
00505         list (APPEND ${MODULE}_NEEDED_BY "${NEEDED_BY}")
00506       endif ()
00507       if (NOT ${MODULE}_ENABLED)
00508         if ("${NEEDED_BY}" STREQUAL "")
00509           set (${MODULE}_NEEDED_BY)
00510         endif ()
00511         set (${MODULE}_ENABLED TRUE)
00512         foreach (D IN LISTS ${MODULE}_DEPENDS)
00513           basis_module_enable (${D} ${MODULE})
00514         endforeach ()
00515       endif ()
00516     endif ()
00517   endmacro ()
00518 
00519   foreach (MODULE ${PROJECT_MODULES})
00520     if (MODULE_${MODULE} OR ${MODULE}_IN_ALL)
00521       basis_module_enable ("${MODULE}" "")
00522     endif ()
00523   endforeach ()
00524 
00525   # build final list of enabled modules
00526   set (PROJECT_MODULES_ENABLED "")
00527   set (PROJECT_MODULES_DISABLED "")
00528   foreach (MODULE ${PROJECT_MODULES})
00529     if (${MODULE}_DECLARED)
00530       if (${MODULE}_ENABLED)
00531         list (APPEND PROJECT_MODULES_ENABLED ${MODULE})
00532       else ()
00533         list (APPEND PROJECT_MODULES_DISABLED ${MODULE})
00534       endif ()
00535     endif ()
00536   endforeach ()
00537   list (SORT PROJECT_MODULES_ENABLED) # Deterministic order.
00538   list (SORT PROJECT_MODULES_DISABLED) # Deterministic order.
00539 
00540   # order list to satisfy dependencies
00541   include (${BASIS_MODULE_PATH}/TopologicalSort.cmake)
00542   topological_sort (PROJECT_MODULES_ENABLED "" "_DEPENDS")
00543 
00544   # remove external dependencies
00545   set (L)
00546   foreach (MODULE ${PROJECT_MODULES_ENABLED})
00547     if (${MODULE}_DECLARED)
00548       list (APPEND L "${MODULE}")
00549     endif ()
00550   endforeach ()
00551   set (PROJECT_MODULES_ENABLED "${L}")
00552   unset (L)
00553 
00554   # report what will be built
00555   if (PROJECT_MODULES_ENABLED)
00556     message (STATUS "Enabled modules [${PROJECT_MODULES_ENABLED}].")
00557   endif ()
00558 
00559   # turn options ON for modules that are required by other modules
00560   foreach (MODULE ${PROJECT_MODULES})
00561     if (DEFINED MODULE_${MODULE} # there was an option for the user
00562         AND NOT MODULE_${MODULE} # user did not set it to ON themself
00563         AND NOT ${MODULE}_IN_ALL # BUILD_ALL_MODULES was not set ON
00564         AND ${MODULE}_NEEDED_BY) # module is needed by other module(s)
00565       set (MODULE_${MODULE} ON CACHE BOOL "Request building module ${MODULE}." FORCE)
00566       message ("Enabled module ${MODULE}, needed by [${${MODULE}_NEEDED_BY}].")
00567     endif ()
00568   endforeach ()
00569 endmacro ()
00570 
00571 # ----------------------------------------------------------------------------
00572 ## @brief Configure public header files.
00573 function (basis_configure_public_headers)
00574   # --------------------------------------------------------------------------
00575   # settings
00576 
00577   # log file which lists the configured header files
00578   set (CMAKE_FILE "${BINARY_INCLUDE_DIR}/${PROJECT_NAME}PublicHeaders.cmake")
00579   # considered extensions (excl. .in suffix)
00580   set (
00581     EXTENSIONS
00582       ".h"
00583       ".hh"
00584       ".hpp"
00585       ".hxx"
00586       ".inl"
00587       ".txx"
00588       ".inc"
00589   )
00590   # considered include directories
00591   basis_get_relative_path (INCLUDE_DIR "${PROJECT_SOURCE_DIR}" "${PROJECT_INCLUDE_DIR}")
00592   set (INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/${INCLUDE_DIR}")
00593 
00594   # --------------------------------------------------------------------------
00595   # clean up last run before the error because a file was added/removed
00596   file (REMOVE "${CMAKE_FILE}.tmp")
00597   file (REMOVE "${CMAKE_FILE}.updated")
00598   if (EXISTS "${CMAKE_FILE}")
00599     # required to be able to remove now obsolete files from the build tree
00600     file (RENAME "${CMAKE_FILE}" "${CMAKE_FILE}.tmp")
00601   endif ()
00602 
00603   # --------------------------------------------------------------------------
00604   # configure public header files
00605   message (STATUS "Configuring public header files...")
00606 
00607   execute_process (
00608     COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00609             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00610             -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00611             -D "EXTENSIONS=${EXTENSIONS}"
00612             -D "CACHE_FILE=${PROJECT_BINARY_DIR}/BasisCache.txt"
00613             -D "CMAKE_FILE=${CMAKE_FILE}"
00614             -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00615     RESULT_VARIABLE RT
00616   )
00617 
00618   if (RT EQUAL 0)
00619     execute_process (
00620       COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
00621     )
00622   else ()
00623     message (FATAL_ERROR "Failed to configure public header files!")
00624   endif ()
00625 
00626   if (NOT EXISTS "${CMAKE_FILE}")
00627     message (FATAL_ERROR "File ${CMAKE_FILE} not generated as it should have been!")
00628   endif ()
00629 
00630   # remove header files from build tree which were copied there before but
00631   # are part of a now disabled module or were simply removed from the source tree
00632   if (EXISTS "${CMAKE_FILE}.tmp")
00633     execute_process (
00634       # Compare current list of headers to list of previously configured files.
00635       # If the lists differ, this command removes files which have been removed
00636       # from the directory tree with root PROJECT_INCLUDE_DIR also from the
00637       # tree with root directory BINARY_INCLUDE_DIR.
00638       COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00639               -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00640               -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00641               -D "CMAKE_FILE=${CMAKE_FILE}.tmp"
00642               -D "REFERENCE_FILE=${CMAKE_FILE}"
00643               -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
00644       VERBATIM
00645     )
00646     file (REMOVE "${CMAKE_FILE}.tmp")
00647     if (NOT RT EQUAL 0)
00648       message (FATAL_ERROR "Failed to remove obsolete header files from build tree."
00649                            " Remove the ${BINARY_INCLUDE_DIR} directory and re-run CMake.")
00650     endif ()
00651   endif ()
00652 
00653   message (STATUS "Configuring public header files... - done")
00654 
00655   # We need a list of the configured files to add them as dependency of the
00656   # custom build targets such that these get re-build whenever a file changed.
00657   # Additionally, including this file here which is modified whenever a
00658   # header file is added or removed triggeres a re-configuration of the
00659   # build system which is required to re-execute this function and adjust
00660   # these custom build targets.
00661 
00662   include ("${CMAKE_FILE}")
00663 
00664   # --------------------------------------------------------------------------
00665   # check if any header was added or removed (always out-of-date)
00666 
00667   # error message displayed when a file was added or removed which requires
00668   # a reconfiguration of the build system
00669   set (ERRORMSG "You have either added, removed, or renamed a public header file"
00670                 " with a .in suffix in the file name. Therefore, the build system"
00671                 " needs to be re-configured. Either try to build again which will"
00672                 " trigger CMake and re-configure the build system or run CMake manually.")
00673   basis_list_to_string (ERRORMSG ${ERRORMSG})
00674 
00675   # custom command which globs the files in the project's include directory
00676   set (COMMENT "Checking if public header files were added or removed")
00677   if (PROJECT_IS_MODULE)
00678     set (COMMENT "${COMMENT} to ${PROJECT_NAME} module")
00679   endif ()
00680   add_custom_command (
00681     OUTPUT  "${CMAKE_FILE}.tmp"
00682     COMMAND "${CMAKE_COMMAND}"
00683             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00684             -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00685             -D "EXTENSIONS=${EXTENSIONS}"
00686             -D "CMAKE_FILE=${CMAKE_FILE}.tmp"
00687             -D "PREVIEW=TRUE" # do not actually configure the files
00688             -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00689     COMMENT "${COMMENT}"
00690     VERBATIM
00691   )
00692 
00693   # custom target to detect whether a file was added or removed
00694   basis_make_target_uid (CHECK_HEADERS_TARGET headers_check)
00695   add_custom_target (
00696     ${CHECK_HEADERS_TARGET} ALL
00697     # trigger execution of custom command that generates the list
00698     # of current files in the project's include directory
00699     DEPENDS "${CMAKE_FILE}.tmp"
00700     # Compare current list of headers to list of previously configured files.
00701     # If the lists differ, the build of this target fails with the given error message.
00702     COMMAND "${CMAKE_COMMAND}"
00703             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00704             -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00705             -D "CMAKE_FILE=${CMAKE_FILE}"
00706             -D "REFERENCE_FILE=${CMAKE_FILE}.tmp"
00707             -D "ERRORMSG=${ERRORMSG}"
00708             -D "REMOVE_FILES_IF_DIFFERENT=TRUE" # triggers reconfigure on next build
00709             -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
00710     # remove temporary file again to force its regeneration
00711     COMMAND "${CMAKE_COMMAND}" -E remove "${CMAKE_FILE}.tmp"
00712     VERBATIM
00713   )
00714   if (PROJECT_IS_MODULE)
00715     if (NOT TARGET headers_check)
00716       add_custom_target (headers_check ALL)
00717     endif ()
00718     add_dependencies (headers_check ${CHECK_HEADERS_TARGET})
00719   endif ()
00720 
00721   # --------------------------------------------------------------------------
00722   # add build command to re-configure public header files
00723   if (PUBLIC_HEADERS)
00724     set (COMMENT "Configuring public header files")
00725     if (PROJECT_IS_MODULE)
00726       set (COMMENT "${COMMENT} of ${PROJECT_NAME} module")
00727     endif ()
00728     add_custom_command (
00729       OUTPUT  "${CMAKE_FILE}.updated" # do not use same file as included
00730                                       # before otherwise CMake will re-configure
00731                                       # the build system next time
00732       COMMAND "${CMAKE_COMMAND}"
00733               -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00734               -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00735               -D "EXTENSIONS=${EXTENSIONS}"
00736               -D "CACHE_FILE=${PROJECT_BINARY_DIR}/BasisCache.txt"
00737               -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00738       COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
00739       DEPENDS ${PUBLIC_HEADERS}
00740       COMMENT "${COMMENT}"
00741       VERBATIM
00742     )
00743     basis_make_target_uid (CONFIGURE_HEADERS_TARGET headers)
00744     add_custom_target (
00745       ${CONFIGURE_HEADERS_TARGET} ALL
00746       DEPENDS ${CHECK_HEADERS_TARGET} "${CMAKE_FILE}.updated"
00747       SOURCES ${PUBLIC_HEADERS}
00748     )
00749     if (PROJECT_IS_MODULE)
00750       if (NOT TARGET headers)
00751         add_custom_target (headers ALL)
00752       endif ()
00753       add_dependencies (headers ${CONFIGURE_HEADERS_TARGET})
00754     endif ()
00755   endif ()
00756 endfunction ()
00757 
00758 # ----------------------------------------------------------------------------
00759 ## @brief Add library targets for the public modules in @c PROJECT_LIBRARY_DIR.
00760 #
00761 # This function configures ("builds") the library modules in the
00762 # @c PROJECT_LIBRARY_DIR that are written in a scripting language such as
00763 # Python or Perl. The names of the added library targets can be modified using
00764 # the <tt>&lt;LANG&gt;_LIBRARY_TARGET</tt> variables, which are set to their
00765 # default values in the @c BasisSettings.cmake file.
00766 function (basis_configure_script_libraries)
00767   if (NOT IS_DIRECTORY "${PROJECT_LIBRARY_DIR}")
00768     return ()
00769   endif ()
00770   # Python
00771   if (PythonInterp_FOUND)
00772     set (PYTHON_EXT .py .py.in)
00773     set (PYTHON_LIB_DIRS)
00774     if (PYTHON_VERSION_MAJOR)
00775       list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/python${PYTHON_VERSION_MAJOR}")
00776     endif ()
00777     list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/python")
00778     list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
00779   else ()
00780     set (PYTHON_LIB_DIRS)
00781   endif ()
00782   # Jython
00783   if (JythonInterp_FOUND)
00784     set (JYTHON_EXT .py .py.in)
00785     set (JYTHON_LIB_DIRS)
00786     if (JYTHON_VERSION_MAJOR)
00787       list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/jython${JYTHON_VERSION_MAJOR}")
00788     endif ()
00789     list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/jython")
00790     list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
00791   else ()
00792     set (JYTHON_LIB_DIRS)
00793   endif ()
00794   # Perl
00795   if (Perl_FOUND)
00796     set (PERL_EXT .pm .pm.in)
00797     set (PERL_LIB_DIRS)
00798     if (PERL_VERSION_MAJOR)
00799       list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}/perl${PERL_VERSION_MAJOR}")
00800     endif ()
00801     list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}/perl")
00802     list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
00803   else ()
00804     set (PERL_LIB_DIRS)
00805   endif ()
00806   # MATLAB
00807   if (MATLAB_FOUND)
00808     set (MATLAB_EXT .m .m.in)
00809     set (MATLAB_LIB_DIRS)
00810     if (MATLAB_RELEASE)
00811       list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab/${MATLAB_RELEASE}")
00812     endif ()
00813     if (MATLAB_VERSION_MAJOR)
00814       list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab${MATLAB_VERSION_MAJOR}")
00815     endif ()
00816     list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab")
00817     list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
00818   else ()
00819     set (MATLAB_LIB_DIRS)
00820   endif ()
00821   # Bash
00822   if (BASH_FOUND)
00823     set (BASH_EXT .sh .sh.in)
00824     set (BASH_LIB_DIRS)
00825     if (BASH_VERSION_MAJOR)
00826       list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}/bash${BASH_VERSION_MAJOR}")
00827     endif ()
00828     list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}/bash")
00829     list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
00830   else ()
00831     set (BASH_LIB_DIRS)
00832   endif ()
00833   # add library targets
00834   set (TARGETS)
00835   foreach (LANGUAGE IN ITEMS PYTHON JYTHON PERL MATLAB BASH)
00836     foreach (LIB_DIR IN LISTS ${LANGUAGE}_LIB_DIRS)
00837       set (EXPRESSIONS)
00838       foreach (MODULE_EXT IN LISTS ${LANGUAGE}_EXT)
00839         list (APPEND EXPRESSIONS "${LIB_DIR}/**${MODULE_EXT}")
00840       endforeach ()
00841       file (GLOB_RECURSE SOURCES ${EXPRESSIONS})
00842       basis_get_source_language (SOURCE_LANGUAGE ${SOURCES}) # in particular required to
00843                                                              # not falsely build Jython modules
00844                                                              # as Python library
00845       if (SOURCE_LANGUAGE MATCHES "UNKNOWN|AMBIGUOUS")
00846         message (WARNING "Failed to auto-detect scripting language of modules in ${LIB_DIR}!"
00847                          " Skipping source files matching one of the extensions [${${LANGUAGE}_EXT}].")
00848       elseif (SOURCE_LANGUAGE MATCHES "${LANGUAGE}")
00849         set (TARGET_NAME "${${LANGUAGE}_LIBRARY_TARGET}")
00850         basis_add_library (${TARGET_NAME} ${EXPRESSIONS} LANGUAGE ${LANGUAGE})
00851         basis_set_target_properties (
00852           ${TARGET_NAME}
00853           PROPERTIES
00854             SOURCE_DIRECTORY          "${LIB_DIR}"
00855             LIBRARY_OUTPUT_DIRECTORY  "${BINARY_${LANGUAGE}_LIBRARY_DIR}"
00856             LIBRARY_INSTALL_DIRECTORY "${INSTALL_${LANGUAGE}_SITE_DIR}"
00857             PREFIX                    ""
00858         )
00859         list (APPEND TARGETS ${TARGET_NAME})
00860         break ()
00861       endif ()
00862     endforeach ()
00863   endforeach ()
00864   if (TARGETS)
00865     basis_make_target_uid (LIBRARY_TARGET lib)
00866     add_custom_target (${LIBRARY_TARGET} ALL)
00867     basis_add_dependencies (${LIBRARY_TARGET} ${TARGETS})
00868   endif ()
00869 endfunction ()
00870 
00871 # ----------------------------------------------------------------------------
00872 ## @brief Configure root documentation files.
00873 #
00874 # The root documentation files are located in the top-level directory of the
00875 # project's source tree. These are, in particular, the
00876 # * @c AUTHORS.txt file with information on the authors of the software,
00877 # * @c COPYING.txt file with copyright and licensing information,
00878 # * @c README.txt file,
00879 # * @c INSTALL.txt file with build and installation instructions,
00880 # * @c WELCOME.txt file with text used as welcome text of the installer.
00881 # where the top-level project requires all of these files except of the
00882 # @c WELCOME.txt file which defaults to the readme file. Modules of a project
00883 # usually do not include any of these files. Otherwise, the content of the
00884 # module's documentation file is appended to the corresponding file of the
00885 # top-level project.
00886 macro (basis_configure_root_documentation_files)
00887   foreach (F AUTHORS COPYING README INSTALL WELCOME)
00888     if (EXISTS "${PROJECT_SOURCE_DIR}/${F}.txt")
00889       set (PROJECT_${F}_FILE "${PROJECT_SOURCE_DIR}/${F}.txt")
00890       if (PROJECT_IS_MODULE)
00891         file (READ "${PROJECT_${F}_FILE}" T)
00892         file (
00893           APPEND "${BASIS_PROJECT_${F}_FILE}"
00894           "\n\n\n"
00895           "------------------------------------------------------------------------------\n"
00896           "${PROJECT_NAME} Module\n"
00897           "------------------------------------------------------------------------------\n"
00898           "${T}"
00899         )
00900       else ()
00901         set (BASIS_PROJECT_${F}_FILE "${PROJECT_BINARY_DIR}/${F}.txt")
00902         # do not use configure_file() to copy the file, otherwise CMake will
00903         # update the build system only because we modified this file in the if-clause
00904         execute_process (COMMAND "${CMAKE_COMMAND}" -E copy "${PROJECT_${F}_FILE}" "${BASIS_PROJECT_${F}_FILE}")
00905         # use extension on Windows, but leave it out on Unix
00906         get_filename_component (N "${F}" NAME_WE)
00907         get_filename_component (E "${F}" EXT)
00908         if (WIN32)
00909           if (NOT E)
00910             set (E ".txt")
00911           endif ()
00912         else ()
00913           if ("${E}" STREQUAL ".txt")
00914             set (E "")
00915           endif ()
00916         endif ()
00917         set (N "${N}${E}")
00918         # install file
00919         if (F MATCHES "COPYING")
00920           install (
00921             FILES       "${PROJECT_BINARY_DIR}/${F}.txt"
00922             DESTINATION "${INSTALL_DOC_DIR}"
00923             RENAME      "${N}"
00924             OPTIONAL
00925           )
00926         endif ()
00927       endif ()
00928     elseif (NOT F MATCHES "WELCOME" AND NOT PROJECT_IS_MODULE)
00929       message (FATAL_ERROR "Project requires a ${F}.txt file in ${PROJECT_SOURCE_DIR}!")
00930     endif ()
00931   endforeach ()
00932   set (PROJECT_LICENSE_FILE "${PROJECT_COPYING_FILE}") # compatibility with Slicer
00933 endmacro ()
00934 
00935 # ----------------------------------------------------------------------------
00936 ## @brief Get build time stamp.
00937 #
00938 # The build time stamp is used as an alternative to the version and revision
00939 # information in @c PROJECT_RELEASE if version is invalid, i.e., set to 0.0.0
00940 # as is the case for development branches, and now revision from a revision
00941 # control system is available.
00942 function (basis_get_build_timestamp TIMESTAMP)
00943   if (WIN32)
00944     execute_process (
00945       COMMAND "${BASIS_MODULE_PATH}/buildtimestamp.cmd"
00946       RESULT_VARIABLE RT
00947       OUTPUT_VARIABLE BUILD_TIMESTAMP
00948       ERROR_QUIET
00949       OUTPUT_STRIP_TRAILING_WHITESPACE
00950     )
00951   else ()
00952     execute_process (
00953       COMMAND "date" -u "+%Y.%m.%d (%H:%M UTC)"
00954       RESULT_VARIABLE RT
00955       OUTPUT_VARIABLE BUILD_TIMESTAMP
00956       ERROR_QUIET
00957       OUTPUT_STRIP_TRAILING_WHITESPACE
00958     )
00959   endif ()
00960   if (RT EQUAL 0)
00961     set (${TIMESTAMP} "${BUILD_TIMESTAMP}" PARENT_SCOPE)
00962   else ()
00963     set (${TIMESTAMP} PARENT_SCOPE)
00964   endif ()
00965 endfunction ()
00966 
00967 # ----------------------------------------------------------------------------
00968 ## @brief Initialize project, calls CMake's project() command.
00969 #
00970 # @sa basis_project()
00971 # @sa basis_project_impl()
00972 #
00973 # @returns Sets the following non-cached CMake variables:
00974 # @retval PROJECT_REVISION         Revision number of Subversion controlled
00975 #                                  source tree or 0 if the source tree is
00976 #                                  not under revision control.
00977 # @retval PROJECT_RELEASE          A string of project version and revision
00978 #                                  that can be used for the output of
00979 #                                  version information. The format of this
00980 #                                  string is either one of the following:
00981 #                                  - "v1.0 (r42)"
00982 #                                  - "v1.0.5 (r50)"
00983 #                                  - "v1.0"   (if revision unknown)
00984 #                                  - "r42"    (if version is 0.0.0)
00985 #                                  - ""       (otherwise)
00986 macro (basis_project_initialize)
00987   # --------------------------------------------------------------------------
00988   # CMake version and policies
00989   cmake_minimum_required (VERSION 2.8.4)
00990 
00991   # Add policies introduced with CMake versions newer than the one specified
00992   # above. These policies would otherwise trigger a policy not set warning by
00993   # newer CMake versions.
00994 
00995   if (POLICY CMP0016)
00996     cmake_policy (SET CMP0016 NEW)
00997   endif ()
00998 
00999   if (POLICY CMP0017)
01000     cmake_policy (SET CMP0017 NEW)
01001   endif ()
01002 
01003   # --------------------------------------------------------------------------
01004   # reset
01005 
01006   # only set if not set by top-level project before configuring a module
01007   basis_set_if_empty (PROJECT_IS_MODULE FALSE)
01008   # set only by basis_use_package() to TRUE such that functions such as
01009   # the overwritten (basis_)link_directories() command or add_library()
01010   # know that these directories/targets belong to an external project which
01011   # is part of the same superbuild. otherwise, it shall be FALSE.
01012   set (BUNDLE_PROJECT FALSE)
01013 
01014   # hide it here to avoid that it shows up in the GUI on error
01015   set (CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "" FORCE)
01016 
01017   # --------------------------------------------------------------------------
01018   # project meta-data
01019   if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
01020     set (BASIS_basis_project_CALLED FALSE)
01021     include ("${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
01022     if (NOT BASIS_basis_project_CALLED)
01023       message (FATAL_ERROR "Missing basis_project() command in BasisProject.cmake!")
01024     endif ()
01025   else ()
01026     message (FATAL_ERROR "Missing BasisProject.cmake file!")
01027   endif ()
01028 
01029   # --------------------------------------------------------------------------
01030   # project()
01031   project ("${PROJECT_NAME}")
01032 
01033   # work-around for issue with CMAKE_PROJECT_NAME always being set to 'Project'
01034   if ("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
01035     set_property (CACHE CMAKE_PROJECT_NAME PROPERTY VALUE "${PROJECT_NAME}")
01036   endif ()
01037 
01038   # get revision of project
01039   #
01040   # Note: Use revision when branch, i.e., either trunk, a branch, or a tag
01041   #       has been modified last. For tags, this should in particular
01042   #       correspond to the revision when the tag was created.
01043   if (BASIS_REVISION_INFO)
01044     basis_svn_get_last_changed_revision ("${PROJECT_SOURCE_DIR}" PROJECT_REVISION)
01045   else ()
01046     set (PROJECT_REVISION 0)
01047   endif ()
01048 
01049   # extract version numbers from version string
01050   basis_version_numbers (
01051     "${PROJECT_VERSION}"
01052       PROJECT_VERSION_MAJOR
01053       PROJECT_VERSION_MINOR
01054       PROJECT_VERSION_PATCH
01055   )
01056 
01057   set (PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
01058 
01059   # version information string
01060   if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?")
01061     if (PROJECT_REVISION)
01062       set (PROJECT_RELEASE "r${PROJECT_REVISION}")
01063     else ()
01064       basis_get_build_timestamp (BUILD_TIMESTAMP)
01065       if (BUILD_TIMESTAMP)
01066         set (PROJECT_RELEASE "b${BUILD_TIMESTAMP}")
01067       else ()
01068         set (PROJECT_RELEASE "")
01069       endif ()
01070     endif ()
01071   else ()
01072     set (PROJECT_RELEASE "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
01073     if (PROJECT_VERSION_PATCH)
01074       set (PROJECT_RELEASE "${PROJECT_RELEASE}.${PROJECT_VERSION_PATCH}")
01075     endif ()
01076     if (PROJECT_REVISION)
01077       set (PROJECT_RELEASE "${PROJECT_RELEASE} (r${PROJECT_REVISION})")
01078     endif ()
01079   endif ()
01080 
01081   set (PROJECT_VERSION_AND_REVISION "${PROJECT_RELEASE}") # backwards compatibility to BASIS < 1.3
01082 
01083   # version number for use in Perl modules
01084   set (PROJECT_VERSION_PERL "${PROJECT_VERSION_MAJOR}")
01085   if (PROJECT_VERSION_MAJOR LESS 10)
01086     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.0${PROJECT_VERSION_MINOR}")
01087   else ()
01088     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.${PROJECT_VERSION_MINOR}")
01089   endif ()
01090   if (PROJECT_VERSION_PATCH LESS 10)
01091     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_0${PROJECT_VERSION_PATCH}")
01092   else ()
01093     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_${PROJECT_VERSION_PATCH}")
01094   endif ()
01095 
01096   # print project information
01097   if (NOT PROJECT_IS_MODULE)
01098     message (STATUS "${PROJECT_NAME} ${PROJECT_RELEASE}")
01099   endif ()
01100 
01101   # --------------------------------------------------------------------------
01102   # reset project properties - *after* PROJECT_NAME was set
01103 
01104   # The following variables are used across BASIS macros and functions. They
01105   # in particular remember information added by one function or macro which
01106   # is required by another function or macro.
01107   #
01108   # These variables need to be properties such that they can be set in
01109   # subdirectories. Moreover, they have to be assigned with the project's
01110   # root source directory such that a top-level project's properties are restored
01111   # after this subproject is finalized such that the top-level project itself can
01112   # be finalized properly.
01113   #
01114   # Attention: In particular the IMPORTED_* properties are already used
01115   #            during the import of targets when including the use files of
01116   #            external packages. Hence, this property has to be reset before.
01117 
01118   # see basis_add_imported_target()
01119   basis_set_project_property (PROPERTY IMPORTED_TARGETS   "")
01120   basis_set_project_property (PROPERTY IMPORTED_TYPES     "")
01121   basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "")
01122   basis_set_project_property (PROPERTY IMPORTED_RANKS     "")
01123   # see basis_include_directories()
01124   basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS "")
01125   # see basis_link_directories()
01126   basis_set_project_property (PROPERTY PROJECT_LINK_DIRS "")
01127   basis_set_project_property (PROPERTY BUNDLE_LINK_DIRS  "")
01128   # see add_executable(), add_library()
01129   basis_set_project_property (PROPERTY TARGETS "")
01130   # see basis_add_*() functions
01131   basis_set_project_property (PROPERTY EXPORT_TARGETS                "")
01132   basis_set_project_property (PROPERTY INSTALL_EXPORT_TARGETS        "")
01133   basis_set_project_property (PROPERTY CUSTOM_EXPORT_TARGETS         "")
01134   basis_set_project_property (PROPERTY TEST_EXPORT_TARGETS           "")
01135   basis_set_project_property (PROPERTY PROJECT_USES_CXX_UTILITIES    FALSE)
01136   basis_set_project_property (PROPERTY PROJECT_USES_PYTHON_UTILITIES FALSE)
01137   basis_set_project_property (PROPERTY PROJECT_USES_PERL_UTILITIES   FALSE)
01138   basis_set_project_property (PROPERTY PROJECT_USES_BASH_UTILITIES   FALSE)
01139   # yet unused
01140   basis_set_project_property (PROPERTY PROJECT_USES_JAVA_UTILITIES   FALSE)
01141   basis_set_project_property (PROPERTY PROJECT_USES_MATLAB_UTILITIES FALSE)
01142 endmacro ()
01143 
01144 # ----------------------------------------------------------------------------
01145 ## @brief Initialize project settings.
01146 macro (basis_initialize_settings)
01147   # --------------------------------------------------------------------------
01148   # configure BASIS directory structure
01149   include ("${BASIS_MODULE_PATH}/DirectoriesSettings.cmake")
01150   configure_file (
01151     "${BASIS_MODULE_PATH}/Directories.cmake.in"
01152     "${BINARY_CONFIG_DIR}/Directories.cmake"
01153     @ONLY
01154   )
01155   # --------------------------------------------------------------------------
01156   # include project specific settings
01157   #
01158   # This file enables the project to modify the default behavior of BASIS,
01159   # but only if BASIS allows so as the BASIS project settings are included
01160   # afterwards.
01161   if (EXISTS "${PROJECT_CONFIG_DIR}/Settings.cmake.in")
01162     configure_file (
01163       "${PROJECT_CONFIG_DIR}/Settings.cmake.in"
01164       "${BINARY_CONFIG_DIR}/Settings.cmake"
01165       @ONLY
01166     )
01167     include ("${BINARY_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE)
01168   else ()
01169     include ("${PROJECT_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE OPTIONAL)
01170   endif ()
01171   # --------------------------------------------------------------------------
01172   # configure project specific BASIS settings
01173   set (_BASIS_NAMESPACE_CMAKE "${PROJECT_PACKAGE_L}")
01174   if (PROJECT_IS_SUBPROJECT OR PROJECT_IS_MODULE)
01175     set (_NAMESPACE_CMAKE "${_BASIS_NAMESPACE_CMAKE}.${PROJECT_NAME_L}")
01176   else ()
01177     set (_NAMESPACE_CMAKE "${_BASIS_NAMESPACE_CMAKE}")
01178   endif ()
01179   # default namespaces used for supported programming languages
01180   foreach (_L IN LISTS BASIS_LANGUAGES_U)
01181     if (_L MATCHES "PERL")
01182       set (_NAMESPACE_${_L} "${PROJECT_PACKAGE}")
01183     else ()
01184       set (_NAMESPACE_${_L} "${PROJECT_PACKAGE_L}")
01185     endif ()
01186   endforeach ()
01187   if (PROJECT_IS_SUBPROJECT)
01188     foreach (_L IN LISTS BASIS_LANGUAGES_U)
01189       if (_L MATCHES "PERL")
01190         set (_NAMESPACE_${_L} "${_NAMESPACE_${_L}}${BASIS_NAMESPACE_DELIMITER_${_L}}${PROJECT_NAME}")
01191       elseif (NOT _L MATCHES "CMAKE")
01192         set (_NAMESPACE_${_L} "${_NAMESPACE_${_L}}${BASIS_NAMESPACE_DELIMITER_${_L}}${PROJECT_NAME_L}")
01193       endif ()
01194     endforeach ()
01195   endif ()
01196   # package configuration
01197   set (_BASIS_PROJECT_PACKAGE_CONFIG_PREFIX "${BASIS_PROJECT_PACKAGE}")
01198   if (PROJECT_IS_SUBPROJECT OR PROJECT_IS_MODULE)
01199     set (_PROJECT_PACKAGE_CONFIG_PREFIX "${_BASIS_PROJECT_PACKAGE_CONFIG_PREFIX}${PROJECT_NAME}")
01200   else ()
01201     set (_PROJECT_PACKAGE_CONFIG_PREFIX "${_BASIS_PROJECT_PACKAGE_CONFIG_PREFIX}")
01202   endif ()
01203   if (PROJECT_PACKAGE_VENDOR)
01204     set (_BASIS_PROJECT_PACKAGE_UID "${PROJECT_PACKAGE_VENDOR}-${PROJECT_PACKAGE}-${PROJECT_VERSION}")
01205   else ()
01206     set (_BASIS_PROJECT_PACKAGE_UID "${PROJECT_PACKAGE}-${PROJECT_VERSION}")
01207   endif ()
01208   # configure settings file which contains the documentation of these variables
01209   configure_file (
01210     "${BASIS_MODULE_PATH}/ProjectSettings.cmake.in"
01211     "${BINARY_CONFIG_DIR}/ProjectSettings.cmake"
01212     @ONLY
01213   )
01214   # unset local variables
01215   foreach (_L IN LISTS BASIS_LANGUAGES_U)
01216     unset (_BASIS_NAMESPACE_${_L})
01217     unset (_NAMESPACE_${_L})
01218   endforeach ()
01219   unset (_BASIS_PROJECT_PACKAGE_UID)
01220   unset (_BASIS_PROJECT_PACKAGE_CONFIG_PREFIX)
01221   unset (_PROJECT_PACKAGE_CONFIG_PREFIX)
01222   unset (_L)
01223   # include configured project specific BASIS settings
01224   include ("${BINARY_CONFIG_DIR}/ProjectSettings.cmake" NO_POLICY_SCOPE)
01225 endmacro ()
01226 
01227 # ----------------------------------------------------------------------------
01228 ## @brief Find packages this project depends on.
01229 macro (basis_find_packages)
01230   set (BASIS_SET_TARGET_PROPERTIES_IMPORT TRUE) # see set_target_properties()
01231 
01232   # Attention: This function is used before the Directories.cmake.in and
01233   #            Settings.cmake.in files were configured and included.
01234   set (PROJECT_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/config")
01235 
01236   # --------------------------------------------------------------------------
01237   # add project config directory to CMAKE_MODULE_PATH
01238   set (CMAKE_MODULE_PATH "${PROJECT_CONFIG_DIR}" ${CMAKE_MODULE_PATH})
01239 
01240   # --------------------------------------------------------------------------
01241   # Depends.cmake
01242 
01243   # This file is in particular of interest if a dependency is required if
01244   # certain modules are enabled, but not others.
01245 
01246   # Attention: This function is used before the Directories.cmake.in and
01247   #            Settings.cmake.in files were configured and included.
01248   include ("${PROJECT_CONFIG_DIR}/Depends.cmake" OPTIONAL)
01249 
01250   # --------------------------------------------------------------------------
01251   # required dependencies
01252   foreach (P IN LISTS PROJECT_DEPENDS)
01253     basis_find_package ("${P}" REQUIRED)
01254     basis_use_package  ("${P}" REQUIRED)
01255   endforeach ()
01256 
01257   # --------------------------------------------------------------------------
01258   # optional dependencies
01259   foreach (P IN LISTS PROJECT_OPTIONAL_DEPENDS)
01260     basis_find_package ("${P}" QUIET)
01261     basis_use_package  ("${P}")
01262   endforeach ()
01263 
01264   # --------------------------------------------------------------------------
01265   # test dependencies
01266   if (BUILD_TESTING)
01267     # required test dependencies
01268     foreach (P IN LISTS PROJECT_TEST_DEPENDS)
01269       basis_find_package ("${P}") # do not use REQUIRED here to be able to show
01270       basis_use_package ("${P}")  # error message below
01271       basis_tokenize_dependency ("${P}" P VER CMPS)
01272       string (TOUPPER "${P}" U)
01273       if (NOT ${P}_FOUND AND NOT ${U}_FOUND)
01274         message (FATAL_ERROR "Could not find package ${P}! It is required by "
01275                              "the tests of ${PROJECT_NAME}. Either specify "
01276                              "package location manually and try again or "
01277                              "disable testing by setting BUILD_TESTING to OFF.")
01278         
01279       endif ()
01280       unset (U)
01281       unset (VER)
01282       unset (CMPS)
01283     endforeach ()
01284     # optional test dependencies
01285     foreach (P IN LISTS PROJECT_OPTIONAL_TEST_DEPENDS)
01286       basis_find_package ("${P}" QUIET)
01287       basis_use_package ("${P}")
01288     endforeach ()
01289   endif ()
01290 
01291   unset (P)
01292 
01293   set (BASIS_SET_TARGET_PROPERTIES_IMPORT FALSE) # see set_target_properties()
01294 endmacro ()
01295 
01296 # ============================================================================
01297 # finalization
01298 # ============================================================================
01299 
01300 # ----------------------------------------------------------------------------
01301 ## @brief Add installation rules for public header files.
01302 macro (basis_install_public_headers)
01303   # subdirectory of basis.h header file
01304   basis_library_prefix (_BASIS_H_PREFIX CXX)
01305   # install public header files from source tree
01306   if (EXISTS "${PROJECT_INCLUDE_DIR}")
01307     basis_install_directory ("${PROJECT_INCLUDE_DIR}" "${INSTALL_INCLUDE_DIR}" PATTERN "*.in" EXCLUDE)
01308   endif ()
01309   # install configured public header files, excluding BASIS utilities
01310   file (GLOB_RECURSE _CONFIGURED_PUBLIC_HEADERS "${BINARY_INCLUDE_DIR}/*")
01311   list (REMOVE_ITEM _CONFIGURED_PUBLIC_HEADERS "${BINARY_INCLUDE_DIR}/${_BASIS_H_PREFIX}basis.h")
01312   if (_CONFIGURED_PUBLIC_HEADERS)
01313     basis_install_directory (
01314       "${BINARY_INCLUDE_DIR}" "${INSTALL_INCLUDE_DIR}"
01315       REGEX   "/${_BASIS_H_PREFIX}basis\\.h$" EXCLUDE # BASIS utilities header only installed
01316                                                       # below if included by any other public header
01317       PATTERN "*.cmake"                       EXCLUDE # e.g., <Name>PublicHeaders.cmake file,
01318       PATTERN "*.cmake.*"                     EXCLUDE # see basis_configure_public_headers()
01319     )
01320   endif ()
01321   # "parse" public header files to check if C++ BASIS utilities are included
01322   if (NOT BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
01323     # get list of all public header files of project
01324     set (_PUBLIC_HEADERS)
01325     if (NOT BASIS_CONFIGURE_INCLUDES)
01326       file (GLOB_RECURSE _PUBLIC_HEADERS "${PROJECT_INCLUDE_DIR}/*.h")
01327     endif ()
01328     list (APPEND _PUBLIC_HEADERS ${_CONFIGURED_PUBLIC_HEADERS})
01329     # check include statements of each public header file
01330     foreach (_A IN LISTS _PUBLIC_HEADERS)
01331       basis_utilities_check (_B "${_A}" CXX)
01332       if (_B)
01333         set (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES TRUE)
01334         break ()
01335       endif ()
01336     endforeach ()
01337     unset (_PUBLIC_HEADERS)
01338     unset (_A)
01339     unset (_B)
01340   endif ()
01341   unset (_CONFIGURED_PUBLIC_HEADERS)
01342   # install public header of BASIS utilities (optional)
01343   if (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
01344     install (
01345       FILES       "${BINARY_INCLUDE_DIR}/${_BASIS_H_DIR}/basis.h"
01346       DESTINATION "${INSTALL_INCLUDE_DIR}/${_BASIS_H_PREFIX}"
01347       COMPONENT   "${BASIS_LIBRARY_COMPONENT}"
01348     )
01349   endif ()
01350 endmacro ()
01351 
01352 
01353 ## @}
01354 # end of Doxygen group
01355 
01356 # ============================================================================
01357 # root CMakeLists.txt implementation
01358 # ============================================================================
01359 
01360 # ----------------------------------------------------------------------------
01361 ## @brief Implementation of root <tt>CMakeLists.txt</tt> file of BASIS project.
01362 #
01363 # This macro implements the entire logic of the top-level
01364 # <tt>CMakeLists.txt</tt> file. At first, the project is initialized and the
01365 # BASIS settings configured using the project information given in the
01366 # <tt>BasisProject.cmake</tt> file which must be located in the same directory.
01367 # The, the code in the <tt>CMakeLists.txt</tt> files in the subdirectories is
01368 # executed in order. At the end, the configuration of the build system is
01369 # finalized, including in particular also the addition of custom build targets
01370 # which perform the actual build of custom build targets such as the ones build
01371 # using the MATLAB Compiler.
01372 #
01373 # @sa BasisProject.cmake
01374 # @sa basis_project()
01375 #
01376 # @ingroup CMakeAPI
01377 macro (basis_project_impl)
01378   # --------------------------------------------------------------------------
01379   # set CMAKE_INSTALL_PREFIX to cached invalid value to have
01380   # basis_initialize_settings() set it to BASIS's default rather than CMake's
01381   # default even if this is not the first configure run because a previous
01382   # one was interrupted by an error such as a requird package that was not found
01383   if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
01384     set (CMAKE_INSTALL_PREFIX "" CACHE INTERNAL "Installation prefix." FORCE)
01385   endif ()
01386 
01387   # --------------------------------------------------------------------------
01388   # initialize project
01389   basis_project_initialize ()
01390 
01391   # --------------------------------------------------------------------------
01392   # load information of modules
01393   if (NOT PROJECT_IS_MODULE)
01394     basis_project_modules ()
01395   endif ()
01396 
01397   if (BASIS_DEBUG)
01398     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterDetectionOfModules.cmake")
01399   endif ()
01400 
01401   # --------------------------------------------------------------------------
01402   # initialize Slicer module
01403   basis_slicer_module_initialize ()
01404 
01405   # --------------------------------------------------------------------------
01406   # Python
01407 
01408   # In case of a Slicer Extension, the UseSlicer.cmake file of Slicer (>= 4.0)
01409   # will set PYTHON_EXECUTABLE and requires us not to set this variable before
01410   # the UseSlicer.cmake file has been included. Hence, we set this variable
01411   # here only if it has not been set by Slicer, but before any PythonInterp
01412   # dependency declared by this package such that the Python interpreter
01413   # configured while building BASIS is used to avoid conflicts of different
01414   # versions used to compile the Python utilities (if BASIS_COMPILE_SCRIPTS
01415   # was set to ON) and the one used to configure/build this package.
01416   #
01417   # Note: The PYTHON_EXECUTABLE variable has to be cached such that
01418   #       PythonInterp.cmake does not look for the interpreter itself.
01419   if (BASIS_PYTHON_EXECUTABLE)
01420     set (
01421       PYTHON_EXECUTABLE
01422         "${BASIS_PYTHON_EXECUTABLE}"
01423       CACHE PATH
01424         "The Python interpreter."
01425     )
01426     mark_as_advanced (PYTHON_EXECUTABLE)
01427   endif ()
01428   # Note that PERL_EXECUTABLE and BASH_EXECUTABLE are set in BASISUse.cmake.
01429 
01430   # --------------------------------------------------------------------------
01431   # find packages
01432 
01433   # any package use file must be included after PROJECT_NAME was set as the
01434   # imported targets are added to the <Project>_TARGETS property using
01435   # basis_set_project_property() in add_executable() and add_library()
01436   basis_use_package (BASIS)
01437   basis_find_packages ()
01438 
01439   if (BASIS_DEBUG)
01440     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFindDependencies.cmake")
01441   endif ()
01442 
01443   # --------------------------------------------------------------------------
01444   # get interpreter versions - set to invalid version if not available
01445   if (NOT PYTHON_VERSION_STRING)
01446     basis_get_python_version ()
01447   endif ()
01448   if (NOT JYTHON_VERSION_STRING)
01449     basis_get_jython_version ()
01450   endif ()
01451   if (NOT PERL_VERSION_STRING)
01452     basis_get_perl_version ()
01453   endif ()
01454   if (NOT BASH_VERSION_STRING)
01455     basis_get_bash_version ()
01456   endif ()
01457   if (NOT MATLAB_VERSION_STRING)
01458     basis_get_matlab_version ()
01459   endif ()
01460 
01461   if (PYTHON_EXECUTABLE AND PYTHON_VERSION_MAJOR EQUAL 0 OR (PYTHON_VERSION_MAJOR EQUAL 1 AND PYTHON_VERSION_MINOR EQUAL 4))
01462     message (WARNING "Failed to determine Python version! Check if you can run \"${PYTHON_EXECUTABLE} -E\" in a Terminal.")
01463   endif ()
01464   if (JYTHON_EXECUTABLE AND JYTHON_VERSION_MAJOR EQUAL 0)
01465     message (WARNING "Failed to determine Jython version! Check if you can run \"${JYTHON_EXECUTABLE}\".")
01466   endif ()
01467   if (PERL_EXECUTABLE AND PERL_VERSION_MAJOR EQUAL 0)
01468     message (WARNING "Failed to determine Perl version! Check if you can run \"${PERL_EXECUTABLE}\".")
01469   endif ()
01470   if (BASH_EXECUTABLE AND BASH_VERSION_MAJOR EQUAL 0)
01471     message (WARNING "Failed to determine Bash version! Check if you can run \"${BASH_EXECUTABLE}\".")
01472   endif ()
01473   if (MATLAB_EXECUTABLE AND MATLAB_VERSION_MAJOR EQUAL 0)
01474     message (WARNING "Failed to determine MATLAB version! Check if you can run \"${MATLAB_EXECUTABLE} -nodesktop -nosplash -r 'version,quit force'\" and try again.")
01475   endif ()
01476 
01477   # --------------------------------------------------------------------------
01478   # initialize settings
01479   basis_initialize_settings ()
01480 
01481   # --------------------------------------------------------------------------
01482   # assertions
01483   basis_buildtree_asserts ()
01484   basis_installtree_asserts ()
01485 
01486   # --------------------------------------------------------------------------
01487   # defaul script configuration - see basis_configure_script()
01488   set (BASIS_SCRIPT_CONFIG_FILE "${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake")
01489   configure_file ("${BASIS_MODULE_PATH}/ScriptConfig.cmake.in" "${BASIS_SCRIPT_CONFIG_FILE}" @ONLY)
01490   if (EXISTS "${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in")
01491     configure_file ("${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in" "${BINARY_CONFIG_DIR}/ScriptConfig.cmake" @ONLY)
01492   endif ()
01493 
01494   # --------------------------------------------------------------------------
01495   # root documentation files
01496   basis_configure_root_documentation_files ()
01497 
01498   # --------------------------------------------------------------------------
01499   # enable testing
01500   if (NOT PROJECT_IS_MODULE)
01501     include ("${BASIS_MODULE_PATH}/BasisTest.cmake")
01502     basis_disable_testing_if_no_tests ()
01503     if (BUILD_TESTING AND NOT EXISTS "${PROJECT_SOURCE_DIR}/CTestConfig.cmake")
01504       message (WARNING "Missing CTestConfig.cmake file in top directory of source tree!"
01505                        " You will not be able to submit test results to the CDash dashboard.")
01506     endif ()
01507   endif ()
01508 
01509   # --------------------------------------------------------------------------
01510   # public header files and script libraries
01511 
01512   # dump currently defined CMake variables such that these can be used to
01513   # configure the .in public header and module files during the build step
01514   basis_dump_variables ("${PROJECT_BINARY_DIR}/BasisCache.txt")
01515   basis_include_directories (BEFORE "${BINARY_INCLUDE_DIR}"
01516                                     "${PROJECT_INCLUDE_DIR}"
01517                                     "${PROJECT_CODE_DIR}")
01518   basis_configure_public_headers ()
01519   basis_configure_script_libraries ()
01520 
01521   # --------------------------------------------------------------------------
01522   # subdirectories
01523   if (BASIS_DEBUG)
01524     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterInitialization.cmake")
01525   endif ()
01526 
01527   # build modules
01528   if (NOT PROJECT_IS_MODULE)
01529     foreach (MODULE IN LISTS PROJECT_MODULES_ENABLED)
01530       message (STATUS "Configuring module ${MODULE}...")
01531       set (PROJECT_IS_MODULE TRUE)
01532       add_subdirectory ("${MODULE_${MODULE}_SOURCE_DIR}" "${MODULE_${MODULE}_BINARY_DIR}")
01533       set (PROJECT_IS_MODULE FALSE)
01534       message (STATUS "Configuring module ${MODULE}... - done")
01535     endforeach ()
01536   endif ()
01537 
01538   # add default project directories to list of subdirectories
01539   # (in reverse order always at beginning of list)
01540   if (BUILD_EXAMPLE)
01541     list (INSERT PROJECT_SUBDIRS 0 "${PROJECT_EXAMPLE_DIR}")
01542   endif ()
01543   if (BUILD_TESTING)
01544     list (INSERT PROJECT_SUBDIRS 0 "${PROJECT_TESTING_DIR}")
01545   endif ()
01546   list (INSERT PROJECT_SUBDIRS 0 "${PROJECT_DATA_DIR}")
01547   list (INSERT PROJECT_SUBDIRS 0 "${PROJECT_CODE_DIR}")
01548 
01549   # process subdirectories
01550   foreach (SUBDIR IN LISTS PROJECT_SUBDIRS)
01551     if (IS_DIRECTORY "${SUBDIR}")
01552       add_subdirectory ("${SUBDIR}")
01553     endif ()
01554   endforeach ()
01555 
01556   if (BASIS_DEBUG)
01557     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterSubdirectories.cmake")
01558   endif ()
01559 
01560   # --------------------------------------------------------------------------
01561   # write convenience file to setup MATLAB environment
01562   if (MATLAB_FOUND)
01563     basis_create_addpaths_mfile ()
01564   endif ()
01565 
01566   # --------------------------------------------------------------------------
01567   # copy project properties of modules
01568   if (NOT PROJECT_IS_MODULE)
01569     # copy properties of modules
01570     foreach (M IN LISTS PROJECT_MODULES_ENABLED)
01571       foreach (P IN ITEMS IMPORTED_TARGETS
01572                           IMPORTED_TYPES
01573                           IMPORTED_LOCATIONS
01574                           IMPORTED_RANKS
01575                           PROJECT_INCLUDE_DIRS
01576                           PROJECT_LINK_DIRS
01577                           BUNDLE_LINK_DIRS
01578                           TARGETS
01579                           CUSTOM_EXPORT_TARGETS
01580                           TEST_EXPORT_TARGETS)
01581         basis_get_project_property (V ${M} ${P})
01582         basis_set_project_property (APPEND PROPERTY ${P} ${V})
01583       endforeach ()
01584     endforeach ()
01585     foreach (L IN ITEMS CXX PYTHON PERL BASH)
01586       foreach (M IN LISTS PROJECT_MODULES_ENABLED)
01587         basis_get_project_property (P ${M} PROJECT_USES_${L}_UTILITIES)
01588         if (P)
01589           basis_set_project_property (PROPERTY PROJECT_USES_${L}_UTILITIES TRUE)
01590           break ()
01591         endif ()
01592       endforeach ()
01593     endforeach ()
01594   endif () 
01595 
01596   # --------------------------------------------------------------------------
01597   # finalize custom targets
01598   if (NOT PROJECT_IS_MODULE OR PROJECT_IS_SUBPROJECT)
01599     # configure the BASIS utilities
01600     basis_configure_utilities ()
01601     # add missing build commands for custom targets
01602     basis_finalize_targets ()
01603     # add build target for missing __init__.py files of Python package
01604     basis_add_init_py_target ()
01605   endif ()
01606 
01607   # --------------------------------------------------------------------------
01608   # add installation rules for public headers
01609   basis_install_public_headers ()
01610 
01611   # --------------------------------------------------------------------------
01612   # generate configuration files
01613   include ("${BASIS_MODULE_PATH}/GenerateConfig.cmake")
01614 
01615   # ----------------------------------------------------------------------------
01616   # change log
01617   basis_add_changelog ()
01618 
01619   # --------------------------------------------------------------------------
01620   # build/install package documentation
01621   #
01622   # This is done after all files which may be interesting for inclusion
01623   # in the documentation are generated. In particular, this has to be done
01624   # after the configuration of the BASIS utilities.
01625   if (EXISTS "${PROJECT_DOC_DIR}" AND BUILD_DOCUMENTATION)
01626     add_subdirectory ("${PROJECT_DOC_DIR}")
01627   endif ()
01628 
01629   # --------------------------------------------------------------------------
01630   # package software
01631   include ("${BASIS_MODULE_PATH}/BasisPack.cmake")
01632 
01633   # --------------------------------------------------------------------------
01634   # add installation rule to register package with CMake
01635   if (BASIS_REGISTER AND NOT PROJECT_IS_MODULE AND PROJECT_VERSION VERSION_GREATER 0.0.0)
01636     basis_register_package ()
01637   endif ()
01638 
01639   # --------------------------------------------------------------------------
01640   # uninstaller
01641   if (NOT PROJECT_IS_MODULE)
01642     # add uninstall target
01643     basis_add_uninstall ()
01644     # add code to generate uninstaller at the end of the installation
01645     #
01646     # Attention: This must be done at last and using a add_subdirectory() call
01647     #            such that the code is executed at last by the root cmake_install.cmake!
01648     add_subdirectory ("${BASIS_MODULE_PATH}/uninstall" "${PROJECT_BINARY_DIR}/uninstall")
01649   endif ()
01650 
01651   if (BASIS_DEBUG)
01652     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFinalization.cmake")
01653   endif ()
01654 endmacro ()