BASIS  version 1.2.3 (revision 2104)
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 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 Defines project meta-data, i.e., attributes.
00017 #
00018 # Any BASIS project has to call this macro in the file BasisProject.cmake
00019 # located in the top level directory of the source tree in order to define
00020 # the project attributes required by BASIS to setup the build system.
00021 # Moreover, if the BASIS project is a module of another BASIS project, this
00022 # file and the variables set by this macro are used by the top-level project to
00023 # identify its modules and the dependencies among them.
00024 #
00025 # @par Project version:
00026 # The version number consists of three components: the major version number,
00027 # the minor version number, and the patch number. The format of the version
00028 # string is "<major>.<minor>.<patch>", where the minor version number and patch
00029 # number default to "0" if not given. Only digits are allowed except of the two
00030 # separating dots.
00031 # @n
00032 # - A change of the major version number indicates changes of the softwares
00033 #   @api (and @abi) and/or its behavior and/or the change or addition of major
00034 #   features.
00035 # - A change of the minor version number indicates changes that are not only
00036 #   bug fixes and no major changes. Hence, changes of the @api but not the @abi.
00037 # - A change of the patch number indicates changes only related to bug fixes
00038 #   which did not change the softwares @api. It is the least important component
00039 #   of the version number.
00040 #
00041 # @par Dependencies:
00042 # Dependencies on other BASIS projects, which can be subprojects of the same
00043 # BASIS top-level project, as well as dependencies on external packages such as ITK
00044 # have to be defined here using the @p DEPENDS argument option. This will be used
00045 # by a top-level project to ensure that the dependencies among its subprojects are
00046 # resolved properly. For each external dependency, the BASIS functions
00047 # basis_find_package() and basis_use_package() are invoked by
00048 # basis_project_initialize(). If an external package is not CMake aware and
00049 # additional CMake code shall be executed to include the settings of the external
00050 # package (which is usually done in a so-called <tt>Use&lt;Pkg&gt;.cmake</tt> file
00051 # if the package would be CMake aware), such code should be added to the
00052 # <tt>Settings.cmake</tt> file of the project.
00053 #
00054 # @param [in] ARGN This list is parsed for the following arguments:
00055 # @par
00056 # <table border="0">
00057 #   <tr>
00058 #     @tp @b NAME name @endtp
00059 #     <td>The name of the project.</td>
00060 #   </tr>
00061 #   <tr>
00062 #     @tp @b VERSION major[.minor[.patch]] @endtp
00063 #     <td>Project version string. Defaults to "1.0.0"</td>
00064 #   </tr>
00065 #   <tr>
00066 #     @tp @b DESCRIPTION description @endtp
00067 #     <td>Package description, used for packing. If multiple arguments are given,
00068 #         they are concatenated using one space character as delimiter.</td>
00069 #   </tr>
00070 #   <tr>
00071 #     @tp @b PACKAGE_VENDOR name @endtp
00072 #     <td>The vendor of this package, used for packaging. If multiple arguments
00073 #         are given, they are concatenated using one space character as delimiter.
00074 #         Default: "SBIA Group at University of Pennsylvania".</td>
00075 #   </tr>
00076 #   <tr>
00077 #     @tp @b DEPENDS name[, name] @endtp
00078 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00079 #         or names of external packages.</td>
00080 #   </tr>
00081 #   <tr>
00082 #     @tp @b OPTIONAL_DEPENDS name[, name] @endtp
00083 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00084 #         or names of external packages which are used only if available.</td>
00085 #   </tr>
00086 #   <tr>
00087 #     @tp @b TEST_DEPENDS name[, name] @endtp
00088 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00089 #         or names of external packages which are only required by the tests.</td>
00090 #   </tr>
00091 #   <tr>
00092 #     @tp @b OPTIONAL_TEST_DEPENDS name[, name] @endtp
00093 #     <td>List of dependencies, i.e., either names of other BASIS (sub)projects
00094 #         or names of external packages which are used only by the tests if available.</td>
00095 #   </tr>
00096 # </table>
00097 #
00098 # @returns Sets the following non-cached CMake variables:
00099 # @retval PROJECT_NAME                    @c NAME argument.
00100 # @retval PROJECT_VERSION                 @c VERSION argument.
00101 # @retval PROJECT_DESCRIPTION             Concatenated @c DESCRIPTION arguments.
00102 # @retval PROJECT_PACKAGE_VENDOR          Concatenated @c PACKAGE_VENDOR argument.
00103 # @retval PROJECT_DEPENDS                 @c DEPENDS arguments.
00104 # @retval PROJECT_OPTIONAL_DEPENDS        @c OPTIONAL_DEPENDS arguments.
00105 # @retval PROJECT_TEST_DEPENDS            @c TEST_DEPENDS arguments.
00106 # @retval PROJECT_OPTIONAL_TEST_DEPENDS   @c OPTIONAL_TEST_DEPENDS arguments.
00107 #
00108 # @ingroup CMakeAPI
00109 macro (basis_project)
00110   # parse arguments and/or include project settings file
00111   CMAKE_PARSE_ARGUMENTS (
00112     PROJECT
00113       ""
00114       "NAME;VERSION"
00115       "DESCRIPTION;PACKAGE_VENDOR;DEPENDS;OPTIONAL_DEPENDS;TEST_DEPENDS;OPTIONAL_TEST_DEPENDS"
00116     ${ARGN}
00117   )
00118 
00119   # check required project attributes or set default values
00120   if (NOT PROJECT_NAME)
00121     message (FATAL_ERROR "basis_project(): Project name not specified!")
00122   endif ()
00123   if (NOT PROJECT_NAME MATCHES "^([a-z][a-z0-9]*|[A-Z][a-zA-Z0-9]*)")
00124     message (FATAL_ERROR "basis_project(): Invalid project name!\n\n"
00125                          "Please choose a project name with either only captial "
00126                          "letters in case of an acronym or a name with mixed case, "
00127                          "but starting with a captial letter.\n\n"
00128                          "Note that numbers are allowed, but not as first character. "
00129                          "Further, do not use characters such as '_' or '-' to "
00130                          "separate parts of the project name. Instead, use the "
00131                          "upper camel case notation "
00132                          "(see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms).")
00133   endif ()
00134   if (NOT PROJECT_IS_MODULE)
00135     set (BASIS_PROJECT_NAME "${PROJECT_NAME}")
00136   endif ()
00137 
00138   if (PROJECT_VERSION)
00139     if (NOT PROJECT_VERSION MATCHES "^[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(rc[0-9]+|[a-z])?$")
00140       message (FATAL_ERROR "basis_project(): Invalid version ${PROJECT_VERSION}!")
00141     endif ()
00142     if (PROJECT_IS_MODULE)
00143       if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?$")
00144         set (PROJECT_VERSION "${BASIS_PROJECT_VERSION}")
00145       endif ()
00146     else ()
00147       set (BASIS_PROJECT_VERSION "${PROJECT_VERSION}")
00148     endif ()
00149   else ()
00150     if (PROJECT_IS_MODULE)
00151       set (PROJECT_VERSION "${BASIS_PROJECT_VERSION}")
00152     else ()
00153       message (FATAL_ERROR "basis_project(): Project version not specified!")
00154     endif ()
00155   endif ()
00156 
00157   if (PROJECT_DESCRIPTION)
00158     basis_list_to_string (PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
00159   else ()
00160     set (PROJECT_DESCRIPTION "")
00161   endif ()
00162 
00163   if (PROJECT_PACKAGE_VENDOR)
00164     basis_list_to_string (PROJECT_PACKAGE_VENDOR ${PROJECT_PACKAGE_VENDOR})
00165     if (NOT PROJECT_IS_MODULE)
00166       set (BASIS_PROJECT_PACKAGE_VENDOR "${PROJECT_PACKAGE_VENDOR}")
00167     endif ()
00168   elseif (PROJECT_IS_MODULE)
00169     set (PROJECT_PACKAGE_VENDOR "${BASIS_PROJECT_PACKAGE_VENDOR}")
00170   else ()
00171     set (PROJECT_PACKAGE_VENDOR "SBIA Group at University of Pennsylvania")
00172   endif ()
00173 
00174   # let basis_project_impl() know that basis_project() was called
00175   set (BASIS_basis_project_CALLED TRUE)
00176 endmacro ()
00177 
00178 
00179 ## @addtogroup CMakeUtilities
00180 # @{
00181 
00182 
00183 # ============================================================================
00184 # initialization
00185 # ============================================================================
00186 
00187 # ----------------------------------------------------------------------------
00188 ## @brief Ensure certain requirements on build tree.
00189 #
00190 # Requirements:
00191 # - Root of build tree must not be root of source tree.
00192 #
00193 # @param [in] ARGN Not used.
00194 #
00195 # @returns Nothing.
00196 macro (basis_buildtree_asserts)
00197   string (TOLOWER "${CMAKE_SOURCE_DIR}" SOURCE_ROOT)
00198   string (TOLOWER "${CMAKE_BINARY_DIR}" BUILD_ROOT)
00199   if ("${BUILD_ROOT}" STREQUAL "${SOURCE_ROOT}")
00200     message(FATAL_ERROR "This project should not be configured & build in the "
00201                         "source directory:\n"
00202                         "  ${CMAKE_SOURCE_DIR}\n"
00203                         "You must run CMake in a separate build directory.")
00204   endif()
00205 endmacro ()
00206 
00207 # ----------------------------------------------------------------------------
00208 ## @brief Ensure certain requirements on install tree.
00209 #
00210 # Requirements:
00211 # - Prefix must be an absolute path.
00212 # - Install tree must be different from source and build tree.
00213 #
00214 # @param [in] ARGN Not used.
00215 #
00216 # @returns Nothing.
00217 macro (basis_installtree_asserts)
00218   if (NOT IS_ABSOLUTE "${INSTALL_PREFIX}")
00219     message (FATAL_ERROR "INSTALL_PREFIX must be an absolute path!")
00220   endif ()
00221   string (TOLOWER "${CMAKE_SOURCE_DIR}" SOURCE_ROOT)
00222   string (TOLOWER "${CMAKE_BINARY_DIR}" BUILD_ROOT)
00223   string (TOLOWER "${INSTALL_PREFIX}"   INSTALL_ROOT)
00224   if ("${INSTALL_ROOT}" MATCHES "${BUILD_ROOT}|${SOURCE_ROOT}")
00225     message (FATAL_ERROR "The current INSTALL_PREFIX points at the source or build tree:\n"
00226                          "  ${INSTALL_PREFIX}\n"
00227                          "This is not permitted by this project. "
00228                          "Please choose another installation prefix."
00229     )
00230   endif()
00231 endmacro ()
00232 
00233 # ----------------------------------------------------------------------------
00234 ## @brief Initialize project modules.
00235 #
00236 # Most parts of this macro were copied from the ITK4 project
00237 # (http://www.vtk.org/Wiki/ITK_Release_4), in particular, the top-level
00238 # CMakeLists.txt file. This file does not state any specific license, but
00239 # the ITK package itself is released under the Apache License Version 2.0,
00240 # January 2004 (http://www.apache.org/licenses/).
00241 #
00242 # @attention At this point, the project-specific variables have not been
00243 #            set yet. For example, use @c CMAKE_CURRENT_SOURCE_DIR instead of
00244 #            @c PROJECT_SOURCE_DIR.
00245 macro (basis_project_modules)
00246   # --------------------------------------------------------------------------
00247   # reset variables
00248   set (PROJECT_MODULES)
00249   set (PROJECT_MODULES_ENABLED)
00250   set (PROJECT_MODULES_DISABLED)
00251 
00252   # --------------------------------------------------------------------------
00253   # load module DAG
00254 
00255   # glob BasisProject.cmake files in modules subdirectory
00256   file (
00257     GLOB
00258       MODULE_INFO_FILES
00259     RELATIVE
00260       "${CMAKE_CURRENT_SOURCE_DIR}"
00261       "${CMAKE_CURRENT_SOURCE_DIR}/modules/*/BasisProject.cmake"
00262   )
00263 
00264   # use function scope to avoid overwriting of this project's variables
00265   function (basis_module_info F)
00266     set (PROJECT_IS_MODULE TRUE)
00267     set (BASIS_basis_project_CALLED FALSE)
00268     include ("${CMAKE_CURRENT_SOURCE_DIR}/${F}")
00269     # make sure that basis_project() was called
00270     if (NOT BASIS_basis_project_CALLED)
00271       message (FATAL_ERROR "basis_module_info(): Missing basis_project() command in ${F}!")
00272     endif ()
00273     # remember dependencies
00274     set (${PROJECT_NAME}_DEPENDS "${PROJECT_DEPENDS}" PARENT_SCOPE)
00275     set (${PROJECT_NAME}_OPTIONAL_DEPENDS "${PROJECT_OPTINOAL_DEPENDS}" PARENT_SCOPE)
00276     set (${PROJECT_NAME}_TEST_DEPENDS "${PROJECT_TEST_DEPENDS}" PARENT_SCOPE)
00277     set (${PROJECT_NAME}_OPTIONAL_TEST_DEPENDS "${PROJECT_OPTIONAL_TEST_DEPENDS}" PARENT_SCOPE)
00278     set (${PROJECT_NAME}_DECLARED TRUE PARENT_SCOPE)
00279     # do not use MODULE instead of PROJECT_NAME in this function as it is not
00280     # set in the scope of this function but its parent scope only
00281     set (MODULE "${PROJECT_NAME}" PARENT_SCOPE)
00282   endfunction ()
00283 
00284   set (PROJECT_MODULES)
00285   foreach (F ${MODULE_INFO_FILES})
00286     basis_module_info (${F})
00287     list (APPEND PROJECT_MODULES ${MODULE})
00288     get_filename_component (${MODULE}_BASE ${F} PATH)
00289     set (MODULE_${MODULE}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${${MODULE}_BASE}")
00290     # use module name as subdirectory name such that the default package
00291     # configuration file knows where to find the module configurations
00292     set (MODULE_${MODULE}_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/modules/${MODULE}")
00293     # help modules to find each other using basis_find_package()
00294     set (${MODULE}_DIR "${MODULE_${MODULE}_BINARY_DIR}")
00295   endforeach()
00296   unset (MODULE)
00297 
00298   # validate the module DAG to identify cyclic dependencies
00299   macro (basis_module_check MODULE NEEDED_BY STACK)
00300     if (${MODULE}_DECLARED)
00301       if (${MODULE}_CHECK_STARTED AND NOT ${MODULE}_CHECK_FINISHED)
00302         # we reached a module while traversing its own dependencies recursively
00303         set (MSG "")
00304         foreach (M ${STACK})
00305           set (MSG " ${M} =>${MSG}")
00306           if ("${M}" STREQUAL "${MODULE}")
00307             break ()
00308           endif ()
00309         endforeach ()
00310         message (FATAL_ERROR "Module dependency cycle detected:\n ${MSG} ${MODULE}")
00311       elseif (NOT ${MODULE}_CHECK_STARTED)
00312         # traverse dependencies of this module
00313         set (${MODULE}_CHECK_STARTED TRUE)
00314         foreach (D IN LISTS ${MODULE}_DEPENDS)
00315           basis_module_check (${D} ${MODULE} "${MODULE};${STACK}")
00316         endforeach ()
00317         set (${MODULE}_CHECK_FINISHED TRUE)
00318       endif ()
00319     endif ()
00320   endmacro ()
00321 
00322   foreach (MODULE ${PROJECT_MODULES})
00323     basis_module_check ("${MODULE}" "" "")
00324   endforeach ()
00325 
00326   # --------------------------------------------------------------------------
00327   # determine list of enabled modules
00328 
00329   # provide an option for all modules
00330   if (PROJECT_MODULES)
00331     option (BUILD_ALL_MODULES "Request to build all modules." OFF)
00332   endif ()
00333 
00334   # provide an option for each module
00335   foreach (MODULE ${PROJECT_MODULES})
00336     option (MODULE_${MODULE} "Request building module ${MODULE}." OFF)
00337     if (${MODULE}_EXCLUDE_FROM_ALL)
00338       set (${MODULE}_IN_ALL FALSE)
00339     else ()
00340       set (${MODULE}_IN_ALL ${BUILD_ALL_MODULES})
00341     endif ()
00342   endforeach ()
00343 
00344   # follow dependencies
00345   macro (basis_module_enable MODULE NEEDED_BY)
00346     if (${MODULE}_DECLARED)
00347       if (NOT "${NEEDED_BY}" STREQUAL "")
00348         list (APPEND ${MODULE}_NEEDED_BY "${NEEDED_BY}")
00349       endif ()
00350       if (NOT ${MODULE}_ENABLED)
00351         if ("${NEEDED_BY}" STREQUAL "")
00352           set (${MODULE}_NEEDED_BY)
00353         endif ()
00354         set (${MODULE}_ENABLED TRUE)
00355         foreach (D IN LISTS ${MODULE}_DEPENDS)
00356           basis_module_enable (${D} ${MODULE})
00357         endforeach ()
00358       endif ()
00359     endif ()
00360   endmacro ()
00361 
00362   foreach (MODULE ${PROJECT_MODULES})
00363     if (MODULE_${MODULE} OR ${MODULE}_IN_ALL)
00364       basis_module_enable ("${MODULE}" "")
00365     endif ()
00366   endforeach ()
00367 
00368   # build final list of enabled modules
00369   set (PROJECT_MODULES_ENABLED "")
00370   set (PROJECT_MODULES_DISABLED "")
00371   foreach (MODULE ${PROJECT_MODULES})
00372     if (${MODULE}_DECLARED)
00373       if (${MODULE}_ENABLED)
00374         list (APPEND PROJECT_MODULES_ENABLED ${MODULE})
00375       else ()
00376         list (APPEND PROJECT_MODULES_DISABLED ${MODULE})
00377       endif ()
00378     endif ()
00379   endforeach ()
00380   list (SORT PROJECT_MODULES_ENABLED) # Deterministic order.
00381   list (SORT PROJECT_MODULES_DISABLED) # Deterministic order.
00382 
00383   # order list to satisfy dependencies
00384   include (${BASIS_MODULE_PATH}/TopologicalSort.cmake)
00385   topological_sort (PROJECT_MODULES_ENABLED "" "_DEPENDS")
00386 
00387   # remove external dependencies
00388   set (L)
00389   foreach (MODULE ${PROJECT_MODULES_ENABLED})
00390     if (${MODULE}_DECLARED)
00391       list (APPEND L "${MODULE}")
00392     endif ()
00393   endforeach ()
00394   set (PROJECT_MODULES_ENABLED "${L}")
00395   unset (L)
00396 
00397   # report what will be built
00398   if (PROJECT_MODULES_ENABLED)
00399     message (STATUS "Enabled modules [${PROJECT_MODULES_ENABLED}].")
00400   endif ()
00401 
00402   # turn options ON for modules that are required by other modules
00403   foreach (MODULE ${PROJECT_MODULES})
00404     if (DEFINED MODULE_${MODULE} # there was an option for the user
00405         AND NOT MODULE_${MODULE} # user did not set it to ON themself
00406         AND NOT ${MODULE}_IN_ALL # BUILD_ALL_MODULES was not set ON
00407         AND ${MODULE}_NEEDED_BY) # module is needed by other module(s)
00408       set (MODULE_${MODULE} ON CACHE BOOL "Request building module ${MODULE}." FORCE)
00409       message ("Enabled module ${MODULE}, needed by [${${MODULE}_NEEDED_BY}].")
00410     endif ()
00411   endforeach ()
00412 endmacro ()
00413 
00414 # ----------------------------------------------------------------------------
00415 ## @brief Configure public header files.
00416 #
00417 # Configure public header files whose file name ends with the .in.
00418 # Moreover, if @c BASIS_COPY_INCLUDES_TO_BINARY_DIR is @c TRUE, this function
00419 # copies all other files to the build tree as well, using the same relative
00420 # paths as will be used for the installation.
00421 #
00422 # @sa BASIS_CONFIGURE_INCLUDES
00423 function (basis_configure_public_headers)
00424   # --------------------------------------------------------------------------
00425   # settings
00426 
00427   # log file which lists the configured header files
00428   set (CMAKE_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}PublicHeaders.cmake")
00429   # cache of currently defined CMake variables
00430   set (CACHE_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}PublicHeadersCache.txt")
00431 
00432   # considered extensions
00433   set (
00434     EXTENSIONS
00435       ".h"
00436       ".hh"
00437       ".hpp"
00438       ".hxx"
00439       ".inl"
00440       ".txx"
00441       ".inc"
00442   )
00443 
00444   # considered include directories
00445   basis_get_relative_path (INCLUDE_DIR "${PROJECT_SOURCE_DIR}" "${PROJECT_INCLUDE_DIR}")
00446   set (INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/${INCLUDE_DIR}")
00447 
00448   # dump currently defined CMake variables such that these can be used to
00449   # configure the .in header files during the build step
00450   basis_dump_variables ("${CACHE_FILE}")
00451 
00452   # --------------------------------------------------------------------------
00453   # common arguments to following commands
00454   # Attention: Arguments which have a CMake list as value cannot be set this way,
00455   #            i.e., the arguments PROJECTS_INCLUDE_DIRS and EXTENSIONS.
00456   set (COMMON_ARGS
00457     -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
00458     -D "INCLUDE_PREFIX=${INCLUDE_PREFIX}"
00459     -D "AUTO_PREFIX_INCLUDES=${BASIS_AUTO_PREFIX_INCLUDES}"
00460     -D "VARIABLE_NAME=PUBLIC_HEADERS"
00461   )
00462 
00463   # --------------------------------------------------------------------------
00464   # clean up last run before the error because a file was added/removed
00465   file (REMOVE "${CMAKE_FILE}.tmp")
00466   file (REMOVE "${CMAKE_FILE}.updated")
00467   if (EXISTS "${CMAKE_FILE}")
00468     # required to be able to remove now obsolete files from the build tree
00469     file (RENAME "${CMAKE_FILE}" "${CMAKE_FILE}.tmp")
00470   endif ()
00471 
00472   # --------------------------------------------------------------------------
00473   # configure public header files
00474   if (BASIS_VERBOSE)
00475     message (STATUS "Configuring public header files...")
00476   endif ()
00477 
00478   execute_process (
00479     COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00480             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00481             -D "EXTENSIONS=${EXTENSIONS}"
00482             -D "INCLUDES_CHECK_EXCLUDE=${BASIS_INCLUDES_CHECK_EXCLUDE}"
00483             -D "INCLUDE_FILE=${CACHE_FILE}"
00484             -D "CMAKE_FILE=${CMAKE_FILE}"
00485             -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00486     RESULT_VARIABLE RT
00487   )
00488 
00489   if (RT EQUAL 0)
00490     execute_process (
00491       COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
00492     )
00493   else ()
00494     message (FATAL_ERROR "Failed to configure public header files!")
00495   endif ()
00496 
00497   if (NOT EXISTS "${CMAKE_FILE}")
00498     message (FATAL_ERROR "File ${CMAKE_FILE} not generated as it should have been!")
00499   endif ()
00500 
00501   # remove header files from build tree which were copied there before but
00502   # are part of a now disabled module or were simply removed from the source tree
00503   if (EXISTS "${CMAKE_FILE}.tmp")
00504     execute_process (
00505       # Compare current list of headers to list of previously configured files.
00506       # If the lists differ, this command removes files which have been removed
00507       # from the directory tree with root PROJECT_INCLUDE_DIR also from the
00508       # tree with root directory BINARY_INCLUDE_DIR.
00509       COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00510               -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00511               -D "OUTPUT_FILE=${CMAKE_FILE}.tmp"
00512               -D "REFERENCE_FILE=${CMAKE_FILE}"
00513               -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
00514       VERBATIM
00515     )
00516     file (REMOVE "${CMAKE_FILE}.tmp")
00517     if (NOT RT EQUAL 0)
00518       message (FATAL_ERROR "Failed to remove obsolete header files from build tree."
00519                            " Remove the ${BINARY_INCLUDE_DIR} directory and re-run CMake.")
00520     endif ()
00521   endif ()
00522 
00523   if (BASIS_VERBOSE)
00524     message (STATUS "Configuring public header files... - done")
00525   endif ()
00526 
00527   # We need a list of the configured files to add them as dependency of the
00528   # custom build targets such that these get re-build whenever a file changed.
00529   # Additionally, including this file here which is modified whenever a
00530   # header file is added or removed triggeres a re-configuration of the
00531   # build system which is required to re-execute this function and adjust
00532   # these custom build targets.
00533 
00534   include ("${CMAKE_FILE}")
00535 
00536   # --------------------------------------------------------------------------
00537   # check if any header was added or removed (always out-of-date)
00538 
00539   # error message displayed when a file was added or removed which requires
00540   # a reconfiguration of the build system
00541   set (ERRORMSG "You have either added, removed, or renamed a public header file")
00542   if (NOT BASIS_AUTO_PREFIX_INCLUDES)
00543     list (APPEND ERRORMSG " with a .in suffix in the file name")
00544   endif ()
00545   list (APPEND ERRORMSG ". Therefore, the build system needs to be"
00546                         " re-configured. Either try to build again which will"
00547                         " trigger CMake and re-configure the build system or"
00548                         " run CMake manually.")
00549   basis_list_to_string (ERRORMSG ${ERRORMSG})
00550 
00551   # custom command which globs the files in the project's include directory
00552   set (COMMENT "Checking if public header files were added or removed")
00553   if (PROJECT_IS_MODULE)
00554     set (COMMENT "${COMMENT} to ${PROJECT_NAME} module")
00555   endif ()
00556   add_custom_command (
00557     OUTPUT  "${CMAKE_FILE}.tmp"
00558     COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00559             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00560             -D "EXTENSIONS=${EXTENSIONS}"
00561             -D "INCLUDES_CHECK_EXCLUDE=${BASIS_INCLUDES_CHECK_EXCLUDE}"
00562             -D "CMAKE_FILE=${CMAKE_FILE}.tmp"
00563             -D "PREVIEW=TRUE" # do not actually configure the files
00564             -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00565     COMMENT "${COMMENT}"
00566     VERBATIM
00567   )
00568 
00569   # custom target to detect whether a file was added or removed
00570   basis_make_target_uid (CHECK_HEADERS_TARGET headers_check)
00571   if (PROJECT_IS_MODULE)
00572     set (CHECK_HEADERS_TARGET "${CHECK_HEADERS_TARGET}_${PROJECT_NAME_LOWER}")
00573   endif ()
00574   add_custom_target (
00575     ${CHECK_HEADERS_TARGET} ALL
00576     # trigger execution of custom command that generates the list
00577     # of current files in the project's include directory
00578     DEPENDS "${CMAKE_FILE}.tmp"
00579     # Compare current list of headers to list of previously configured files.
00580     # If the lists differ, the build of this target fails with the given error message.
00581     COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00582             -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00583             -D "OUTPUT_FILE=${CMAKE_FILE}"
00584             -D "REFERENCE_FILE=${CMAKE_FILE}.tmp"
00585             -D "ERRORMSG=${ERRORMSG}"
00586             -D "REMOVE_FILES_IF_DIFFERENT=TRUE" # triggers reconfigure on next build
00587             -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
00588     # remove temporary file again to force its regeneration
00589     COMMAND "${CMAKE_COMMAND}" -E remove "${CMAKE_FILE}.tmp"
00590     VERBATIM
00591   )
00592   if (PROJECT_IS_MODULE)
00593     basis_add_dependencies (headers_check ${CHECK_HEADERS_TARGET})
00594   endif ()
00595 
00596   # --------------------------------------------------------------------------
00597   # add build command to re-configure public header files
00598   if (PUBLIC_HEADERS)
00599     set (COMMENT "Configuring public header files")
00600     if (PROJECT_IS_MODULE)
00601       set (COMMENT "${COMMENT} of ${PROJECT_NAME} module")
00602     endif ()
00603     add_custom_command (
00604       OUTPUT  "${CMAKE_FILE}.updated" # do not use same file as included
00605                                       # before otherwise CMake will re-configure
00606                                       # the build system next time
00607       COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
00608               -D "PROJECT_INCLUDE_DIRS=${INCLUDE_DIRS}"
00609               -D "EXTENSIONS=${EXTENSIONS}"
00610               -D "INCLUDES_CHECK_EXCLUDE=${BASIS_INCLUDES_CHECK_EXCLUDE}"
00611               -D "INCLUDE_FILE=${CACHE_FILE}"
00612               -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
00613       COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
00614       DEPENDS ${PUBLIC_HEADERS}
00615       COMMENT "${COMMENT}"
00616       VERBATIM
00617     )
00618     basis_make_target_uid (CONFIGURE_HEADERS_TARGET headers)
00619     if (PROJECT_IS_MODULE)
00620       set (CONFIGURE_HEADERS_TARGET "${CONFIGURE_HEADERS_TARGET}_${PROJECT_NAME_LOWER}")
00621     endif ()
00622     add_custom_target (
00623       ${CONFIGURE_HEADERS_TARGET} ALL
00624       DEPENDS ${CHECK_HEADERS_TARGET} "${CMAKE_FILE}.updated"
00625       SOURCES ${PUBLIC_HEADERS}
00626     )
00627     if (PROJECT_IS_MODULE)
00628       basis_add_dependencies (headers ${CONFIGURE_HEADERS_TARGET})
00629     endif ()
00630   endif ()
00631 
00632   # --------------------------------------------------------------------------
00633   # add include directories
00634   if (NOT BASIS_AUTO_PREFIX_INCLUDES)
00635     basis_include_directories (BEFORE "${PROJECT_INCLUDE_DIR}")
00636   endif ()
00637   basis_include_directories (BEFORE "${BINARY_INCLUDE_DIR}")
00638   # Attention: BASIS includes public header files which are named the
00639   #            same as system-wide header files. Therefore, avoid to add
00640   #            include/sbia/basis/ to the include search path.
00641   if (NOT PROJECT_NAME MATCHES "^BASIS$")
00642     basis_include_directories (BEFORE "${BINARY_INCLUDE_DIR}/${INCLUDE_PREFIX}")
00643     if (NOT BASIS_AUTO_PREFIX_INCLUDES)
00644       basis_include_directories (BEFORE "${PROJECT_INCLUDE_DIR}/${INCLUDE_PREFIX}")
00645     endif ()
00646   endif ()
00647 endfunction ()
00648 
00649 # ----------------------------------------------------------------------------
00650 ## @brief Configure root documentation files.
00651 #
00652 # The root documentation files are located in the top-level directory of the
00653 # project's source tree. These are, in particular, the
00654 # * @c AUTHORS.txt file with information on the authors of the software,
00655 # * @c COPYING.txt file with copyright and licensing information,
00656 # * @c README.txt file,
00657 # * @c INSTALL.txt file with build and installation instructions,
00658 # * @c WELCOME.txt file with text used as welcome text of the installer.
00659 # where the top-level project requires all of these files except of the
00660 # @c WELCOME.txt file which defaults to the readme file. Modules of a project
00661 # usually do not include any of these files. Otherwise, the content of the
00662 # module's documentation file is appended to the corresponding file of the
00663 # top-level project.
00664 macro (basis_configure_root_documentation_files)
00665   foreach (F AUTHORS COPYING README INSTALL WELCOME)
00666     if (EXISTS "${PROJECT_SOURCE_DIR}/${F}.txt")
00667       set (PROJECT_${F}_FILE "${PROJECT_SOURCE_DIR}/${F}.txt")
00668       if (PROJECT_IS_MODULE)
00669         file (READ "${PROJECT_${F}_FILE}" T)
00670         file (
00671           APPEND "${BASIS_PROJECT_${F}_FILE}"
00672           "\n\n\n"
00673           "------------------------------------------------------------------------------\n"
00674           "${PROJECT_NAME} Module\n"
00675           "------------------------------------------------------------------------------\n"
00676           "${T}"
00677         )
00678       else ()
00679         set (BASIS_PROJECT_${F}_FILE "${PROJECT_BINARY_DIR}/${F}.txt")
00680         # do not use configure_file() to copy the file, otherwise CMake will
00681         # update the build system only because we modified this file in the if-clause
00682         execute_process (COMMAND "${CMAKE_COMMAND}" -E copy "${PROJECT_${F}_FILE}" "${BASIS_PROJECT_${F}_FILE}")
00683         # use extension on Windows, but leave it out on Unix
00684         get_filename_component (N "${F}" NAME_WE)
00685         get_filename_component (E "${F}" EXT)
00686         if (WIN32)
00687           if (NOT E)
00688             set (E ".txt")
00689           endif ()
00690         else ()
00691           if ("${E}" STREQUAL ".txt")
00692             set (E "")
00693           endif ()
00694         endif ()
00695         set (N "${N}${E}")
00696         # install file
00697         install (
00698           FILES       "${PROJECT_BINARY_DIR}/${F}.txt"
00699           DESTINATION "${INSTALL_DOC_DIR}"
00700           RENAME      "${N}"
00701           OPTIONAL
00702         )
00703       endif ()
00704     elseif (NOT F MATCHES "WELCOME" AND NOT PROJECT_IS_MODULE)
00705       message (FATAL_ERROR "Project requires a ${F}.txt file in ${PROJECT_SOURCE_DIR}!")
00706     endif ()
00707   endforeach ()
00708 endmacro ()
00709 
00710 # ----------------------------------------------------------------------------
00711 ## @brief Get build time stamp.
00712 #
00713 # The build time stamp is used as an alternative to the version and revision
00714 # information in @c PROJECT_VERSION_AND_REVISION if version is invalid, i.e.,
00715 # set to 0.0.0 as is the case for development branches, and now revision
00716 # from a revision control system is available.
00717 function (basis_get_build_timestamp TIMESTAMP)
00718   if (WIN32)
00719     execute_process (
00720       COMMAND "${BASIS_MODULE_PATH}/buildtimestamp.cmd"
00721       RESULT_VARIABLE RT
00722       OUTPUT_VARIABLE BUILD_TIMESTAMP
00723       ERROR_QUIET
00724       OUTPUT_STRIP_TRAILING_WHITESPACE
00725     )
00726   else ()
00727     execute_process (
00728       COMMAND "date" -u "+%Y.%m.%d (%H:%M UTC)"
00729       RESULT_VARIABLE RT
00730       OUTPUT_VARIABLE BUILD_TIMESTAMP
00731       ERROR_QUIET
00732       OUTPUT_STRIP_TRAILING_WHITESPACE
00733     )
00734   endif ()
00735   if (RT EQUAL 0)
00736     set (${TIMESTAMP} "${BUILD_TIMESTAMP}" PARENT_SCOPE)
00737   else ()
00738     set (${TIMESTAMP} PARENT_SCOPE)
00739   endif ()
00740 endfunction ()
00741 
00742 # ----------------------------------------------------------------------------
00743 ## @brief Initialize project, calls CMake's project() command.
00744 #
00745 # @sa basis_project()
00746 # @sa basis_project_impl()
00747 #
00748 # @returns Sets the following non-cached CMake variables:
00749 # @retval PROJECT_NAME_LOWER             Project name in all lowercase letters.
00750 # @retval PROJECT_NAME_UPPER             Project name in all uppercase letters.
00751 # @retval PROJECT_NAME_INFIX             Project name used as infix for installation
00752 #                                        directories and namespace identifiers.
00753 #                                        In particular, the project name in either
00754 #                                        all lowercase or mixed case starting with
00755 #                                        an uppercase letter depending on whether
00756 #                                        the @c PROJECT_NAME has mixed case or not.
00757 # @retval PROJECT_REVISION               Revision number of Subversion controlled
00758 #                                        source tree or 0 if the source tree is
00759 #                                        not under revision control.
00760 # @retval PROJECT_VERSION_AND_REVISION   A string of project version and revision
00761 #                                        that can be used for the output of
00762 #                                        version information. The format of this
00763 #                                        string is either one of the following:
00764 #                                          - "version 1.0.0 (revision 42)"
00765 #                                          - "version 1.0.0" (if revision unknown)
00766 #                                          - "revision 42" (if version is 0.0.0)
00767 #                                          - "version unknown" (otherwise)
00768 macro (basis_project_initialize)
00769   # --------------------------------------------------------------------------
00770   # CMake version and policies
00771   cmake_minimum_required (VERSION 2.8.4)
00772 
00773   # Add policies introduced with CMake versions newer than the one specified
00774   # above. These policies would otherwise trigger a policy not set warning by
00775   # newer CMake versions.
00776 
00777   if (POLICY CMP0016)
00778     cmake_policy (SET CMP0016 NEW)
00779   endif ()
00780 
00781   if (POLICY CMP0017)
00782     cmake_policy (SET CMP0017 NEW)
00783   endif ()
00784 
00785   # --------------------------------------------------------------------------
00786   # reset
00787 
00788   # only set if not set by top-level project before configuring a module
00789   basis_set_if_empty (PROJECT_IS_MODULE FALSE)
00790 
00791   # hide it here to avoid that it shows up in the GUI on error
00792   set (CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "" FORCE)
00793 
00794   # --------------------------------------------------------------------------
00795   # project meta-data
00796   if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
00797     set (BASIS_basis_project_CALLED FALSE)
00798     include ("${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
00799     if (NOT BASIS_basis_project_CALLED)
00800       message (FATAL_ERROR "Missing basis_project() command in BasisProject.cmake!")
00801     endif ()
00802   else ()
00803     message (FATAL_ERROR "Missing BasisProject.cmake file!")
00804   endif ()
00805 
00806   # --------------------------------------------------------------------------
00807   # Slicer extension
00808 
00809   # Unfortunately, Slicer invokes the project() command in the SlicerConfig.cmake
00810   # file. Furthermore, it must be the first package to be included. Therefore,
00811   # scan dependencies for Slicer, which is an indicator that this project is
00812   # an extension for Slicer and look for it here already.
00813 
00814   list (FIND PROJECT_DEPENDS "Slicer" IDX)
00815   if (IDX EQUAL -1)
00816     # A module that only optionally can be a Slicer Extension by itself
00817     # shall not be build as Slicer Extension if this project is not an
00818     # extension for Slicer. Only a project can be a Slicer Extension.
00819     if (NOT PROJECT_IS_MODULE)
00820       list (FIND PROJECT_OPTIONAL_DEPENDS "Slicer" IDX)
00821       if (NOT IDX EQUAL -1)
00822         basis_find_package ("Slicer" QUIET)
00823         if (Slicer_FOUND)
00824           basis_use_package ("Slicer")
00825         endif ()
00826       endif ()
00827     endif ()
00828   else ()
00829     # If a module requires Slicer, the top-level project must be a
00830     # Slicer Extension and hence specify Slicer as a dependency.
00831     if (PROJECT_IS_MODULE AND NOT Slicer_FOUND)
00832       message (FATAL_ERROR "Module ${PROJECT_NAME} requires Slicer, which "
00833                            "indicates it is a Slicer Extension. Therefore, "
00834                            "the top-level project must be a Slicer Extension "
00835                            "as well and declare Slicer as a dependency such "
00836                            "that the configuration file of the Slicer package "
00837                            "is included before the modules are being configured.")
00838     endif ()
00839     basis_find_package ("Slicer" REQUIRED)
00840     if (Slicer_FOUND)
00841       basis_use_package ("Slicer")
00842     else ()
00843       message (FATAL_ERROR "Package Slicer not found!")
00844       return ()
00845     endif ()
00846   endif ()
00847 
00848   # --------------------------------------------------------------------------
00849   # project()
00850 
00851   # note that SlicerConfig.cmake will invoke project() by itself
00852   if (NOT Slicer_FOUND)
00853     project ("${PROJECT_NAME}")
00854   endif ()
00855 
00856   # work-around for issue with CMAKE_PROJECT_NAME always being set to 'Project'
00857   if ("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
00858     set_property (CACHE CMAKE_PROJECT_NAME PROPERTY VALUE "${PROJECT_NAME}")
00859   endif ()
00860 
00861   # convert project name to upper and lower case only, respectively
00862   string (TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER)
00863   string (TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER)
00864 
00865   # This variable is in particular used in the Directories.cmake.in template
00866   # file to separate the files of modules of a project from each other
00867   # if BASIS_USE_MODULE_NAMESPACES is set to ON.
00868   if (WINDOWS)
00869     # Windows users prefer mixed case directory names
00870     set (PROJECT_NAME_INFIX "${PROJECT_NAME}")
00871   else ()
00872     # Unix users often prefer lowercase directory names
00873     set (PROJECT_NAME_INFIX "${PROJECT_NAME_LOWER}")
00874   endif ()
00875 
00876   # get revision of project
00877   #
00878   # Note: Use revision when branch, i.e., either trunk, a branch, or a tag
00879   #       has been modified last. For tags, this should in particular
00880   #       correspond to the revision when the tag was created.
00881   basis_svn_get_last_changed_revision ("${PROJECT_SOURCE_DIR}" PROJECT_REVISION)
00882 
00883   # extract version numbers from version string
00884   basis_version_numbers (
00885     "${PROJECT_VERSION}"
00886       PROJECT_VERSION_MAJOR
00887       PROJECT_VERSION_MINOR
00888       PROJECT_VERSION_PATCH
00889   )
00890 
00891   set (PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
00892 
00893   # version information string
00894   if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?")
00895     if (PROJECT_REVISION)
00896       set (PROJECT_VERSION_AND_REVISION "revision ${PROJECT_REVISION}")
00897     else ()
00898       basis_get_build_timestamp (BUILD_TIMESTAMP)
00899       if (BUILD_TIMESTAMP)
00900         set (PROJECT_VERSION_AND_REVISION "build ${BUILD_TIMESTAMP}")
00901       else ()
00902         set (PROJECT_VERSION_AND_REVISION "version unknown")
00903       endif ()
00904     endif ()
00905   else ()
00906     set (PROJECT_VERSION_AND_REVISION "version ${PROJECT_VERSION}")
00907     if (PROJECT_REVISION)
00908       set (PROJECT_VERSION_AND_REVISION "${PROJECT_VERSION_AND_REVISION} (revision ${PROJECT_REVISION})")
00909     endif ()
00910   endif ()
00911 
00912   # version number for use in Perl modules
00913   set (PROJECT_VERSION_PERL "${PROJECT_VERSION_MAJOR}")
00914   if (PROJECT_VERSION_MAJOR LESS 10)
00915     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.0${PROJECT_VERSION_MINOR}")
00916   else ()
00917     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.${PROJECT_VERSION_MINOR}")
00918   endif ()
00919   if (PROJECT_VERSION_PATCH LESS 10)
00920     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_0${PROJECT_VERSION_PATCH}")
00921   else ()
00922     set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_${PROJECT_VERSION_PATCH}")
00923   endif ()
00924 
00925   # print project information
00926   if (BASIS_VERBOSE AND NOT PROJECT_IS_MODULE)
00927     message (STATUS "Project:")
00928     message (STATUS "  Name:    ${PROJECT_NAME}")
00929     message (STATUS "  Version: ${PROJECT_VERSION_AND_REVISION}")
00930   endif ()
00931 
00932   # --------------------------------------------------------------------------
00933   # reset project properties - *after* PROJECT_NAME was set
00934 
00935   # The following variables are used across BASIS macros and functions. They
00936   # in particular remember information added by one function or macro which
00937   # is required by another function or macro.
00938   #
00939   # These variables need to be properties such that they can be set in
00940   # subdirectories. Moreover, they have to be assigned with the project's
00941   # root source directory such that a top-level project's properties are restored
00942   # after this subproject is finalized such that the top-level project itself can
00943   # be finalized properly.
00944   #
00945   # Attention: In particular the IMPORTED_* properties are already used
00946   #            during the import of targets when including the use files of
00947   #            external packages. Hence, this property has to be reset before.
00948 
00949   # see basis_add_imported_target()
00950   basis_set_project_property (PROPERTY IMPORTED_TARGETS "")
00951   basis_set_project_property (PROPERTY IMPORTED_TYPES "")
00952   basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "")
00953   basis_set_project_property (PROPERTY IMPORTED_RANKS "")
00954   # see basis_include_directories()
00955   basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS "")
00956   # see add_executable(), add_library()
00957   basis_set_project_property (PROPERTY TARGETS "")
00958   # see basis_add_*() functions
00959   basis_set_project_property (PROPERTY EXPORT_TARGETS "")
00960   basis_set_project_property (PROPERTY CUSTOM_EXPORT_TARGETS "")
00961   basis_set_project_property (PROPERTY TEST_EXPORT_TARGETS "")
00962   # see basis_add_script()
00963   basis_set_project_property (PROPERTY PROJECT_USES_PYTHON_UTILITIES FALSE)
00964   basis_set_project_property (PROPERTY PROJECT_USES_PERL_UTILITIES   FALSE)
00965   basis_set_project_property (PROPERTY PROJECT_USES_BASH_UTILITIES   FALSE)
00966   # yet unused
00967   basis_set_project_property (PROPERTY PROJECT_USES_JAVA_UTILITIES   FALSE)
00968   basis_set_project_property (PROPERTY PROJECT_USES_MATLAB_UTILITIES FALSE)
00969 endmacro ()
00970 
00971 # ----------------------------------------------------------------------------
00972 ## @brief Initialize project settings.
00973 macro (basis_initialize_settings)
00974   # configure and include BASIS directory structure
00975   if (PROJECT_NAME MATCHES "^BASIS$")
00976     set (FilesystemHierarchyStandardPageRef "@ref FilesystemHierarchyStandard")
00977   else ()
00978     set (FilesystemHierarchyStandardPageRef "Filesystem Hierarchy Standard")
00979   endif ()
00980   configure_file (
00981     "${BASIS_MODULE_PATH}/Directories.cmake.in"
00982     "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Directories.cmake"
00983     @ONLY
00984   )
00985 
00986   include ("${PROJECT_BINARY_DIR}/${PROJECT_NAME}Directories.cmake")
00987 
00988   # include project specific settings
00989   #
00990   # This file enables the project to modify the default behavior of BASIS,
00991   # but only if BASIS allows so as the BASIS settings are included afterwards.
00992   if (EXISTS "${PROJECT_CONFIG_DIR}/Settings.cmake.in")
00993     configure_file (
00994       "${PROJECT_CONFIG_DIR}/Settings.cmake.in"
00995       "${BINARY_CONFIG_DIR}/Settings.cmake"
00996       @ONLY
00997     )
00998     include ("${BINARY_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE)
00999   else ()
01000     include ("${PROJECT_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE OPTIONAL)
01001   endif ()
01002 
01003   # configure and include BASIS settings
01004   configure_file (
01005     "${BASIS_MODULE_PATH}/ProjectSettings.cmake.in"
01006     "${BINARY_CONFIG_DIR}/ProjectSettings.cmake"
01007     @ONLY
01008   )
01009 
01010   include ("${BINARY_CONFIG_DIR}/ProjectSettings.cmake" NO_POLICY_SCOPE)
01011 endmacro ()
01012 
01013 # ----------------------------------------------------------------------------
01014 ## @brief Find packages this project depends on.
01015 macro (basis_find_packages)
01016   set (BASIS_SET_TARGET_PROPERTIES_IMPORT TRUE) # see set_target_properties()
01017 
01018   # Attention: This function is used before the Directories.cmake.in and
01019   #            Settings.cmake.in files were configured and included.
01020   set (PROJECT_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/config")
01021 
01022   # --------------------------------------------------------------------------
01023   # add project config directory to CMAKE_MODULE_PATH
01024   set (CMAKE_MODULE_PATH "${PROJECT_CONFIG_DIR}" ${CMAKE_MODULE_PATH})
01025 
01026   # --------------------------------------------------------------------------
01027   # Depends.cmake
01028 
01029   # This file is in particular of interest if a dependency is required if
01030   # certain modules are enabled, but not others.
01031   #
01032   # For example, if a module is a Slicer extension which integrates the tools
01033   # of other modules as extension for Slicer, the package configuration of
01034   # Slicer has to be included first and hence, in this case Slicer must be
01035   # added as dependency of the top-level project. Not so, however, if the Slicer
01036   # extension module is not enabled. Thus, the top-level project can look for
01037   # Slicer using basis_find_package() only if the Slicer Extension module
01038   # is enabled. It can check for this using the variable <Module>_ENABLED or
01039   # the list PROJECT_MODULES_ENABLED.
01040 
01041   # Attention: This function is used before the Directories.cmake.in and
01042   #            Settings.cmake.in files were configured and included.
01043   include ("${PROJECT_CONFIG_DIR}/Depends.cmake" OPTIONAL)
01044 
01045   # --------------------------------------------------------------------------
01046   # Slicer must be found before all others...
01047   if (PROJECT_DEPENDS          MATCHES "^Slicer(-[0-9.]+)?({})?" OR
01048       PROJECT_OPTIONAL_DEPENDS MATCHES "^Slicer(-[0-9.]+)?({})?")
01049     basis_find_package ("Slicer${CMAKE_MATCH_1}")
01050     basis_use_package  ("Slicer")
01051   endif ()
01052 
01053   # --------------------------------------------------------------------------
01054   # optional dependencies - first in case a newer version of a package
01055   #                         can optionally be used, but at least an older
01056   #                         one is required
01057   foreach (P IN LISTS PROJECT_OPTIONAL_DEPENDS)
01058     basis_find_package ("${P}" QUIET)
01059     basis_use_package ("${P}")
01060   endforeach ()
01061 
01062   # --------------------------------------------------------------------------
01063   # optional test dependencies
01064   if (BUILD_TESTING)
01065     foreach (P IN LISTS PROJECT_OPTIONAL_TEST_DEPENDS)
01066       basis_find_package ("${P}" QUIET)
01067       basis_use_package ("${P}")
01068     endforeach ()
01069   endif ()
01070 
01071   # --------------------------------------------------------------------------
01072   # required dependencies
01073   foreach (P IN LISTS PROJECT_DEPENDS)
01074     basis_find_package ("${P}" REQUIRED)
01075     basis_use_package ("${P}"  REQUIRED)
01076   endforeach ()
01077 
01078   # --------------------------------------------------------------------------
01079   # test dependencies
01080   if (BUILD_TESTING)
01081     foreach (P IN LISTS PROJECT_TEST_DEPENDS)
01082       basis_find_package ("${P}") # do not use REQUIRED here to be able to show
01083       basis_use_package ("${P}")  # error message below
01084       if (P MATCHES "^(.*)-([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(\\.[0-9]+)?$")
01085         set (P "${CMAKE_MATCH_1}")
01086       endif ()
01087       string (TOUPPER "${P}" U)
01088       if (NOT ${P}_FOUND AND NOT ${U}_FOUND)
01089         message (FATAL_ERROR "Could not find package ${P}! It is required by "
01090                              "the tests of ${PROJECT_NAME}. Either specify "
01091                              "package location manually and try again or "
01092                              "disable testing by setting BUILD_TESTING to OFF.")
01093         
01094       endif ()
01095     endforeach ()
01096   endif ()
01097 
01098   unset (P)
01099 
01100   set (BASIS_SET_TARGET_PROPERTIES_IMPORT FALSE) # see set_target_properties()
01101 endmacro ()
01102 
01103 # ============================================================================
01104 # finalization
01105 # ============================================================================
01106 
01107 # ----------------------------------------------------------------------------
01108 ## @brief Finalize build configuration of project.
01109 #
01110 # This macro has to be called at the end of the root CMakeLists.txt file of
01111 # each BASIS project initialized by basis_project().
01112 #
01113 # The project configuration files are generated by including the CMake script
01114 # PROJECT_CONFIG_DIR/GenerateConfig.cmake when this file exists or using
01115 # the default script of BASIS.
01116 #
01117 # @returns Finalizes addition of custom build targets, i.e., adds the
01118 #          custom targets which actually perform the build of these targets.
01119 #          See basis_add_custom_finalize() function.
01120 #
01121 # @sa basis_project_initialize()
01122 macro (basis_project_finalize)
01123   # write convenience file to setup MATLAB environment
01124   if (MATLAB_FOUND)
01125     basis_create_addpaths_mfile ()
01126   endif ()
01127 
01128   # --------------------------------------------------------------------------
01129   # module
01130 
01131   if (PROJECT_IS_MODULE)
01132 
01133     # finalize addition of custom targets
01134     #
01135     # Note: Should be done for each module as the finalize functions
01136     #       might use the PROJECT_* variables.
01137     basis_add_custom_finalize ()
01138     # generate configuration files
01139     include ("${BASIS_MODULE_PATH}/GenerateConfig.cmake")
01140 
01141   # --------------------------------------------------------------------------
01142   # project
01143 
01144   else ()
01145 
01146     # install public headers
01147     if (NOT BASIS_AUTO_PREFIX_INCLUDES)
01148       basis_install_directory ("${PROJECT_INCLUDE_DIR}" "${INSTALL_INCLUDE_DIR}" OPTIONAL)
01149     endif ()
01150     set (PUBLIC_HEADERS_EXCLUDE_PATTERNS)
01151     foreach (P IN LISTS BASIS_UTILITIES_PUBLIC_HEADERS)
01152       list (APPEND PUBLIC_HEADERS_EXCLUDE_PATTERNS "PATTERN" "${P}" EXCLUDE)
01153     endforeach ()
01154     basis_install_directory (
01155       "${BINARY_INCLUDE_DIR}"
01156       "${INSTALL_INCLUDE_DIR}"
01157       OPTIONAL
01158       ${PUBLIC_HEADERS_EXCLUDE_PATTERNS}
01159     )
01160     unset (PUBLIC_HEADERS_EXCLUDE_PATTERNS)
01161     # "parse" public header files to check if C++ BASIS utilities are included
01162     if (BASIS_UTILITIES_PUBLIC_HEADERS)
01163       set (PUBLIC_HEADERS)
01164       if (PROJECT_INCLUDE_DIR AND NOT BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
01165         if (BASIS_CONFIGURE_INCLUDES)
01166           file (GLOB_RECURSE PUBLIC_HEADERS "${BINARY_INCLUDE_DIR}/*.h")
01167         else ()
01168           file (GLOB_RECURSE PUBLIC_HEADERS "${PROJECT_INCLUDE_DIR}/*.h")
01169         endif ()
01170       endif ()
01171       set (REGEX)
01172       foreach (P IN LISTS BASIS_UTILITIES_PUBLIC_HEADERS)
01173         basis_get_relative_path (H "${BINARY_INCLUDE_DIR}" "${P}")
01174         if (NOT REGEX)
01175           set (REGEX "#include +[<\"](${H}")
01176         else ()
01177           set (REGEX "${REGEX}|${H}")
01178         endif ()
01179       endforeach ()
01180       if (REGEX AND PUBLIC_HEADERS)
01181         set (REGEX "${REGEX})[>\"]")
01182         foreach (P ${PUBLIC_HEADERS})
01183           file (READ "${P}" C)
01184           if (C MATCHES "${REGEX}")
01185             set (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES TRUE)
01186             break ()
01187           endif ()
01188         endforeach ()
01189       endif ()
01190       # install public headers of C++ utilities
01191       if (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
01192         install (
01193           FILES       ${BASIS_UTILITIES_PUBLIC_HEADERS}
01194           DESTINATION "${INSTALL_INCLUDE_DIR}/sbia/${PROJECT_NAME_LOWER}"
01195           COMPONENT   "${BASIS_LIBRARY_COMPONENT}"
01196         )
01197       endif ()
01198     endif ()
01199     # inherit PROJECT_USES_*_UTILITIES properties from modules
01200     foreach (L IN ITEMS PYTHON PERL BASH)
01201       foreach (M IN LISTS PROJECT_MODULES_ENABLED)
01202         basis_get_project_property (P ${M} PROJECT_USES_${L}_UTILITIES)
01203         if (P)
01204           basis_set_project_property (PROPERTY PROJECT_USES_${L}_UTILITIES TRUE)
01205           break ()
01206         endif ()
01207       endforeach ()
01208     endforeach ()
01209     # configure auxiliary modules
01210     basis_configure_auxiliary_modules ()
01211     # configure ExecutableTargetInfo modules
01212     basis_configure_ExecutableTargetInfo ()
01213     # finalize addition of custom targets
01214     basis_add_custom_finalize ()
01215     basis_add_init_py_target ()
01216     # generate configuration files
01217     include ("${BASIS_MODULE_PATH}/GenerateConfig.cmake")
01218     # package software
01219     include ("${BASIS_MODULE_PATH}/BasisPack.cmake")
01220 
01221   endif ()
01222 endmacro ()
01223 
01224 
01225 ## @}
01226 # end of Doxygen group
01227 
01228 # ============================================================================
01229 # root CMakeLists.txt implementation
01230 # ============================================================================
01231 
01232 # ----------------------------------------------------------------------------
01233 ## @brief Implementation of root <tt>CMakeLists.txt</tt> file of BASIS project.
01234 #
01235 # This macro implements the entire logic of the top-level
01236 # <tt>CMakeLists.txt</tt> file. At first, the project is initialized and the
01237 # BASIS settings configured using the project information given in the
01238 # <tt>BasisProject.cmake</tt> file which must be located in the same directory.
01239 # The, the code in the <tt>CMakeLists.txt</tt> files in the subdirectories is
01240 # executed in order. At the end, the configuration of the build system is
01241 # finalized, including in particular also the addition of custom build targets
01242 # which perform the actual build of custom build targets such as the ones build
01243 # using the MATLAB Compiler.
01244 #
01245 # @sa BasisProject.cmake
01246 # @sa basis_project()
01247 #
01248 # @ingroup CMakeAPI
01249 macro (basis_project_impl)
01250   # --------------------------------------------------------------------------
01251   # initialize project
01252   basis_project_initialize ()
01253 
01254   # --------------------------------------------------------------------------
01255   # load information of modules
01256   if (NOT PROJECT_IS_MODULE)
01257     basis_project_modules ()
01258   endif ()
01259 
01260   if (BASIS_DEBUG)
01261     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterDetectionOfModules.cmake")
01262   endif ()
01263 
01264   # --------------------------------------------------------------------------
01265   # find packages
01266 
01267   # any package use file must be included after PROJECT_NAME was set as the
01268   # imported targets are added to the <Project>_TARGETS property using
01269   # basis_set_project_property() in add_executable() and add_library()
01270   if (BASIS_USE_FILE)
01271     include ("${BASIS_USE_FILE}" NO_POLICY_SCOPE)
01272   endif ()
01273   basis_find_packages ()
01274 
01275   if (BASIS_DEBUG)
01276     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFindDependencies.cmake")
01277   endif ()
01278 
01279   # --------------------------------------------------------------------------
01280   # initialize settings
01281   basis_initialize_settings ()
01282 
01283   # --------------------------------------------------------------------------
01284   # assertions
01285   basis_buildtree_asserts ()
01286   basis_installtree_asserts ()
01287 
01288   # --------------------------------------------------------------------------
01289   # root documentation files
01290   basis_configure_root_documentation_files ()
01291 
01292   # --------------------------------------------------------------------------
01293   # enable testing
01294   if (NOT PROJECT_IS_MODULE)
01295     include ("${BASIS_MODULE_PATH}/BasisTest.cmake")
01296     basis_disable_testing_if_no_tests ()
01297   endif ()
01298 
01299   # --------------------------------------------------------------------------
01300   # public header files
01301   basis_include_directories (BEFORE "${PROJECT_CODE_DIR}")
01302   basis_configure_public_headers ()
01303 
01304   # --------------------------------------------------------------------------
01305   # pre-configure C++ utilities
01306   if (NOT PROJECT_IS_MODULE)
01307     basis_configure_auxiliary_sources (
01308       BASIS_UTILITIES_SOURCES
01309       BASIS_UTILITIES_HEADERS
01310       BASIS_UTILITIES_PUBLIC_HEADERS
01311     )
01312 
01313     basis_use_auxiliary_sources (
01314       BASIS_UTILITIES_SOURCES
01315       BASIS_UTILITIES_HEADERS
01316     )
01317   endif ()
01318 
01319   # --------------------------------------------------------------------------
01320   # top-level project settings
01321   if (NOT PROJECT_IS_MODULE)
01322     # used to only build one global BASIS utilities library for all modules
01323     set (BASIS_PROJECT_NAME            "${PROJECT_NAME}")
01324     set (BASIS_PROJECT_NAMESPACE_CMAKE "${PROJECT_NAMESPACE_CMAKE}")
01325     set (BASIS_BINARY_ARCHIVE_DIR      "${BINARY_ARCHIVE_DIR}")
01326     set (BASIS_INSTALL_ARCHIVE_DIR     "${INSTALL_ARCHIVE_DIR}")
01327   endif ()
01328 
01329   # --------------------------------------------------------------------------
01330   # subdirectories
01331   if (BASIS_DEBUG)
01332     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterInitialization.cmake")
01333   endif ()
01334 
01335   # build modules
01336   if (NOT PROJECT_IS_MODULE)
01337     foreach (MODULE IN LISTS PROJECT_MODULES_ENABLED)
01338       if (BASIS_VERBOSE)
01339         message (STATUS "Configuring module ${MODULE}...")
01340       endif ()
01341       set (PROJECT_IS_MODULE TRUE)
01342       add_subdirectory ("${MODULE_${MODULE}_SOURCE_DIR}" "${MODULE_${MODULE}_BINARY_DIR}")
01343       set (PROJECT_IS_MODULE FALSE)
01344       if (BASIS_VERBOSE)
01345         message (STATUS "Configuring module ${MODULE}... - done")
01346       endif ()
01347     endforeach ()
01348   endif ()
01349 
01350   # build source code
01351   if (EXISTS "${PROJECT_CODE_DIR}")
01352     add_subdirectory ("${PROJECT_CODE_DIR}")
01353   endif ()
01354 
01355   # install auxiliary data files
01356   if (EXISTS "${PROJECT_DATA_DIR}")
01357     add_subdirectory ("${PROJECT_DATA_DIR}")
01358   endif ()
01359 
01360   # build software tests
01361   if (EXISTS "${PROJECT_TESTING_DIR}" AND BUILD_TESTING)
01362    add_subdirectory ("${PROJECT_TESTING_DIR}")
01363   endif ()
01364 
01365   # build/install example application
01366   if (EXISTS "${PROJECT_EXAMPLE_DIR}" AND BUILD_EXAMPLE)
01367     add_subdirectory ("${PROJECT_EXAMPLE_DIR}")
01368   endif ()
01369 
01370   # build/install package documentation
01371   if (EXISTS "${PROJECT_DOC_DIR}" AND BUILD_DOCUMENTATION)
01372     add_subdirectory ("${PROJECT_DOC_DIR}")
01373   endif ()
01374 
01375   if (BASIS_DEBUG)
01376     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterSubdirectories.cmake")
01377   endif ()
01378 
01379   # ----------------------------------------------------------------------------
01380   # change log
01381   if (NOT PROJECT_IS_MODULE)
01382     basis_add_changelog ()
01383   endif ()
01384 
01385   # --------------------------------------------------------------------------
01386   # finalize
01387   basis_project_finalize ()
01388 
01389   # install symbolic links
01390   if (INSTALL_LINKS)
01391     basis_install_links ()
01392     # documentation
01393     # Note: Not all CPack generators preserve symbolic links to directories
01394     # Note: This is not part of the filesystem hierarchy standard of Linux,
01395     #       but of the standard of certain distributions including Ubuntu.
01396     #if (NOT PROJECT_IS_MODULE AND INSTALL_SINFIX AND BASIS_INSTALL_SINFIX)
01397     #  basis_install_link (
01398     #    "${INSTALL_DOC_DIR}"
01399     #    "share/doc/${BASIS_INSTALL_SINFIX}"
01400     #  )
01401     #endif ()
01402   endif ()
01403 
01404   if (NOT PROJECT_IS_MODULE)
01405     # add uninstall target
01406     basis_add_uninstall ()
01407     # add code to generate uninstaller at the end of the installation
01408     #
01409     # Attention: This must be done at last and using a add_subdirector() call
01410     #            such that the code is executed by the root cmake_install.cmake
01411     #            at last!
01412     add_subdirectory ("${BASIS_MODULE_PATH}/uninstall" "${PROJECT_BINARY_DIR}/uninstall")
01413   endif ()
01414 
01415   if (BASIS_DEBUG)
01416     basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFinalization.cmake")
01417   endif ()
01418 endmacro ()