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