CommonTools.cmake
Go to the documentation of this file.
00001 ############################################################################## 00002 # @file CommonTools.cmake 00003 # @brief Definition of common CMake functions. 00004 # 00005 # Copyright (c) 2011, 2012, 2013 University of Pennsylvania. All rights reserved.<br /> 00006 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00007 # 00008 # Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00009 # 00010 # @ingroup CMakeTools 00011 ############################################################################## 00012 00013 if (__BASIS_COMMONTOOLS_INCLUDED) 00014 return () 00015 else () 00016 set (__BASIS_COMMONTOOLS_INCLUDED TRUE) 00017 endif () 00018 00019 00020 include (CMakeParseArguments) 00021 00022 00023 ## @addtogroup CMakeUtilities 00024 # @{ 00025 00026 00027 # ============================================================================ 00028 # find other packages 00029 # ============================================================================ 00030 00031 # ---------------------------------------------------------------------------- 00032 ## @brief Overloaded find_package() command. 00033 # 00034 # This macro calls CMake's 00035 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package"> 00036 # find_package()</a> command and converts obsolete all uppercase "<PKG>_<VAR>" 00037 # variables to case-sensitive "<Pkg>_<VAR>" variables. 00038 # It further ensures that the global variables CMAKE_FIND_LIBRARY_SUFFIXES 00039 # and CMAKE_FIND_EXECUTABLE_SUFFIX are reset to the values they had before 00040 # the call to find_package(). This is required if the "Find<Pkg>.cmake" module 00041 # has modified these variables, but not restored their initial value. 00042 macro (find_package) 00043 if (BASIS_DEBUG) 00044 message ("find_package(${ARGV})") 00045 endif () 00046 # attention: find_package() can be recursive. Hence, use "stack" to keep 00047 # track of library suffixes. Further note that we need to 00048 # maintain a list of lists, which is not supported by CMake. 00049 list (APPEND _BASIS_FIND_LIBRARY_SUFFIXES "{${CMAKE_FIND_LIBRARY_SUFFIXES}}") 00050 list (APPEND _BASIS_FIND_EXECUTABLE_SUFFIX "${CMAKE_FIND_EXECUTABLE_SUFFIX}") 00051 _find_package(${ARGV}) 00052 # map obsolete <PKG>_* variables to case-sensitive <Pkg>_* 00053 string (TOUPPER "${ARGV0}" _FP_ARGV0_U) 00054 foreach (_FP_VAR IN ITEMS FOUND DIR USE_FILE 00055 VERSION VERSION_STRING VERSION_MAJOR VERSION_MINOR VERSION_PATCH 00056 INCLUDE_DIR INCLUDE_DIRS INCLUDE_PATH 00057 LIBRARY_DIR LIBRARY_DIRS LIBRARY_PATH) 00058 if (NOT DEFINED ${ARGV0}_${_FP_VAR} AND DEFINED ${_FP_ARGV0_U}_${_FP_VAR}) 00059 set (${ARGV0}_${_FP_VAR} "${${_FP_ARGV0_U}_${_FP_VAR}}") 00060 endif () 00061 endforeach () 00062 unset (_FP_VAR) 00063 unset (_FP_ARGV0_U) 00064 # restore CMAKE_FIND_LIBRARY_SUFFIXES 00065 string (REGEX REPLACE ";?{([^}]*)}$" "" _BASIS_FIND_LIBRARY_SUFFIXES "${_BASIS_FIND_LIBRARY_SUFFIXES}") 00066 set (CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_MATCH_1}") 00067 # restore CMAKE_FIND_EXECUTABLE_SUFFIX 00068 list (LENGTH _BASIS_FIND_EXECUTABLE_SUFFIX _FP_LAST) 00069 if (_FP_LAST GREATER 0) 00070 math (EXPR _FP_LAST "${_FP_LAST} - 1") 00071 list (REMOVE_AT _BASIS_FIND_EXECUTABLE_SUFFIX ${_FP_LAST}) 00072 endif () 00073 unset (_FP_LAST) 00074 endmacro () 00075 00076 # ---------------------------------------------------------------------------- 00077 ## @brief Tokenize dependency specification. 00078 # 00079 # This function parses a dependency specification such as 00080 # "ITK-4.1{TestKernel,IO}" into the package name, i.e., ITK, the requested 00081 # (minimum) package version, i.e., 4.1, and a list of package components, i.e., 00082 # TestKernel and IO. A valid dependency specification must specify the package 00083 # name of the dependency (case-sensitive). The version and components 00084 # specification are optional. Note that the components specification may 00085 # be separated by an arbitrary number of whitespace characters including 00086 # newlines. The same applies to the specification of the components themselves. 00087 # This allows one to format the dependency specification as follows, for example: 00088 # @code 00089 # ITK { 00090 # TestKernel, 00091 # IO 00092 # } 00093 # @endcode 00094 # 00095 # @param [in] DEP Dependency specification, i.e., "<Pkg>[-<version>][{<Component1>[,...]}]". 00096 # @param [out] PKG Package name. 00097 # @param [out] VER Package version. 00098 # @param [out] CMP List of package components. 00099 function (basis_tokenize_dependency DEP PKG VER CMP) 00100 set (CMPS) 00101 if (DEP MATCHES "^([^ ]+)[ \\n\\t]*{([^}]*)}$") 00102 set (DEP "${CMAKE_MATCH_1}") 00103 string (REPLACE "," ";" COMPONENTS "${CMAKE_MATCH_2}") 00104 foreach (C IN LISTS COMPONENTS) 00105 string (STRIP "${C}" C) 00106 list (APPEND CMPS ${C}) 00107 endforeach () 00108 endif () 00109 if (DEP MATCHES "^(.*)-([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(\\.[0-9]+)?$") 00110 set (${PKG} "${CMAKE_MATCH_1}" PARENT_SCOPE) 00111 set (${VER} "${CMAKE_MATCH_2}${CMAKE_MATCH_3}${CMAKE_MATCH_4}${CMAKE_MATCH_5}" PARENT_SCOPE) 00112 else () 00113 set (${PKG} "${DEP}" PARENT_SCOPE) 00114 set (${VER} "" PARENT_SCOPE) 00115 endif () 00116 set (${CMP} "${CMPS}" PARENT_SCOPE) 00117 endfunction () 00118 00119 # ---------------------------------------------------------------------------- 00120 ## @brief Find external software package or other project module. 00121 # 00122 # This function replaces CMake's 00123 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package"> 00124 # find_package()</a> command and extends its functionality. 00125 # In particular, if the given package name is the name of another module 00126 # of this project (the top-level project), it ensures that this module is 00127 # found instead of an external package. 00128 # 00129 # If the package is found, but only optionally used, i.e., the @c REQUIRED 00130 # argument was not given to this macro, a <tt>USE_<Pkg></tt> option is 00131 # added by this macro which is by default @c ON. This option can be set to 00132 # @c OFF by the user in order to force the <tt><Pkg>_FOUND</tt> variable 00133 # to be set to @c FALSE again even if the package was found. This allows the 00134 # user to specify which of the optional dependencies should actually not be 00135 # used for the build of the software even though these packages are installed 00136 # on their system. 00137 # 00138 # @param [in] PACKAGE Name of other package. Optionally, the package name 00139 # can include a version specification as suffix which 00140 # is separated by the package name using a dash (-), i.e., 00141 # <Package>[-major[.minor[.patch[.tweak]]]]. 00142 # If a version specification is given, it is passed on as 00143 # @c version argument to CMake's 00144 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package"> 00145 # find_package()</a> command. 00146 # @param [in] ARGN Advanced arguments for 00147 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package"> 00148 # find_package()</a>. 00149 # 00150 # @retval <PACKAGE>_FOUND Whether the given package was found. 00151 # 00152 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package 00153 # 00154 # @ingroup CMakeAPI 00155 macro (basis_find_package PACKAGE) 00156 # parse arguments 00157 CMAKE_PARSE_ARGUMENTS ( 00158 ARGN 00159 "EXACT;QUIET;REQUIRED" 00160 "" 00161 "COMPONENTS" 00162 ${ARGN} 00163 ) 00164 # -------------------------------------------------------------------------- 00165 # tokenize dependency specification 00166 basis_tokenize_dependency ("${PACKAGE}" PKG VER CMPS) 00167 list (APPEND ARGN_COMPONENTS ${CMPS}) 00168 unset (CMPS) 00169 if (ARGN_UNPARSED_ARGUMENTS MATCHES "^[0-9]+(\\.[0-9]+)*$" AND VER) 00170 message (FATAL_ERROR "Cannot use both version specification as part of " 00171 "package name and explicit version argument.") 00172 else () 00173 set (VER "${CMAKE_MATCH_0}") 00174 endif () 00175 # -------------------------------------------------------------------------- 00176 # preserve <PKG>_DIR variable which might get reset if different versions 00177 # of the package are searched or if package is optional and deselected 00178 set (PKG_DIR "${${PKG}_DIR}") 00179 # -------------------------------------------------------------------------- 00180 # some debugging output 00181 if (BASIS_DEBUG) 00182 message ("** basis_find_package()") 00183 message ("** Package: ${PKG}") 00184 if (VER) 00185 message ("** Version: ${VER}") 00186 endif () 00187 if (ARGN_COMPONENTS) 00188 message ("** Components: [${ARGN_COMPONENTS}]") 00189 endif () 00190 endif () 00191 # -------------------------------------------------------------------------- 00192 # find other modules of same project 00193 set (PKG_IS_MODULE FALSE) 00194 if (PROJECT_IS_MODULE) 00195 # allow modules to specify top-level project as dependency 00196 if (PKG MATCHES "^${BASIS_PROJECT_NAME}$") 00197 if (BASIS_DEBUG) 00198 message ("** This is the top-level project.") 00199 endif () 00200 set (${PKG}_FOUND TRUE) 00201 # look for other module of top-level project 00202 elseif (PROJECT_MODULES MATCHES "(^|;)${PKG}(;|$)") 00203 set (PKG_IS_MODULE TRUE) 00204 if (PROJECT_MODULES_ENABLED MATCHES "(^|;)${PKG}(;|$)") 00205 if (BASIS_DEBUG) 00206 message ("** Identified it as other module of this project.") 00207 endif () 00208 include ("${${PKG}_DIR}/${BASIS_PROJECT_PACKAGE_CONFIG_PREFIX}${PKG}Config.cmake") 00209 set (${PKG}_FOUND TRUE) 00210 else () 00211 set (${PKG}_FOUND FALSE) 00212 endif () 00213 endif () 00214 # -------------------------------------------------------------------------- 00215 # find bundled packages 00216 elseif (BUNDLE_PROJECTS MATCHES "(^|;)${PKG}(;|$)") 00217 if (EXISTS "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG}Config.cmake") 00218 set (PKG_CONFIG_FILE "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG}Config.cmake") 00219 else () 00220 string (TOLOWER "${PKG}" PKG_L) 00221 if (EXISTS "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG_L}-config.cmake") 00222 set (PKG_CONFIG_FILE "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG_L}-config.cmake") 00223 else () 00224 set (PKG_CONFIG_FILE) 00225 endif () 00226 unset (PKG_L) 00227 endif () 00228 if (PKG_CONFIG_FILE) 00229 if (BASIS_DEBUG) 00230 message ("** Identified it as other package of this bundle.") 00231 endif () 00232 get_filename_component (PKG_CONFIG_DIR "${PKG_CONFIG_FILE}" PATH) 00233 basis_set_or_update_value (${PKG}_DIR "${PKG_CONFIG_DIR}") 00234 include ("${PKG_CONFIG_FILE}") 00235 set (${PKG}_FOUND TRUE) 00236 unset (PKG_CONFIG_DIR) 00237 endif () 00238 unset (PKG_CONFIG_FILE) 00239 endif () 00240 # -------------------------------------------------------------------------- 00241 # otherwise, look for external package 00242 if (NOT PKG_IS_MODULE) 00243 # ------------------------------------------------------------------------ 00244 # make <PKG>_DIR variable visible in GUI by caching it if not done yet 00245 basis_is_cached (_BFP_CACHED ${PKG}_DIR) 00246 if (DEFINED ${PKG}_DIR AND NOT _BFP_CACHED) 00247 set (${PKG}_DIR "${${PKG}_DIR}" CACHE PATH "Installation directory of ${PKG}.") 00248 endif () 00249 unset (_BFP_CACHED) 00250 # ------------------------------------------------------------------------ 00251 # determine if additional components of found package should be discovered 00252 set (FIND_ADDITIONAL_COMPONENTS FALSE) 00253 if (${PKG}_FOUND) 00254 if (${PKG}_FOUND_COMPONENTS AND ARGN_COMPONENTS) 00255 foreach (_C ${ARGN_COMPONENTS}) 00256 list (FIND ${PKG}_FOUND_COMPONENTS "${_C}" _IDX) 00257 if (_IDX EQUAL -1) 00258 set (FIND_ADDITIONAL_COMPONENTS TRUE) 00259 break () 00260 endif () 00261 endforeach () 00262 elseif (${PKG}_FOUND_COMPONENTS OR ARGN_COMPONENTS) 00263 set (FIND_ADDITIONAL_COMPONENTS TRUE) 00264 endif () 00265 endif () 00266 # ------------------------------------------------------------------------ 00267 # look for external package if not found or additional components needed 00268 if (NOT ${PKG}_FOUND OR FIND_ADDITIONAL_COMPONENTS) 00269 set (_${PKG}_FOUND "${${PKG}_FOUND}") # used to decide what the intersection of 00270 # of multiple find invocations for the same 00271 # package with different components will be 00272 # ---------------------------------------------------------------------- 00273 # reset other <PKG>_* variables if <PKG>_DIR changed 00274 if (_${PKG}_DIR AND ${PKG}_DIR) # internal _<PKG>_DIR cache entry set below 00275 basis_sanitize_for_regex (_BFP_RE "${${PKG}_DIR}") 00276 if (NOT _${PKG}_DIR MATCHES "^${_BFP_RE}$") 00277 get_cmake_property (_BFP_VARS VARIABLES) 00278 foreach (_BFP_VAR IN LISTS _BFP_VARS) 00279 if (_BFP_VAR MATCHES "^${PKG}_" AND NOT _BFP_VAR MATCHES "^${PKG}_DIR$") 00280 basis_is_cached (_BFP_CACHED ${_BFP_VAR}) 00281 if (_BFP_CACHED) 00282 get_property (_BFP_TYPE CACHE ${_BFP_VAR} PROPERTY TYPE) 00283 if (NOT _BFP_TYPE MATCHES INTERNAL) 00284 set_property (CACHE ${_BFP_VAR} PROPERTY VALUE "${_BFP_VAR}-NOTFOUND") 00285 set_property (CACHE ${_BFP_VAR} PROPERTY TYPE INTERNAL) 00286 endif () 00287 endif () 00288 endif () 00289 endforeach () 00290 unset (_BFP_VAR) 00291 unset (_BFP_VARS) 00292 unset (_BFP_CACHED) 00293 unset (_BFP_TYPE) 00294 endif () 00295 unset (_BFP_RE) 00296 endif () 00297 # ---------------------------------------------------------------------- 00298 # hide or show already defined <PKG>_DIR cache entry 00299 if (DEFINED ${PKG}_DIR AND DEFINED USE_${PKG}) 00300 if (USE_${PKG}) 00301 mark_as_advanced (CLEAR ${PKG}_DIR) 00302 else () 00303 mark_as_advanced (FORCE ${PKG}_DIR) 00304 endif () 00305 endif () 00306 # ---------------------------------------------------------------------- 00307 # find external packages 00308 if (DEFINED USE_${PKG} AND NOT USE_${PKG}) 00309 set (${PKG}_FOUND FALSE) 00310 else () 00311 # circumvent issue with CMake's find_package() interpreting these variables 00312 # relative to the current binary directory instead of the top-level directory 00313 if (${PKG}_DIR AND NOT IS_ABSOLUTE "${${PKG}_DIR}") 00314 set (${PKG}_DIR "${CMAKE_BINARY_DIR}/${${PKG}_DIR}") 00315 get_filename_component (${PKG}_DIR "${${PKG}_DIR}" ABSOLUTE) 00316 endif () 00317 # moreover, users tend to specify the installation prefix instead of the 00318 # actual directory containing the package configuration file 00319 if (IS_DIRECTORY "${${PKG}_DIR}") 00320 list (INSERT CMAKE_PREFIX_PATH 0 "${${PKG}_DIR}") 00321 endif () 00322 # now look for the package 00323 set (FIND_ARGN) 00324 if (ARGN_EXACT) 00325 list (APPEND FIND_ARGN "EXACT") 00326 endif () 00327 if (ARGN_QUIET) 00328 list (APPEND FIND_ARGN "QUIET") 00329 endif () 00330 if (ARGN_COMPONENTS) 00331 list (APPEND FIND_ARGN "COMPONENTS" ${ARGN_COMPONENTS}) 00332 elseif (ARGN_REQUIRED) 00333 list (APPEND FIND_ARGN "REQUIRED") 00334 endif () 00335 if ("${PKG}" MATCHES "^(MFC|wxWidgets)$") 00336 # if Find<Pkg>.cmake prints status message, don't do it here 00337 find_package (${PKG} ${VER} ${FIND_ARGN}) 00338 else () 00339 set (_STATUS "Looking for ${PKG}") 00340 if (VER) 00341 set (_STATUS "${_STATUS} ${VER}") 00342 endif () 00343 if (ARGN_COMPONENTS) 00344 set (_STATUS "${_STATUS} [${ARGN_COMPONENTS}]") 00345 endif () 00346 if (NOT ARGN_REQUIRED) 00347 set (_STATUS "${_STATUS} (optional)") 00348 endif () 00349 set (_STATUS "${_STATUS}...") 00350 message (STATUS "${_STATUS}") 00351 find_package (${PKG} ${VER} ${FIND_ARGN}) 00352 # set common <Pkg>_VERSION_STRING variable if possible and not set 00353 if (NOT DEFINED ${PKG}_VERSION_STRING) 00354 if (PKG MATCHES "^PythonInterp$") 00355 set (${PKG}_VERSION_STRING ${PYTHON_VERSION_STRING}) 00356 elseif (PKG MATCHES "^JythonInterp$") 00357 set (${PKG}_VERSION_STRING ${JYTHON_VERSION_STRING}) 00358 elseif (DEFINED ${PKG}_VERSION_MAJOR) 00359 set (${PKG}_VERSION_STRING ${${PKG}_VERSION_MAJOR}) 00360 if (DEFINED ${PKG}_VERSION_MINOR) 00361 set (${PKG}_VERSION_STRING ${${PKG}_VERSION_STRING}.${${PKG}_VERSION_MINOR}) 00362 if (DEFINED ${PKG}_VERSION_PATCH) 00363 set (${PKG}_VERSION_STRING ${${PKG}_VERSION_STRING}.${${PKG}_VERSION_PATCH}) 00364 endif () 00365 endif () 00366 elseif (DEFINED ${PKG}_VERSION) 00367 set (${PKG}_VERSION_STRING ${${PKG}_VERSION}) 00368 endif () 00369 endif () 00370 # verbose output of information about found package 00371 if (${PKG}_FOUND) 00372 set (_STATUS "${_STATUS} - found") 00373 if (BASIS_VERBOSE) 00374 if (DEFINED ${PKG}_VERSION_STRING AND NOT ${PKG}_VERSION_STRING MATCHES "^0.0.0$") 00375 set (_STATUS "${_STATUS} v${${PKG}_VERSION_STRING}") 00376 endif () 00377 if (${PKG}_DIR) 00378 set (_STATUS "${_STATUS} at ${${PKG}_DIR}") 00379 endif () 00380 endif () 00381 else () 00382 set (_STATUS "${_STATUS} - not found") 00383 endif () 00384 message (STATUS "${_STATUS}") 00385 endif () 00386 # remember which components where found already 00387 if (${PKG}_FOUND AND ARGN_COMPONENTS) 00388 if (${PKG}_FOUND_COMPONENTS) 00389 list (APPEND ARGN_COMPONENTS ${${PKG}_FOUND_COMPONENTS}) 00390 list (REMOVE_DUPLICATES ARGN_COMPONENTS) 00391 endif () 00392 set (${PKG}_FOUND_COMPONENTS "${ARGN_COMPONENTS}") 00393 endif () 00394 # if previously components of this package where found and the additional 00395 # components are only optional, set <PKG>_FOUND to TRUE again 00396 if (_${PKG}_FOUND AND NOT ARGN_REQUIRED) 00397 set (${PKG}_FOUND TRUE) 00398 endif () 00399 # provide option which allows users to disable use of not required packages 00400 if (${PKG}_FOUND AND NOT ARGN_REQUIRED) 00401 option (USE_${PKG} "Enable/disable use of package ${PKG}." ON) 00402 mark_as_advanced (USE_${PKG}) 00403 if (NOT USE_${PKG}) 00404 set (${PKG}_FOUND FALSE) 00405 endif () 00406 endif () 00407 endif () 00408 # ---------------------------------------------------------------------- 00409 # reset <PKG>_DIR variable for possible search of different package version 00410 if (PKG_DIR AND NOT ${PKG}_DIR) 00411 basis_set_or_update_value (${PKG}_DIR "${PKG_DIR}") 00412 endif () 00413 # ---------------------------------------------------------------------- 00414 # remember current/previous <PKG>_DIR 00415 # (used above to reset other <PKG>_* variables whenever <PKG>_DIR changed) 00416 if (DEFINED ${PKG}_DIR) 00417 set (_${PKG}_DIR "${${PKG}_DIR}" CACHE INTERNAL "(Previous) Installation directory of ${PKG}." FORCE) 00418 endif () 00419 endif () 00420 endif () 00421 # -------------------------------------------------------------------------- 00422 # unset locally used variables 00423 unset (PACKAGE_DIR) 00424 unset (PKG) 00425 unset (VER) 00426 unset (USE_PKG_OPTION) 00427 unset (PKG_IS_MODULE) 00428 unset (FIND_ADDITIONAL_COMPONENTS) 00429 endmacro () 00430 00431 # ---------------------------------------------------------------------------- 00432 ## @brief Use found package. 00433 # 00434 # This macro includes the package's use file if the variable @c <Pkg>_USE_FILE 00435 # is defined. Otherwise, it adds the include directories to the search path 00436 # for include paths if possible. Therefore, the corresponding package 00437 # configuration file has to set the proper CMake variables, i.e., 00438 # either @c <Pkg>_INCLUDES, @c <Pkg>_INCLUDE_DIRS, or @c <Pkg>_INCLUDE_DIR. 00439 # 00440 # If the given package name is the name of another module of this project 00441 # (the top-level project), this function includes the use file of the specified 00442 # module. 00443 # 00444 # @note As some packages still use all captial variables instead of ones 00445 # prefixed by a string that follows the same capitalization as the 00446 # package's name, this function also considers these if defined instead. 00447 # Hence, if @c <PKG>_INCLUDES is defined, but not @c <Pkg>_INCLUDES, it 00448 # is used in place of the latter. 00449 # 00450 # @note According to an email on the CMake mailing list, it is not a good idea 00451 # to use basis_link_directories() any more given that the arguments to 00452 # basis_target_link_libraries() are absolute paths to the library files. 00453 # Therefore, this code is commented and not used. It remains here as a 00454 # reminder only. 00455 # 00456 # @param [in] PACKAGE Name of other package. Optionally, the package name 00457 # can include a version specification as suffix which 00458 # is separated by the package name using a dash (-), i.e., 00459 # <Package>[-major[.minor[.patch[.tweak]]]]. 00460 # A version specification is simply ignored by this macro. 00461 # 00462 # @ingroup CMakeAPI 00463 macro (basis_use_package PACKAGE) 00464 # tokenize package specification 00465 basis_tokenize_dependency ("${PACKAGE}" PKG VER CMPS) 00466 # use package 00467 foreach (A IN ITEMS "WORKAROUND FOR NOT BEING ABLE TO USE RETURN") 00468 if (BASIS_DEBUG) 00469 message ("** basis_use_package()") 00470 message ("** Package: ${PKG}") 00471 endif () 00472 if (PROJECT_IS_MODULE) 00473 # allow modules to specify top-level project as dependency 00474 if (PKG MATCHES "^${BASIS_PROJECT_NAME}$") 00475 if (BASIS_DEBUG) 00476 message ("** This is the top-level project.") 00477 endif () 00478 break () # instead of return() 00479 # use other module of top-level project 00480 elseif (PROJECT_MODULES MATCHES "(^|;)${PKG}(;|$)") 00481 if (${PKG}_FOUND) 00482 if (BASIS_DEBUG) 00483 message ("** Include package use file of other module.") 00484 endif () 00485 include ("${${PKG}_USE_FILE}") 00486 break () # instead of return() 00487 else () 00488 message (FATAL_ERROR "Module ${PKG} not found! This must be a mistake of BASIS." 00489 " Report this issue to the maintainer of this package.") 00490 endif () 00491 endif () 00492 endif () 00493 # if this package is an external project, i.e., a project build as part 00494 # of the same superbuild as this project, set BUNDLE_PROJECT to TRUE. 00495 # it is used by (basis_)link_directories() and add_library() to mark 00496 # the imported link directories and target as belonging to the same 00497 # installation. this is in particular important for the RPATH settings. 00498 # whether this package is an external project or not, is decided by the 00499 # BUNDLE_PROJECTS variable which must be set using the -D option of 00500 # cmake to a list naming all the other packages which are part of the 00501 # superbuild. 00502 if (BUNDLE_PROJECTS) 00503 list (FIND BUNDLE_PROJECTS "${PKG}" IDX) 00504 if (IDX EQUAL -1) 00505 set (BUNDLE_PROJECT FALSE) 00506 else () 00507 set (BUNDLE_PROJECT TRUE) 00508 endif () 00509 endif () 00510 # use external package 00511 if (${PKG}_FOUND) 00512 # use package only if basis_use_package() not invoked before 00513 if (BASIS_USE_${PKG}_INCLUDED) 00514 if (BASIS_DEBUG) 00515 message ("** External package used before already.") 00516 endif () 00517 break () 00518 endif () 00519 if (${PKG}_USE_FILE) 00520 if (BASIS_DEBUG) 00521 message ("** Include package use file of external package.") 00522 endif () 00523 if (PKG MATCHES "^BASIS$") 00524 include ("${${PKG}_USE_FILE}" NO_POLICY_SCOPE) 00525 else () 00526 include ("${${PKG}_USE_FILE}") 00527 endif () 00528 else () 00529 if (BASIS_DEBUG) 00530 message ("** Use variables which were set by basis_find_package().") 00531 endif () 00532 # OpenCV 00533 if (PKG MATCHES "^OpenCV$") 00534 # the cv.h may be found as part of PerlLibs, the include path of 00535 # which is added at first by BASISConfig.cmake 00536 if (OpenCV_INCLUDE_DIRS) 00537 basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIRS}) 00538 elseif (OpenCV_INCLUDE_DIR) 00539 basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIR}) 00540 endif () 00541 # generic 00542 else () 00543 if (${PKG}_INCLUDE_DIRS) 00544 basis_include_directories (${${PKG}_INCLUDE_DIRS}) 00545 elseif (${PKG}_INCLUDES) 00546 basis_include_directories (${${PKG}_INCLUDES}) 00547 elseif (${PKG}_INCLUDE_PATH) 00548 basis_include_directories (${${PKG}_INCLUDE_PATH}) 00549 elseif (${PKG}_INCLUDE_DIR) 00550 basis_include_directories (${${PKG}_INCLUDE_DIR}) 00551 endif () 00552 endif () 00553 endif () 00554 set (BASIS_USE_${PKG}_INCLUDED TRUE) 00555 elseif (ARGC GREATER 1 AND "${ARGV1}" MATCHES "^REQUIRED$") 00556 if (BASIS_DEBUG) 00557 basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFind${PKG}.cmake") 00558 endif () 00559 message (FATAL_ERROR "Package ${PACKAGE} not found!") 00560 endif () 00561 # reset switch that identifies currently imported targets and link directories 00562 # as belonging to an external project which is part of the same superbuild 00563 set (BUNDLE_PROJECT FALSE) 00564 endforeach () 00565 endmacro () 00566 00567 # ============================================================================ 00568 # basis_get_filename_component / basis_get_relative_path 00569 # ============================================================================ 00570 00571 # ---------------------------------------------------------------------------- 00572 ## @brief Fixes CMake's 00573 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component"> 00574 # get_filename_component()</a> command. 00575 # 00576 # The get_filename_component() command of CMake returns the entire portion 00577 # after the first period (.) [including the period] as extension. However, 00578 # only the component following the last period (.) [including the period] 00579 # should be considered to be the extension. 00580 # 00581 # @note Consider the use of the basis_get_filename_component() macro as 00582 # an alias to emphasize that this function is different from CMake's 00583 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component"> 00584 # get_filename_component()</a> command. 00585 # 00586 # @param [in,out] ARGN Arguments as accepted by get_filename_component(). 00587 # 00588 # @returns Sets the variable named by the first argument to the requested 00589 # component of the given file path. 00590 # 00591 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component 00592 # @sa basis_get_filename_component() 00593 function (get_filename_component) 00594 if (ARGC LESS 3) 00595 message (FATAL_ERROR "[basis_]get_filename_component(): At least three arguments required!") 00596 elseif (ARGC GREATER 4) 00597 message (FATAL_ERROR "[basis_]get_filename_component(): Too many arguments!") 00598 endif () 00599 list (GET ARGN 0 VAR) 00600 list (GET ARGN 1 STR) 00601 list (GET ARGN 2 CMD) 00602 if (CMD MATCHES "^EXT") 00603 _get_filename_component (${VAR} "${STR}" ${CMD}) 00604 string (REGEX MATCHALL "\\.[^.]*" PARTS "${${VAR}}") 00605 list (LENGTH PARTS LEN) 00606 if (LEN GREATER 1) 00607 math (EXPR LEN "${LEN} - 1") 00608 list (GET PARTS ${LEN} ${VAR}) 00609 endif () 00610 elseif (CMD MATCHES "NAME_WE") 00611 _get_filename_component (${VAR} "${STR}" NAME) 00612 string (REGEX REPLACE "\\.[^.]*$" "" ${VAR} ${${VAR}}) 00613 else () 00614 _get_filename_component (${VAR} "${STR}" ${CMD}) 00615 endif () 00616 if (ARGC EQUAL 4) 00617 if (NOT ARGV3 MATCHES "^CACHE$") 00618 message (FATAL_ERROR "[basis_]get_filename_component(): Invalid fourth argument: ${ARGV3}!") 00619 else () 00620 set (${VAR} "${${VAR}}" CACHE STRING "") 00621 endif () 00622 else () 00623 set (${VAR} "${${VAR}}" PARENT_SCOPE) 00624 endif () 00625 endfunction () 00626 00627 # ---------------------------------------------------------------------------- 00628 ## @brief Alias for the overwritten get_filename_component() function. 00629 # 00630 # @sa get_filename_component() 00631 # 00632 # @ingroup CMakeAPI 00633 macro (basis_get_filename_component) 00634 get_filename_component (${ARGN}) 00635 endmacro () 00636 00637 # ---------------------------------------------------------------------------- 00638 ## @brief Get path relative to a given base directory. 00639 # 00640 # Unlike the file(RELATIVE_PATH ...) command of CMake which if @p PATH and 00641 # @p BASE are the same directory returns an empty string, this function 00642 # returns a dot (.) in this case instead. 00643 # 00644 # @param [out] REL @c PATH relative to @c BASE. 00645 # @param [in] BASE Path of base directory. If a relative path is given, it 00646 # is made absolute using basis_get_filename_component() 00647 # with ABSOLUTE as last argument. 00648 # @param [in] PATH Absolute or relative path. If a relative path is given 00649 # it is made absolute using basis_get_filename_component() 00650 # with ABSOLUTE as last argument. 00651 # 00652 # @returns Sets the variable named by the first argument to the relative path. 00653 # 00654 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:file 00655 # 00656 # @ingroup CMakeAPI 00657 function (basis_get_relative_path REL BASE PATH) 00658 if (BASE MATCHES "^$") 00659 message (FATAL_ERROR "Empty string given where (absolute) base directory path expected!") 00660 endif () 00661 if (PATH MATCHES "^$") 00662 set (PATH ".") 00663 endif () 00664 basis_get_filename_component (PATH "${PATH}" ABSOLUTE) 00665 basis_get_filename_component (BASE "${BASE}" ABSOLUTE) 00666 if (NOT PATH) 00667 message (FATAL_ERROR "basis_get_relative_path(): No PATH given!") 00668 endif () 00669 if (NOT BASE) 00670 message (FATAL_ERROR "basis_get_relative_path(): No BASE given!") 00671 endif () 00672 file (RELATIVE_PATH P "${BASE}" "${PATH}") 00673 if ("${P}" STREQUAL "") 00674 set (P ".") 00675 endif () 00676 set (${REL} "${P}" PARENT_SCOPE) 00677 endfunction () 00678 00679 # ============================================================================ 00680 # name / version 00681 # ============================================================================ 00682 00683 # ---------------------------------------------------------------------------- 00684 ## @brief Convert string to lowercase only or mixed case. 00685 # 00686 # Strings in all uppercase or all lowercase are converted to all lowercase 00687 # letters because these are usually used for acronymns. All other strings 00688 # are returned unmodified with the one exception that the first letter has 00689 # to be uppercase for mixed case strings. 00690 # 00691 # This function is in particular used to normalize the project name for use 00692 # in installation directory paths and namespaces. 00693 # 00694 # @param [out] OUT String in CamelCase. 00695 # @param [in] STR String. 00696 function (basis_normalize_name OUT STR) 00697 # strings in all uppercase or all lowercase such as acronymns are an 00698 # exception and shall be converted to all lowercase instead 00699 string (TOLOWER "${STR}" L) 00700 string (TOUPPER "${STR}" U) 00701 if ("${STR}" STREQUAL "${L}" OR "${STR}" STREQUAL "${U}") 00702 set (${OUT} "${L}" PARENT_SCOPE) 00703 # change first letter to uppercase 00704 else () 00705 string (SUBSTRING "${U}" 0 1 A) 00706 string (SUBSTRING "${STR}" 1 -1 B) 00707 set (${OUT} "${A}${B}" PARENT_SCOPE) 00708 endif () 00709 endfunction () 00710 00711 # ---------------------------------------------------------------------------- 00712 ## @brief Extract version numbers from version string. 00713 # 00714 # @param [in] VERSION Version string in the format "MAJOR[.MINOR[.PATCH]]". 00715 # @param [out] MAJOR Major version number if given or 0. 00716 # @param [out] MINOR Minor version number if given or 0. 00717 # @param [out] PATCH Patch number if given or 0. 00718 # 00719 # @returns See @c [out] parameters. 00720 function (basis_version_numbers VERSION MAJOR MINOR PATCH) 00721 if (VERSION MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?") 00722 if (CMAKE_MATCH_1) 00723 set (VERSION_MAJOR ${CMAKE_MATCH_1}) 00724 else () 00725 set (VERSION_MAJOR 0) 00726 endif () 00727 if (CMAKE_MATCH_2) 00728 set (VERSION_MINOR ${CMAKE_MATCH_2}) 00729 string (REGEX REPLACE "^\\." "" VERSION_MINOR "${VERSION_MINOR}") 00730 else () 00731 set (VERSION_MINOR 0) 00732 endif () 00733 if (CMAKE_MATCH_3) 00734 set (VERSION_PATCH ${CMAKE_MATCH_3}) 00735 string (REGEX REPLACE "^\\." "" VERSION_PATCH "${VERSION_PATCH}") 00736 else () 00737 set (VERSION_PATCH 0) 00738 endif () 00739 else () 00740 set (VERSION_MAJOR 0) 00741 set (VERSION_MINOR 0) 00742 set (VERSION_PATCH 0) 00743 endif () 00744 set ("${MAJOR}" "${VERSION_MAJOR}" PARENT_SCOPE) 00745 set ("${MINOR}" "${VERSION_MINOR}" PARENT_SCOPE) 00746 set ("${PATCH}" "${VERSION_PATCH}" PARENT_SCOPE) 00747 endfunction () 00748 00749 # ============================================================================ 00750 # set 00751 # ============================================================================ 00752 00753 # ---------------------------------------------------------------------------- 00754 ## @brief Set flag given mutually exclusive 00755 # ARGN_<FLAG> and ARGN_NO<FLAG> function arguments. 00756 # 00757 # @param [in] PREFIX Prefix of function arguments. Set to the first argument 00758 # of the CMAKE_PARSE_ARGUMENTS() command. 00759 # @param [out] FLAG Name of flag. 00760 # @param [in] DEFAULT Default flag value if neither <tt>ARGN_<FLAG;gt;</tt> 00761 # nor <tt>ARGN_NO<FLAG;gt;</tt> evaluates to true. 00762 macro (basis_set_flag PREFIX FLAG DEFAULT) 00763 if (${PREFIX}_${FLAG} AND ${PREFIX}_NO${FLAG}) 00764 message (FATAL_ERROR "Options ${FLAG} and NO${FLAG} are mutually exclusive!") 00765 endif () 00766 if (${PREFIX}_${FLAG}) 00767 set (${FLAG} TRUE) 00768 elseif (${PREFIX}_NO${FLAG}) 00769 set (${FLAG} FALSE) 00770 else () 00771 set (${FLAG} ${DEFAULT}) 00772 endif () 00773 endmacro () 00774 00775 # ---------------------------------------------------------------------------- 00776 ## @brief Determine if cache entry exists. 00777 # 00778 # @param [out] VAR Name of boolean result variable. 00779 # @param [in] ENTRY Name of cache entry. 00780 macro (basis_is_cached VAR ENTRY) 00781 if (DEFINED ${ENTRY}) 00782 get_property (${VAR} CACHE ${ENTRY} PROPERTY TYPE SET) 00783 else () 00784 set (${VAR} FALSE) 00785 endif () 00786 endmacro () 00787 00788 # ---------------------------------------------------------------------------- 00789 ## @brief Set type of variable. 00790 # 00791 # If the variable is cached, the type is updated, otherwise, a cache entry 00792 # of the given type with the current value of the variable is added. 00793 # 00794 # @param [in] VAR Name of variable. 00795 # @param [in] TYPE Desired type of variable. 00796 # @param [in] ARGN Optional DOC string used if variable was not cached before. 00797 macro (basis_set_or_update_type VAR TYPE) 00798 basis_is_cached (_CACHED ${VAR}) 00799 if (_CACHED) 00800 set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE}) 00801 else () 00802 set (${VAR} "${${VAR}}" CACHE ${TYPE} "${ARGN}" FORCE) 00803 endif () 00804 unset (_CACHED) 00805 endmacro () 00806 00807 # ---------------------------------------------------------------------------- 00808 ## @brief Change type of cached variable. 00809 # 00810 # If the variable is not cached, nothing is done. 00811 macro (basis_update_type_of_variable VAR TYPE) 00812 basis_is_cached (_CACHED ${VAR}) 00813 if (_CACHED) 00814 set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE}) 00815 endif () 00816 unset (_CACHED) 00817 endmacro () 00818 00819 # ---------------------------------------------------------------------------- 00820 ## @brief Set variable value. 00821 # 00822 # If the variable is cached, this function will update the cache value, 00823 # otherwise, it simply sets the CMake variable uncached to the given value(s). 00824 macro (basis_set_or_update_value VAR) 00825 basis_is_cached (_CACHED ${VAR}) 00826 if (_CACHED) 00827 if (ARGC GREATER 1) 00828 set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN}) 00829 else () 00830 set (${VAR} "" CACHE INTERNAL "" FORCE) 00831 endif () 00832 else () 00833 set (${VAR} ${ARGN}) 00834 endif () 00835 unset (_CACHED) 00836 endmacro () 00837 00838 # ---------------------------------------------------------------------------- 00839 ## @brief Update cache variable. 00840 macro (basis_update_value VAR) 00841 basis_is_cached (_CACHED ${VAR}) 00842 if (_CACHED) 00843 set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN}) 00844 endif () 00845 unset (_CACHED) 00846 endmacro () 00847 00848 # ---------------------------------------------------------------------------- 00849 ## @brief Set value of variable only if variable is not set already. 00850 # 00851 # @param [out] VAR Name of variable. 00852 # @param [in] ARGN Arguments to set() command excluding variable name. 00853 # 00854 # @returns Sets @p VAR if its value was not valid before. 00855 macro (basis_set_if_empty VAR) 00856 if (NOT ${VAR}) 00857 set (${VAR} ${ARGN}) 00858 endif () 00859 endmacro () 00860 00861 # ---------------------------------------------------------------------------- 00862 ## @brief Set value of variable only if variable is not defined yet. 00863 # 00864 # @param [out] VAR Name of variable. 00865 # @param [in] ARGN Arguments to set() command excluding variable name. 00866 # 00867 # @returns Sets @p VAR if it was not defined before. 00868 macro (basis_set_if_not_set VAR) 00869 if (NOT DEFINED "${VAR}") 00870 set ("${VAR}" ${ARGN}) 00871 endif () 00872 endmacro () 00873 00874 # ---------------------------------------------------------------------------- 00875 ## @brief Set path relative to script file. 00876 # 00877 # This function can be used in script configurations. It takes a variable 00878 # name and a path as input arguments. If the given path is relative, it makes 00879 # it first absolute using @c PROJECT_SOURCE_DIR. Then the path is made 00880 # relative to the directory of the built script file. A CMake variable of the 00881 # given name is set to the specified relative path. Optionally, a third 00882 # argument, the path used for building the script for the install tree 00883 # can be passed as well. If a relative path is given as this argument, 00884 # it is made absolute by prefixing it with @c CMAKE_INSTALL_PREFIX instead. 00885 # 00886 # @note This function may only be used in script configurations such as 00887 # in particular the ScriptConfig.cmake.in file. It requires that the 00888 # variables @c __DIR__ and @c BUILD_INSTALL_SCRIPT are set properly. 00889 # These variables are set by the configure_script() function. 00890 # Moreover, it makes use of the global @c CMAKE_INSTALL_PREFIX and 00891 # @c PROJECT_SOURCE_DIR variables. 00892 # 00893 # @param [out] VAR Name of the variable. 00894 # @param [in] PATH Path to directory or file. 00895 # @param [in] ARGV3 Path to directory or file inside install tree. 00896 # If this argument is not given, PATH is used for both 00897 # the build and install tree version of the script. 00898 # 00899 # @ingroup CMakeAPI 00900 function (basis_set_script_path VAR PATH) 00901 if (NOT __DIR__) 00902 message (FATAL_ERROR "__DIR__ not set! Note that basis_set_script_path() may" 00903 " only be used in script configurations (e.g., ScriptConfig.cmake.in).") 00904 endif () 00905 if (ARGC GREATER 3) 00906 message (FATAL_ERROR "Too many arguments given for function basis_set_script_path()") 00907 endif () 00908 if (ARGC EQUAL 3 AND BUILD_INSTALL_SCRIPT) 00909 set (PREFIX "${CMAKE_INSTALL_PREFIX}") 00910 set (PATH "${ARGV2}") 00911 else () 00912 set (PREFIX "${PROJECT_SOURCE_DIR}") 00913 endif () 00914 if (NOT IS_ABSOLUTE "${PATH}") 00915 set (PATH "${PREFIX}/${PATH}") 00916 endif () 00917 basis_get_relative_path (PATH "${__DIR__}" "${PATH}") 00918 if (NOT PATH) 00919 set (PATH ".") 00920 endif () 00921 string (REGEX REPLACE "/$" "" PATH "${PATH}") 00922 set (${VAR} "${PATH}" PARENT_SCOPE) 00923 endfunction () 00924 00925 # ============================================================================ 00926 # set/get any property 00927 # ============================================================================ 00928 00929 # ---------------------------------------------------------------------------- 00930 ## @brief Convert list into regular expression. 00931 # 00932 # This function is in particular used to convert a list of property names 00933 # such as <CONFIG>_OUTPUT_NAME, e.g., the list @c BASIS_PROPERTIES_ON_TARGETS, 00934 # into a regular expression which can be used in pattern matches. 00935 # 00936 # @param [out] REGEX Name of variable for resulting regular expression. 00937 # @param [in] ARGN List of patterns which may contain placeholders in the 00938 # form of "<this is a placeholder>". These are replaced 00939 # by the regular expression "[^ ]+". 00940 macro (basis_list_to_regex REGEX) 00941 string (REGEX REPLACE "<[^>]+>" "[^ ]+" ${REGEX} "${ARGN}") 00942 string (REGEX REPLACE ";" "|" ${REGEX} "${${REGEX}}") 00943 set (${REGEX} "^(${${REGEX}})$") 00944 endmacro () 00945 00946 # ---------------------------------------------------------------------------- 00947 ## @brief Output current CMake variables to file. 00948 function (basis_dump_variables RESULT_FILE) 00949 set (DUMP) 00950 get_cmake_property (VARIABLE_NAMES VARIABLES) 00951 foreach (V IN LISTS VARIABLE_NAMES) 00952 if (NOT V MATCHES "^_|^RESULT_FILE$|^ARGC$|^ARGV[0-9]?$|^ARGN_") 00953 set (VALUE "${${V}}") 00954 # sanitize value for use in set() command 00955 string (REPLACE "\\" "\\\\" VALUE "${VALUE}") # escape backspaces 00956 string (REPLACE "\"" "\\\"" VALUE "${VALUE}") # escape double quotes 00957 # Escape ${VAR} by \${VAR} such that CMake does not evaluate it. 00958 # Escape $STR{VAR} by \$STR{VAR} such that CMake does not report a 00959 # syntax error b/c it expects either ${VAR}, $ENV{VAR}, or $CACHE{VAR}. 00960 # Escape @VAR@ by \@VAR\@ such that CMake does not evaluate it. 00961 string (REGEX REPLACE "([^\\])\\\$([^ ]*){" "\\1\\\\\$\\2{" VALUE "${VALUE}") 00962 string (REGEX REPLACE "([^\\])\\\@([^ ]*)\@" "\\1\\\\\@\\2\\\\\@" VALUE "${VALUE}") 00963 # append variable to output file 00964 set (DUMP "${DUMP}set (${V} \"${VALUE}\")\n") 00965 endif () 00966 endforeach () 00967 file (WRITE "${RESULT_FILE}" "# CMake variables dump created by BASIS\n${DUMP}") 00968 endfunction () 00969 00970 # ---------------------------------------------------------------------------- 00971 ## @brief Write CMake script file which sets the named variable to the 00972 # specified (list of) values. 00973 function (basis_write_list FILENAME VARIABLE) 00974 file (WRITE "${FILENAME}" "# Automatically generated. Do not edit this file!\nset (${VARIABLE}\n") 00975 foreach (V IN LISTS ARGN) 00976 file (APPEND "${FILENAME}" " \"${V}\"\n") 00977 endforeach () 00978 file (APPEND "${FILENAME}" ")\n") 00979 endfunction () 00980 00981 # ---------------------------------------------------------------------------- 00982 ## @brief Set a named property in a given scope. 00983 # 00984 # This function replaces CMake's 00985 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 00986 # set_property()</a> command. 00987 # 00988 # @param [in] SCOPE The argument for the @p SCOPE parameter of 00989 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 00990 # set_property()</a>. 00991 # @param [in] ARGN Arguments as accepted by. 00992 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 00993 # set_property()</a>. 00994 # 00995 # @returns Sets the specified property. 00996 # 00997 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property 00998 # 00999 # @ingroup CMakeAPI 01000 function (basis_set_property SCOPE) 01001 if (SCOPE MATCHES "^TARGET$|^TEST$") 01002 # map target/test names to UIDs 01003 list (LENGTH ARGN ARGN_LENGTH) 01004 if (ARGN_LENGTH EQUAL 0) 01005 message (FATAL_ERROR "basis_set_property(${SCOPE}): Expected arguments after SCOPE!") 01006 endif () 01007 set (IDX 0) 01008 set (ARG) 01009 while (IDX LESS ARGN_LENGTH) 01010 list (GET ARGN ${IDX} ARG) 01011 if (ARG MATCHES "^APPEND$") 01012 math (EXPR IDX "${IDX} + 1") 01013 list (GET ARGN ${IDX} ARG) 01014 if (NOT ARG MATCHES "^PROPERTY$") 01015 message (FATAL_ERROR "basis_set_properties(${SCOPE}): Expected PROPERTY keyword after APPEND!") 01016 endif () 01017 break () 01018 elseif (ARG MATCHES "^PROPERTY$") 01019 break () 01020 else () 01021 if (SCOPE MATCHES "^TEST$") 01022 basis_get_test_uid (UID "${ARG}") 01023 else () 01024 basis_get_target_uid (UID "${ARG}") 01025 endif () 01026 list (INSERT ARGN ${IDX} "${UID}") 01027 math (EXPR IDX "${IDX} + 1") 01028 list (REMOVE_AT ARGN ${IDX}) # after insert to avoid index out of range 01029 endif () 01030 endwhile () 01031 if (IDX EQUAL ARGN_LENGTH) 01032 message (FATAL_ERROR "basis_set_properties(${SCOPE}): Missing PROPERTY keyword!") 01033 endif () 01034 math (EXPR IDX "${IDX} + 1") 01035 list (GET ARGN ${IDX} ARG) 01036 # property name matches DEPENDS 01037 if (ARG MATCHES "DEPENDS") 01038 math (EXPR IDX "${IDX} + 1") 01039 while (IDX LESS ARGN_LENGTH) 01040 list (GET ARGN ${IDX} ARG) 01041 if (SCOPE MATCHES "^TEST$") 01042 basis_get_test_uid (UID "${ARG}") 01043 else () 01044 basis_get_target_uid (UID "${ARG}") 01045 endif () 01046 list (INSERT ARGN ${IDX} "${UID}") 01047 math (EXPR IDX "${IDX} + 1") 01048 list (REMOVE_AT ARGN ${IDX}) # after insert ot avoid index out of range 01049 endwhile () 01050 endif () 01051 endif () 01052 if (BASIS_DEBUG) 01053 message ("** basis_set_property():") 01054 message ("** Scope: ${SCOPE}") 01055 message ("** Arguments: [${ARGN}]") 01056 endif () 01057 set_property (${SCOPE} ${ARGN}) 01058 endfunction () 01059 01060 # ---------------------------------------------------------------------------- 01061 ## @brief Get a property. 01062 # 01063 # This function replaces CMake's 01064 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 01065 # get_property()</a> command. 01066 # 01067 # @param [out] VAR Property value. 01068 # @param [in] SCOPE The argument for the @p SCOPE argument of 01069 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 01070 # get_property()</a>. 01071 # @param [in] ELEMENT The argument for the @p ELEMENT argument of 01072 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 01073 # get_property()</a>. 01074 # @param [in] ARGN Arguments as accepted by 01075 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 01076 # get_property()</a>. 01077 # 01078 # @returns Sets @p VAR to the value of the requested property. 01079 # 01080 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property 01081 # 01082 # @ingroup CMakeAPI 01083 function (basis_get_property VAR SCOPE ELEMENT) 01084 if (SCOPE MATCHES "^TARGET$") 01085 basis_get_target_uid (ELEMENT "${ELEMENT}") 01086 elseif (SCOPE MATCHES "^TEST$") 01087 basis_get_test_uid (ELEMENT "${ELEMENT}") 01088 endif () 01089 get_property (VALUE ${SCOPE} ${ELEMENT} ${ARGN}) 01090 set ("${VAR}" "${VALUE}" PARENT_SCOPE) 01091 endfunction () 01092 01093 # ---------------------------------------------------------------------------- 01094 ## @brief Set project-global property. 01095 # 01096 # Set property associated with current project/module. The property is in 01097 # fact just a cached variable whose name is prefixed by the project's name. 01098 function (basis_set_project_property) 01099 CMAKE_PARSE_ARGUMENTS ( 01100 ARGN 01101 "APPEND" 01102 "PROJECT" 01103 "PROPERTY" 01104 ${ARGN} 01105 ) 01106 01107 if (NOT ARGN_PROJECT) 01108 set (ARGN_PROJECT "${PROJECT_NAME}") 01109 endif () 01110 if (NOT ARGN_PROPERTY) 01111 message (FATAL_ERROR "Missing PROPERTY argument!") 01112 endif () 01113 01114 list (GET ARGN_PROPERTY 0 PROPERTY_NAME) 01115 list (REMOVE_AT ARGN_PROPERTY 0) # remove property name from values 01116 01117 if (ARGN_APPEND) 01118 basis_get_project_property (CURRENT PROPERTY ${PROPERTY_NAME}) 01119 if (NOT "${CURRENT}" STREQUAL "") 01120 list (INSERT ARGN_PROPERTY 0 "${CURRENT}") 01121 endif () 01122 endif () 01123 01124 set ( 01125 ${ARGN_PROJECT}_${PROPERTY_NAME} 01126 "${ARGN_PROPERTY}" 01127 CACHE INTERNAL 01128 "Property ${PROPERTY_NAME} of project ${ARGN_PROJECT}." 01129 FORCE 01130 ) 01131 endfunction () 01132 01133 # ---------------------------------------------------------------------------- 01134 ## @brief Get project-global property value. 01135 # 01136 # Example: 01137 # @code 01138 # basis_get_project_property(TARGETS) 01139 # basis_get_project_property(TARGETS ${PROJECT_NAME}) 01140 # basis_get_project_property(TARGETS ${PROJECT_NAME} TARGETS) 01141 # basis_get_project_property(TARGETS PROPERTY TARGETS) 01142 # @endcode 01143 # 01144 # @param [out] VARIABLE Name of result variable. 01145 # @param [in] ARGN See the example uses. The optional second argument 01146 # is either the name of the project similar to CMake's 01147 # get_target_property() command or the keyword PROPERTY 01148 # followed by the name of the property. 01149 function (basis_get_project_property VARIABLE) 01150 if (ARGC GREATER 3) 01151 message (FATAL_ERROR "Too many arguments!") 01152 endif () 01153 if (ARGC EQUAL 1) 01154 set (ARGN_PROJECT "${PROJECT_NAME}") 01155 set (ARGN_PROPERTY "${VARIABLE}") 01156 elseif (ARGC EQUAL 2) 01157 if (ARGV1 MATCHES "^PROPERTY$") 01158 message (FATAL_ERROR "Expected argument after PROPERTY keyword!") 01159 endif () 01160 set (ARGN_PROJECT "${ARGV1}") 01161 set (ARGN_PROPERTY "${VARIABLE}") 01162 else () 01163 if (ARGV1 MATCHES "^PROPERTY$") 01164 set (ARGN_PROJECT "${PROJECT_NAME}") 01165 else () 01166 set (ARGN_PROJECT "${ARGV1}") 01167 endif () 01168 set (ARGN_PROPERTY "${ARGV2}") 01169 endif () 01170 set (${VARIABLE} "${${ARGN_PROJECT}_${ARGN_PROPERTY}}" PARENT_SCOPE) 01171 endfunction () 01172 01173 # ============================================================================ 01174 # list / string manipulations 01175 # ============================================================================ 01176 01177 # ---------------------------------------------------------------------------- 01178 ## @brief Sanitize string variable for use in regular expression. 01179 # 01180 # @note This function may not work for all cases, but is used in particular 01181 # to sanitize project names, target names, namespace identifiers,... 01182 # 01183 # @param [out] OUT String that can be used in regular expression. 01184 # @param [in] STR String to sanitize. 01185 macro (basis_sanitize_for_regex OUT STR) 01186 string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" ${OUT} "${STR}") 01187 endmacro () 01188 01189 # ---------------------------------------------------------------------------- 01190 ## @brief Concatenates all list elements into a single string. 01191 # 01192 # The list elements are concatenated without any delimiter in between. 01193 # Use basis_list_to_delimited_string() to specify a delimiter such as a 01194 # whitespace character or comma (,) as delimiter. 01195 # 01196 # @param [out] STR Output string. 01197 # @param [in] ARGN Input list. 01198 # 01199 # @returns Sets @p STR to the resulting string. 01200 # 01201 # @sa basis_list_to_delimited_string() 01202 function (basis_list_to_string STR) 01203 set (OUT) 01204 foreach (ELEM ${ARGN}) 01205 set (OUT "${OUT}${ELEM}") 01206 endforeach () 01207 set ("${STR}" "${OUT}" PARENT_SCOPE) 01208 endfunction () 01209 01210 # ---------------------------------------------------------------------------- 01211 ## @brief Concatenates all list elements into a single delimited string. 01212 # 01213 # @param [out] STR Output string. 01214 # @param [in] DELIM Delimiter used to separate list elements. 01215 # Each element which contains the delimiter as substring 01216 # is surrounded by double quotes (") in the output string. 01217 # @param [in] ARGN Input list. If this list starts with the argument 01218 # @c NOAUTOQUOTE, the automatic quoting of list elements 01219 # which contain the delimiter is disabled. 01220 # 01221 # @returns Sets @p STR to the resulting string. 01222 function (basis_list_to_delimited_string STR DELIM) 01223 set (OUT) 01224 set (AUTOQUOTE TRUE) 01225 if (ARGN) 01226 list (GET ARGN 0 FIRST) 01227 if (FIRST MATCHES "^NOAUTOQUOTE$") 01228 list (REMOVE_AT ARGN 0) 01229 set (AUTOQUOTE FALSE) 01230 endif () 01231 endif () 01232 foreach (ELEM ${ARGN}) 01233 if (OUT) 01234 set (OUT "${OUT}${DELIM}") 01235 endif () 01236 if (AUTOQUOTE AND ELEM MATCHES "${DELIM}") 01237 set (OUT "${OUT}\"${ELEM}\"") 01238 else () 01239 set (OUT "${OUT}${ELEM}") 01240 endif () 01241 endforeach () 01242 set ("${STR}" "${OUT}" PARENT_SCOPE) 01243 endfunction () 01244 01245 # ---------------------------------------------------------------------------- 01246 ## @brief Splits a string at space characters into a list. 01247 # 01248 # @todo Probably this can be done in a better way... 01249 # Difficulty is, that string(REPLACE) does always replace all 01250 # occurrences. Therefore, we need a regular expression which matches 01251 # the entire string. More sophisticated regular expressions should do 01252 # a better job, though. 01253 # 01254 # @param [out] LST Output list. 01255 # @param [in] STR Input string. 01256 # 01257 # @returns Sets @p LST to the resulting CMake list. 01258 function (basis_string_to_list LST STR) 01259 set (TMP "${STR}") 01260 set (OUT) 01261 # 1. extract elements such as "a string with spaces" 01262 while (TMP MATCHES "\"[^\"]*\"") 01263 string (REGEX REPLACE "^(.*)\"([^\"]*)\"(.*)$" "\\1\\3" TMP "${TMP}") 01264 if (OUT) 01265 set (OUT "${CMAKE_MATCH_2};${OUT}") 01266 else (OUT) 01267 set (OUT "${CMAKE_MATCH_2}") 01268 endif () 01269 endwhile () 01270 # 2. extract other elements separated by spaces (excluding first and last) 01271 while (TMP MATCHES " [^\" ]+ ") 01272 string (REGEX REPLACE "^(.*) ([^\" ]+) (.*)$" "\\1\\3" TMP "${TMP}") 01273 if (OUT) 01274 set (OUT "${CMAKE_MATCH_2};${OUT}") 01275 else (OUT) 01276 set (OUT "${CMAKE_MATCH_2}") 01277 endif () 01278 endwhile () 01279 # 3. extract first and last elements (if not done yet) 01280 if (TMP MATCHES "^[^\" ]+") 01281 set (OUT "${CMAKE_MATCH_0};${OUT}") 01282 endif () 01283 if (NOT "${CMAKE_MATCH_0}" STREQUAL "${TMP}" AND TMP MATCHES "[^\" ]+$") 01284 set (OUT "${OUT};${CMAKE_MATCH_0}") 01285 endif () 01286 # return resulting list 01287 set (${LST} "${OUT}" PARENT_SCOPE) 01288 endfunction () 01289 01290 # ---------------------------------------------------------------------------- 01291 ## @brief Compare two lists. 01292 # 01293 # @param [out] RESULT Result of comparison. 01294 # @param [in] LIST1 Name of variable holding the first list. 01295 # @param [in] LIST2 Name of varaible holding the second list. 01296 # 01297 # @retval 0 The two lists are not identical. 01298 # @retval 1 Both lists have identical elements (not necessarily in the same order). 01299 macro (basis_compare_lists RESULT LIST1 LIST2) 01300 set (_L1 "${${LIST1}}") 01301 set (_L2 "${${LIST2}}") 01302 list (SORT _L1) 01303 list (SORT _L2) 01304 if ("${_L1}" STREQUAL "${_L2}") 01305 set (RESULT TRUE) 01306 else () 01307 set (RESULT FALSE) 01308 endif () 01309 unset (_L1) 01310 unset (_L2) 01311 endmacro () 01312 01313 # ============================================================================ 01314 # name <=> UID 01315 # ============================================================================ 01316 01317 # ---------------------------------------------------------------------------- 01318 ## @brief Derive target name from source file name. 01319 # 01320 # @param [out] TARGET_NAME Target name. 01321 # @param [in] SOURCE_FILE Source file. 01322 # @param [in] ARGN Third argument to get_filename_component(). 01323 # If not specified, the given path is only sanitized. 01324 # 01325 # @returns Target name derived from @p SOURCE_FILE. 01326 function (basis_get_source_target_name TARGET_NAME SOURCE_FILE) 01327 # remove ".in" suffix from file name 01328 string (REGEX REPLACE "\\.in$" "" OUT "${SOURCE_FILE}") 01329 # get name component 01330 if (ARGC GREATER 2) 01331 get_filename_component (OUT "${OUT}" ${ARGV2}) 01332 endif () 01333 # replace special characters 01334 string (REGEX REPLACE "[./\\]" "_" OUT "${OUT}") 01335 # return 01336 set (${TARGET_NAME} "${OUT}" PARENT_SCOPE) 01337 endfunction () 01338 01339 # ---------------------------------------------------------------------------- 01340 ## @brief Make target UID from given target name. 01341 # 01342 # This function is intended for use by the basis_add_*() functions only. 01343 # 01344 # @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name. 01345 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 01346 # 01347 # @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME. 01348 # 01349 # @sa basis_get_target_uid() 01350 macro (basis_make_target_uid TARGET_UID TARGET_NAME) 01351 set (${TARGET_UID} "${PROJECT_NAMESPACE_CMAKE}.${TARGET_NAME}") 01352 # optionally strip off top-level namespace part 01353 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 01354 basis_sanitize_for_regex (_bmtu_RE "${BASIS_PROJECT_NAMESPACE_CMAKE}") 01355 string (REGEX REPLACE "^${_bmtu_RE}\\." "" ${TARGET_UID} "${${TARGET_UID}}") 01356 unset (_bmtu_RE) 01357 endif () 01358 endmacro () 01359 01360 # ---------------------------------------------------------------------------- 01361 ## @brief Get "global" target name, i.e., actual CMake target name. 01362 # 01363 # In order to ensure that CMake target names are unique across modules of 01364 # a BASIS project, the target name given to the BASIS CMake functions is 01365 # converted by basis_make_target_uid() into a so-called target UID which is 01366 # used as actual CMake target name. This function can be used to get for a 01367 # given target name or UID the closest match of a known target UID. 01368 # 01369 # The individual parts of the target UID, i.e, package name, 01370 # module name, and target name are separated by a dot (.). 01371 # If @c BASIS_USE_FULLY_QUALIFIED_UIDS is set to @c OFF, the common part of 01372 # all target UIDs is removed by this function from the target UID. 01373 # When the target is exported, however, this common part will be 01374 # prefixed again. This is done by the basis_export_targets() function. 01375 # 01376 # Note that names of imported targets are not prefixed in any case. 01377 # 01378 # The counterpart basis_get_target_name() can be used to convert the target UID 01379 # back to the target name without namespace prefix. 01380 # 01381 # @note At the moment, BASIS does not support modules which themselves have 01382 # modules again. This would require a more nested namespace hierarchy 01383 # and makes things unnecessarily complicated. 01384 # 01385 # @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name. 01386 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 01387 # 01388 # @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME. 01389 # 01390 # @sa basis_get_target_name() 01391 function (basis_get_target_uid TARGET_UID TARGET_NAME) 01392 basis_sanitize_for_regex (BASE_RE "${BASIS_PROJECT_NAMESPACE_CMAKE}") 01393 # in case of a leading namespace separator, do not modify target name 01394 if (TARGET_NAME MATCHES "^\\.") 01395 set (UID "${TARGET_NAME}") 01396 # otherwise, 01397 else () 01398 set (UID "${TARGET_NAME}") 01399 # try prepending namespace or parts of it until target is known, 01400 # first assuming the simplified UIDs without the common prefix 01401 # of this package which applies to targets of this package 01402 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS AND NOT TARGET "${UID}") 01403 string (REGEX REPLACE "^${BASE_RE}\\." "" PREFIX "${PROJECT_NAMESPACE_CMAKE}") 01404 while (PREFIX) 01405 if (TARGET "${PREFIX}.${TARGET_NAME}") 01406 set (UID "${PREFIX}.${TARGET_NAME}") 01407 break () 01408 else () 01409 if (PREFIX MATCHES "(.*)\\.[^.]+") 01410 set (PREFIX "${CMAKE_MATCH_1}") 01411 else () 01412 break () 01413 endif () 01414 endif () 01415 endwhile () 01416 endif () 01417 # and then with the fully qualified UIDs for imported targets 01418 if (NOT TARGET "${UID}") 01419 set (PREFIX "${PROJECT_NAMESPACE_CMAKE}") 01420 while (PREFIX) 01421 if (TARGET "${PREFIX}.${TARGET_NAME}") 01422 set (UID "${PREFIX}.${TARGET_NAME}") 01423 break () 01424 else () 01425 if (PREFIX MATCHES "(.*)\\.[^.]+") 01426 set (PREFIX "${CMAKE_MATCH_1}") 01427 else () 01428 break () 01429 endif () 01430 endif () 01431 endwhile () 01432 endif () 01433 endif () 01434 # strip off top-level namespace part (optional) 01435 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 01436 string (REGEX REPLACE "^${BASE_RE}\\." "" UID "${UID}") 01437 endif () 01438 # return 01439 set ("${TARGET_UID}" "${UID}" PARENT_SCOPE) 01440 endfunction () 01441 01442 # ---------------------------------------------------------------------------- 01443 ## @brief Get fully-qualified target name. 01444 # 01445 # This function always returns a fully-qualified target UID, no matter if 01446 # the option @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c OFF. Note that 01447 # if this option is @c ON, the returned target UID is may not be the 01448 # actual name of a CMake target. 01449 # 01450 # @param [out] TARGET_UID Fully-qualified target UID. 01451 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 01452 # 01453 # @sa basis_get_target_uid() 01454 function (basis_get_fully_qualified_target_uid TARGET_UID TARGET_NAME) 01455 basis_get_target_uid (UID "${TARGET_NAME}") 01456 if (TARGET "${UID}" AND NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 01457 get_target_property (IMPORTED "${UID}" IMPORTED) 01458 if (NOT IMPORTED) 01459 set (UID "${BASIS_PROJECT_NAMESPACE_CMAKE}.${UID}") 01460 endif () 01461 endif () 01462 set (${TARGET_UID} "${UID}" PARENT_SCOPE) 01463 endfunction () 01464 01465 # ---------------------------------------------------------------------------- 01466 ## @brief Get namespace of build target. 01467 # 01468 # @param [out] TARGET_NS Namespace part of target UID. 01469 # @param [in] TARGET_UID Target UID/name. 01470 function (basis_get_target_namespace TARGET_NS TARGET_UID) 01471 # make sure we have a fully-qualified target UID 01472 basis_get_fully_qualified_target_uid (UID "${TARGET_UID}") 01473 # return namespace part 01474 if (UID MATCHES "^(.*)\\.") 01475 set ("${TARGET_NS}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 01476 else () 01477 set ("${TARGET_NS}" "" PARENT_SCOPE) 01478 endif () 01479 endfunction () 01480 01481 # ---------------------------------------------------------------------------- 01482 ## @brief Get "local" target name, i.e., BASIS target name. 01483 # 01484 # @param [out] TARGET_NAME Target name used as argument to BASIS functions. 01485 # @param [in] TARGET_UID "Global" target name, i.e., actual CMake target name. 01486 # 01487 # @returns Sets @p TARGET_NAME to the name of the build target with UID @p TARGET_UID. 01488 # 01489 # @sa basis_get_target_uid() 01490 function (basis_get_target_name TARGET_NAME TARGET_UID) 01491 # make sure we have a fully-qualified target UID 01492 basis_get_fully_qualified_target_uid (UID "${TARGET_UID}") 01493 # strip off namespace of current project 01494 basis_sanitize_for_regex (RE "${PROJECT_NAMESPACE_CMAKE}") 01495 string (REGEX REPLACE "^${RE}\\." "" NAME "${UID}") 01496 # return 01497 set (${TARGET_NAME} "${NAME}" PARENT_SCOPE) 01498 endfunction () 01499 01500 # ---------------------------------------------------------------------------- 01501 ## @brief Checks whether a given name is a valid target name. 01502 # 01503 # Displays fatal error message when target name is invalid. 01504 # 01505 # @param [in] TARGET_NAME Desired target name. 01506 # 01507 # @returns Nothing. 01508 function (basis_check_target_name TARGET_NAME) 01509 # reserved target name ? 01510 foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES) 01511 if (TARGET_NAME MATCHES "^${PATTERN}$") 01512 message (FATAL_ERROR "Target name \"${TARGET_NAME}\" is reserved and cannot be used.") 01513 endif () 01514 endforeach () 01515 # invalid target name ? 01516 if (NOT TARGET_NAME MATCHES "^[a-zA-Z]([a-zA-Z0-9_+]|-)*$|^__init__(_py)?$") 01517 message (FATAL_ERROR "Target name '${TARGET_NAME}' is invalid.\nChoose a target name" 01518 " which only contains alphanumeric characters," 01519 " '_', '-', or '+', and starts with a letter." 01520 " The only exception from this rule is __init__[_py] for" 01521 " a __init__.py script.\n") 01522 endif () 01523 01524 # unique ? 01525 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 01526 if (TARGET "${TARGET_UID}") 01527 message (FATAL_ERROR "There exists already a target named ${TARGET_UID}." 01528 " Target names must be unique.") 01529 endif () 01530 endfunction () 01531 01532 # ---------------------------------------------------------------------------- 01533 ## @brief Make test UID from given test name. 01534 # 01535 # This function is intended for use by the basis_add_test() only. 01536 # 01537 # @param [out] TEST_UID "Global" test name, i.e., actual CTest test name. 01538 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 01539 # 01540 # @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME. 01541 # 01542 # @sa basis_get_test_uid() 01543 macro (basis_make_test_uid TEST_UID TEST_NAME) 01544 basis_make_target_uid ("${TEST_UID}" "${TEST_NAME}") 01545 endmacro () 01546 01547 # ---------------------------------------------------------------------------- 01548 ## @brief Get "global" test name, i.e., actual CTest test name. 01549 # 01550 # In order to ensure that CTest test names are unique across BASIS projects, 01551 # the test name used by a developer of a BASIS project is converted by this 01552 # function into another test name which is used as actual CTest test name. 01553 # 01554 # The function basis_get_test_name() can be used to convert the unique test 01555 # name, the test UID, back to the original test name passed to this function. 01556 # 01557 # @param [out] TEST_UID "Global" test name, i.e., actual CTest test name. 01558 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 01559 # 01560 # @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME. 01561 # 01562 # @sa basis_get_test_name() 01563 function (basis_get_test_uid TEST_UID TEST_NAME) 01564 if (TEST_NAME MATCHES "^\\.") 01565 set (UID "${TEST_NAME}") 01566 else () 01567 set (UID "${PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}") 01568 endif () 01569 # strip off top-level namespace part (optional) 01570 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 01571 basis_sanitize_for_regex (RE "${BASIS_PROJECT_NAMESPACE_CMAKE}") 01572 string (REGEX REPLACE "^${RE}\\." "" UID "${UID}") 01573 endif () 01574 # return 01575 set (${TEST_UID} "${UID}" PARENT_SCOPE) 01576 endfunction () 01577 01578 # ---------------------------------------------------------------------------- 01579 ## @brief Get "global" test name, i.e., actual CTest test name. 01580 # 01581 # This function always returns a fully-qualified test UID, no matter if 01582 # the option @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c OFF. Note that 01583 # if this option is @c ON, the returned test UID may not be the 01584 # actual name of a CMake test. 01585 # 01586 # @param [out] TEST_UID Fully-qualified test UID. 01587 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 01588 # 01589 # @sa basis_get_test_uid() 01590 function (basis_get_fully_qualified_test_uid TEST_UID TEST_NAME) 01591 if (TEST_NAME MATCHES "\\.") 01592 set (UID "${TEST_NAME}") 01593 else () 01594 set (UID "${BASIS_PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}") 01595 endif () 01596 set (${TEST_UID} "${UID}" PARENT_SCOPE) 01597 endfunction () 01598 01599 # ---------------------------------------------------------------------------- 01600 ## @brief Get namespace of test. 01601 # 01602 # @param [out] TEST_NS Namespace part of test UID. If @p TEST_UID is 01603 # no UID, i.e., does not contain a namespace part, 01604 # the namespace of this project is returned. 01605 # @param [in] TEST_UID Test UID/name. 01606 macro (basis_get_test_namespace TEST_NS TEST_UID) 01607 if (TEST_UID MATCHES "^(.*)\\.") 01608 set (${TEST_NS} "${CMAKE_MATCH_1}") 01609 else () 01610 set (${TEST_NS} "") 01611 endif () 01612 endmacro () 01613 01614 # ---------------------------------------------------------------------------- 01615 ## @brief Get "local" test name, i.e., BASIS test name. 01616 # 01617 # @param [out] TEST_NAME Test name used as argument to BASIS functions. 01618 # @param [in] TEST_UID "Global" test name, i.e., actual CTest test name. 01619 # 01620 # @returns Sets @p TEST_NAME to the name of the test with UID @p TEST_UID. 01621 # 01622 # @sa basis_get_test_uid() 01623 macro (basis_get_test_name TEST_NAME TEST_UID) 01624 if (TEST_UID MATCHES "([^.]+)$") 01625 set (${TEST_NAME} "${CMAKE_MATCH_1}") 01626 else () 01627 set (${TEST_NAME} "") 01628 endif () 01629 endmacro () 01630 01631 # ---------------------------------------------------------------------------- 01632 ## @brief Checks whether a given name is a valid test name. 01633 # 01634 # Displays fatal error message when test name is invalid. 01635 # 01636 # @param [in] TEST_NAME Desired test name. 01637 # 01638 # @returns Nothing. 01639 function (basis_check_test_name TEST_NAME) 01640 # reserved test name ? 01641 foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES) 01642 if (TARGET_NAME MATCHES "^${PATTERN}$") 01643 message (FATAL_ERROR "Test name \"${TARGET_NAME}\" is reserved and cannot be used.") 01644 endif () 01645 endforeach () 01646 # invalid test name ? 01647 if (NOT TEST_NAME MATCHES "^[a-zA-Z]([a-zA-Z0-9_+]|-)*$") 01648 message (FATAL_ERROR "Test name ${TEST_NAME} is invalid.\nChoose a test name " 01649 " which only contains alphanumeric characters," 01650 " '_', '-', or '+', and starts with a letter.\n") 01651 endif () 01652 endfunction () 01653 01654 # ============================================================================ 01655 # common target tools 01656 # ============================================================================ 01657 01658 # ---------------------------------------------------------------------------- 01659 ## @brief Whether a given target exists. 01660 # 01661 # This function should be used instead of the if(TARGET) command of CMake 01662 # because target names are mapped by BASIS to target UIDs. 01663 # 01664 # @param [out] RESULT_VARIABLE Boolean result variable. 01665 # @param [in] TARGET_NAME Name which to check whether it is a target. 01666 # 01667 # @sa basis_make_target_uid() 01668 # @sa basis_get_target_uid() 01669 macro (basis_exists_target RESULT_VARIABLE TARGET_NAME) 01670 basis_get_target_uid (_UID "${TARGET_NAME}") 01671 if (TARGET ${_UID}) 01672 set (${RESULT_VARIABLE} TRUE) 01673 else () 01674 set (${RESULT_VARIABLE} FALSE) 01675 endif () 01676 unset (_UID) 01677 endmacro () 01678 01679 # ---------------------------------------------------------------------------- 01680 ## @brief Get default subdirectory prefix of scripted library modules. 01681 # 01682 # @param [out] PREFIX Name of variable which is set to the default library 01683 # prefix, i.e., subdirectory relative to the library 01684 # root directory as used for the @c PREFIX property of 01685 # scripted module libraries (see basis_add_script_library()) 01686 # or relative to the include directory in case of C++. 01687 # Note that this prefix includes a trailing slash to 01688 # indicate that the prefix is a subdirectory. 01689 # @param [in] LANGUAGE Programming language (case-insenitive), e.g., 01690 # @c CXX, @c Python, @c Matlab... 01691 macro (basis_library_prefix PREFIX LANGUAGE) 01692 string (TOUPPER "${LANGUAGE}" _LANGUAGE_U) 01693 if (PROJECT_NAMESPACE_${_LANGUAGE_U}) 01694 basis_sanitize_for_regex (_RE "${BASIS_NAMESPACE_DELIMITER_${_LANGUAGE_U}}") 01695 string (REGEX REPLACE "${_RE}" "/" ${PREFIX} "${PROJECT_NAMESPACE_${_LANGUAGE_U}}") 01696 set (${PREFIX} "${${PREFIX}}/") 01697 unset (_RE) 01698 else () 01699 message (FATAL_ERROR "basis_library_prefix(): PROJECT_NAMESPACE_${_LANGUAGE_U} not set!" 01700 " Make sure that the LANGUAGE argument is supported and in" 01701 " uppercase letters only.") 01702 endif () 01703 unset (_LANGUAGE_U) 01704 endmacro () 01705 01706 # ---------------------------------------------------------------------------- 01707 ## @brief Get file name of compiled script. 01708 # 01709 # @param [out] CFILE File path of compiled script file. 01710 # @param [in] SOURCE Script source file. 01711 # @param [in] ARGV2 Language of script file. If not specified, the language 01712 # is derived from the file name extension and shebang of 01713 # the script source file. 01714 function (basis_get_compiled_file CFILE SOURCE) 01715 if (ARGC GREATER 2) 01716 set (LANGUAGE "${ARGV2}") 01717 else () 01718 basis_get_source_language (LANGUAGE "${SOURCE}") 01719 endif () 01720 set (${CFILE} "" PARENT_SCOPE) 01721 if (SOURCE) 01722 if (LANGUAGE MATCHES "PYTHON") 01723 set (${CFILE} "${SOURCE}c" PARENT_SCOPE) 01724 elseif (LANGUAGE MATCHES "JYTHON") 01725 if (SOURCE MATCHES "(.*)\\.([^.]+)$") 01726 set (${CFILE} "${CMAKE_MATCH_1}$${CMAKE_MATCH_2}.class" PARENT_SCOPE) 01727 endif () 01728 endif () 01729 endif () 01730 endfunction () 01731 01732 # ---------------------------------------------------------------------------- 01733 ## @brief Get file path of Jython file compiled from the given Python module. 01734 # 01735 # Python modules are also compiled using Jython. This macro returns the file 01736 # path of the compiled Jython file in the build tree which corresponds to the 01737 # specified Python module. 01738 # 01739 # @param [out] CFILE Path of corresponding compiled Jython file. 01740 # @param [in] MODULE Path of input Python module in build tree. 01741 macro (basis_get_compiled_jython_file_of_python_module CFILE MODULE) 01742 if (BINARY_PYTHON_LIBRARY_DIR AND BINARY_JYTHON_LIBRARY_DIR) 01743 file (RELATIVE_PATH _GCJFOPM_REL "${BINARY_PYTHON_LIBRARY_DIR}" "${MODULE}") 01744 else () 01745 set (_GCJFOPM_REL) 01746 endif () 01747 if (NOT _GCJFOPM_REL MATCHES "^$|^\\.\\./") 01748 basis_get_compiled_file (${CFILE} "${BINARY_JYTHON_LIBRARY_DIR}/${_GCJFOPM_REL}" JYTHON) 01749 else () 01750 basis_get_compiled_file (${CFILE} "${MODULE}" JYTHON) 01751 endif () 01752 unset (_GCJFOPM_REL) 01753 endmacro () 01754 01755 # ---------------------------------------------------------------------------- 01756 ## @brief Whether to compile Python modules for Jython interpreter. 01757 # 01758 # This macro returns a boolean value stating whether Python modules shall also 01759 # be compiled for use by Jython interpreter if BASIS_COMPILE_SCRIPTS is ON. 01760 # 01761 # @param [out] FLAG Set to either TRUE or FALSE depending on whether Python 01762 # modules shall be compiled using Jython or not. 01763 macro (basis_compile_python_modules_for_jython FLAG) 01764 if (BASIS_COMPILE_SCRIPTS AND JYTHON_EXECUTABLE) 01765 set (${FLAG} TRUE) 01766 else () 01767 set (${FLAG} FALSE) 01768 endif () 01769 if (DEFINED USE_JythonInterp AND NOT USE_JythonInterp) 01770 set (${FLAG} FALSE) 01771 endif () 01772 endmacro () 01773 01774 # ---------------------------------------------------------------------------- 01775 ## @brief Glob source files. 01776 # 01777 # This function gets a list of source files and globbing expressions, evaluates 01778 # the globbing expression, and replaces these by the found source files such 01779 # that the resulting list of source files contains only absolute paths of 01780 # source files. It is used by basis_add_executable() and basis_add_library() 01781 # to get a list of all source files. The syntax for the glob expressions 01782 # corresponds to the one used by CMake's 01783 # <a href="http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:file"> 01784 # file(GLOB)</a> command. Additionally, if the pattern <tt>**</tt> is found 01785 # in a glob expression, it is replaced by a single <tt>*</tt> and the 01786 # recursive version, i.e., <tt>file(GLOB_RECURSE)</tt>, is used instead. 01787 # 01788 # @param [in] TARGET_UID UID of build target which builds the globbed source files. 01789 # The custom target which re-globs the source files 01790 # before each build of this target is named after this 01791 # build target with two leading underscores (__). 01792 # @param [out] SOURCES List of absolute source paths. 01793 # @param [in] ARGN Input file paths and/or globbing expressions. 01794 # 01795 # @sa basis_add_executable() 01796 # @sa basis_add_library() 01797 function (basis_add_glob_target TARGET_UID SOURCES) 01798 # prepare globbing expressions 01799 # make paths absolute and turn directories into recursive globbing expressions 01800 set (EXPRESSIONS) 01801 foreach (EXPRESSION IN LISTS ARGN) 01802 if (NOT IS_ABSOLUTE "${EXPRESSION}") 01803 set (EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/${EXPRESSION}") 01804 endif () 01805 if (IS_DIRECTORY "${EXPRESSION}") 01806 set (EXPRESSION "${EXPRESSION}/**") 01807 endif () 01808 list (APPEND EXPRESSIONS "${EXPRESSION}") 01809 endforeach () 01810 # only if at least one globbing expression is given we need to go through this hassle 01811 if (EXPRESSIONS MATCHES "[*?]|\\[[0-9]+-[0-9]+\\]") 01812 set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}.dir") 01813 set (SOURCES_FILE "${BUILD_DIR}/sources.txt") 01814 # get initial list of source files 01815 execute_process ( 01816 COMMAND "${CMAKE_COMMAND}" 01817 "-DEXPRESSIONS:STRING=${EXPRESSIONS}" 01818 "-DINIT:BOOLEAN=TRUE" 01819 "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}" 01820 -P "${BASIS_MODULE_PATH}/glob.cmake" 01821 RESULT_VARIABLE RETVAL 01822 ) 01823 if (NOT RETVAL EQUAL 0 OR NOT EXISTS "${SOURCES_FILE}") 01824 message (FATAL_ERROR "Target ${TARGET_UID}: Failed to glob source files!") 01825 endif () 01826 # note that including this file here, which is modified whenever a 01827 # source file is added or removed, triggers a re-configuration of the 01828 # build system which is required to re-execute this function. 01829 include ("${SOURCES_FILE}") 01830 set (${SOURCES} "${INITIAL_SOURCES}" PARENT_SCOPE) 01831 # add custom target to re-glob files before each build 01832 set (ERRORMSG "You have either added, removed, or renamed a source file which" 01833 " matches one of the globbing expressions specified for the" 01834 " list of source files from which to build the ${TARGET_UID} target." 01835 " Therefore, the build system must be re-configured. Either try to" 01836 " build again which should trigger CMake and re-configure the build" 01837 " system or run CMake manually.") 01838 basis_list_to_string (ERRORMSG ${ERRORMSG}) 01839 add_custom_target ( 01840 __${TARGET_UID} 01841 COMMAND "${CMAKE_COMMAND}" 01842 "-DEXPRESSIONS:STRING=${EXPRESSIONS}" 01843 "-DINIT:BOOLEAN=FALSE" 01844 "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}" 01845 "-DERRORMSG:STRING=${ERRORMSG}" 01846 -P "${BASIS_MODULE_PATH}/glob.cmake" 01847 COMMENT "Checking if source files for target ${TARGET_UID} were added or removed" 01848 VERBATIM 01849 ) 01850 # otherwise, just return the given absolute source file paths 01851 else () 01852 set (${SOURCES} "${EXPRESSIONS}" PARENT_SCOPE) 01853 endif () 01854 endfunction () 01855 01856 # ---------------------------------------------------------------------------- 01857 ## @brief Detect programming language of given source code files. 01858 # 01859 # This function determines the programming language in which the given source 01860 # code files are written. If no common programming language could be determined, 01861 # "AMBIGUOUS" is returned. If none of the following programming languages 01862 # could be determined, "UNKNOWN" is returned: CXX (i.e., C++), JAVA, MATLAB, 01863 # PYTHON, JYTHON, PERL, BASH, BATCH. 01864 # 01865 # @param [out] LANGUAGE Detected programming language. 01866 # @param [in] ARGN List of source code files. 01867 function (basis_get_source_language LANGUAGE) 01868 set (LANGUAGE_OUT) 01869 # iterate over source files 01870 foreach (SOURCE_FILE ${ARGN}) 01871 get_filename_component (SOURCE_FILE "${SOURCE_FILE}" ABSOLUTE) 01872 01873 if (IS_DIRECTORY "${SOURCE_FILE}") 01874 01875 file (GLOB_RECURSE SOURCE_FILES "${SOURCE_FILE}/*") 01876 list (APPEND ARGN ${SOURCE_FILES}) 01877 01878 else () 01879 01880 # ------------------------------------------------------------------------ 01881 # determine language based on extension for those without shebang 01882 set (LANG) 01883 # C++ 01884 if (SOURCE_FILE MATCHES "\\.(c|cc|cpp|cxx|h|hpp|hxx|txx|inl)(\\.in)?$") 01885 set (LANG "CXX") 01886 # Java 01887 elseif (SOURCE_FILE MATCHES "\\.java(\\.in)?$") 01888 set (LANG "JAVA") 01889 # MATLAB 01890 elseif (SOURCE_FILE MATCHES "\\.m(\\.in)?$") 01891 set (LANG "MATLAB") 01892 endif () 01893 01894 # ------------------------------------------------------------------------ 01895 # determine language from shebang directive 01896 # 01897 # Note that some scripting languages may use identical file name extensions. 01898 # This is in particular the case for Python and Jython. The only way we 01899 # can distinguish these two is by looking at the shebang directive. 01900 if (NOT LANG) 01901 01902 if (NOT EXISTS "${SOURCE_FILE}" AND EXISTS "${SOURCE_FILE}.in") 01903 set (SOURCE_FILE "${SOURCE_FILE}.in") 01904 endif () 01905 if (EXISTS "${SOURCE_FILE}") 01906 file (STRINGS "${SOURCE_FILE}" FIRST_LINE LIMIT_COUNT 1) 01907 if (FIRST_LINE MATCHES "^#!") 01908 if (FIRST_LINE MATCHES "^#! */usr/bin/env +([^ ]+)") 01909 set (INTERPRETER "${CMAKE_MATCH_1}") 01910 elseif (FIRST_LINE MATCHES "^#! *([^ ]+)") 01911 set (INTERPRETER "${CMAKE_MATCH_1}") 01912 get_filename_component (INTERPRETER "${INTERPRETER}" NAME) 01913 else () 01914 set (INTERPRETER) 01915 endif () 01916 if (INTERPRETER MATCHES "^(python|jython|perl|bash)$") 01917 string (TOUPPER "${INTERPRETER}" LANG) 01918 endif () 01919 endif () 01920 endif () 01921 endif () 01922 01923 # ------------------------------------------------------------------------ 01924 # determine language from further known extensions 01925 if (NOT LANG) 01926 # Python 01927 if (SOURCE_FILE MATCHES "\\.py(\\.in)?$") 01928 set (LANG "PYTHON") 01929 # Perl 01930 elseif (SOURCE_FILE MATCHES "\\.(pl|pm|t)(\\.in)?$") 01931 set (LANG "PERL") 01932 # BASH 01933 elseif (SOURCE_FILE MATCHES "\\.sh(\\.in)?$") 01934 set (LANG "BASH") 01935 # Batch 01936 elseif (SOURCE_FILE MATCHES "\\.bat(\\.in)?$") 01937 set (LANG "BATCH") 01938 # unknown 01939 else () 01940 set (LANGUAGE_OUT "UNKNOWN") 01941 break () 01942 endif () 01943 endif () 01944 01945 # ------------------------------------------------------------------------ 01946 # detect ambiguity 01947 if (LANGUAGE_OUT AND NOT LANG MATCHES "^${LANGUAGE_OUT}$") 01948 if (LANGUAGE_OUT MATCHES "CXX" AND LANG MATCHES "MATLAB") 01949 # MATLAB Compiler can handle this... 01950 elseif (LANGUAGE_OUT MATCHES "MATLAB" AND LANG MATCHES "CXX") 01951 set (LANG "MATLAB") # language stays MATLAB 01952 elseif (LANGUAGE_OUT MATCHES "PYTHON" AND LANG MATCHES "JYTHON") 01953 # Jython can deal with Python scripts/modules 01954 elseif (LANGUAGE_OUT MATCHES "JYTHON" AND LANG MATCHES "PYTHON") 01955 set (LANG "JYTHON") # language stays JYTHON 01956 else () 01957 # ambiguity 01958 set (LANGUAGE_OUT "AMBIGUOUS") 01959 break () 01960 endif () 01961 endif () 01962 01963 # update current language 01964 set (LANGUAGE_OUT "${LANG}") 01965 endif () 01966 endforeach () 01967 # return 01968 set (${LANGUAGE} "${LANGUAGE_OUT}" PARENT_SCOPE) 01969 endfunction () 01970 01971 # ---------------------------------------------------------------------------- 01972 ## @brief Configure .in source files. 01973 # 01974 # This function configures each source file in the given argument list with 01975 # a .in file name suffix and stores the configured file in the build tree 01976 # with the same relative directory as the template source file itself. 01977 # The first argument names the CMake variable of the list of configured 01978 # source files where each list item is the absolute file path of the 01979 # corresponding (configured) source file. 01980 # 01981 # @param [out] LIST_NAME Name of output list. 01982 # @param [in] ARGN These arguments are parsed and the following 01983 # options recognized. All remaining arguments are 01984 # considered to be source file paths. 01985 # @par 01986 # <table border="0"> 01987 # <tr> 01988 # @tp @b BINARY_DIRECTORY @endtp 01989 # <td>Explicitly specify directory in build tree where configured 01990 # source files should be written to.</td> 01991 # </tr> 01992 # <tr> 01993 # @tp @b KEEP_DOT_IN_SUFFIX @endtp 01994 # <td>By default, after a source file with the .in extension has been 01995 # configured, the .in suffix is removed from the file name. 01996 # This can be omitted by giving this option.</td> 01997 # </tr> 01998 # </table> 01999 # 02000 # @returns Nothing. 02001 function (basis_configure_sources LIST_NAME) 02002 # parse arguments 02003 CMAKE_PARSE_ARGUMENTS (ARGN "KEEP_DOT_IN_SUFFIX" "BINARY_DIRECTORY" "" ${ARGN}) 02004 02005 if (ARGN_BINARY_DIRECTORY AND NOT ARGN_BINARY_DIRECTORY MATCHES "^${PROJECT_BINARY_DIR}") 02006 message (FATAL_ERROR "Specified BINARY_DIRECTORY must be inside the build tree!") 02007 endif () 02008 02009 # configure source files 02010 set (CONFIGURED_SOURCES) 02011 foreach (SOURCE ${ARGN_UNPARSED_ARGUMENTS}) 02012 # The .in suffix is optional, add it here if a .in file exists for this 02013 # source file, but only if the source file itself does not name an actually 02014 # existing source file. 02015 # 02016 # If the source file path is relative, prefer possibly already configured 02017 # sources in build tree such as the test driver source file created by 02018 # create_test_sourcelist() or a manual use of configure_file(). 02019 # 02020 # Note: Make path absolute, otherwise EXISTS check will not work! 02021 if (NOT IS_ABSOLUTE "${SOURCE}") 02022 if (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}") 02023 set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}") 02024 elseif (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in") 02025 set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in") 02026 elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}") 02027 set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}") 02028 elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in") 02029 set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in") 02030 endif () 02031 else () 02032 if (NOT EXISTS "${SOURCE}" AND EXISTS "${SOURCE}.in") 02033 set (SOURCE "${SOURCE}.in") 02034 endif () 02035 endif () 02036 # configure source file if filename ends in .in suffix 02037 if (SOURCE MATCHES "\\.in$") 02038 # if binary directory was given explicitly, use it 02039 if (ARGN_BINARY_DIRECTORY) 02040 get_filename_component (SOURCE_NAME "${SOURCE}" NAME) 02041 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 02042 string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}") 02043 endif () 02044 set (CONFIGURED_SOURCE "${ARGN_BINARY_DIRECTORY}/${SOURCE_NAME}") 02045 # otherwise, 02046 else () 02047 # if source is in project's source tree use relative binary directory 02048 basis_sanitize_for_regex (REGEX "${PROJECT_SOURCE_DIR}") 02049 if (SOURCE MATCHES "^${REGEX}") 02050 basis_get_relative_path (CONFIGURED_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}" "${SOURCE}") 02051 get_filename_component (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURED_SOURCE}" ABSOLUTE) 02052 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 02053 string (REGEX REPLACE "\\.in$" "" CONFIGURED_SOURCE "${CONFIGURED_SOURCE}") 02054 endif () 02055 # otherwise, use current binary directory 02056 else () 02057 get_filename_component (SOURCE_NAME "${SOURCE}" NAME) 02058 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 02059 string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}") 02060 endif () 02061 set (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE_NAME}") 02062 endif () 02063 endif () 02064 # configure source file 02065 configure_file ("${SOURCE}" "${CONFIGURED_SOURCE}" @ONLY) 02066 if (BASIS_DEBUG) 02067 message ("** Configured source file with .in extension") 02068 endif () 02069 # otherwise, skip configuration of this source file 02070 else () 02071 set (CONFIGURED_SOURCE "${SOURCE}") 02072 if (BASIS_DEBUG) 02073 message ("** Skipped configuration of source file") 02074 endif () 02075 endif () 02076 if (BASIS_DEBUG) 02077 message ("** Source: ${SOURCE}") 02078 message ("** Configured source: ${CONFIGURED_SOURCE}") 02079 endif () 02080 list (APPEND CONFIGURED_SOURCES "${CONFIGURED_SOURCE}") 02081 endforeach () 02082 # return 02083 set (${LIST_NAME} "${CONFIGURED_SOURCES}" PARENT_SCOPE) 02084 endfunction () 02085 02086 # ---------------------------------------------------------------------------- 02087 ## @brief Configure and optionally compile script file. 02088 # 02089 # This function is used to configure script files during the build. It is 02090 # called by the build script generated by basis_add_script_target() for each script 02091 # target. It is further used to configure the modules of the packages 02092 # implemented in supported scripting languages which are located in the 02093 # @c PROJECT_LIBRARY_DIR of the source tree. 02094 # 02095 # In case of executable scripts, this function automatically prepends the 02096 # module search paths such that the modules of this software package are found 02097 # (and preferred in case of potential name conflicts with other packages). 02098 # Moreover, it adds (or replaces) the shebang directive on Unix such that the 02099 # configured interpreter version is used. On Windows, it converts the executable 02100 # script into a Windows Command instead which executes the proper interpreter 02101 # with the code section of the input script. 02102 # 02103 # @param [in] INPUT Input script file. 02104 # @param [in] OUTPUT Configured output script file. 02105 # @param [in] ARGN Optional arguments: 02106 # @par 02107 # <table border=0> 02108 # <tr> 02109 # @tp @b COMPILE @endtp 02110 # <td>Whether to compile module scripts if suitable, i.e., an intermediate 02111 # format exists for the specific scripting language. For example, 02112 # Python modules can be compiled.</td> 02113 # </tr> 02114 # <tr> 02115 # @tp @b COPYONLY @endtp 02116 # <td>Whether to only copy the script file without replacing CMake variables 02117 # within the file. This option is passed on to CMake's configure_file() 02118 # command used to configure the script file. By default, the option 02119 # \@ONLY is used instead.</td> 02120 # </tr> 02121 # <tr> 02122 # @tp @b EXECUTABLE @endtp 02123 # <td>Specifies that the given script file is an executable script and not a 02124 # module script. Otherwise, if this option is not given and the output 02125 # file name contains a file name extension, the given script file is 02126 # configured as module script. A script file with an output file name 02127 # that has no extension, is always considered to be an executable.</td> 02128 # </tr> 02129 # <tr> 02130 # @tp @b DESTINATION dir @endtp 02131 # <td>Installation directory for configured script. If this option is given, 02132 # the @c BUILD_INSTALL_SCRIPT variable is set to @c TRUE before including 02133 # any specified script configuration files (see @p CONFIG_FILE option). 02134 # Moreover, the @c __DIR__ variable is set to the specified directory. 02135 # Otherwise, if this option is omitted, the @c BUILD_INSTALL_SCRIPT variable 02136 # is set to @c FALSE instead and @c __DIR__ is set to the directory of 02137 # the configured @p OUTPUT file. Note that the @c BUILD_INSTALL_SCRIPT and 02138 # @c __DIR__ variables are in particular used by basis_set_script_path() 02139 # to convert the given paths to paths relative to the location of the 02140 # configured/installed script.</td> 02141 # </tr> 02142 # <tr> 02143 # @tp @b CACHE_FILE file1 [file2...] @endtp 02144 # <td>List of CMake files with dump of variables which should be included 02145 # before configuring the script. The cache files can be generated using 02146 # the basis_dump_variables() function.</td> 02147 # </tr> 02148 # <tr> 02149 # @tp @b CONFIG_FILE file1 [file2...] @endtp 02150 # <td>List of script configuration files to include before the configuration 02151 # of the script. See also the documentation of the @p DESTINATION option.</td> 02152 # </tr> 02153 # <tr> 02154 # @tp @b LINK_DEPENDS dep1 [dep2...] @endtp 02155 # <td>List of "link" dependencies, i.e., modules and script/module libraries 02156 # required by this script. For executable scripts, the paths to these 02157 # modules/packages is added to the module search path. If the prefix 02158 # "relative " is given before a file path, it is made relative to the 02159 # output/installation directory of the script file. All given input paths 02160 # must be absolute, however, as the relative location depends on 02161 # whether the script will be installed, i.e., the @c DESTINATION 02162 # is specified, or not.</td> 02163 # </tr> 02164 # </table> 02165 function (basis_configure_script INPUT OUTPUT) 02166 # rename arguments to avoid conflict with script configuration 02167 set (_INPUT_FILE "${INPUT}") 02168 set (_OUTPUT_FILE "${OUTPUT}") 02169 # -------------------------------------------------------------------------- 02170 # parse arguments 02171 CMAKE_PARSE_ARGUMENTS ( 02172 ARGN 02173 "COMPILE;COPYONLY;EXECUTABLE" 02174 "DESTINATION;LANGUAGE" 02175 "CACHE_FILE;CONFIG_FILE;LINK_DEPENDS" 02176 ${ARGN} 02177 ) 02178 if (ARGN_UNPARSED_ARGUMENTS) 02179 message (FATAL_ERROR "Unrecognized arguments given: ${ARGN_UNPARSED_ARGUMENTS}") 02180 endif () 02181 if (NOT ARGN_LANGUAGE) 02182 basis_get_source_language (ARGN_LANGUAGE "${_INPUT_FILE}") 02183 endif () 02184 # -------------------------------------------------------------------------- 02185 # include cache files 02186 foreach (_F IN LISTS ARGN_CACHE_FILE) 02187 get_filename_component (_F "${_F}" ABSOLUTE) 02188 if (NOT EXISTS "${_F}") 02189 message (FATAL_ERROR "Cache file ${_F} does not exist!") 02190 endif () 02191 include ("${_F}") 02192 endforeach () 02193 # -------------------------------------------------------------------------- 02194 # set general variables for use in scripts 02195 set (__FILE__ "${_OUTPUT_FILE}") 02196 get_filename_component (__NAME__ "${_OUTPUT_FILE}" NAME) 02197 # -------------------------------------------------------------------------- 02198 # variables mainly intended for use in script configurations, in particular, 02199 # these are used by basis_set_script_path() to make absolute paths relative 02200 if (ARGN_DESTINATION) 02201 if (NOT IS_ABSOLUTE "${ARGN_DESTINATION}") 02202 set (ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}/${ARGN_DESTINATION}") 02203 endif () 02204 set (BUILD_INSTALL_SCRIPT TRUE) 02205 set (__DIR__ "${ARGN_DESTINATION}") 02206 else () 02207 set (BUILD_INSTALL_SCRIPT FALSE) 02208 get_filename_component (__DIR__ "${_OUTPUT_FILE}" PATH) 02209 endif () 02210 # -------------------------------------------------------------------------- 02211 # include script configuration files 02212 foreach (_F IN LISTS ARGN_CONFIG_FILE) 02213 get_filename_component (_F "${_F}" ABSOLUTE) 02214 if (NOT EXISTS "${_F}") 02215 message (FATAL_ERROR "Script configuration file ${_F} does not exist!") 02216 endif () 02217 include ("${_F}") 02218 endforeach () 02219 # -------------------------------------------------------------------------- 02220 # configure executable script 02221 if (ARGN_EXECUTABLE) 02222 # Attention: Every line of code added/removed will introduce a mismatch 02223 # between error messages of the interpreter and the original 02224 # source file. To not confuse/mislead developers too much, 02225 # keep number of lines added/removed at a minimum or at least 02226 # try to balance the number of lines added and removed. 02227 # Moreover, blank lines can be used to insert code without 02228 # changing the number of source code lines. 02229 file (READ "${_INPUT_FILE}" SCRIPT) 02230 # (temporarily) remove existing shebang directive 02231 file (STRINGS "${_INPUT_FILE}" FIRST_LINE LIMIT_COUNT 1) 02232 if (FIRST_LINE MATCHES "^#!") 02233 basis_sanitize_for_regex (FIRST_LINE_RE "${FIRST_LINE}") 02234 string (REGEX REPLACE "^${FIRST_LINE_RE}\n?" "" SCRIPT "${SCRIPT}") 02235 set (SHEBANG "${FIRST_LINE}") 02236 endif () 02237 # replace CMake variables used in script 02238 if (NOT ARGN_COPYONLY) 02239 string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY) 02240 endif () 02241 # add code to set module search path 02242 if (ARGN_LANGUAGE MATCHES "[JP]YTHON") 02243 if (ARGN_LINK_DEPENDS) 02244 string (REGEX REPLACE "^[ \t]*\n" "" SCRIPT "${SCRIPT}") # remove a blank line therefore 02245 set (PYTHON_CODE "import sys; import os.path; __dir__ = os.path.dirname(os.path.realpath(__file__))") 02246 list (REVERSE ARGN_LINK_DEPENDS) 02247 foreach (DIR ${ARGN_LINK_DEPENDS}) 02248 if (DIR MATCHES "^relative +(.*)$") 02249 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 02250 endif () 02251 if (DIR MATCHES "\\.(py|class)$") 02252 get_filename_component (DIR "${DIR}" PATH) 02253 endif () 02254 if (IS_ABSOLUTE "${DIR}") 02255 set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath('${DIR}'))") 02256 else () 02257 set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath(os.path.join(__dir__, '${DIR}')))") 02258 endif () 02259 endforeach () 02260 set (SCRIPT "${PYTHON_CODE} # <-- added by BASIS\n${SCRIPT}") 02261 endif () 02262 elseif (ARGN_LANGUAGE MATCHES "PERL") 02263 if (ARGN_LINK_DEPENDS) 02264 string (REGEX REPLACE "^[ \t]*\n" "" SCRIPT "${SCRIPT}") # remove a blank line therefore 02265 set (PERL_CODE "use Cwd qw(realpath); use File::Basename;") 02266 foreach (DIR ${ARGN_LINK_DEPENDS}) 02267 if (DIR MATCHES "^relative +(.*)$") 02268 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 02269 endif () 02270 if (DIR MATCHES "\\.pm$") 02271 get_filename_component (DIR "${DIR}" PATH) 02272 endif () 02273 if (IS_ABSOLUTE "${DIR}") 02274 set (PERL_CODE "${PERL_CODE} use lib '${DIR}';") 02275 else () 02276 set (PERL_CODE "${PERL_CODE} use lib dirname(realpath(__FILE__)) . '/${DIR}';") 02277 endif () 02278 endforeach () 02279 set (SCRIPT "${PERL_CODE} # <-- added by BASIS\n${SCRIPT}") 02280 endif () 02281 elseif (ARGN_LANGUAGE MATCHES "BASH") 02282 basis_library_prefix (PREFIX BASH) 02283 # In case of Bash, set BASIS_BASH_UTILITIES which is required to first source the 02284 # BASIS utilities modules (in particular core.sh). This variable should be set to 02285 # the utilities.sh module of BASIS by default as part of the BASIS installation 02286 # (environment variable) and is here set to the project-specific basis.sh module. 02287 # 02288 # Note that folks at SBIA may submit a Bash script directly to a batch queuing 02289 # system such as the Oracle Grid Engine (SGE) instead of writing a separate submit 02290 # script. To avoid not finding the BASIS utilities in this case only because the 02291 # Bash file was copied by SGE to a temporary file, consider the <PROJECT>_DIR 02292 # environment variable as an alternative. 02293 string (REGEX REPLACE "^[ \t]*\n" "" SCRIPT "${SCRIPT}") # remove a blank line therefore 02294 set (BASH_CODE 02295 # Note: Code formatted such that it can be on single line. Use no comments within! 02296 "__FILE__=\"$(cd -P -- \"$(dirname -- \"$BASH_SOURCE\")\" && pwd -P)/$(basename -- \"$BASH_SOURCE\")\" 02297 if [[ -n \"$SGE_ROOT\" ]] && [[ $__FILE__ =~ $SGE_ROOT/.* ]] && [[ -n \"\${${PROJECT_NAME}_DIR}\" ]] && [[ -f \"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\" ]] 02298 then __FILE__=\"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\" 02299 fi 02300 i=0 02301 lnk=\"$__FILE__\" 02302 while [[ -h \"$lnk\" ]] && [[ $i -lt 100 ]] 02303 do dir=`dirname -- \"$lnk\"` 02304 lnk=`readlink -- \"$lnk\"` 02305 lnk=`cd \"$dir\" && cd $(dirname -- \"$lnk\") && pwd`/`basename -- \"$lnk\"` 02306 let i++ 02307 done 02308 [[ $i -lt 100 ]] && __FILE__=\"$lnk\" 02309 unset -v i dir lnk 02310 __DIR__=\"$(dirname -- \"$__FILE__\")\" 02311 BASIS_BASH_UTILITIES=\"$__DIR__/${BASH_LIBRARY_DIR}/${PREFIX}basis.sh\"" 02312 ) 02313 string (REPLACE "\n" "; " BASH_CODE "${BASH_CODE}") 02314 # set BASHPATH which is used by import() function provided by core.sh module of BASIS 02315 set (BASHPATH) 02316 foreach (DIR ${ARGN_LINK_DEPENDS}) 02317 if (DIR MATCHES "^relative +(.*)$") 02318 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 02319 endif () 02320 if (DIR MATCHES "\\.sh$") 02321 get_filename_component (DIR "${DIR}" PATH) 02322 endif () 02323 if (IS_ABSOLUTE "${DIR}") 02324 list (APPEND BASHPATH "${DIR}") 02325 else () 02326 list (APPEND BASHPATH "$__DIR__/${DIR}") 02327 endif () 02328 endforeach () 02329 if (BASHPATH) 02330 list (REMOVE_DUPLICATES BASHPATH) 02331 list (APPEND BASHPATH "$BASHPATH") 02332 basis_list_to_delimited_string (BASHPATH ":" NOAUTOQUOTE ${BASHPATH}) 02333 set (BASH_CODE "${BASH_CODE}; BASHPATH=\"${BASHPATH}\"") 02334 endif () 02335 set (SCRIPT "${BASH_CODE} # <-- added by BASIS\n${SCRIPT}") 02336 endif () 02337 # replace shebang directive 02338 if (ARGN_LANGUAGE MATCHES "PYTHON" AND PYTHON_EXECUTABLE) 02339 if (WIN32) 02340 set (SHEBANG "@setlocal enableextensions & \"${PYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF") 02341 else () 02342 set (SHEBANG "#! ${PYTHON_EXECUTABLE}") 02343 endif () 02344 elseif (ARGN_LANGUAGE MATCHES "JYTHON" AND JYTHON_EXECUTABLE) 02345 if (WIN32) 02346 set (SHEBANG "@setlocal enableextensions & \"${JYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF") 02347 else () 02348 # Attention: It is IMPORTANT to not use "#! <interpreter>" even if the <interpreter> 02349 # is given as full path in case of jython. Otherwise, the Jython executable 02350 # fails to execute from within a Python script using the os.system(), 02351 # subprocess.popen(), subprocess.call() or similar function! 02352 # Don't ask me for an explanation, but possibly the used shell otherwise does 02353 # not recognize the shebang as being valid. Using /usr/bin/env helps out here, 02354 # -schuha 02355 set (SHEBANG "#! /usr/bin/env ${JYTHON_EXECUTABLE}") 02356 endif () 02357 elseif (ARGN_LANGUAGE MATCHES "PERL" AND PERL_EXECUTABLE) 02358 if (WIN32) 02359 set (SHEBANG "@goto = \"START_OF_BATCH\" ;\n@goto = ();") 02360 set (SCRIPT "${SCRIPT}\n\n__END__\n\n:\"START_OF_BATCH\"\n@\"${PERL_EXECUTABLE}\" -w -S \"%~f0\" %*") 02361 else () 02362 set (SHEBANG "#! ${PERL_EXECUTABLE} -w") 02363 endif () 02364 elseif (ARGN_LANGUAGE MATCHES "BASH" AND BASH_EXECUTABLE) 02365 set (SHEBANG "#! ${BASH_EXECUTABLE}") 02366 endif () 02367 # add (modified) shebang directive again 02368 if (SHEBANG) 02369 set (SCRIPT "${SHEBANG}\n${SCRIPT}") 02370 endif () 02371 # write configured script 02372 file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}") 02373 # make script executable on Unix 02374 if (UNIX AND NOT ARGN_DESTINATION) 02375 execute_process (COMMAND /bin/chmod +x "${_OUTPUT_FILE}") 02376 endif () 02377 # -------------------------------------------------------------------------- 02378 # configure module script 02379 else () 02380 # configure module - do not use configure_file() as it will not update the 02381 # file if nothing has changed. the update of the modification 02382 # time is however in particular required for the 02383 # configure_script.cmake build command which uses this 02384 # function to build script targets. otherwise, the custom 02385 # build command is reexecuted only because the output files 02386 # never appear to be more recent than the dependencies 02387 file (READ "${_INPUT_FILE}" SCRIPT) 02388 if (NOT ARGN_COPYONLY) 02389 string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY) 02390 endif () 02391 file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}") 02392 # compile module if requested 02393 if (ARGN_COMPILE) 02394 if (ARGN_LANGUAGE MATCHES "PYTHON" AND PYTHON_EXECUTABLE) 02395 basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" PYTHON) 02396 execute_process (COMMAND "${PYTHON_EXECUTABLE}" -E -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 02397 basis_compile_python_modules_for_jython (RV) 02398 if (RV) 02399 basis_get_compiled_jython_file_of_python_module (CFILE "${_OUTPUT_FILE}") 02400 get_filename_component (CDIR "${CFILE}" PATH) 02401 file (MAKE_DIRECTORY "${CDIR}") 02402 execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 02403 endif () 02404 elseif (ARGN_LANGUAGE MATCHES "JYTHON" AND JYTHON_EXECUTABLE) 02405 basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" JYTHON) 02406 execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 02407 endif () 02408 endif () 02409 endif () 02410 endfunction () 02411 02412 # ---------------------------------------------------------------------------- 02413 ## @brief Get type name of target. 02414 # 02415 # @param [out] TYPE The target's type name or NOTFOUND. 02416 # @param [in] TARGET_NAME The name of the target. 02417 function (basis_get_target_type TYPE TARGET_NAME) 02418 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 02419 if (TARGET ${TARGET_UID}) 02420 get_target_property (TYPE_OUT ${TARGET_UID} "BASIS_TYPE") 02421 if (NOT TYPE_OUT) 02422 # in particular imported targets may not have a BASIS_TYPE property 02423 get_target_property (TYPE_OUT ${TARGET_UID} "TYPE") 02424 endif () 02425 else () 02426 set (TYPE_OUT "NOTFOUND") 02427 endif () 02428 set ("${TYPE}" "${TYPE_OUT}" PARENT_SCOPE) 02429 endfunction () 02430 02431 # ---------------------------------------------------------------------------- 02432 ## @brief Get location of build target output file(s). 02433 # 02434 # This convenience function can be used to get the full path of the output 02435 # file(s) generated by a given build target. It is similar to the read-only 02436 # @c LOCATION property of CMake targets and should be used instead of 02437 # reading this porperty. In case of scripted libraries, this function returns 02438 # the path of the root directory of the library that has to be added to the 02439 # module search path. 02440 # 02441 # @param [out] VAR Path of build target output file. 02442 # @param [in] TARGET_NAME Name of build target. 02443 # @param [in] PART Which file name component of the @c LOCATION 02444 # property to return. See get_filename_component(). 02445 # If POST_INSTALL_RELATIVE is given as argument, 02446 # @p VAR is set to the path of the installed file 02447 # relative to the installation prefix. Similarly, 02448 # POST_INSTALL sets @p VAR to the absolute path 02449 # of the installed file post installation. 02450 # 02451 # @returns Path of output file similar to @c LOCATION property of CMake targets. 02452 # 02453 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:LOCATION 02454 function (basis_get_target_location VAR TARGET_NAME PART) 02455 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 02456 if (TARGET "${TARGET_UID}") 02457 basis_get_target_name (TARGET_NAME "${TARGET_UID}") 02458 basis_get_target_type (TYPE "${TARGET_UID}") 02459 get_target_property (IMPORTED ${TARGET_UID} IMPORTED) 02460 # ------------------------------------------------------------------------ 02461 # imported custom targets 02462 # 02463 # Note: This might not be required though as even custom executable 02464 # and library targets can be imported using CMake's 02465 # add_executable(<NAME> IMPORTED) and add_library(<NAME> <TYPE> IMPORTED) 02466 # commands. Such executable can, for example, also be a BASH 02467 # script built by basis_add_script(). 02468 if (IMPORTED) 02469 # 1. Try IMPORTED_LOCATION_<CMAKE_BUILD_TYPE> 02470 if (CMAKE_BUILD_TYPE) 02471 string (TOUPPER "${CMAKE_BUILD_TYPE}" U) 02472 else () 02473 set (U "NOCONFIG") 02474 endif () 02475 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${U}) 02476 # 2. Try IMPORTED_LOCATION 02477 if (NOT LOCATION) 02478 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION) 02479 endif () 02480 # 3. Prefer Release over all other configurations 02481 if (NOT LOCATION) 02482 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_RELEASE) 02483 endif () 02484 # 4. Just use any of the imported configurations 02485 if (NOT LOCATION) 02486 get_property (CONFIGS TARGET ${TARGET_UID} PROPERTY IMPORTED_CONFIGURATIONS) 02487 foreach (C IN LISTS CONFIGS) 02488 string (TOUPPER "${C}" C) 02489 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${C}) 02490 if (LOCATION) 02491 break () 02492 endif () 02493 endforeach () 02494 endif () 02495 # make path relative to CMAKE_INSTALL_PREFIX if POST_CMAKE_INSTALL_PREFIX given 02496 if (LOCATION AND ARGV2 MATCHES "POST_INSTALL_RELATIVE") 02497 file (RELATIVE_PATH LOCATION "${CMAKE_INSTALL_PREFIX}" "${LOCATION}") 02498 endif () 02499 # ------------------------------------------------------------------------ 02500 # non-imported custom targets 02501 else () 02502 # Attention: The order of the matches/if cases is matters here! 02503 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02504 # scripts 02505 if (TYPE MATCHES "^SCRIPT_(EXECUTABLE|MODULE)$") 02506 if (PART MATCHES "POST_INSTALL") 02507 get_target_property (DIRECTORY ${TARGET_UID} INSTALL_DIRECTORY) 02508 else () 02509 get_target_property (DIRECTORY ${TARGET_UID} OUTPUT_DIRECTORY) 02510 endif () 02511 get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME) 02512 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02513 # libraries 02514 elseif (TYPE MATCHES "LIBRARY|MODULE|MEX") 02515 if (TYPE MATCHES "STATIC") 02516 if (PART MATCHES "POST_INSTALL") 02517 get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_INSTALL_DIRECTORY) 02518 else () 02519 get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_OUTPUT_DIRECTORY) 02520 endif () 02521 get_target_property (FNAME ${TARGET_UID} ARCHIVE_OUTPUT_NAME) 02522 else () 02523 if (PART MATCHES "POST_INSTALL") 02524 get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_INSTALL_DIRECTORY) 02525 else () 02526 get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_OUTPUT_DIRECTORY) 02527 endif () 02528 get_target_property (FNAME ${TARGET_UID} LIBRARY_OUTPUT_NAME) 02529 endif () 02530 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02531 # executables 02532 else () 02533 if (PART MATCHES "POST_INSTALL") 02534 get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_INSTALL_DIRECTORY) 02535 else () 02536 get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_OUTPUT_DIRECTORY) 02537 endif () 02538 get_target_property (FNAME ${TARGET_UID} RUNTIME_OUTPUT_NAME) 02539 endif () 02540 if (DIRECTORY MATCHES "NOTFOUND") 02541 message (FATAL_ERROR "Failed to get directory of ${TYPE} ${TARGET_UID}!" 02542 " Check implementation of basis_get_target_location()" 02543 " and make sure that the required *INSTALL_DIRECTORY" 02544 " property is set on the target!") 02545 endif () 02546 if (DIRECTORY) 02547 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02548 # get output name of built file (if applicable) 02549 if (NOT FNAME) 02550 get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME) 02551 endif () 02552 if (NOT TYPE MATCHES "^SCRIPT_LIBRARY$") 02553 get_target_property (PREFIX ${TARGET_UID} PREFIX) 02554 get_target_property (SUFFIX ${TARGET_UID} SUFFIX) 02555 if (FNAME) 02556 set (TARGET_FILE "${FNAME}") 02557 else () 02558 set (TARGET_FILE "${TARGET_NAME}") 02559 endif () 02560 if (PREFIX) 02561 set (TARGET_FILE "${PREFIX}${TARGET_FILE}") 02562 endif () 02563 if (SUFFIX) 02564 set (TARGET_FILE "${TARGET_FILE}${SUFFIX}") 02565 elseif (WIN32 AND TYPE MATCHES "^EXECUTABLE$") 02566 set (TARGET_FILE "${TARGET_FILE}.exe") 02567 endif () 02568 endif () 02569 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02570 # assemble final path 02571 if (PART MATCHES "POST_INSTALL_RELATIVE") 02572 if (IS_ABSOLUTE "${DIRECTORY}") 02573 file (RELATIVE_PATH DIRECTORY "${CMAKE_INSTALL_PREFIX}" "${DIRECTORY}") 02574 if (NOT DIRECTORY) 02575 set (DIRECTORY ".") 02576 endif () 02577 endif () 02578 elseif (PART MATCHES "POST_INSTALL") 02579 if (NOT IS_ABSOLUTE "${DIRECTORY}") 02580 set (DIRECTORY "${CMAKE_INSTALL_PREFIX}/${DIRECTORY}") 02581 endif () 02582 endif () 02583 if (TARGET_FILE) 02584 set (LOCATION "${DIRECTORY}/${TARGET_FILE}") 02585 else () 02586 set (LOCATION "${DIRECTORY}") 02587 endif () 02588 else () 02589 set (LOCATION "${DIRECTORY}") 02590 endif () 02591 endif () 02592 # get filename component 02593 if (LOCATION AND PART MATCHES "(^|_)(PATH|NAME|NAME_WE)$") 02594 get_filename_component (LOCATION "${LOCATION}" "${CMAKE_MATCH_2}") 02595 endif () 02596 else () 02597 message (FATAL_ERROR "basis_get_target_location(): Unknown target ${TARGET_UID}") 02598 endif () 02599 # return 02600 set ("${VAR}" "${LOCATION}" PARENT_SCOPE) 02601 endfunction () 02602 02603 # ---------------------------------------------------------------------------- 02604 ## @brief Get link libraries/dependencies of (imported) target. 02605 # 02606 # This function recursively adds the dependencies of the dependencies as well 02607 # and returns them together with the list of the direct link dependencies. 02608 # Moreover, for script targets, if any of the dependencies uses the BASIS 02609 # utilities for the given language (@c BASIS_UTILITIES property), the 02610 # corresponding utilities library is added to the list of dependencies. 02611 # Note that therefore the BASIS utilities targets have to be added already, 02612 # which is only the case during the finalization of script targets. 02613 # 02614 # @param [out] LINK_DEPENDS List of all link dependencies. In case of scripts, 02615 # the dependencies are the required modules or 02616 # paths to required packages, respectively. 02617 # @param [in] TARGET_NAME Name of the target. 02618 function (basis_get_target_link_libraries LINK_DEPENDS TARGET_NAME) 02619 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 02620 if (NOT TARGET "${TARGET_UID}") 02621 message (FATAL_ERROR "basis_get_target_link_libraries(): Unknown target: ${TARGET_UID}") 02622 endif () 02623 if (BASIS_DEBUG AND BASIS_VERBOSE) 02624 message (STATUS "** basis_get_target_link_libraries():") 02625 message (STATUS "** TARGET_NAME: ${TARGET_NAME}") 02626 message (STATUS "** CURRENT_DEPENDS: ${ARGN}") 02627 endif () 02628 # get type of target 02629 get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE) 02630 # get direct link dependencies of target 02631 get_target_property (IMPORTED ${TARGET_UID} IMPORTED) 02632 if (IMPORTED) 02633 # 1. Try IMPORTED_LINK_INTERFACE_LIBRARIES_<CMAKE_BUILD_TYPE> 02634 if (CMAKE_BUILD_TYPE) 02635 string (TOUPPER "${CMAKE_BUILD_TYPE}" U) 02636 else () 02637 set (U "NOCONFIG") 02638 endif () 02639 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${U}") 02640 # 2. Try IMPORTED_LINK_INTERFACE_LIBRARIES 02641 if (NOT DEPENDS) 02642 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES") 02643 endif () 02644 # 3. Prefer Release over all other configurations 02645 if (NOT DEPENDS) 02646 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE") 02647 endif () 02648 # 4. Just use any of the imported configurations 02649 if (NOT DEPENDS) 02650 get_property (CONFIGS TARGET "${TARGET_UID}" PROPERTY IMPORTED_CONFIGURATIONS) 02651 foreach (C IN LISTS CONFIGS) 02652 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${C}") 02653 if (DEPENDS) 02654 break () 02655 endif () 02656 endforeach () 02657 endif () 02658 # otherwise, get LINK_DEPENDS property value 02659 elseif (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$") 02660 get_target_property (DEPENDS ${TARGET_UID} BASIS_LINK_DEPENDS) 02661 else () 02662 get_target_property (DEPENDS ${TARGET_UID} LINK_DEPENDS) 02663 endif () 02664 if (NOT DEPENDS) 02665 set (DEPENDS) 02666 endif () 02667 # prepend BASIS utilities if used (and added) 02668 if (BASIS_TYPE MATCHES "SCRIPT") 02669 set (BASIS_UTILITIES_TARGETS) 02670 foreach (UID IN ITEMS ${TARGET_UID} ${DEPENDS}) 02671 if (TARGET "${UID}") 02672 get_target_property (BASIS_UTILITIES ${UID} BASIS_UTILITIES) 02673 get_target_property (LANGUAGE ${UID} LANGUAGE) 02674 if (BASIS_UTILITIES) 02675 set (BASIS_UTILITIES_TARGET) 02676 if (LANGUAGE MATCHES "[JP]YTHON") 02677 basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.py" NAME) 02678 elseif (LANGUAGE MATCHES "PERL") 02679 basis_get_source_target_name (BASIS_UTILITIES_TARGET "Basis.pm" NAME) 02680 elseif (LANGUAGE MATCHES "BASH") 02681 basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.sh" NAME) 02682 endif () 02683 if (BASIS_UTILITIES_TARGET) 02684 basis_get_target_uid (BASIS_UTILITIES_TARGET ${BASIS_UTILITIES_TARGET}) 02685 endif () 02686 if (TARGET ${BASIS_UTILITIES_TARGET}) 02687 list (APPEND BASIS_UTILITIES_TARGETS ${BASIS_UTILITIES_TARGET}) 02688 endif () 02689 endif () 02690 endif () 02691 endforeach () 02692 if (BASIS_UTILITIES_TARGETS) 02693 list (INSERT DEPENDS 0 ${BASIS_UTILITIES_TARGETS}) 02694 endif () 02695 endif () 02696 # convert target names to UIDs 02697 set (_DEPENDS) 02698 foreach (LIB IN LISTS DEPENDS) 02699 basis_get_target_uid (UID "${LIB}") 02700 if (TARGET ${UID}) 02701 list (APPEND _DEPENDS "${UID}") 02702 else () 02703 list (APPEND _DEPENDS "${LIB}") 02704 endif () 02705 endforeach () 02706 set (DEPENDS "${_DEPENDS}") 02707 unset (_DEPENDS) 02708 # recursively add link dependencies of dependencies 02709 # TODO implement it non-recursively for better performance 02710 foreach (LIB IN LISTS DEPENDS) 02711 if (TARGET ${LIB}) 02712 list (FIND ARGN "${LIB}" IDX) # avoid recursive loop 02713 if (IDX EQUAL -1) 02714 basis_get_target_link_libraries (LIB_DEPENDS ${LIB} ${ARGN} ${DEPENDS}) 02715 list (APPEND DEPENDS ${LIB_DEPENDS}) 02716 endif () 02717 endif () 02718 endforeach () 02719 # remove duplicate entries 02720 if (DEPENDS) 02721 list (REMOVE_DUPLICATES DEPENDS) 02722 endif () 02723 # return 02724 set (${LINK_DEPENDS} "${DEPENDS}" PARENT_SCOPE) 02725 endfunction () 02726 02727 # ============================================================================ 02728 # generator expressions 02729 # ============================================================================ 02730 02731 # ---------------------------------------------------------------------------- 02732 ## @brief Process generator expressions in arguments. 02733 # 02734 # This command evaluates the $<TARGET_FILE:tgt> and related generator 02735 # expressions also for custom targets such as scripts and MATLAB Compiler 02736 # targets. For other generator expressions whose argument is a target name, 02737 # this function replaces the target name by the target UID, i.e., the actual 02738 # CMake target name such that the expression can be evaluated by CMake. 02739 # The following generator expressions are directly evaluated by this function: 02740 # <table border=0> 02741 # <tr> 02742 # @tp <b><tt>$<TARGET_FILE:tgt></tt></b> @endtp 02743 # <td>Absolute file path of built target.</td> 02744 # </tr> 02745 # <tr> 02746 # @tp <b><tt>$<TARGET_FILE_POST_INSTALL:tgt></tt></b> @endtp 02747 # <td>Absolute path of target file after installation using the 02748 # current @c CMAKE_INSTALL_PREFIX.</td> 02749 # </tr> 02750 # <tr> 02751 # @tp <b><tt>$<TARGET_FILE_POST_INSTALL_RELATIVE:tgt></tt></b> @endtp 02752 # <td>Path of target file after installation relative to @c CMAKE_INSTALL_PREFIX.</td> 02753 # </tr> 02754 # </table> 02755 # Additionally, the suffix <tt>_NAME</tt> or <tt>_DIR</tt> can be appended 02756 # to the name of each of these generator expressions to get only the basename 02757 # of the target file including the extension or the corresponding directory 02758 # path, respectively. 02759 # 02760 # Generator expressions are in particular supported by basis_add_test(). 02761 # 02762 # @param [out] ARGS Name of output list variable. 02763 # @param [in] ARGN List of arguments to process. 02764 # 02765 # @sa basis_add_test() 02766 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test 02767 function (basis_process_generator_expressions ARGS) 02768 set (ARGS_OUT) 02769 foreach (ARG IN LISTS ARGN) 02770 string (REGEX MATCHALL "\\$<.*TARGET.*:.*>" EXPRS "${ARG}") 02771 foreach (EXPR IN LISTS EXPRS) 02772 if (EXPR MATCHES "\\$<(.*):(.*)>") 02773 set (EXPR_NAME "${CMAKE_MATCH_1}") 02774 set (TARGET_NAME "${CMAKE_MATCH_2}") 02775 # TARGET_FILE* expression, including custom targets 02776 if (EXPR_NAME MATCHES "^TARGET_FILE(.*)") 02777 if (NOT CMAKE_MATCH_1) 02778 set (CMAKE_MATCH_1 "ABSOLUTE") 02779 endif () 02780 string (REGEX REPLACE "^_" "" PART "${CMAKE_MATCH_1}") 02781 basis_get_target_location (ARG "${TARGET_NAME}" ${PART}) 02782 # other generator expression supported by CMake 02783 # only replace target name, but do not evaluate expression 02784 else () 02785 basis_get_target_uid (TARGET_UID "${CMAKE_MATCH_2}") 02786 string (REPLACE "${EXPR}" "$<${CMAKE_MATCH_1}:${TARGET_UID}>" ARG "${ARG}") 02787 endif () 02788 if (BASIS_DEBUG AND BASIS_VERBOSE) 02789 message ("** basis_process_generator_expressions():") 02790 message ("** Expression: ${EXPR}") 02791 message ("** Keyword: ${EXPR_NAME}") 02792 message ("** Argument: ${TARGET_NAME}") 02793 message ("** Replaced by: ${ARG}") 02794 endif () 02795 endif () 02796 endforeach () 02797 list (APPEND ARGS_OUT "${ARG}") 02798 endforeach () 02799 set (${ARGS} "${ARGS_OUT}" PARENT_SCOPE) 02800 endfunction () 02801 02802 02803 ## @} 02804 # end of Doxygen group