1# ============================================================================ 2# Copyright (c) 2011-2012 University of Pennsylvania 3# Copyright (c) 2013-2014 Carnegie Mellon University 4# Copyright (c) 2013-2016 Andreas Schuh 5# All rights reserved. 6# 7# See COPYING file for license information or visit 8# https://cmake-basis.github.io/download.html#license 9# ============================================================================ 10 11############################################################################## 12# @file CommonTools.cmake 13# @brief Definition of common CMake functions. 14# 15# @ingroup CMakeTools 16############################################################################## 17 18if (__BASIS_COMMONTOOLS_INCLUDED) 19 return () 20else () 21 set (__BASIS_COMMONTOOLS_INCLUDED TRUE) 22endif () 23 24 25include (CMakeParseArguments) 26 27 28## @addtogroup CMakeUtilities 29# @{ 30 31 32# ============================================================================ 33# find other packages 34# ============================================================================ 35 36# ---------------------------------------------------------------------------- 37## @brief Overloaded find_package() command. 38# 39# This macro calls CMake's 40# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package"> 41# find_package()</a> command and converts obsolete all uppercase "<PKG>_<VAR>" 42# variables to case-sensitive "<Pkg>_<VAR>" variables. 43# It further ensures that the global variables CMAKE_FIND_LIBRARY_SUFFIXES 44# and CMAKE_FIND_EXECUTABLE_SUFFIX are reset to the values they had before 45# the call to find_package(). This is required if the "Find<Pkg>.cmake" module 46# has modified these variables, but not restored their initial value. 47macro (find_package) 48 if (BASIS_DEBUG) 49 message ("** find_package(${ARGV})") 50 endif () 51 # attention: find_package() can be recursive. Hence, use "stack" to keep 52 # track of library suffixes. Further note that we need to 53 # maintain a list of lists, which is not supported by CMake. 54 list (APPEND _BASIS_FIND_LIBRARY_SUFFIXES "{${CMAKE_FIND_LIBRARY_SUFFIXES}}") 55 list (APPEND _BASIS_FIND_EXECUTABLE_SUFFIX "${CMAKE_FIND_EXECUTABLE_SUFFIX}") 56 _find_package(${ARGV}) 57 # map common uppercase <PKG>_* variables to case-preserving <Pkg>_* 58 string (TOUPPER "${ARGV0}" _FP_ARGV0_U) 59 foreach (_FP_VAR IN ITEMS FOUND DIR USE_FILE 60 VERSION VERSION_STRING 61 VERSION_MAJOR VERSION_MINOR VERSION_SUBMINOR VERSION_PATCH 62 MAJOR_VERSION MINOR_VERSION SUBMINOR_VERSION PATCH_VERSION 63 INCLUDE_DIR INCLUDE_DIRS INCLUDE_PATH 64 LIBRARY_DIR LIBRARY_DIRS LIBRARY_PATH 65 EXECUTABLE COMPILER CONVERTER) 66 if (NOT ${ARGV0}_${_FP_VAR} AND DEFINED ${_FP_ARGV0_U}_${_FP_VAR}) 67 set (${ARGV0}_${_FP_VAR} "${${_FP_ARGV0_U}_${_FP_VAR}}") 68 endif () 69 endforeach () 70 unset (_FP_VAR) 71 unset (_FP_ARGV0_U) 72 # restore CMAKE_FIND_LIBRARY_SUFFIXES 73 string (REGEX REPLACE ";?{([^}]*)}$" "" _BASIS_FIND_LIBRARY_SUFFIXES "${_BASIS_FIND_LIBRARY_SUFFIXES}") 74 set (CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_MATCH_1}") 75 # restore CMAKE_FIND_EXECUTABLE_SUFFIX 76 list (LENGTH _BASIS_FIND_EXECUTABLE_SUFFIX _FP_LAST) 77 if (_FP_LAST GREATER 0) 78 math (EXPR _FP_LAST "${_FP_LAST} - 1") 79 list (REMOVE_AT _BASIS_FIND_EXECUTABLE_SUFFIX ${_FP_LAST}) 80 endif () 81 unset (_FP_LAST) 82endmacro () 83 84# ---------------------------------------------------------------------------- 85## @brief Tokenize dependency specification. 86# 87# This function parses a dependency specification such as 88# "ITK-4.1{TestKernel,IO}" into the package name, i.e., ITK, the requested 89# (minimum) package version(s), i.e., 4.1, and a list of package components, i.e., 90# TestKernel and IO. A valid dependency specification must specify the package 91# name of the dependency (case-sensitive). The version and components 92# specification are optional. Note that the components specification may 93# be separated by an arbitrary number of whitespace characters including 94# newlines. The same applies to the specification of the components themselves. 95# This allows one to format the dependency specification as follows, for example: 96# @code 97# ITK { 98# TestKernel, 99# IO 100# } 101# @endcode 102# 103# VTK-7|6{} 104# 105# @param [in] DEP Dependency specification, i.e., "<Pkg>[-<version>[|...]][{<Component1>[,...]}]". 106# @param [out] PKG Package name. 107# @param [out] VER Package version(s). 108# @param [out] CMP List of package components. 109function (basis_tokenize_dependency DEP PKG VER CMP) 110 set (CMPS) 111 if (DEP MATCHES "^([^ ]+)[ \\n\\t]*{([^}]*)}$") 112 set (DEP "${CMAKE_MATCH_1}") 113 string (REPLACE "," ";" COMPONENTS "${CMAKE_MATCH_2}") 114 foreach (C IN LISTS COMPONENTS) 115 string (STRIP "${C}" C) 116 list (APPEND CMPS ${C}) 117 endforeach () 118 endif () 119 if (DEP MATCHES "^(.*)-([0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(\\|[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?)*)$") 120 string (REPLACE "|" ";" CMAKE_MATCH_2 "${CMAKE_MATCH_2}") 121 set (${PKG} "${CMAKE_MATCH_1}" PARENT_SCOPE) 122 set (${VER} "${CMAKE_MATCH_2}" PARENT_SCOPE) 123 else () 124 set (${PKG} "${DEP}" PARENT_SCOPE) 125 set (${VER} "" PARENT_SCOPE) 126 endif () 127 set (${CMP} "${CMPS}" PARENT_SCOPE) 128endfunction () 129 130## @brief Get installation prefix given path of <PKG>Config directory 131function (_basis_config_to_prefix_dir PKG PKG_DIR PREFIX) 132 if (PKG_DIR) 133 if (APPLE) 134 if (PKG_DIR MATCHES "^(.*)/([^/]+)\\.(framework|app)(/|$)") 135 set (${PREFIX} "${CMAKE_MATCH_1}/${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE) 136 return () 137 endif () 138 endif () 139 string (REGEX REPLACE "/+(cmake|CMake)/*$" "" prefix "${PKG_DIR}") 140 set (SUBDIR_RE "/+(lib[0-9]*(/[^/]+)?|share)(/+cmake)?") 141 if (UNIX AND prefix MATCHES "${SUBDIR_RE}(/+[^/]+|/*$)") 142 get_filename_component (subdir "${prefix}" NAME) 143 string (TOLOWER "${subdir}" subdir) 144 string (TOLOWER "${PKG}" pkg) 145 if ("^${subdir}$" STREQUAL "^${pkg}$") 146 get_filename_component (prefix "${prefix}" PATH) 147 endif () 148 string(REGEX REPLACE "${SUBDIR_RE}/*$" "" prefix "${prefix}") 149 endif () 150 else () 151 set(prefix "NOTFOUND") 152 endif () 153 set(${PREFIX} "${prefix}" PARENT_SCOPE) 154endfunction () 155 156# ---------------------------------------------------------------------------- 157## @brief Find external software package or other project module. 158# 159# This macro replaces CMake's 160# <a href="https://cmake.org/cmake/help/v2.8.12/cmake.html#command:find_package"> 161# find_package()</a> command and extends its functionality. 162# In particular, if the given package name is the name of another module 163# of this project (the top-level project), it ensures that this module is 164# found instead of an external package. 165# 166# If the package is found, but only optionally used, i.e., the @c REQUIRED 167# argument was not given to this macro, a <tt>WITH_<PACKAGE></tt> option 168# is added by this macro which is by default @c OFF. This option can be set to 169# @c ON by the user in order to require the discovery of the package. 170# When this option is OFF, the (non-cached) <tt>USE_<PACKAGE></tt> variable 171# can be used by project developers to still request the discovery of the 172# optional package, but no error is raised when the package is not found. 173# This allows a project to use an optional dependency when an installation 174# is found regardless of the <tt>WITH_<PACKAGE></tt> option. Note 175# that when <tt>USE_<PACKAGE></tt> is defined, no <tt>WITH_<PACKAGE></tt> 176# entry is added by this macro to the cache. 177# 178# @param [in] PACKAGE Name of software package or other project module. 179# Optionally, the package name can include a version 180# specification as suffix which is separated from the 181# package name using a dash (-), i.e., <Package>[-major[.minor[.patch[.tweak]]]]. 182# Multiple alternative versions have to be separated by 183# a pipe character "|", the logical OR. 184# If a version specification is given, it is passed on as 185# @c version argument to CMake's 186# <a href="https://cmake.org/cmake/help/v2.8.12/cmake.html#command:find_package"> 187# find_package()</a> command. The discovery of multiple 188# alternative versions is only supported for the CONFIG 189# mode of the find_package command. 190# @param [in] ARGN Additional arguments for 191# <a href="https://cmake.org/cmake/help/v2.8.12/cmake.html#command:find_package"> 192# find_package()</a>. 193# 194# @retval <PACKAGE>_FOUND Whether the given package was found. 195# @retval <PACKAGE>_COMPONENTS_FOUND Names of found components. 196# Optional components are only included when 197# "<PACKAGE>_<COMPONENT>_FOUND" is set to @c TRUE 198# for each found component by the find_package call, 199# i.e., either the "Find<PACKAGE>" module or the 200# "<PACKAGE>Config" file. 201# 202# @sa https://cmake.org/cmake/help/v2.8.12/cmake.html#command:find_package 203# 204# @ingroup CMakeAPI 205macro (basis_find_package PACKAGE) 206 # Note that this MUST be a macro such that non-cached variables 207 # set by find_package are set within the callers scope 208 # ------------------------------------------------------------------------ 209 # parse arguments 210 set (_BFP_OPTIONS 211 QUIET 212 REQUIRED 213 MODULE 214 NO_MODULE 215 CONFIG 216 NO_NOTFOUND_ERROR 217 ) 218 set (_BFP_MULTI_ARGS 219 COMPONENTS 220 OPTIONAL_COMPONENTS 221 ) 222 cmake_parse_arguments ( 223 _BFP_ARGN 224 "${_BFP_OPTIONS}" 225 "" 226 "${_BFP_MULTI_ARGS}" 227 ${ARGN} 228 ) 229 # ------------------------------------------------------------------------ 230 # tokenize dependency specification 231 basis_tokenize_dependency ("${PACKAGE}" PKG _BFP_VERSIONS _BFP_COMPONENTS) 232 list (GET _BFP_ARGN_UNPARSED_ARGUMENTS 0 _BFP_VERSION) 233 if (_BFP_VERSION MATCHES "^[0-9]+(\\.[0-9]+)*(\\|[0-9]+(\\.[0-9]+)*)*$") 234 if (_BFP_VERSIONS) 235 message (FATAL_ERROR "Cannot use both version specification as part of " 236 "package name and explicit version argument.") 237 endif () 238 list (REMOVE_AT _BFP_ARGN_UNPARSED_ARGUMENTS 0) 239 string(REPLACE "|" ";" _BFP_VERSIONS ${_BFP_VERSION}) 240 endif () 241 list (LENGTH _BFP_VERSIONS _BFP_VERSIONS_COUNT) 242 if (_BFP_ARGN_MODULE AND _BFP_VERSIONS GREATER 1) 243 message (FATAL_ERROR "Cannot look for multiple alternative package versions" 244 " in MODULE mode. The CONFIG|NO_MODULE mode of find_package" 245 " is used in this case. When MODULE mode is required" 246 " by package ${PKG}, only one version can be specified.") 247 endif () 248 string (TOLOWER "${PKG}" PKG_L) 249 string (TOUPPER "${PKG}" PKG_U) 250 # ------------------------------------------------------------------------ 251 # set <PKG>_FIND_REQUIRED_<CMP> 252 foreach (_BFP_CMP IN LISTS _BFP_COMPONENTS) 253 set (${PKG}_FIND_REQUIRED_${_BFP_CMP} ${_BFP_ARGN_REQUIRED}) 254 endforeach () 255 foreach (_BFP_CMP IN LISTS _BFP_ARGN_COMPONENTS) 256 set (${PKG}_FIND_REQUIRED_${_BFP_CMP} TRUE) 257 endforeach () 258 foreach (_BFP_CMP IN LISTS _BFP_ARGN_OPTIONAL_COMPONENTS) 259 set (${PKG}_FIND_REQUIRED_${_BFP_CMP} FALSE) 260 endforeach () 261 list (APPEND _BFP_ARGN_COMPONENTS ${_BFP_COMPONENTS}) 262 if (_BFP_ARGN_COMPONENTS) 263 list (REMOVE_DUPLICATES _BFP_ARGN_COMPONENTS) 264 endif () 265 # ------------------------------------------------------------------------ 266 # prefix of package variable names set by Find<Pkg> or <Pkg>Config 267 if (PKG MATCHES "^((P|J)ython)Interp$") 268 string (TOUPPER "${CMAKE_MATCH_1}" _BFP_NS) 269 else () 270 set (_BFP_NS "${PKG}") 271 endif () 272 # ------------------------------------------------------------------------ 273 # some debugging output 274 if (BASIS_DEBUG) 275 set (_BFP_ARGS) 276 if (_BFP_ARGN_REQUIRED) 277 list (APPEND _BFP_ARGS REQUIRED) 278 endif () 279 if (_BFP_ARGN_QUIET) 280 list (APPEND _BFP_ARGS QUIET) 281 endif () 282 if (_BFP_ARGN_MODULE) 283 list (APPEND _BFP_ARGS MODULE) 284 endif () 285 if (_BFP_ARGN_NO_MODULE OR _BFP_ARGN_CONFIG) 286 list (APPEND _BFP_ARGS CONFIG) 287 endif () 288 list (APPEND _BFP_ARGS ${_BFP_ARGN_UNPARSED_ARGUMENTS}) 289 set (_BFP_INFO "** basis_find_package()") 290 set (_BFP_INFO "${_BFP_INFO}\n** Package: ${PKG}") 291 if (_BFP_VERSIONS) 292 set (_BFP_INFO "${_BFP_INFO}\n** Versions: ${_BFP_VERSIONS}") 293 endif () 294 set (_BFP_INFO "${_BFP_INFO}\n** Arguments: [${_BFP_ARGS}]") 295 if (_BFP_ARGN_COMPONENTS OR _BFP_ARGN_OPTIONAL_COMPONENTS) 296 set (_BFP_INFO "${_BFP_INFO}\n** Components: ") 297 if (_BFP_ARGN_COMPONENTS AND _BFP_ARGN_OPTIONAL_COMPONENTS) 298 set (_BFP_INFO "${_BFP_INFO}[${_BFP_ARGN_COMPONENTS}] and [${_BFP_ARGN_OPTIONAL_COMPONENTS}] (optional)") 299 elseif (_BFP_ARGN_COMPONENTS) 300 set (_BFP_INFO "${_BFP_INFO}[${_BFP_ARGN_COMPONENTS}]") 301 else () 302 set (_BFP_INFO "${_BFP_INFO}[${_BFP_ARGN_OPTIONAL_COMPONENTS}] (optional)") 303 endif () 304 endif () 305 message ("${_BFP_INFO}") 306 unset (_BFP_INFO) 307 unset (_BFP_ARGS) 308 endif () 309 # ------------------------------------------------------------------------ 310 # find other modules of same project 311 set (_BFP_IS_PROJECT FALSE) 312 set (_BFP_IS_MODULE FALSE) 313 if (PROJECT_IS_MODULE) 314 # allow modules to specify top-level project as dependency, 315 # respectively, other modules as components of top-level project 316 if ("^${PKG}$" STREQUAL "^${TOPLEVEL_PROJECT_NAME}$") 317 if (_BFP_ARGN_COMPONENTS OR _BFP_ARGN_OPTIONAL_COMPONENTS) 318 if (BASIS_DEBUG) 319 message ("** This is the top-level project. Components must be other modules of this project.") 320 endif () 321 foreach (_BFP_CMP IN LISTS _BFP_ARGN_COMPONENTS _BFP_ARGN_OPTIONAL_COMPONENTS) 322 list (FIND PROJECT_MODULES "${_BFP_CMP}" _BFP_CMPIDX) 323 if (_BFP_CMPIDX EQUAL -1) 324 message (FATAL_ERROR "Module ${PROJECT_NAME} has module ${_BFP_CMP} of top-level project ${PKG}" 325 " as dependency, but no such module exists.") 326 endif () 327 list (FIND PROJECT_MODULES_ENABLED "${_BFP_CMP}" _BFP_CMPIDX) 328 if (_BFP_CMPIDX EQUAL -1) 329 if (BASIS_DEBUG) 330 message ("** Identified it as disabled module of this project.") 331 endif () 332 if (${PKG}_FIND_REQUIRED_${_BFP_CMP}) 333 if (_BFP_ARGN_REQUIRED) 334 message (FATAL_ERROR 335 "Module ${PROJECT_NAME} requires module ${_BFP_CMP} of top-level project ${PKG}," 336 " but module ${_BFP_CMP} is not enabled." 337 ) 338 elseif (NOT _BFP_ARGN_QUIET) 339 message (STATUS 340 "Module ${PROJECT_NAME} optionally uses module ${_BFP_CMP} of top-level project ${PKG}," 341 " but module ${_BFP_CMP} is not enabled." 342 ) 343 endif () 344 endif () 345 set (${PKG}_${_BFP_CMP}_FOUND FALSE) 346 else () 347 if (BASIS_DEBUG) 348 message ("** Identified it as enabled module of this project.") 349 endif () 350 include ("${BINARY_LIBCONF_DIR}/${TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX}${_BFP_CMP}Config.cmake") 351 set (${PKG}_${_BFP_CMP}_FOUND TRUE) 352 endif () 353 endforeach () 354 else () 355 if (BASIS_DEBUG) 356 message ("** This is the top-level project.") 357 endif () 358 endif () 359 set (${PKG}_FOUND TRUE) 360 set (_BFP_IS_PROJECT TRUE) 361 # look for other module of top-level project 362 else () 363 list (FIND PROJECT_MODULES "${PKG}" _BFP_PKGIDX) 364 if (NOT _BFP_PKGIDX EQUAL -1) 365 set (_BFP_IS_MODULE TRUE) 366 list (FIND PROJECT_MODULES_ENABLED "${PKG}" _BFP_PKGIDX) 367 if (_BFP_PKGIDX EQUAL -1) 368 if (BASIS_DEBUG) 369 message ("** Identified it as disable module of this project.") 370 endif () 371 if (_BFP_ARGN_REQUIRED) 372 message (FATAL_ERROR 373 "Module ${PROJECT_NAME} requires module ${_BFP_CMP} of top-level project ${PKG}," 374 " but module ${_BFP_CMP} is not enabled." 375 ) 376 elseif (NOT _BFP_ARGN_QUIET) 377 message (STATUS 378 "Module ${PROJECT_NAME} optionally uses module ${_BFP_CMP} of top-level project ${PKG}," 379 " but module ${_BFP_CMP} is not enabled." 380 ) 381 endif () 382 set (${PKG}_FOUND FALSE) 383 else () 384 if (BASIS_DEBUG) 385 message ("** Identified it as enabled module of this project.") 386 endif () 387 include ("${BINARY_LIBCONF_DIR}/${TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX}${PKG}Config.cmake") 388 set (${PKG}_FOUND TRUE) 389 endif () 390 endif () 391 endif () 392 # -------------------------------------------------------------------------- 393 # find bundled packages 394 else () 395 list (FIND BUNDLE_PROJECTS "${PKG}" _BFP_PKGIDX) 396 if (NOT _BFP_PKGIDX EQUAL -1) 397 if (EXISTS "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG}Config.cmake") 398 set (_BFP_CONFIG_FILE "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG}Config.cmake") 399 else () 400 if (EXISTS "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG_L}-config.cmake") 401 set (_BFP_CONFIG_FILE "${CMAKE_INSTALL_PREFIX}/${INSTALL_CONFIG_DIR}/${PKG_L}-config.cmake") 402 else () 403 set (_BFP_CONFIG_FILE) 404 endif () 405 endif () 406 if (_BFP_CONFIG_FILE) 407 if (BASIS_DEBUG) 408 message ("** Identified it as other package of this bundle.") 409 endif () 410 get_filename_component (_BFP_CONFIG_DIR "${_BFP_CONFIG_FILE}" PATH) 411 _basis_config_to_prefix_dir (${PKG} "${_BFP_CONFIG_DIR}" _BFP_PREFIX) 412 basis_set_or_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}" PATH) 413 include ("${_BFP_CONFIG_FILE}") 414 set (${PKG}_FOUND TRUE) 415 unset (_BFP_CONFIG_DIR) 416 endif () 417 unset (_BFP_CONFIG_FILE) 418 endif () 419 endif () 420 # -------------------------------------------------------------------------- 421 # otherwise, look for external package 422 if (NOT _BFP_IS_PROJECT AND NOT _BFP_IS_MODULE) 423 # ------------------------------------------------------------------------ 424 # provide option which allows users to request use of optional packages 425 # 426 # - WITH_<PKG> == ON: optional dependency is required 427 # - WITH_<PKG> == OFF: 428 # - USE_<PKG> == ON: dependency is looked for and used if available 429 # - USE_<PKG> == OFF: dependency is ignored 430 # 431 # The default of the WITH_<PKG> option is OFF unless WITH_<PKG>_DEFAULT 432 # is set in the Depends.cmake, the CMake command-line using the -D switch 433 # or the root CMakeLists.txt file before the basis_project_begin call. 434 # The (uncached) WITH_${PKG}_DEFAULT variable can be used by a project 435 # to require optional dependencies by default, e.g., to enable optional 436 # program features that depend on these external packages. 437 if (NOT _BFP_ARGN_REQUIRED) 438 if (NOT DEFINED WITH_${PKG}_DEFAULT) 439 set (WITH_${PKG}_DEFAULT OFF) 440 endif () 441 if (DEFINED USE_${PKG} AND NOT DEFINED WITH_${PKG}) 442 set (WITH_${PKG} ${WITH_${PKG}_DEFAULT}) 443 else () 444 option (WITH_${PKG} "Build with optional ${PKG} dependency" ${WITH_${PKG}_DEFAULT}) 445 endif () 446 endif () 447 # look for external package only if required, built with optional dependency 448 # enabled by user (cf. WITH_<PKG> option above) or deprecated -DUSE_<PKG>=ON 449 if (_BFP_ARGN_REQUIRED OR WITH_${PKG} OR USE_${PKG}) 450 # ---------------------------------------------------------------------- 451 # Use more user friendly hybrid DEPENDS_<PKG>_DIR cache variable which 452 # allows grouping of DEPENDS paths cache entry, but still consider more 453 # common variables named <PKG>_DIR, <PKG>_ROOT, <PKG>ROOT, or <PKG>_ROOT_DIR 454 # set in the user shell environment or on the CMake command-line using -D. 455 set ( 456 DEPENDS_${PKG}_DIR "${DEPENDS_${PKG}_DIR}" CACHE PATH 457 "Top-level installation directory of ${PKG} or directory containing ${PKG}Config.cmake file." 458 ) 459 if (DEPENDS_${PKG}_DIR) 460 file (TO_CMAKE_PATH "${DEPENDS_${PKG}_DIR}" _BFP_PREFIX) 461 if (NOT "^${DEPENDS_${PKG}_DIR}$" STREQUAL "^${_BFP_PREFIX}$") 462 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 463 endif () 464 endif () 465 # Names of considered alternative find search path variables excl. <PKG>_DIR 466 set (_BFP_PKG_DIR_VARS 467 ${PKG}_ROOT ${PKG_U}_ROOT 468 ${PKG}ROOT ${PKG_U}ROOT 469 ${PKG}_ROOT_DIR ${PKG_U}_ROOT_DIR 470 ) 471 list (REMOVE_DUPLICATES _BFP_PKG_DIR_VARS) 472 # Override DEPENDS_<PKG>_DIR by alternative search path variable value if these 473 # were specified on the command line using the -D option. Note that these variables 474 # cannot be set in the CMake GUI because their type is changed here to INTERNAL. 475 # This has two reasons, firstly to not have duplicate variables with different 476 # names for the same purpose, and secondly to be able to recognize when their 477 # value is changed using the -D command line option of the cmake command. 478 # 479 # Order of precedence: 480 # 1. <PKG>_DIR 481 # 2. <PKG>_ROOT... CMake variable 482 # 3. <PKG>_ROOT... environment variable 483 foreach (_BFP_VAR IN LISTS _BFP_PKG_DIR_VARS) 484 file (TO_CMAKE_PATH "${${_BFP_VAR}}" _BFP_PREFIX) # CMake (cache) variable 485 if (_BFP_PREFIX) 486 # first configure run or new value specified using -D option of cmake command 487 if (NOT DEFINED _DEPENDS_${PKG}_DIR OR (DEFINED _DEPENDS_${PKG}_DIR AND NOT "^${_BFP_PREFIX}$" STREQUAL "^${_DEPENDS_${PKG}_DIR}$")) 488 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 489 break () 490 endif () 491 endif () 492 endforeach () 493 if (${PKG}_DIR) # find_package CONFIG mode variable 494 # first configure run or new value specified using -D option of cmake command 495 if (NOT DEFINED _${PKG}_DIR OR (DEFINED _${PKG}_DIR AND NOT "^${${PKG}_DIR}$" STREQUAL "^${_${PKG}_DIR}$")) 496 file (TO_CMAKE_PATH "${${PKG}_DIR}" _BFP_PREFIX) 497 _basis_config_to_prefix_dir(${PKG} "${_BFP_PREFIX}" _BFP_PREFIX) 498 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 499 endif () 500 endif () 501 # mark alternatives as internal cache entries 502 foreach (_BFP_VAR IN LISTS _BFP_PKG_DIR_VARS) 503 basis_is_cached (_BFP_CACHED ${_BFP_VAR}) 504 if (_BFP_CACHED) 505 basis_update_type_of_variable (${_BFP_VAR} INTERNAL) 506 endif () 507 endforeach () 508 # if still not set, use common environment variables to set DEPENDS_<PKG>_DIR 509 if (NOT DEPENDS_${PKG}_DIR) 510 foreach (_BFP_VAR IN LISTS _BFP_PKG_DIR_VARS) 511 file (TO_CMAKE_PATH "$ENV{${_BFP_VAR}}" _BFP_PREFIX) # shell environment variable 512 if (_BFP_PREFIX) 513 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 514 break() 515 endif () 516 endforeach () 517 endif () 518 # circumvent issue with find_package interpreting <PKG>_DIR relative 519 # to the current binary directory instead of the top-level directory 520 if (DEPENDS_${PKG}_DIR AND NOT IS_ABSOLUTE "${DEPENDS_${PKG}_DIR}") 521 get_filename_component (_BFP_PREFIX "${CMAKE_BINARY_DIR}/${DEPENDS_${PKG}_DIR}" ABSOLUTE) 522 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 523 endif () 524 # -------------------------------------------------------------------- 525 # reset _?<PKG>[_-]* variables when DEPENDS_<PKG>_DIR has changed 526 if (_DEPENDS_${PKG}_DIR AND DEPENDS_${PKG}_DIR) 527 if (NOT "^${_DEPENDS_${PKG}_DIR}$" STREQUAL "^${DEPENDS_${PKG}_DIR}$") 528 get_cmake_property (_BFP_VARS VARIABLES) 529 basis_sanitize_for_regex (PKG_RE "${PKG}") 530 basis_sanitize_for_regex (PKG_U_RE "${PKG_U}") 531 basis_sanitize_for_regex (_BFP_NS_RE "${_BFP_NS}") 532 foreach (_BFP_VAR IN LISTS _BFP_VARS) 533 if (_BFP_VAR MATCHES "^_?(${_BFP_NS_RE}|${PKG_RE}|${PKG_U_RE})[_-]") 534 basis_is_cached (_BFP_CACHED ${_BFP_VAR}) 535 if (_BFP_CACHED) 536 set_property (CACHE ${_BFP_VAR} PROPERTY VALUE "${_BFP_VAR}-NOTFOUND") 537 set_property (CACHE ${_BFP_VAR} PROPERTY TYPE INTERNAL) 538 elseif (NOT _BFP_VAR MATCHES "^${PKG_RE}_FIND_") 539 unset (${_BFP_VAR}) 540 endif () 541 endif () 542 endforeach () 543 unset (PKG_RE) 544 unset (PKG_U_RE) 545 unset (_BFP_NS_RE) 546 endif () 547 endif () 548 # ---------------------------------------------------------------------- 549 # determine if additional components of found package should be discovered 550 if (${PKG}_FOUND) 551 set (_BFP_NO_FIND_PACKAGE TRUE) 552 if (${PKG}_COMPONENTS_FOUND) 553 # previously called with COMPONENTS 554 set (_BFP_FIND_COMPONENTS) 555 set (_BFP_FIND_OPTIONAL_COMPONENTS) 556 if (_BFP_ARGN_COMPONENTS OR _BFP_ARGN_OPTIONAL_COMPONENTS) 557 foreach (_BFP_CMP IN LISTS _BFP_ARGN_COMPONENTS _BFP_ARGN_OPTIONAL_COMPONENTS) 558 list (FIND ${PKG}_COMPONENTS_FOUND "${_BFP_CMP}" _BFP_CMPIDX) 559 if (_BFP_CMPIDX EQUAL -1) 560 if (${PKG}_FIND_REQUIRED_${_BFP_CMP}) 561 list (APPEND _BFP_FIND_COMPONENTS "${_BFP_CMP}") 562 elseif (NOT DEFINED ${PKG}_${_BFP_CMP}_FOUND) 563 list (APPEND _BFP_FIND_OPTIONAL_COMPONENTS "${_BFP_CMP}") 564 endif () 565 endif () 566 endforeach () 567 else () 568 # Not sure if "default" components were found when find_package 569 # was previously invoked with the COMPONENTS argument, but 570 # now without it. This depends on the Find<PKG> module. 571 set (_BFP_NO_FIND_PACKAGE FALSE) 572 endif () 573 else () 574 # previously called without COMPONENTS 575 set (_BFP_FIND_COMPONENTS ${_BFP_ARGN_COMPONENTS}) 576 set (_BFP_FIND_OPTIONAL_COMPONENTS ${_BFP_ARGN_OPTIONAL_COMPONENTS}) 577 endif () 578 if (_BFP_FIND_COMPONENTS OR _BFP_FIND_OPTIONAL_COMPONENTS) 579 set (_BFP_NO_FIND_PACKAGE FALSE) 580 endif () 581 else () 582 set (_BFP_NO_FIND_PACKAGE FALSE) 583 set (_BFP_FIND_COMPONENTS ${_BFP_ARGN_COMPONENTS}) 584 set (_BFP_FIND_OPTIONAL_COMPONENTS ${_BFP_ARGN_OPTIONAL_COMPONENTS}) 585 endif () 586 # ---------------------------------------------------------------------- 587 # look for external package if not found or additional components needed 588 if (NOT ${PKG}_FOUND AND NOT _BFP_ARGN_REQUIRED AND NOT WITH_${PKG} AND ((DEFINED USE_${PKG} AND NOT USE_${PKG}) OR NOT DEFINED USE_${PKG})) 589 # skip if package is optional and user did not ask us to look for it 590 # when package was found before, still perform steps below to ensure 591 # that everything is set properly even when find_package was called 592 mark_as_advanced (FORCE DEPENDS_${PKG}_DIR) 593 else () 594 # status message with information what we are looking for 595 if (_BFP_ARGN_QUIET) 596 set (_BFP_STATUS) 597 else () 598 set (_BFP_STATUS "Looking for ${PKG}") 599 if (_BFP_VERSIONS) 600 string (REPLACE ";" " or " _BFP_VERSION_STRING "${_BFP_VERSIONS}") 601 set (_BFP_STATUS "${_BFP_STATUS} ${_BFP_VERSION_STRING}") 602 unset (_BFP_VERSION_STRING) 603 endif () 604 if (_BFP_FIND_COMPONENTS) 605 set (_BFP_STATUS "${_BFP_STATUS} [${_BFP_FIND_COMPONENTS}]") 606 endif () 607 if (_BFP_FIND_OPTIONAL_COMPONENTS) 608 set (_BFP_STATUS "${_BFP_STATUS}, optional components [${_BFP_FIND_OPTIONAL_COMPONENTS}]") 609 endif () 610 if (NOT _BFP_ARGN_REQUIRED) 611 set (_BFP_STATUS "${_BFP_STATUS} (optional)") 612 endif () 613 set (_BFP_STATUS "${_BFP_STATUS}...") 614 message (STATUS "${_BFP_STATUS}") 615 endif () 616 # make copy of previous <Pkg>_VERSION_STRING if already set which is used 617 # as "last resort" when variable not set by the following find_package 618 set (_BFP_VERSION_STRING "${${_BFP_NS}_VERSION_STRING}") 619 unset (${_BFP_NS}_VERSION_STRING) 620 # set internal <Pkg>_DIR used by find_package to locate <Pkg>Config 621 set (${PKG}_DIR "${DEPENDS_${PKG}_DIR}" CACHE INTERNAL "Directory containing ${PKG}Config.cmake file." FORCE) 622 # call find_package if not all components found yet 623 set (_BFP_FOUND "${${PKG}_FOUND}") # used to decide what the intersection of 624 # multiple find invocations for the same 625 # package with different components will be 626 # for the setting of <PKG>_FOUND 627 if (NOT _BFP_NO_FIND_PACKAGE) 628 # reset <PKG>_FOUND 629 set (${PKG}_FOUND FALSE) 630 set (${PKG_U}_FOUND FALSE) 631 # make copy of find_* search path variables 632 foreach (_BFP_VAR IN ITEMS CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH) 633 set (_BFP_${_BFP_VAR} "${${_BFP_VAR}}") 634 endforeach () 635 # insert DEPENDS_<PKG>_DIR into find_* search paths 636 if (IS_DIRECTORY "${DEPENDS_${PKG}_DIR}") 637 # add directory to CMAKE_PROGRAM_PATH when the name 638 # of the last subdirectory is "bin", "Bin", "sbin", 639 # or "texbin" (i.e., MacTeX's "/Library/TeX/texbin" path) 640 if (DEPENDS_${PKG}_DIR MATCHES "/([bB]in|sbin|texbin)/+$") 641 list (INSERT CMAKE_PROGRAM_PATH 0 "${DEPENDS_${PKG}_DIR}") 642 list (REMOVE_DUPLICATES CMAKE_PROGRAM_PATH) 643 # add directory to CMAKE_PREFIX_PATH otherwise as users 644 # tend to specify the installation prefix instead of the 645 # actual directory containing the package configuration file 646 else () 647 list (INSERT CMAKE_PREFIX_PATH 0 "${DEPENDS_${PKG}_DIR}") 648 list (REMOVE_DUPLICATES CMAKE_PREFIX_PATH) 649 endif () 650 endif () 651 # now look for the package using find_package 652 set (_BFP_FIND_PACKAGE_ARGS ${_BFP_ARGN_UNPARSED_ARGUMENTS}) 653 if (_BFP_ARGN_QUIET OR "^${PKG}$" STREQUAL "^Boost$") 654 list (APPEND _BFP_FIND_PACKAGE_ARGS "QUIET") 655 endif () 656 if (_BFP_FIND_COMPONENTS OR _BFP_FIND_OPTIONAL_COMPONENTS) 657 if (${PKG}_COMPONENTS_FOUND OR _BFP_FIND_COMPONENTS) 658 list (APPEND _BFP_FIND_PACKAGE_ARGS "COMPONENTS" ${${PKG}_COMPONENTS_FOUND} ${_BFP_FIND_COMPONENTS}) 659 endif () 660 if (_BFP_FIND_OPTIONAL_COMPONENTS) 661 list (APPEND _BFP_FIND_PACKAGE_ARGS "OPTIONAL_COMPONENTS" ${_BFP_FIND_OPTIONAL_COMPONENTS}) 662 endif () 663 endif () 664 if (${_BFP_VERSIONS_COUNT} GREATER 1) 665 list (APPEND _BFP_FIND_PACKAGE_ARGS CONFIG) 666 if (DEPENDS_${PKG}_DIR) 667 foreach (_BFP_VERSION ${_BFP_VERSIONS}) 668 find_package (${PKG} ${_BFP_VERSION} ${_BFP_FIND_PACKAGE_ARGS} QUIET 669 PATHS ${DEPENDS_${PKG}_DIR} NO_DEFAULT_PATH 670 ) 671 if (${PKG}_FOUND) 672 break () 673 endif () 674 endforeach () 675 endif () 676 if (NOT ${PKG}_FOUND) 677 foreach (_BFP_VERSION ${_BFP_VERSIONS}) 678 find_package (${PKG} ${_BFP_VERSION} ${_BFP_FIND_PACKAGE_ARGS} QUIET) 679 if (${PKG}_FOUND) 680 break () 681 endif () 682 endforeach () 683 endif () 684 else () 685 if (_BFP_ARGN_MODULE) 686 list (APPEND _BFP_FIND_PACKAGE_ARGS MODULE) 687 endif () 688 if (_BFP_ARGN_NO_MODULE OR _BFP_ARGN_CONFIG) 689 list (APPEND _BFP_FIND_PACKAGE_ARGS CONFIG) 690 endif () 691 find_package (${PKG} ${_BFP_VERSIONS} ${_BFP_FIND_PACKAGE_ARGS} QUIET) 692 endif () 693 unset (_BFP_FIND_PACKAGE_ARGS) 694 # restore find_* search path variables 695 foreach (_BFP_VAR IN ITEMS CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH) 696 set (${_BFP_VAR} "${_BFP_${_BFP_VAR}}") 697 unset (_BFP_${_BFP_VAR}) 698 endforeach () 699 # ensure that <PKG>_DIR is still an internal cache entry 700 basis_update_type_of_variable (${PKG}_DIR INTERNAL) 701 # force reinclusion of package use file 702 if (${PKG}_FOUND) 703 if (${PKG}_USE_FILE_INCLUDED) 704 set (${PKG}_USE_FILE_INCLUDED 0) 705 endif () 706 if (BASIS_USE_${PKG}_INCLUDED) 707 set (BASIS_USE_${PKG}_INCLUDED FALSE) 708 endif () 709 endif () 710 endif () # NOT _BFP_NO_FIND_PACKAGE 711 # set common <Pkg>_VERSION_STRING variable if possible and not set 712 if (NOT DEFINED ${_BFP_NS}_VERSION_STRING) 713 if (DEFINED ${_BFP_NS}_VERSION_MAJOR) 714 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_MAJOR}) 715 if (DEFINED ${_BFP_NS}_VERSION_MINOR) 716 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_VERSION_MINOR}) 717 if (DEFINED ${_BFP_NS}_VERSION_PATCH) 718 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_VERSION_PATCH}) 719 elseif (DEFINED ${_BFP_NS}_SUBMINOR_VERSION) # e.g., FindBoost 720 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_SUBMINOR_VERSION}) 721 endif () 722 endif () 723 elseif (DEFINED ${_BFP_NS}_MAJOR_VERSION) 724 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_MAJOR_VERSION}) 725 if (DEFINED ${_BFP_NS}_MINOR_VERSION) 726 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_MINOR_VERSION}) 727 if (DEFINED ${PKG}_PATCH_VERSION) 728 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_PATCH_VERSION}) 729 elseif (DEFINED ${_BFP_NS}_SUBMINOR_VERSION) # e.g., FindBoost 730 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION_STRING}.${${_BFP_NS}_SUBMINOR_VERSION}) 731 endif () 732 endif () 733 elseif (DEFINED ${_BFP_NS}_VERSION) 734 set (${_BFP_NS}_VERSION_STRING ${${_BFP_NS}_VERSION}) 735 else () 736 set (${_BFP_NS}_VERSION_STRING "${_BFP_VERSION_STRING}") 737 endif () 738 endif () 739 unset (_BFP_VERSION_STRING) 740 # update DEPENDS_<PKG>_DIR from variables set by find_package 741 if (${PKG}_FOUND) 742 if (${PKG}_DIR AND IS_ABSOLUTE "${${PKG}_DIR}" AND 743 (EXISTS "${${PKG}_DIR}/${PKG}Config.cmake" OR 744 EXISTS "${${PKG}_DIR}/${PKG_L}-config.cmake")) 745 _basis_config_to_prefix_dir(${PKG} "${${PKG}_DIR}" _BFP_PREFIX) 746 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 747 elseif (NOT DEPENDS_${PKG}_DIR) 748 if (${_BFP_NS}_INCLUDE_DIR) 749 list (GET ${_BFP_NS}_INCLUDE_DIR 0 _BFP_PREFIX) 750 string (REGEX REPLACE "^(.*)/[iI]ncludes?(/.*)?$" "\\1" _BFP_PREFIX "${_BFP_PREFIX}") 751 elseif (${_BFP_NS}_LIBRARY_DIR) 752 list (GET ${_BFP_NS}_LIBRARY_DIR 0 _BFP_PREFIX) 753 string (REGEX REPLACE "^(.*)/[lL]ib(s|exec|64)?(/.*)?$" "\\1" _BFP_PREFIX "${_BFP_PREFIX}") 754 else () 755 set (_BFP_VARS 756 ${_BFP_NS}_EXECUTABLE # e.g., FindBASH 757 ${_BFP_NS}_COMPILER # e.g., FindLATEX 758 ${_BFP_NS}_CONVERTER # e.g., FindLATEX 759 ) 760 foreach (_BFP_VAR IN LISTS _BFP_VARS) 761 if (${_BFP_VAR}) 762 get_filename_component (_BFP_PREFIX "${${_BFP_VAR}}" PATH) 763 break () 764 endif () 765 endforeach () 766 endif () 767 basis_update_value (DEPENDS_${PKG}_DIR "${_BFP_PREFIX}") 768 endif () 769 else () 770 basis_update_value (DEPENDS_${PKG}_DIR "NOTFOUND") 771 endif () 772 # make internal copy of DEPENDS_<PKG>_DIR used to detect change 773 set (_DEPENDS_${PKG}_DIR "${DEPENDS_${PKG}_DIR}" CACHE INTERNAL "(Previous) DEPENDS_${PKG}_DIR value." FORCE) 774 # make internal search path cache entries consistent with DEPENDS_<PKG>_DIR 775 foreach (_BFP_VAR IN LISTS _BFP_PKG_DIR_VARS) 776 basis_is_cached (_BFP_CACHED ${_BFP_VAR}) 777 if (_BFP_CACHED) 778 set (${_BFP_VAR} "${DEPENDS_${PKG}_DIR}" CACHE INTERNAL "Installation prefix of ${PKG}." FORCE) 779 endif () 780 endforeach () 781 # make internal copy of <PKG>_DIR used to detect change via -D option 782 # 783 # Note: All other alternative variables such as <PKG>_ROOT are forced to 784 # be equal DEPENDS_<PKG>_DIR. Only <PKG>_DIR usually points to the 785 # <PKG>Config, while DEPENDS_<PKG>_DIR is the installation prefix. 786 set (_${PKG}_DIR "${${PKG}_DIR}" CACHE INTERNAL "(Previous) ${PKG}_DIR value." FORCE) 787 # status message with information about found package 788 if (_BFP_STATUS) 789 if (${PKG}_FOUND) 790 if (_BFP_NO_FIND_PACKAGE) 791 set (_BFP_STATUS "${_BFP_STATUS} - already found") 792 else () 793 set (_BFP_STATUS "${_BFP_STATUS} - found") 794 endif () 795 if ("^${PKG}$" STREQUAL "^Boost$") 796 set (_BFP_STATUS "${_BFP_STATUS} v${${_BFP_NS}_MAJOR_VERSION}.${${_BFP_NS}_MINOR_VERSION}.${${_BFP_NS}_SUBMINOR_VERSION}") 797 elseif (DEFINED ${_BFP_NS}_VERSION_STRING AND NOT ${_BFP_NS}_VERSION_STRING MATCHES "^(0(\\.0)?(\\.0)?)?$") 798 set (_BFP_STATUS "${_BFP_STATUS} v${${_BFP_NS}_VERSION_STRING}") 799 endif () 800 if (BASIS_VERBOSE AND DEPENDS_${PKG}_DIR) 801 set (_BFP_STATUS "${_BFP_STATUS} at ${DEPENDS_${PKG}_DIR}") 802 endif () 803 else () 804 set (_BFP_STATUS "${_BFP_STATUS} - not found") 805 endif () 806 message (STATUS "${_BFP_STATUS}") 807 endif () 808 unset (_BFP_STATUS) 809 # raise error when a required package was not found 810 if (NOT ${PKG}_FOUND AND NOT _BFP_ARGN_NO_NOTFOUND_ERROR AND (_BFP_ARGN_REQUIRED OR WITH_${PKG})) 811 set (_BFP_ERROR) 812 if (PROJECT_IS_MODULE) 813 set (_BFP_ERROR "Module") 814 else () 815 set (_BFP_ERROR "Project") 816 endif () 817 set (_BFP_ERROR "${_BFP_ERROR} ${PROJECT_NAME}") 818 if (_BFP_ARGN_REQUIRED) 819 set (_BFP_ERROR "${_BFP_ERROR} requires ${PKG}") 820 else () 821 set (_BFP_ERROR "${_BFP_ERROR} was requested to be build with ${PKG}") 822 endif () 823 if (_BFP_VERSIONS) 824 set (_BFP_ERROR "${_BFP_ERROR} version ${_BFP_VERSIONS}") 825 endif () 826 set (_BFP_ERROR "${_BFP_ERROR}. Please ensure that the package is installed in a" 827 " standard system location or set DEPENDS_${PKG}_DIR to the" 828 " installation prefix (i.e., root directory of the installation).") 829 if (NOT _BFP_ARGN_REQUIRED AND DEFINED WITH_${PKG}) 830 set (_BFP_ERROR "${_BFP_ERROR} To disable features which require this optional dependency," 831 " set the WITH_${PKG} option to OFF and try again.") 832 endif () 833 if (DEFINED ${PKG}_DIR) 834 set (_BFP_ERROR "${_BFP_ERROR}\nThe DEPENDS_${PKG}_DIR variable can alternatively be set" 835 " to the directory containing a ${PKG}Config.cmake or ${PKG_L}-config.cmake" 836 " file. If no such file exists, contact either the developer of" 837 " this project or CMake BASIS to provide a Find${PKG}.cmake file.") 838 endif () 839 basis_list_to_string(_BFP_ERROR ${_BFP_ERROR}) 840 message (FATAL_ERROR "\n${_BFP_ERROR}\n") 841 endif () 842 # update list of found components 843 if (${PKG}_FOUND) 844 if (_BFP_FIND_COMPONENTS) 845 list (APPEND ${PKG}_COMPONENTS_FOUND ${_BFP_FIND_COMPONENTS}) 846 endif () 847 foreach (_BFP_CMP IN LISTS _BFP_FIND_OPTIONAL_COMPONENTS) 848 if (${PKG}_${_BFP_CMP}_FOUND) 849 list (APPEND ${PKG}_COMPONENTS_FOUND ${_BFP_CMP}) 850 endif () 851 endforeach () 852 if (${PKG}_COMPONENTS_FOUND) 853 list (REMOVE_DUPLICATES ${PKG}_COMPONENTS_FOUND) 854 endif () 855 endif () 856 # if previously this package or components of it where found and the 857 # re-discovery of the package or additional components is only optional, 858 # set <PKG>_FOUND to TRUE again 859 if (_BFP_FOUND AND NOT _BFP_ARGN_REQUIRED AND NOT WITH_${PKG}) 860 set (${PKG}_FOUND TRUE) 861 endif () 862 unset (_BFP_FOUND) 863 endif () 864 endif () 865 endif () 866 # -------------------------------------------------------------------------- 867 # unset locally used variables 868 foreach (_BFP_CMP IN LISTS _BFP_ARGN_COMPONENTS _BFP_ARGN_OPTIONAL_COMPONENTS) 869 unset (${PKG}_FIND_REQUIRED_${_BFP_CMP}) 870 endforeach () 871 foreach (_BFP_VAR IN LISTS _BFP_OPTIONS _BFP_MULTI_ARGS) 872 unset (_BFP_ARGN_${_BFP_VAR}) 873 endforeach () 874 unset (_BFP_COMPONENTS) 875 unset (_BFP_ARGN_UNPARSED_ARGUMENTS) 876 unset (_BFP_OPTIONS) 877 unset (_BFP_MULTI_ARGS) 878 unset (_BFP_IS_MODULE) 879 unset (_BFP_IS_PROJECT) 880 unset (_BFP_VERSION) 881 unset (_BFP_VERSIONS) 882 unset (_BFP_VERSIONS_COUNT) 883 unset (_BFP_PKGIDX) 884 unset (_BFP_CMPIDX) 885 unset (_BFP_CMP) 886 unset (_BFP_VAR) 887 unset (_BFP_VARS) 888 unset (_BFP_CACHED) 889 unset (_BFP_TYPE) 890 unset (_BFP_PREFIX) 891 unset (_BFP_PKG_DIR_VARS) 892 unset (_BFP_FIND_COMPONENTS) 893 unset (_BFP_FIND_OPTIONAL_COMPONENTS) 894 unset (_BFP_NO_FIND_PACKAGE) 895 unset (_BFP_NS) 896 unset (PKG) 897 unset (PKG_L) 898 unset (PKG_U) 899endmacro () 900 901# ---------------------------------------------------------------------------- 902## @brief Use found package. 903# 904# This macro includes the package's use file if the variable @c <Pkg>_USE_FILE 905# is defined. Otherwise, it adds the include directories to the search path 906# for include paths if possible. Therefore, the corresponding package 907# configuration file has to set the proper CMake variables, i.e., 908# either @c <Pkg>_INCLUDES, @c <Pkg>_INCLUDE_DIRS, or @c <Pkg>_INCLUDE_DIR. 909# 910# If the given package name is the name of another module of this project 911# (the top-level project), this function includes the use file of the specified 912# module. 913# 914# @note As some packages still use all captial variables instead of ones 915# prefixed by a string that follows the same capitalization as the 916# package's name, this function also considers these if defined instead. 917# Hence, if @c <PKG>_INCLUDES is defined, but not @c <Pkg>_INCLUDES, it 918# is used in place of the latter. 919# 920# @note According to an email on the CMake mailing list, it is not a good idea 921# to use basis_link_directories() any more given that the arguments to 922# basis_target_link_libraries() are absolute paths to the library files. 923# Therefore, this code is commented and not used. It remains here as a 924# reminder only. 925# 926# @param [in] PACKAGE Name of other package. Optionally, the package name 927# can include a version specification as suffix which 928# is separated by the package name using a dash (-), i.e., 929# <Package>[-major[.minor[.patch[.tweak]]]]. 930# A version specification is simply ignored by this macro. 931# 932# @ingroup CMakeAPI 933macro (basis_use_package PACKAGE) 934 # tokenize package specification 935 basis_tokenize_dependency ("${PACKAGE}" PKG VER CMPS) 936 # use package 937 foreach (A IN ITEMS "WORKAROUND FOR NOT BEING ABLE TO USE RETURN") 938 if (BASIS_DEBUG) 939 message ("** basis_use_package()") 940 message ("** Package: ${PKG}") 941 endif () 942 if (PROJECT_IS_MODULE) 943 # ignore BASIS as module dependency 944 # important if BASIS itself is a project module 945 if ("^${PKG}$" STREQUAL "^BASIS$") 946 if (BASIS_DEBUG) 947 message ("** Ignoring BASIS dependency as it clearly is used already by the top-level project.") 948 endif () 949 break () 950 # allow modules to specify top-level project as dependency 951 elseif ("^${PKG}$" STREQUAL "^${TOPLEVEL_PROJECT_NAME}$") 952 if (CMPS) 953 if (BASIS_DEBUG) 954 message ("** These are other modules of the top-level project.") 955 endif () 956 foreach (CMP IN LISTS CMPS) 957 list (FIND PROJECT_MODULES "${CMP}" CMPIDX) 958 if (CMPIDX EQUAL -1) 959 message (FATAL_ERROR "Module ${PROJECT_NAME} has module ${CMP} of project ${TOPLEVEL_PROJECT_NAME}" 960 " as dependency, but no such module exists.") 961 endif () 962 list (FIND PROJECT_MODULES_ENABLED "${CMP}" CMPIDX) 963 if (NOT CMPIDX EQUAL -1) 964 if (BASIS_DEBUG) 965 message ("** Include package use file of module ${CMP}.") 966 endif () 967 include ("${${${CMP}_CONFIG_PREFIX}_USE_FILE}") 968 if (PROJECT_PACKAGE_NAME) 969 add_definitions(-DHAVE_${PROJECT_PACKAGE_NAME}_${CMP}) 970 else () 971 add_definitions(-DHAVE_${TOPLEVEL_PROJECT_NAME}_${CMP}) 972 endif () 973 endif () 974 endforeach () 975 unset (CMPIDX) 976 unset (CMP) 977 else () 978 if (BASIS_DEBUG) 979 message ("** This is the top-level project.") 980 endif () 981 endif () 982 break () # instead of return() 983 # use other module of top-level project 984 else () 985 list (FIND PROJECT_MODULES "${PKG}" PKGIDX) 986 if (NOT PKGIDX EQUAL -1 AND ${PKG}_FOUND) 987 if (BASIS_DEBUG) 988 message ("** Include package use file of other module.") 989 endif () 990 include ("${${PKG}_USE_FILE}") 991 add_definitions(-DHAVE_${PKG}) 992 unset (PKGIDX) 993 break () # instead of return() 994 endif () 995 unset (PKGIDX) 996 endif () 997 endif () 998 # if this package is an external project, i.e., a project build as part 999 # of the same superbuild as this project, set BUNDLE_PROJECT to TRUE. 1000 # it is used by (basis_)link_directories() and add_library() to mark 1001 # the imported link directories and target as belonging to the same 1002 # installation. this is in particular important for the RPATH settings. 1003 # whether this package is an external project or not, is decided by the 1004 # BUNDLE_PROJECTS variable which must be set using the -D option of 1005 # cmake to a list naming all the other packages which are part of the 1006 # superbuild. 1007 if (BUNDLE_PROJECTS) 1008 list (FIND BUNDLE_PROJECTS "${PKG}" PKGIDX) 1009 if (PKGIDX EQUAL -1) 1010 set (BUNDLE_PROJECT FALSE) 1011 else () 1012 set (BUNDLE_PROJECT TRUE) 1013 endif () 1014 unset (PKGIDX) 1015 endif () 1016 # use external package 1017 if (${PKG}_FOUND) 1018 # use package only if basis_use_package() not invoked before 1019 if (BASIS_USE_${PKG}_INCLUDED) 1020 if (BASIS_DEBUG) 1021 message ("** External package used before already.") 1022 endif () 1023 break () 1024 endif () 1025 if (${PKG}_USE_FILE) 1026 if ("^${PKG}$" STREQUAL "^VTK$" AND VTK_VERSION VERSION_GREATER_EQUAL 8.90.0) 1027 if (BASIS_DEBUG) 1028 message ("** Ignore deprecated use file of VTK >=8.90.0.") 1029 endif () 1030 else () 1031 if (BASIS_DEBUG) 1032 message ("** Include package use file of external package.") 1033 endif () 1034 if ("^${PKG}$" STREQUAL "^BASIS$") 1035 include ("${${PKG}_USE_FILE}" NO_POLICY_SCOPE) 1036 else () 1037 include ("${${PKG}_USE_FILE}") 1038 endif () 1039 endif() 1040 else () 1041 if (BASIS_DEBUG) 1042 message ("** Use variables which were set by basis_find_package().") 1043 endif () 1044 # OpenCV 1045 if ("^${PKG}$" STREQUAL "^OpenCV$") 1046 # the cv.h may be found as part of PerlLibs, the include path of 1047 # which is added at first by BASISConfig.cmake 1048 if (OpenCV_INCLUDE_DIRS) 1049 basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIRS}) 1050 elseif (OpenCV_INCLUDE_DIR) 1051 basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIR}) 1052 endif () 1053 # generic 1054 else () 1055 if (${PKG}_INCLUDE_DIRS) 1056 basis_include_directories (${${PKG}_INCLUDE_DIRS}) 1057 elseif (${PKG}_INCLUDES) 1058 basis_include_directories (${${PKG}_INCLUDES}) 1059 elseif (${PKG}_INCLUDE_PATH) 1060 basis_include_directories (${${PKG}_INCLUDE_PATH}) 1061 elseif (${PKG}_INCLUDE_DIR) 1062 basis_include_directories (${${PKG}_INCLUDE_DIR}) 1063 endif () 1064 endif () 1065 endif () 1066 add_definitions(-DHAVE_${PKG}) 1067 set (BASIS_USE_${PKG}_INCLUDED TRUE) 1068 elseif (ARGC GREATER 1 AND "^${ARGV1}$" STREQUAL "^REQUIRED$") 1069 if (BASIS_DEBUG) 1070 basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFind${PKG}.cmake") 1071 endif () 1072 message (FATAL_ERROR "Package ${PACKAGE} not found!") 1073 endif () 1074 # reset switch that identifies currently imported targets and link directories 1075 # as belonging to an external project which is part of the same superbuild 1076 set (BUNDLE_PROJECT FALSE) 1077 endforeach () 1078endmacro () 1079 1080# ============================================================================ 1081# basis_get_filename_component / basis_get_relative_path 1082# ============================================================================ 1083 1084# ---------------------------------------------------------------------------- 1085## @brief Fixes CMake's 1086# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component"> 1087# get_filename_component()</a> command. 1088# 1089# The get_filename_component() command of CMake returns the entire portion 1090# after the first period (.) [including the period] as extension. However, 1091# only the component following the last period (.) [including the period] 1092# should be considered to be the extension. 1093# 1094# @note Consider the use of the basis_get_filename_component() macro as 1095# an alias to emphasize that this function is different from CMake's 1096# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component"> 1097# get_filename_component()</a> command. 1098# 1099# @todo Fix issue http://public.kitware.com/Bug/view.php?id=15743 which 1100# affects also basis_get_relative_path. 1101# 1102# @param [in,out] ARGN Arguments as accepted by get_filename_component(). 1103# 1104# @returns Sets the variable named by the first argument to the requested 1105# component of the given file path. 1106# 1107# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component 1108# @sa basis_get_filename_component() 1109function (get_filename_component VAR STR CMP) 1110 list (FIND ARGN "CACHE" IDX) 1111 if (IDX EQUAL -1) 1112 set (OPT_CACHE 0) 1113 else () 1114 list (REMOVE_ITEM ARGN "CACHE") 1115 set (OPT_CACHE 1) 1116 endif () 1117 if (CMP MATCHES "^EXT") 1118 _get_filename_component (${VAR} "${STR}" ${CMP} ${ARGN}) 1119 string (REGEX MATCHALL "\\.[^.]*" PARTS "${${VAR}}") 1120 list (LENGTH PARTS LEN) 1121 if (LEN GREATER 1) 1122 math (EXPR LEN "${LEN} - 1") 1123 list (GET PARTS ${LEN} ${VAR}) 1124 endif () 1125 elseif (CMP MATCHES "NAME_WE") 1126 _get_filename_component (${VAR} "${STR}" NAME ${ARGN}) 1127 string (REGEX REPLACE "\\.[^.]*$" "" ${VAR} ${${VAR}}) 1128 else () 1129 _get_filename_component (${VAR} "${STR}" ${CMP} ${ARGN}) 1130 if (CMP MATCHES "PROGRAM") 1131 list (FIND ARGN "PROGRAM_ARGS" IDX) 1132 if (NOT IDX EQUAL -1) 1133 math (EXPR IDX "${IDX} + 1") 1134 list (GET ARGN ${IDX} ARG_VAR) 1135 set (${ARG_VAR} "${${ARG_VAR}}" PARENT_SCOPE) 1136 endif () 1137 endif () 1138 endif () 1139 if (OPT_CACHE) 1140 set (${VAR} "${${VAR}}" CACHE STRING "") 1141 else () 1142 set (${VAR} "${${VAR}}" PARENT_SCOPE) 1143 endif () 1144endfunction () 1145 1146# ---------------------------------------------------------------------------- 1147## @brief Alias for the overwritten get_filename_component() function. 1148# 1149# @sa get_filename_component() 1150# 1151# @ingroup CMakeAPI 1152macro (basis_get_filename_component) 1153 get_filename_component (${ARGN}) 1154endmacro () 1155 1156# ---------------------------------------------------------------------------- 1157## @brief Get path relative to a given base directory. 1158# 1159# Unlike the file(RELATIVE_PATH ...) command of CMake which if @p PATH and 1160# @p BASE are the same directory returns an empty string, this function 1161# returns a dot (.) in this case instead. 1162# 1163# @param [out] REL @c PATH relative to @c BASE. 1164# @param [in] BASE Path of base directory. If a relative path is given, it 1165# is made absolute using basis_get_filename_component() 1166# with ABSOLUTE as last argument. 1167# @param [in] PATH Absolute or relative path. If a relative path is given 1168# it is made absolute using basis_get_filename_component() 1169# with ABSOLUTE as last argument. 1170# 1171# @returns Sets the variable named by the first argument to the relative path. 1172# 1173# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:file 1174# 1175# @ingroup CMakeAPI 1176function (basis_get_relative_path REL BASE PATH) 1177 if (BASE MATCHES "^$") 1178 message (FATAL_ERROR "Empty string given where (absolute) base directory path expected!") 1179 endif () 1180 if (PATH MATCHES "^$") 1181 set (PATH ".") 1182 endif () 1183 # Attention: http://public.kitware.com/Bug/view.php?id=15743 1184 basis_get_filename_component (PATH "${PATH}" ABSOLUTE) 1185 basis_get_filename_component (BASE "${BASE}" ABSOLUTE) 1186 if (NOT PATH) 1187 message (FATAL_ERROR "basis_get_relative_path(): No PATH given!") 1188 endif () 1189 if (NOT BASE) 1190 message (FATAL_ERROR "basis_get_relative_path(): No BASE given!") 1191 endif () 1192 file (RELATIVE_PATH P "${BASE}" "${PATH}") 1193 if ("${P}" STREQUAL "") 1194 set (P ".") 1195 endif () 1196 set (${REL} "${P}" PARENT_SCOPE) 1197endfunction () 1198 1199## @brief Create a string from a list of variables indicating if they are defined and their values. 1200# 1201# Useful for debug and user errors, for example: 1202# @code 1203# set(VAR1 "I'm a string") 1204# set(VAR2 2) 1205# basis_variable_value_status(VAR_INFO_STRING VAR1 VAR2 VAR3) 1206# message(STATUS ${VAR_INFO_STRING}) 1207# @endcode 1208# 1209# @param[out] VAR_INFO_STRING The output string variable that will set with the debug string. 1210# @param[in] ARGN List of variables to be put into a string along with their value. 1211function(basis_variable_value_status VAR_INFO_STRING) 1212 set (OUTPUT_STRING) 1213 foreach (VARIABLE_NAME IN ITEMS ${ARGN}) 1214 if (DEFINED ${VARIABLE_NAME}) 1215 set (OUTPUT_STRING "${OUTPUT_STRING}\n variable name: ${VARIABLE_NAME} value: ${${VARIABLE_NAME}}") 1216 else () 1217 set (OUTPUT_STRING "${OUTPUT_STRING}\n variable name: ${VARIABLE_NAME} value is not defined") 1218 endif () 1219 endforeach () 1220 set (${VAR_INFO_STRING} ${OUTPUT_STRING} PARENT_SCOPE) 1221endfunction() 1222 1223## @brief Checks for a list of variables required later in the script. 1224# 1225# Produces a clear error message explaining the problem and how to fix it if they are not present. 1226# 1227# @code 1228# basis_variable_check( 1229# REQUIRED 1230# LIBRARY1_INCLUDE_DIRS 1231# LIBRARY2_INCLUDE_DIRS 1232# LIBRARY2_LIBRARIES 1233# OPTIONAL 1234# LIBRARY3_INCLUDE_DIRS 1235# LIBRARY3_LIBRARIES 1236# OPTIONAL_PATH 1237# 1238# ) 1239# @endcode 1240# 1241# @param [in] ARGN This argument list is parsed and the following 1242# arguments are extracted. 1243# @par 1244# <table border="0"> 1245# <tr> 1246# @tp @b REQUIRED var... @endtp 1247# <td>List of variables that MUST be set to run this script correctly. 1248# Will produce a FATAL_ERROR message explaining which variables 1249# are misisng and exit the cmake script.</td> 1250# </tr> 1251# <tr> 1252# @tp @b OPTIONAL var... @endtp 1253# <td>List of variables need not be set to run this script correctly.</td> 1254# </tr> 1255# <tr> 1256# @tp @b PATH_EXISTS var... @endtp 1257# <td>List of path variables that MUST be set to a location that exists.</td> 1258# </tr> 1259# <tr> 1260# @tp @b OPTIONAL_PATH_EXISTS var... @endtp 1261# <td>List of path variables that are optional, but once set must be empty 1262# or provide a path to location that exists.</td> 1263# </tr> 1264# </table> 1265function(basis_variable_check) 1266 1267 set(options ) # currently none 1268 set(oneValueArgs ) # currently none 1269 set(multiValueArgs REQUIRED OPTIONAL PATH_EXISTS OPTIONAL_PATH_EXISTS ) 1270 cmake_parse_arguments(VARIABLE_CONFIGURATION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 1271 1272 1273 #------------------------------------------- 1274 # Create the error strings for missing REQUIRED variables 1275 set(MISSING_REQUIRED_VARIABLES) 1276 foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_REQUIRED) 1277 if(NOT ${VARIABLE_NAME}) 1278 list(APPEND MISSING_REQUIRED_VARIABLES ${VARIABLE_NAME}) 1279 endif() 1280 endforeach() 1281 if(MISSING_REQUIRED_VARIABLES) 1282 basis_variable_value_status(MISSING_REQUIRED_VARIABLES_STATUS ${MISSING_REQUIRED_VARIABLES}) 1283 set(MISSING_VARIABLES_ERROR "\nThe following variables are marked as REQUIRED but they are not set to a valid value. Please define the variables correctly in your cmake script or on the command line using -D. ${MISSING_REQUIRED_VARIABLES_STATUS}") 1284 endif(MISSING_REQUIRED_VARIABLES) 1285 1286 1287 #------------------------------------------- 1288 # Create and print the warning strings for missing OPTIONAL variables 1289 set(MISSING_OPTIONAL_VARIABLES) 1290 foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_OPTIONAL) 1291 if(NOT ${VARIABLE_NAME}) 1292 list(APPEND MISSING_OPTIONAL_VARIABLES ${VARIABLE_NAME}) 1293 endif() 1294 endforeach() 1295 if(MISSING_OPTIONAL_VARIABLES) 1296 basis_variable_value_status(MISSING_OPTIONAL_VARIABLES_STATUS ${MISSING_OPTIONAL_VARIABLES}) 1297 set(MISSING_VARIABLES_WARNING "\nThe following variables are marked as OPTIONAL but they are not set to a valid value. Please define the variables correctly in your cmake script or on the command line using -D. ${MISSING_OPTIONAL_VARIABLES_STATUS}") 1298 message(AUTHOR_WARNING "${MISSING_VARIABLES_WARNING}") 1299 endif(MISSING_OPTIONAL_VARIABLES) 1300 1301 1302 1303 #------------------------------------------- 1304 # Create the error strings for missing or nonexistant REQUIRED PATH variables 1305 set(MISSING_PATH_EXISTS) 1306 foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_PATH_EXISTS) 1307 if(NOT DEFINED ${VARIABLE_NAME} OR NOT EXISTS ${${VARIABLE_NAME}}) 1308 list(APPEND MISSING_PATH_EXISTS ${VARIABLE_NAME}) 1309 endif() 1310 endforeach() 1311 if(MISSING_PATH_EXISTS) 1312 basis_variable_value_status(MISSING_PATH_EXISTS_STATUS ${MISSING_PATH_EXISTS}) 1313 set(PATH_EXISTS_ERROR "\nThe following PATH variables are marked as REQUIRED but they are not set to a valid location. Please define the variables correctly in your cmake script or on the command line using -D. ${MISSING_PATH_EXISTS_STATUS}") 1314 endif(MISSING_PATH_EXISTS) 1315 1316 1317 1318 #------------------------------------------- 1319 # Create the error strings for missing or nonexistant OPTIONAL PATH variables 1320 set(MISSING_OPTIONAL_PATH_EXISTS) 1321 foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_OPTIONAL_PATH_EXISTS) 1322 if(DEFINED ${VARIABLE_NAME} AND NOT ${${VARIABLE_NAME}} STREQUAL "" AND NOT EXISTS ${${VARIABLE_NAME}}) 1323 # add VARIABLE_NAME to error list if a nonempty path is defined, but does not point to a real location 1324 list(APPEND MISSING_OPTIONAL_PATH_EXISTS ${VARIABLE_NAME}) 1325 endif() 1326 endforeach() 1327 if(MISSING_OPTIONAL_PATH_EXISTS) 1328 basis_variable_value_status(MISSING_OPTIONAL_PATH_EXISTS_STATUS ${MISSING_OPTIONAL_PATH_EXISTS}) 1329 #debug: 1330 #message(STATUS "MISSING_OPTIONAL_PATH_EXISTS: ${MISSING_OPTIONAL_PATH_EXISTS}") 1331 #message(STATUS "MISSING_OPTIONAL_PATH_EXISTS_STATUS: ${MISSING_OPTIONAL_PATH_EXISTS_STATUS}") 1332 set(OPTIONAL_PATH_EXISTS_ERROR "\nThe following PATH variables are marked as OPTIONAL but they are not set to a valid location. Please define the variables correctly in your cmake script or on the command line using -D. ${MISSING_OPTIONAL_PATH_EXISTS_STATUS}") 1333 endif(MISSING_OPTIONAL_PATH_EXISTS) 1334 1335 #------------------------------------------- 1336 # Print all fatal errors at once, because the script will halt 1337 if(MISSING_VARIABLES_ERROR OR PATH_EXISTS_ERROR OR OPTIONAL_PATH_EXISTS_ERROR) 1338 message(FATAL_ERROR "${MISSING_VARIABLES_ERROR}${PATH_EXISTS_ERROR}${OPTIONAL_PATH_EXISTS_ERROR}\n") 1339 endif(MISSING_VARIABLES_ERROR OR PATH_EXISTS_ERROR OR OPTIONAL_PATH_EXISTS_ERROR) 1340 1341endfunction(basis_variable_check) 1342 1343 1344 1345# ============================================================================ 1346# name / version 1347# ============================================================================ 1348 1349# ---------------------------------------------------------------------------- 1350## @brief Convert string to lowercase only or mixed case. 1351# 1352# Strings in all uppercase or all lowercase are converted to all lowercase 1353# letters because these are usually used for acronymns. All other strings 1354# are returned unmodified with the one exception that the first letter has 1355# to be uppercase for mixed case strings. 1356# 1357# This function is in particular used to normalize the project name for use 1358# in installation directory paths and namespaces. 1359# 1360# @param [out] OUT String in CamelCase. 1361# @param [in] STR String. 1362function (basis_normalize_name OUT STR) 1363 # strings in all uppercase or all lowercase such as acronymns are an 1364 # exception and shall be converted to all lowercase instead 1365 string (TOLOWER "${STR}" L) 1366 string (TOUPPER "${STR}" U) 1367 if ("${STR}" STREQUAL "${L}" OR "${STR}" STREQUAL "${U}") 1368 set (${OUT} "${L}" PARENT_SCOPE) 1369 # change first letter to uppercase 1370 else () 1371 string (SUBSTRING "${U}" 0 1 A) 1372 string (SUBSTRING "${STR}" 1 -1 B) 1373 set (${OUT} "${A}${B}" PARENT_SCOPE) 1374 endif () 1375endfunction () 1376 1377# ---------------------------------------------------------------------------- 1378## @brief Extract version numbers from version string. 1379# 1380# @param [in] VERSION Version string in the format "MAJOR[.MINOR[.PATCH]]". 1381# @param [out] MAJOR Major version number if given or 0. 1382# @param [out] MINOR Minor version number if given or 0. 1383# @param [out] PATCH Patch number if given or 0. 1384# 1385# @returns See @c [out] parameters. 1386function (basis_version_numbers VERSION MAJOR MINOR PATCH) 1387 if (VERSION MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?") 1388 if (CMAKE_MATCH_1) 1389 set (VERSION_MAJOR ${CMAKE_MATCH_1}) 1390 else () 1391 set (VERSION_MAJOR 0) 1392 endif () 1393 if (CMAKE_MATCH_2) 1394 set (VERSION_MINOR ${CMAKE_MATCH_2}) 1395 string (REGEX REPLACE "^\\." "" VERSION_MINOR "${VERSION_MINOR}") 1396 else () 1397 set (VERSION_MINOR 0) 1398 endif () 1399 if (CMAKE_MATCH_3) 1400 set (VERSION_PATCH ${CMAKE_MATCH_3}) 1401 string (REGEX REPLACE "^\\." "" VERSION_PATCH "${VERSION_PATCH}") 1402 else () 1403 set (VERSION_PATCH 0) 1404 endif () 1405 else () 1406 set (VERSION_MAJOR 0) 1407 set (VERSION_MINOR 0) 1408 set (VERSION_PATCH 0) 1409 endif () 1410 set ("${MAJOR}" "${VERSION_MAJOR}" PARENT_SCOPE) 1411 set ("${MINOR}" "${VERSION_MINOR}" PARENT_SCOPE) 1412 set ("${PATCH}" "${VERSION_PATCH}" PARENT_SCOPE) 1413endfunction () 1414 1415# ============================================================================ 1416# set 1417# ============================================================================ 1418 1419# ---------------------------------------------------------------------------- 1420## @brief Set flag given mutually exclusive 1421# ARGN_<FLAG> and ARGN_NO<FLAG> function arguments. 1422# 1423# @param [in] PREFIX Prefix of function arguments. Set to the first argument 1424# of the CMAKE_PARSE_ARGUMENTS() command. 1425# @param [out] FLAG Name of flag. 1426# @param [in] DEFAULT Default flag value if neither <tt>ARGN_<FLAG;gt;</tt> 1427# nor <tt>ARGN_NO<FLAG;gt;</tt> evaluates to true. 1428macro (basis_set_flag PREFIX FLAG DEFAULT) 1429 if (${PREFIX}_${FLAG} AND ${PREFIX}_NO${FLAG}) 1430 message (FATAL_ERROR "Options ${FLAG} and NO${FLAG} are mutually exclusive!") 1431 endif () 1432 if (${PREFIX}_${FLAG}) 1433 set (${FLAG} TRUE) 1434 elseif (${PREFIX}_NO${FLAG}) 1435 set (${FLAG} FALSE) 1436 else () 1437 set (${FLAG} ${DEFAULT}) 1438 endif () 1439endmacro () 1440 1441# ---------------------------------------------------------------------------- 1442## @brief Determine if cache entry exists. 1443# 1444# @param [out] VAR Name of boolean result variable. 1445# @param [in] ENTRY Name of cache entry. 1446macro (basis_is_cached VAR ENTRY) 1447 if (DEFINED ${ENTRY}) 1448 get_property (${VAR} CACHE ${ENTRY} PROPERTY TYPE SET) 1449 else () 1450 set (${VAR} FALSE) 1451 endif () 1452endmacro () 1453 1454# ---------------------------------------------------------------------------- 1455## @brief Set type of variable. 1456# 1457# If the variable is cached, the type is updated, otherwise, a cache entry 1458# of the given type with the current value of the variable is added. 1459# 1460# @param [in] VAR Name of variable. 1461# @param [in] TYPE Desired type of variable. 1462# @param [in] ARGN Optional DOC string used if variable was not cached before. 1463macro (basis_set_or_update_type VAR TYPE) 1464 basis_is_cached (_CACHED ${VAR}) 1465 if (_CACHED) 1466 set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE}) 1467 else () 1468 set (${VAR} "${${VAR}}" CACHE ${TYPE} "${ARGN}" FORCE) 1469 endif () 1470 unset (_CACHED) 1471endmacro () 1472 1473# ---------------------------------------------------------------------------- 1474## @brief Change type of cached variable. 1475# 1476# If the variable is not cached, nothing is done. 1477macro (basis_update_type_of_variable VAR TYPE) 1478 basis_is_cached (_CACHED ${VAR}) 1479 if (_CACHED) 1480 set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE}) 1481 endif () 1482 unset (_CACHED) 1483endmacro () 1484 1485# ---------------------------------------------------------------------------- 1486## @brief Set variable value. 1487# 1488# If the variable is cached, this function will update the cache value, 1489# otherwise, it simply sets the CMake variable uncached to the given value(s). 1490macro (basis_set_or_update_value VAR) 1491 basis_is_cached (_CACHED ${VAR}) 1492 if (_CACHED) 1493 if (ARGC GREATER 1) 1494 set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN}) 1495 else () 1496 set (${VAR} "" CACHE INTERNAL "" FORCE) 1497 endif () 1498 else () 1499 set (${VAR} ${ARGN}) 1500 endif () 1501 unset (_CACHED) 1502endmacro () 1503 1504# ---------------------------------------------------------------------------- 1505## @brief Update cache variable. 1506macro (basis_update_value VAR) 1507 basis_is_cached (_CACHED ${VAR}) 1508 if (_CACHED) 1509 set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN}) 1510 endif () 1511 unset (_CACHED) 1512endmacro () 1513 1514# ---------------------------------------------------------------------------- 1515## @brief Set value of variable only if variable is not set already. 1516# 1517# @param [out] VAR Name of variable. 1518# @param [in] ARGN Arguments to set() command excluding variable name. 1519# 1520# @returns Sets @p VAR if its value was not valid before. 1521macro (basis_set_if_empty VAR) 1522 if (NOT ${VAR}) 1523 set (${VAR} ${ARGN}) 1524 endif () 1525endmacro () 1526 1527# ---------------------------------------------------------------------------- 1528## @brief Set value of variable only if variable is not defined yet. 1529# 1530# @param [out] VAR Name of variable. 1531# @param [in] ARGN Arguments to set() command excluding variable name. 1532# 1533# @returns Sets @p VAR if it was not defined before. 1534macro (basis_set_if_not_set VAR) 1535 if (NOT DEFINED "${VAR}") 1536 set ("${VAR}" ${ARGN}) 1537 endif () 1538endmacro () 1539 1540# ---------------------------------------------------------------------------- 1541## @brief Set value of variable to either 0 or 1 based on option value 1542# 1543# This function can be used to convert option values from TRUE/ON to 1 and 1544# FALSE/OFF to 0 such that they can be used to configure a config.h.in header. 1545# 1546# @param [out] VAR Name of configuration header variable. 1547# @param [in] OPT Value of CMake option. 1548macro (basis_set_config_option VAR OPT) 1549 if (${OPT}) 1550 set ("${VAR}" 1) 1551 else () 1552 set ("${VAR}" 0) 1553 endif () 1554endmacro () 1555 1556# ---------------------------------------------------------------------------- 1557## @brief Set path relative to script file. 1558# 1559# This function can be used in script configurations. It takes a variable 1560# name and a path as input arguments. If the given path is relative, it makes 1561# it first absolute using @c PROJECT_SOURCE_DIR. Then the path is made 1562# relative to the directory of the built script file. A CMake variable of the 1563# given name is set to the specified relative path. Optionally, a third 1564# argument, the path used for building the script for the install tree 1565# can be passed as well. If a relative path is given as this argument, 1566# it is made absolute by prefixing it with @c CMAKE_INSTALL_PREFIX instead. 1567# 1568# @note This function may only be used in script configurations such as 1569# in particular the ScriptConfig.cmake.in file. It requires that the 1570# variables @c __DIR__ and @c BUILD_INSTALL_SCRIPT are set properly. 1571# These variables are set by the basis_configure_script() function. 1572# Moreover, it makes use of the global @c CMAKE_INSTALL_PREFIX and 1573# @c PROJECT_SOURCE_DIR variables. 1574# 1575# @param [out] VAR Name of the variable. 1576# @param [in] PATH Path to directory or file. 1577# @param [in] ARGV3 Path to directory or file inside install tree. 1578# If this argument is not given, PATH is used for both 1579# the build and install tree version of the script. 1580# 1581# @ingroup CMakeAPI 1582function (basis_set_script_path VAR PATH) 1583 if (NOT __DIR__) 1584 message (FATAL_ERROR "__DIR__ not set! Note that basis_set_script_path() may" 1585 " only be used in script configurations (e.g., ScriptConfig.cmake.in).") 1586 endif () 1587 if (ARGC GREATER 3) 1588 message (FATAL_ERROR "Too many arguments given for function basis_set_script_path()") 1589 endif () 1590 if (ARGC EQUAL 3 AND BUILD_INSTALL_SCRIPT) 1591 set (PREFIX "${CMAKE_INSTALL_PREFIX}") 1592 set (PATH "${ARGV2}") 1593 else () 1594 set (PREFIX "${PROJECT_SOURCE_DIR}") 1595 endif () 1596 if (NOT IS_ABSOLUTE "${PATH}") 1597 set (PATH "${PREFIX}/${PATH}") 1598 endif () 1599 basis_get_relative_path (PATH "${__DIR__}" "${PATH}") 1600 if (NOT PATH) 1601 set (${VAR} "." PARENT_SCOPE) 1602 else () 1603 string (REGEX REPLACE "/+$" "" PATH "${PATH}") 1604 set (${VAR} "${PATH}" PARENT_SCOPE) 1605 endif () 1606endfunction () 1607 1608# ============================================================================ 1609# set/get any property 1610# ============================================================================ 1611 1612# ---------------------------------------------------------------------------- 1613## @brief Convert list into regular expression. 1614# 1615# This function is in particular used to convert a list of property names 1616# such as <CONFIG>_OUTPUT_NAME, e.g., the list @c BASIS_PROPERTIES_ON_TARGETS, 1617# into a regular expression which can be used in pattern matches. 1618# 1619# @param [out] REGEX Name of variable for resulting regular expression. 1620# @param [in] ARGN List of patterns which may contain placeholders in the 1621# form of "<this is a placeholder>". These are replaced 1622# by the regular expression "[^ ]+". 1623macro (basis_list_to_regex REGEX) 1624 string (REGEX REPLACE "<[^>]+>" "[^ ]+" ${REGEX} "${ARGN}") 1625 string (REGEX REPLACE ";" "|" ${REGEX} "${${REGEX}}") 1626 set (${REGEX} "^(${${REGEX}})$") 1627endmacro () 1628 1629# ---------------------------------------------------------------------------- 1630## @brief Output current CMake variables to file. 1631function (basis_dump_variables RESULT_FILE) 1632 set (DUMP) 1633 get_cmake_property (VARIABLE_NAMES VARIABLES) 1634 foreach (V IN LISTS VARIABLE_NAMES) 1635 if (NOT V MATCHES "^_|^RESULT_FILE$|^ARGC$|^ARGV[0-9]?$|^ARGN_") 1636 set (VALUE "${${V}}") 1637 # sanitize value for use in set() command 1638 string (REPLACE "\\" "\\\\" VALUE "${VALUE}") # escape backspaces 1639 string (REPLACE "\"" "\\\"" VALUE "${VALUE}") # escape double quotes 1640 # Escape ${VAR} by \${VAR} such that CMake does not evaluate it. 1641 # Escape $STR{VAR} by \$STR{VAR} such that CMake does not report a 1642 # syntax error b/c it expects either ${VAR}, $ENV{VAR}, or $CACHE{VAR}. 1643 # Escape @VAR@ by \@VAR\@ such that CMake does not evaluate it. 1644 string (REGEX REPLACE "([^\\])\\\$([^ ]*){" "\\1\\\\\$\\2{" VALUE "${VALUE}") 1645 string (REGEX REPLACE "([^\\])\\\@([^ ]*)\@" "\\1\\\\\@\\2\\\\\@" VALUE "${VALUE}") 1646 # append variable to output file 1647 set (DUMP "${DUMP}set (${V} \"${VALUE}\")\n") 1648 endif () 1649 endforeach () 1650 file (WRITE "${RESULT_FILE}" "# CMake variables dump created by BASIS\n${DUMP}") 1651endfunction () 1652 1653# ---------------------------------------------------------------------------- 1654## @brief Write CMake script file which sets the named variable to the 1655# specified (list of) values. 1656function (basis_write_list FILENAME VARIABLE) 1657 file (WRITE "${FILENAME}" "# Automatically generated. Do not edit this file!\nset (${VARIABLE}\n") 1658 foreach (V IN LISTS ARGN) 1659 file (APPEND "${FILENAME}" " \"${V}\"\n") 1660 endforeach () 1661 file (APPEND "${FILENAME}" ")\n") 1662endfunction () 1663 1664# ---------------------------------------------------------------------------- 1665## @brief Set a named property in a given scope. 1666# 1667# This function replaces CMake's 1668# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 1669# set_property()</a> command. 1670# 1671# @param [in] SCOPE The argument for the @p SCOPE parameter of 1672# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 1673# set_property()</a>. 1674# @param [in] ARGN Arguments as accepted by. 1675# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property"> 1676# set_property()</a>. 1677# 1678# @returns Sets the specified property. 1679# 1680# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property 1681# 1682# @ingroup CMakeAPI 1683if (BASIS_USE_TARGET_UIDS) 1684 function (basis_set_property SCOPE) 1685 if (SCOPE MATCHES "^TARGET$|^TEST$") 1686 # map target/test names to UIDs 1687 list (LENGTH ARGN ARGN_LENGTH) 1688 if (ARGN_LENGTH EQUAL 0) 1689 message (FATAL_ERROR "basis_set_property(${SCOPE}): Expected arguments after SCOPE!") 1690 endif () 1691 set (IDX 0) 1692 set (ARG) 1693 while (IDX LESS ARGN_LENGTH) 1694 list (GET ARGN ${IDX} ARG) 1695 if (ARG MATCHES "^APPEND$") 1696 math (EXPR IDX "${IDX} + 1") 1697 list (GET ARGN ${IDX} ARG) 1698 if (NOT ARG MATCHES "^PROPERTY$") 1699 message (FATAL_ERROR "basis_set_properties(${SCOPE}): Expected PROPERTY keyword after APPEND!") 1700 endif () 1701 break () 1702 elseif (ARG MATCHES "^PROPERTY$") 1703 break () 1704 else () 1705 if (SCOPE MATCHES "^TEST$") 1706 basis_get_test_uid (UID "${ARG}") 1707 else () 1708 basis_get_target_uid (UID "${ARG}") 1709 endif () 1710 list (INSERT ARGN ${IDX} "${UID}") 1711 math (EXPR IDX "${IDX} + 1") 1712 list (REMOVE_AT ARGN ${IDX}) # after insert to avoid index out of range 1713 endif () 1714 endwhile () 1715 if (IDX EQUAL ARGN_LENGTH) 1716 message (FATAL_ERROR "basis_set_properties(${SCOPE}): Missing PROPERTY keyword!") 1717 endif () 1718 math (EXPR IDX "${IDX} + 1") 1719 list (GET ARGN ${IDX} ARG) 1720 # property name matches DEPENDS 1721 if (ARG MATCHES "DEPENDS") 1722 math (EXPR IDX "${IDX} + 1") 1723 while (IDX LESS ARGN_LENGTH) 1724 list (GET ARGN ${IDX} ARG) 1725 if (SCOPE MATCHES "^TEST$") 1726 basis_get_test_uid (UID "${ARG}") 1727 else () 1728 basis_get_target_uid (UID "${ARG}") 1729 endif () 1730 list (INSERT ARGN ${IDX} "${UID}") 1731 math (EXPR IDX "${IDX} + 1") 1732 list (REMOVE_AT ARGN ${IDX}) # after insert to avoid index out of range 1733 endwhile () 1734 endif () 1735 endif () 1736 if (BASIS_DEBUG) 1737 message ("** basis_set_property():") 1738 message ("** Scope: ${SCOPE}") 1739 message ("** Arguments: [${ARGN}]") 1740 endif () 1741 set_property (${SCOPE} ${ARGN}) 1742 endfunction () 1743else () 1744 macro (basis_set_property) 1745 set_property (${ARGV}) 1746 endmacro () 1747endif () 1748 1749# ---------------------------------------------------------------------------- 1750## @brief Get a property. 1751# 1752# This function replaces CMake's 1753# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 1754# get_property()</a> command. 1755# 1756# @param [out] VAR Property value. 1757# @param [in] SCOPE The argument for the @p SCOPE argument of 1758# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 1759# get_property()</a>. 1760# @param [in] ELEMENT The argument for the @p ELEMENT argument of 1761# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 1762# get_property()</a>. 1763# @param [in] ARGN Arguments as accepted by 1764# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property"> 1765# get_property()</a>. 1766# 1767# @returns Sets @p VAR to the value of the requested property. 1768# 1769# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property 1770# 1771# @ingroup CMakeAPI 1772if (BASIS_USE_TARGET_UIDS) 1773 function (basis_get_property VAR SCOPE ELEMENT) 1774 if (SCOPE MATCHES "^TARGET$") 1775 basis_get_target_uid (ELEMENT "${ELEMENT}") 1776 elseif (SCOPE MATCHES "^TEST$") 1777 basis_get_test_uid (ELEMENT "${ELEMENT}") 1778 endif () 1779 get_property (VALUE ${SCOPE} ${ELEMENT} ${ARGN}) 1780 set ("${VAR}" "${VALUE}" PARENT_SCOPE) 1781 endfunction () 1782else () 1783 macro (basis_get_property) 1784 get_property (${ARGV}) 1785 endmacro () 1786endif () 1787 1788# ---------------------------------------------------------------------------- 1789## @brief Set project-global property. 1790# 1791# Set property associated with current project/module. The property is in 1792# fact just a cached variable whose name is prefixed by the project's name. 1793function (basis_set_project_property) 1794 CMAKE_PARSE_ARGUMENTS ( 1795 ARGN 1796 "APPEND" 1797 "PROJECT" 1798 "PROPERTY" 1799 ${ARGN} 1800 ) 1801 1802 if (NOT ARGN_PROJECT) 1803 set (ARGN_PROJECT "${PROJECT_NAME}") 1804 endif () 1805 if (NOT ARGN_PROPERTY) 1806 message (FATAL_ERROR "Missing PROPERTY argument!") 1807 endif () 1808 1809 list (GET ARGN_PROPERTY 0 PROPERTY_NAME) 1810 list (REMOVE_AT ARGN_PROPERTY 0) # remove property name from values 1811 1812 if (ARGN_APPEND) 1813 basis_get_project_property (CURRENT ${ARGN_PROJECT} ${PROPERTY_NAME}) 1814 if (NOT "${CURRENT}" STREQUAL "") 1815 list (INSERT ARGN_PROPERTY 0 "${CURRENT}") 1816 endif () 1817 endif () 1818 1819 set ( 1820 ${ARGN_PROJECT}_${PROPERTY_NAME} 1821 "${ARGN_PROPERTY}" 1822 CACHE INTERNAL 1823 "Property ${PROPERTY_NAME} of project ${ARGN_PROJECT}." 1824 FORCE 1825 ) 1826endfunction () 1827 1828# ---------------------------------------------------------------------------- 1829## @brief Get project-global property value. 1830# 1831# Example: 1832# @code 1833# basis_get_project_property(TARGETS) 1834# basis_get_project_property(TARGETS ${PROJECT_NAME}) 1835# basis_get_project_property(TARGETS ${PROJECT_NAME} TARGETS) 1836# basis_get_project_property(TARGETS PROPERTY TARGETS) 1837# @endcode 1838# 1839# @param [out] VARIABLE Name of result variable. 1840# @param [in] ARGN See the example uses. The optional second argument 1841# is either the name of the project similar to CMake's 1842# get_target_property() command or the keyword PROPERTY 1843# followed by the name of the property. 1844function (basis_get_project_property VARIABLE) 1845 if (ARGC GREATER 3) 1846 message (FATAL_ERROR "Too many arguments!") 1847 endif () 1848 if (ARGC EQUAL 1) 1849 set (ARGN_PROJECT "${PROJECT_NAME}") 1850 set (ARGN_PROPERTY "${VARIABLE}") 1851 elseif (ARGC EQUAL 2) 1852 if (ARGV1 MATCHES "^PROPERTY$") 1853 message (FATAL_ERROR "Expected argument after PROPERTY keyword!") 1854 endif () 1855 set (ARGN_PROJECT "${ARGV1}") 1856 set (ARGN_PROPERTY "${VARIABLE}") 1857 else () 1858 if (ARGV1 MATCHES "^PROPERTY$") 1859 set (ARGN_PROJECT "${PROJECT_NAME}") 1860 else () 1861 set (ARGN_PROJECT "${ARGV1}") 1862 endif () 1863 set (ARGN_PROPERTY "${ARGV2}") 1864 endif () 1865 set (${VARIABLE} "${${ARGN_PROJECT}_${ARGN_PROPERTY}}" PARENT_SCOPE) 1866endfunction () 1867 1868# ============================================================================ 1869# list / string manipulations 1870# ============================================================================ 1871 1872# ---------------------------------------------------------------------------- 1873## @brief Sanitize string variable for use in regular expression. 1874# 1875# @note This function may not work for all cases, but is used in particular 1876# to sanitize project names, target names, namespace identifiers,... 1877# 1878# This takes all of the dollar signs, and other special characters and 1879# adds escape characters such as backslash as necessary. 1880# 1881# @param [out] OUT String that can be used in regular expression. 1882# @param [in] STR String to sanitize. 1883macro (basis_sanitize_for_regex OUT STR) 1884 string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" ${OUT} "${STR}") 1885endmacro () 1886 1887# ---------------------------------------------------------------------------- 1888## @brief Concatenates all list elements into a single string. 1889# 1890# The list elements are concatenated without any delimiter in between. 1891# Use basis_list_to_delimited_string() to specify a delimiter such as a 1892# whitespace character or comma (,) as delimiter. 1893# 1894# @param [out] STR Output string. 1895# @param [in] ARGN Input list. 1896# 1897# @returns Sets @p STR to the resulting string. 1898# 1899# @sa basis_list_to_delimited_string() 1900function (basis_list_to_string STR) 1901 set (OUT) 1902 foreach (ELEM IN LISTS ARGN) 1903 set (OUT "${OUT}${ELEM}") 1904 endforeach () 1905 set ("${STR}" "${OUT}" PARENT_SCOPE) 1906endfunction () 1907 1908# ---------------------------------------------------------------------------- 1909## @brief Concatenates all list elements into a single delimited string. 1910# 1911# @param [out] STR Output string. 1912# @param [in] DELIM Delimiter used to separate list elements. 1913# Each element which contains the delimiter as substring 1914# is surrounded by double quotes (") in the output string. 1915# @param [in] ARGN Input list. If this list starts with the argument 1916# @c NOAUTOQUOTE, the automatic quoting of list elements 1917# which contain the delimiter is disabled. 1918# 1919# @returns Sets @p STR to the resulting string. 1920# 1921# @see basis_join 1922# 1923# @todo consider replacing basis_list_to_delimited_string with basis_join 1924function (basis_list_to_delimited_string STR DELIM) 1925 set (OUT) 1926 set (AUTOQUOTE TRUE) 1927 if (ARGN) 1928 list (GET ARGN 0 FIRST) 1929 if (FIRST MATCHES "^NOAUTOQUOTE$") 1930 list (REMOVE_AT ARGN 0) 1931 set (AUTOQUOTE FALSE) 1932 endif () 1933 endif () 1934 basis_sanitize_for_regex (DELIM_RE "${DELIM}") 1935 foreach (ELEM ${ARGN}) 1936 if (OUT) 1937 set (OUT "${OUT}${DELIM}") 1938 endif () 1939 if (AUTOQUOTE AND ELEM MATCHES "${DELIM_RE}") 1940 set (OUT "${OUT}\"${ELEM}\"") 1941 else () 1942 set (OUT "${OUT}${ELEM}") 1943 endif () 1944 endforeach () 1945 set ("${STR}" "${OUT}" PARENT_SCOPE) 1946endfunction () 1947 1948# ---------------------------------------------------------------------------- 1949## @brief Concatenates all list elements into a single delimited string. 1950# 1951# @param [in] VALUES Input list string. 1952# @param [in] DELIMITER Delimiter glue used to separate list elements. 1953# Each element which contains the delimiter as substring 1954# is surrounded by double quotes (") in the output string. 1955# @param [out] OUTPUT Output string variable name. 1956# 1957# @code 1958# set( letters "" "\;a" b c "d\;d" ) 1959# basis_join("${letters}" ":" output) 1960# message("${output}") # :;a:b:c:d;d 1961# @endcode 1962# 1963# @returns Sets @p OUTPUT to the resulting string. 1964# 1965# @see basis_list_to_delimited_string 1966function(basis_join VALUES DELIMITER OUTPUT) 1967 string (REGEX REPLACE "([^\\]|^);" "\\1${DELIMITER}" _TMP_STR "${VALUES}") 1968 string (REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping 1969 set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) 1970endfunction() 1971 1972# ---------------------------------------------------------------------------- 1973## @brief Splits a string at space characters into a list. 1974# 1975# @todo Probably this can be done in a better way... 1976# Difficulty is, that string(REPLACE) does always replace all 1977# occurrences. Therefore, we need a regular expression which matches 1978# the entire string. More sophisticated regular expressions should do 1979# a better job, though. 1980# 1981# @param [out] LST Output list. 1982# @param [in] STR Input string. 1983# 1984# @returns Sets @p LST to the resulting CMake list. 1985function (basis_string_to_list LST STR) 1986 set (TMP "${STR}") 1987 set (OUT) 1988 # 1. extract elements such as "a string with spaces" 1989 while (TMP MATCHES "\"[^\"]*\"") 1990 string (REGEX REPLACE "^(.*)\"([^\"]*)\"(.*)$" "\\1\\3" TMP "${TMP}") 1991 if (OUT) 1992 set (OUT "${CMAKE_MATCH_2};${OUT}") 1993 else (OUT) 1994 set (OUT "${CMAKE_MATCH_2}") 1995 endif () 1996 endwhile () 1997 # 2. extract other elements separated by spaces (excluding first and last) 1998 while (TMP MATCHES " [^\" ]+ ") 1999 string (REGEX REPLACE "^(.*) ([^\" ]+) (.*)$" "\\1\\3" TMP "${TMP}") 2000 if (OUT) 2001 set (OUT "${CMAKE_MATCH_2};${OUT}") 2002 else (OUT) 2003 set (OUT "${CMAKE_MATCH_2}") 2004 endif () 2005 endwhile () 2006 # 3. extract first and last elements (if not done yet) 2007 if (TMP MATCHES "^[^\" ]+") 2008 set (OUT "${CMAKE_MATCH_0};${OUT}") 2009 endif () 2010 if (NOT "${CMAKE_MATCH_0}" STREQUAL "${TMP}" AND TMP MATCHES "[^\" ]+$") 2011 set (OUT "${OUT};${CMAKE_MATCH_0}") 2012 endif () 2013 # return resulting list 2014 set (${LST} "${OUT}" PARENT_SCOPE) 2015endfunction () 2016 2017# ---------------------------------------------------------------------------- 2018## @brief Compare two lists. 2019# 2020# @param [out] RESULT Result of comparison. 2021# @param [in] LIST1 Name of variable holding the first list. 2022# @param [in] LIST2 Name of varaible holding the second list. 2023# 2024# @retval 0 The two lists are not identical. 2025# @retval 1 Both lists have identical elements (not necessarily in the same order). 2026macro (basis_compare_lists RESULT LIST1 LIST2) 2027 set (_L1 "${${LIST1}}") 2028 set (_L2 "${${LIST2}}") 2029 list (SORT _L1) 2030 list (SORT _L2) 2031 if ("${_L1}" STREQUAL "${_L2}") 2032 set (RESULT TRUE) 2033 else () 2034 set (RESULT FALSE) 2035 endif () 2036 unset (_L1) 2037 unset (_L2) 2038endmacro () 2039 2040# ============================================================================ 2041# name <=> UID 2042# ============================================================================ 2043 2044# ---------------------------------------------------------------------------- 2045## @brief Derive target name from source file name. 2046# 2047# @param [out] TARGET_NAME Target name. 2048# @param [in] SOURCE_FILE Source file. 2049# @param [in] ARGN Third argument to get_filename_component(). 2050# If not specified, the given path is only sanitized. 2051# 2052# @returns Target name derived from @p SOURCE_FILE. 2053function (basis_get_source_target_name TARGET_NAME SOURCE_FILE) 2054 # remove ".in" suffix from file name 2055 string (REGEX REPLACE "\\.in$" "" OUT "${SOURCE_FILE}") 2056 # get name component 2057 if (ARGC GREATER 2) 2058 get_filename_component (OUT "${OUT}" ${ARGV2}) 2059 endif () 2060 # replace special characters 2061 string (REGEX REPLACE "[./\\]" "_" OUT "${OUT}") 2062 # return 2063 set (${TARGET_NAME} "${OUT}" PARENT_SCOPE) 2064endfunction () 2065 2066# ---------------------------------------------------------------------------- 2067## @brief Strip of top-level package name from target UID if present. 2068# 2069# If @c BASIS_USE_FULLY_QUALIFIED_TARGET_UID is @c ON, the top-level package 2070# name is always preserved and this operation does nothing. 2071# 2072# @param[in,out] TARGET_UID "Global" target name, i.e., actual CMake target name. 2073# 2074# @returns Sets @p TARGET_UID to the (stripped) UID. 2075function (basis_strip_target_uid TARGET_UID) 2076 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 2077 basis_sanitize_for_regex (RE "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}") 2078 string (REGEX REPLACE "^\\.*${RE}\\." "" UID "${${TARGET_UID}}") 2079 set ("${TARGET_UID}" "${UID}" PARENT_SCOPE) 2080 endif () 2081endfunction () 2082 2083# ---------------------------------------------------------------------------- 2084## @brief Make target UID from given target name. 2085# 2086# This function is intended for internal use only. 2087# 2088# @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name. 2089# @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 2090# 2091# @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME. 2092# 2093# @sa basis_make_target_uid() 2094function (_basis_make_target_uid TARGET_UID TARGET_NAME) 2095 if (TARGET_NAME MATCHES "^\\.+(.*)$") 2096 set (${TARGET_UID} "${CMAKE_MATCH_1}" PARENT_SCOPE) 2097 else () 2098 set (UID "${PROJECT_NAMESPACE_CMAKE}.${TARGET_NAME}") 2099 basis_strip_target_uid (UID) 2100 set (${TARGET_UID} "${UID}" PARENT_SCOPE) 2101 endif () 2102endfunction () 2103 2104# ---------------------------------------------------------------------------- 2105## @brief Make target UID from given target name. 2106# 2107# This function is intended for use by the basis_add_*() functions only. 2108# 2109# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2110# always just sets the @p TARGET_UID to the given @p TARGET_NAME. 2111# 2112# @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name. 2113# @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 2114# 2115# @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME. 2116# 2117# @sa basis_get_target_uid() 2118if (BASIS_USE_TARGET_UIDS) 2119 function (basis_make_target_uid TARGET_UID TARGET_NAME) 2120 _basis_make_target_uid (UID "${TARGET_NAME}") 2121 set ("${TARGET_UID}" "${UID}" PARENT_SCOPE) 2122 endfunction () 2123else () 2124 function (basis_make_target_uid TARGET_UID TARGET_NAME) 2125 if (TARGET_NAME MATCHES "^\\.+(.*)$") 2126 set ("${TARGET_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2127 else () 2128 set ("${TARGET_UID}" "${TARGET_NAME}" PARENT_SCOPE) 2129 endif () 2130 endfunction () 2131endif () 2132 2133# ---------------------------------------------------------------------------- 2134## @brief Get "global" target name, i.e., actual CMake target name. 2135# 2136# In order to ensure that CMake target names are unique across modules of 2137# a BASIS project, the target name given to the BASIS CMake functions is 2138# converted by basis_make_target_uid() into a so-called target UID which is 2139# used as actual CMake target name. This function can be used to get for a 2140# given target name or UID the closest match of a known target UID. 2141# 2142# The individual parts of the target UID, i.e, package name, 2143# module name, and target name are separated by a dot (.). 2144# If @c BASIS_USE_FULLY_QUALIFIED_UIDS is set to @c OFF, the common part of 2145# all target UIDs is removed by this function from the target UID. 2146# When the target is exported, however, this common part will be 2147# prefixed again. This is done by the basis_export_targets() function. 2148# 2149# Note that names of imported targets are not prefixed in any case. 2150# 2151# The counterpart basis_get_target_name() can be used to convert the target UID 2152# back to the target name without namespace prefix. 2153# 2154# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2155# always just sets the @p TARGET_UID to the given @p TARGET_NAME. 2156# 2157# @note At the moment, BASIS does not support modules which themselves have 2158# modules again. This would require a more nested namespace hierarchy 2159# and makes things unnecessarily complicated. 2160# 2161# @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name. 2162# @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 2163# 2164# @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME. 2165# 2166# @sa basis_get_target_name() 2167if (BASIS_USE_TARGET_UIDS) 2168 function (basis_get_target_uid TARGET_UID TARGET_NAME) 2169 # in case of a leading namespace separator, do not modify target name 2170 if (TARGET_NAME MATCHES "^\\.+(.*)$") 2171 set (UID "${CMAKE_MATCH_1}") 2172 # otherwise, 2173 else () 2174 set (UID "${TARGET_NAME}") 2175 basis_sanitize_for_regex (BASE_RE "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}") 2176 # try prepending namespace or parts of it until target is known, 2177 # first assuming the simplified UIDs without the common prefix 2178 # of this package which applies to targets of this package 2179 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS AND NOT TARGET "${UID}") 2180 string (REGEX REPLACE "^${BASE_RE}\\." "" PREFIX "${PROJECT_NAMESPACE_CMAKE}") 2181 while (PREFIX) 2182 if (TARGET "${PREFIX}.${TARGET_NAME}") 2183 set (UID "${PREFIX}.${TARGET_NAME}") 2184 break () 2185 else () 2186 if (PREFIX MATCHES "(.*)\\.[^.]+") 2187 set (PREFIX "${CMAKE_MATCH_1}") 2188 else () 2189 break () 2190 endif () 2191 endif () 2192 endwhile () 2193 endif () 2194 # and then with the fully qualified UIDs for imported targets 2195 if (NOT TARGET "${UID}") 2196 set (PREFIX "${PROJECT_NAMESPACE_CMAKE}") 2197 while (PREFIX) 2198 if (TARGET "${PREFIX}.${TARGET_NAME}") 2199 set (UID "${PREFIX}.${TARGET_NAME}") 2200 break () 2201 else () 2202 if (PREFIX MATCHES "(.*)\\.[^.]+") 2203 set (PREFIX "${CMAKE_MATCH_1}") 2204 else () 2205 break () 2206 endif () 2207 endif () 2208 endwhile () 2209 endif () 2210 endif () 2211 # strip off top-level namespace part (optional) 2212 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 2213 string (REGEX REPLACE "^${BASE_RE}\\." "" UID "${UID}") 2214 endif () 2215 # return 2216 set ("${TARGET_UID}" "${UID}" PARENT_SCOPE) 2217 endfunction () 2218else () 2219 function (basis_get_target_uid TARGET_UID TARGET_NAME) 2220 if (TARGET_NAME MATCHES "^\\.+(.*)$") 2221 set (${TARGET_UID} "${CMAKE_MATCH_1}" PARENT_SCOPE) 2222 else () 2223 set ("${TARGET_UID}" "${TARGET_NAME}" PARENT_SCOPE) 2224 endif () 2225 endfunction () 2226endif () 2227 2228# ---------------------------------------------------------------------------- 2229## @brief Get fully-qualified target name. 2230# 2231# This function always returns a fully-qualified target UID, no matter if 2232# the option @c BASIS_USE_TARGET_UIDS or @c BASIS_USE_FULLY_QUALIFIED_UIDS 2233# is @c OFF. Note that if @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c ON, the 2234# returned target UID may not be the actual name of a CMake target. 2235# 2236# @param [out] TARGET_UID Fully-qualified target UID. 2237# @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions. 2238# 2239# @sa basis_get_target_uid() 2240function (basis_get_fully_qualified_target_uid TARGET_UID TARGET_NAME) 2241 if (BASIS_USE_TARGET_UIDS) 2242 basis_get_target_uid (UID "${TARGET_NAME}") 2243 if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS) 2244 if (TARGET "${UID}") 2245 get_target_property (IMPORTED "${UID}" IMPORTED) 2246 if (NOT IMPORTED) 2247 set (UID "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${UID}") 2248 endif () 2249 else () 2250 set (UID "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${UID}") 2251 endif () 2252 endif () 2253 else () 2254 if (TARGET "${TARGET_NAME}") 2255 get_target_property (IMPORTED "${TARGET_NAME}" IMPORTED) 2256 else () 2257 set (IMPORTED FALSE) 2258 endif () 2259 if (IMPORTED) 2260 set (UID "${TARGET_NAME}") 2261 else () 2262 set (UID "${PROJECT_NAMESPACE_CMAKE}.${TARGET_NAME}") 2263 endif () 2264 endif () 2265 set (${TARGET_UID} "${UID}" PARENT_SCOPE) 2266endfunction () 2267 2268# ---------------------------------------------------------------------------- 2269## @brief Get namespace of build target without check of UID. 2270# 2271# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2272# always just sets the @p TARGET_NS to an empty string. 2273# 2274# @param [out] TARGET_NS Namespace part of target UID. 2275# @param [in] TARGET_UID Target UID. 2276if (BASIS_USE_TARGET_UIDS) 2277 function (_basis_get_target_namespace TARGET_NS TARGET_UID) 2278 if (UID MATCHES "^(.*)\\.") 2279 set ("${TARGET_NS}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2280 else () 2281 set ("${TARGET_NS}" "" PARENT_SCOPE) 2282 endif () 2283 endfunction () 2284else () 2285 function (_basis_get_target_namespace TARGET_NS TARGET_UID) 2286 set ("${TARGET_NS}" "" PARENT_SCOPE) 2287 endfunction () 2288endif () 2289 2290# ---------------------------------------------------------------------------- 2291## @brief Get namespace of build target. 2292# 2293# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2294# always just sets the @p TARGET_NS to an empty string. 2295# 2296# @param [out] TARGET_NS Namespace part of target UID. 2297# @param [in] TARGET_UID Target UID/name. 2298if (BASIS_USE_TARGET_UIDS) 2299 function (basis_get_target_namespace TARGET_NS TARGET_UID) 2300 basis_get_fully_qualified_target_uid (UID "${TARGET_UID}") 2301 _basis_get_target_namespace (NS "${UID}") 2302 set ("${TARGET_NS}" "${NS}" PARENT_SCOPE) 2303 endfunction () 2304else () 2305 function (basis_get_target_namespace TARGET_NS TARGET_UID) 2306 set ("${TARGET_NS}" "" PARENT_SCOPE) 2307 endfunction () 2308endif () 2309 2310# ---------------------------------------------------------------------------- 2311## @brief Get "local" target name, i.e., BASIS target name without check of UID. 2312# 2313# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2314# always just sets the @p TARGET_NAME to the given @p TARGET_UID. 2315# 2316# @param [out] TARGET_NAME Target name used as argument to BASIS functions. 2317# @param [in] TARGET_UID "Global" target name, i.e., actual CMake target name. 2318# 2319# @returns Sets @p TARGET_NAME to the name of the build target with UID @p TARGET_UID. 2320# 2321# @sa basis_get_target_name(), basis_get_target_uid() 2322if (BASIS_USE_TARGET_UIDS) 2323 function (_basis_get_target_name TARGET_NAME TARGET_UID) 2324 # strip off namespace of current project 2325 basis_sanitize_for_regex (RE "${PROJECT_NAMESPACE_CMAKE}") 2326 string (REGEX REPLACE "^${RE}\\." "" NAME "${UID}") 2327 # return 2328 set (${TARGET_NAME} "${NAME}" PARENT_SCOPE) 2329 endfunction () 2330else () 2331 function (_basis_get_target_name TARGET_NAME TARGET_UID) 2332 set (${TARGET_NAME} "${TARGET_UID}" PARENT_SCOPE) 2333 endfunction () 2334endif () 2335 2336# ---------------------------------------------------------------------------- 2337## @brief Get "local" target name, i.e., BASIS target name. 2338# 2339# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2340# always just sets the @p TARGET_NAME to the given @p TARGET_UID. 2341# 2342# @param [out] TARGET_NAME Target name used as argument to BASIS functions. 2343# @param [in] TARGET_UID "Global" target name, i.e., actual CMake target name. 2344# 2345# @returns Sets @p TARGET_NAME to the name of the build target with UID @p TARGET_UID. 2346# 2347# @sa basis_get_target_uid() 2348if (BASIS_USE_TARGET_UIDS) 2349 function (basis_get_target_name TARGET_NAME TARGET_UID) 2350 basis_get_fully_qualified_target_uid (UID "${TARGET_UID}") 2351 _basis_get_target_name (NAME "${UID}") 2352 set (${TARGET_NAME} "${NAME}" PARENT_SCOPE) 2353 endfunction () 2354else () 2355 function (basis_get_target_name TARGET_NAME TARGET_UID) 2356 set (${TARGET_NAME} "${TARGET_UID}" PARENT_SCOPE) 2357 endfunction () 2358endif () 2359 2360# ---------------------------------------------------------------------------- 2361## @brief Checks whether a given name is a valid target name. 2362# 2363# Displays fatal error message when target name is invalid. 2364# 2365# @param [in] TARGET_NAME Desired target name. 2366# 2367# @returns Nothing. 2368function (basis_check_target_name TARGET_NAME) 2369 # reserved target name ? 2370 foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES) 2371 if ("^${TARGET_NAME}$" STREQUAL "^${PATTERN}$") 2372 message (FATAL_ERROR "Target name \"${TARGET_NAME}\" is reserved and cannot be used.") 2373 endif () 2374 endforeach () 2375 # invalid target name ? 2376 if (NOT TARGET_NAME MATCHES "^\\.?[a-zA-Z]([a-zA-Z0-9_+.]|-)*$|^__init__(_py)?$") 2377 message (FATAL_ERROR "Target name '${TARGET_NAME}' is invalid.\nChoose a target name" 2378 " which only contains alphanumeric characters," 2379 " '_', '-', or '+', and starts with a letter." 2380 " The only exception from this rule is __init__[_py] for" 2381 " a __init__.py script.\n") 2382 endif () 2383 2384 # unique ? 2385 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 2386 if (TARGET "${TARGET_UID}") 2387 message (FATAL_ERROR "There exists already a target named ${TARGET_UID}." 2388 " Target names must be unique.") 2389 endif () 2390endfunction () 2391 2392# ---------------------------------------------------------------------------- 2393## @brief Make test UID from given test name. 2394# 2395# This function is intended for use by the basis_add_test() only. 2396# 2397# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2398# always just sets the @p TEST_UID to the given @p TEST_NAME. 2399# 2400# @param [out] TEST_UID "Global" test name, i.e., actual CTest test name. 2401# @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 2402# 2403# @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME. 2404# 2405# @sa basis_get_test_uid() 2406function (basis_make_test_uid TEST_UID TEST_NAME) 2407 basis_make_target_uid (UID "${TEST_NAME}") 2408 set ("${TEST_UID}" "${UID}" PARENT_SCOPE) 2409endfunction () 2410 2411# ---------------------------------------------------------------------------- 2412## @brief Get "global" test name, i.e., actual CTest test name. 2413# 2414# In order to ensure that CTest test names are unique across BASIS projects, 2415# the test name used by a developer of a BASIS project is converted by this 2416# function into another test name which is used as actual CTest test name. 2417# 2418# The function basis_get_test_name() can be used to convert the unique test 2419# name, the test UID, back to the original test name passed to this function. 2420# 2421# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2422# always just sets the @p TEST_UID to the given @p TEST_NAME. 2423# 2424# @param [out] TEST_UID "Global" test name, i.e., actual CTest test name. 2425# @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 2426# 2427# @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME. 2428# 2429# @sa basis_get_test_name() 2430if (BASIS_USE_TARGET_UIDS) 2431 function (basis_get_test_uid TEST_UID TEST_NAME) 2432 if (TEST_NAME MATCHES "^\\.+(.*)$") 2433 set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2434 else () 2435 set (UID "${PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}") 2436 basis_strip_target_uid (UID ${UID}) 2437 set ("${TEST_UID}" "${UID}" PARENT_SCOPE) 2438 endif () 2439 endfunction () 2440else () 2441 function (basis_get_test_uid TEST_UID TEST_NAME) 2442 if (TEST_NAME MATCHES "^\\.+(.*)$") 2443 set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2444 else () 2445 set ("${TEST_UID}" "${TEST_NAME}" PARENT_SCOPE) 2446 endif () 2447 endfunction () 2448endif () 2449 2450# ---------------------------------------------------------------------------- 2451## @brief Get "global" test name, i.e., actual CTest test name. 2452# 2453# This function always returns a fully-qualified test UID, no matter if 2454# the option @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c OFF. Note that 2455# if this option is @c ON, the returned test UID may not be the 2456# actual name of a CMake test. 2457# 2458# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2459# always just sets the @p TEST_UID to the given @p TEST_NAME. 2460# 2461# @param [out] TEST_UID Fully-qualified test UID. 2462# @param [in] TEST_NAME Test name used as argument to BASIS CMake functions. 2463# 2464# @sa basis_get_test_uid() 2465if (BASIS_USE_TARGET_UIDS) 2466 function (basis_get_fully_qualified_test_uid TEST_UID TEST_NAME) 2467 if (TEST_NAME MATCHES "^\\.+(.*)$") 2468 set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2469 else () 2470 set ("${TEST_UID}" "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}" PARENT_SCOPE) 2471 endif () 2472 endfunction () 2473else () 2474 function (basis_get_fully_qualified_test_uid TEST_UID TEST_NAME) 2475 if (TEST_NAME MATCHES "^\\.+(.*)$") 2476 set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE) 2477 else () 2478 set ("${TEST_UID}" "${TEST_NAME}" PARENT_SCOPE) 2479 endif () 2480 endfunction () 2481endif () 2482 2483# ---------------------------------------------------------------------------- 2484## @brief Get namespace of test. 2485# 2486# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2487# always just sets the @p TEST_NS to an empty string. 2488# 2489# @param [out] TEST_NS Namespace part of test UID. If @p TEST_UID is 2490# no UID, i.e., does not contain a namespace part, 2491# the namespace of this project is returned. 2492# @param [in] TEST_UID Test UID/name. 2493if (BASIS_USE_TARGET_UIDS) 2494 function (basis_get_test_namespace TEST_NS TEST_UID) 2495 if (TEST_UID MATCHES "^(.*)\\.") 2496 set (${TEST_NS} "${CMAKE_MATCH_1}" PARENT_SCOPE) 2497 else () 2498 set (${TEST_NS} "" PARENT_SCOPE) 2499 endif () 2500 endfunction () 2501else () 2502 function (basis_get_test_namespace TEST_NS TEST_UID) 2503 set ("${TEST_UID}" "" PARENT_SCOPE) 2504 endfunction () 2505endif () 2506 2507# ---------------------------------------------------------------------------- 2508## @brief Get "local" test name, i.e., BASIS test name. 2509# 2510# If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation 2511# always just sets the @p TEST_NAME to the given @p TEST_UID. 2512# 2513# @param [out] TEST_NAME Test name used as argument to BASIS functions. 2514# @param [in] TEST_UID "Global" test name, i.e., actual CTest test name. 2515# 2516# @returns Sets @p TEST_NAME to the name of the test with UID @p TEST_UID. 2517# 2518# @sa basis_get_test_uid() 2519if (BASIS_USE_TARGET_UIDS) 2520 function (basis_get_test_name TEST_NAME TEST_UID) 2521 if (TEST_UID MATCHES "([^.]+)$") 2522 set (${TEST_NAME} "${CMAKE_MATCH_1}" PARENT_SCOPE) 2523 else () 2524 set (${TEST_NAME} "" PARENT_SCOPE) 2525 endif () 2526 endfunction () 2527else () 2528 function (basis_get_test_name TEST_NAME TEST_UID) 2529 set ("${TEST_NAME}" "${TEST_UID}" PARENT_SCOPE) 2530 endfunction () 2531endif () 2532 2533# ---------------------------------------------------------------------------- 2534## @brief Checks whether a given name is a valid test name. 2535# 2536# Displays fatal error message when test name is invalid. 2537# 2538# @param [in] TEST_NAME Desired test name. 2539# 2540# @returns Nothing. 2541function (basis_check_test_name TEST_NAME) 2542 # reserved test name ? 2543 foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES) 2544 if ("^${TARGET_NAME}$" STREQUAL "^${PATTERN}$") 2545 message (FATAL_ERROR "Test name \"${TARGET_NAME}\" is reserved and cannot be used.") 2546 endif () 2547 endforeach () 2548 # invalid test name ? 2549 if (NOT TEST_NAME MATCHES "^\\.?[a-zA-Z]([a-zA-Z0-9_+.]|-)*$") 2550 message (FATAL_ERROR "Test name ${TEST_NAME} is invalid.\nChoose a test name " 2551 " which only contains alphanumeric characters," 2552 " '_', '-', or '+', and starts with a letter.\n") 2553 endif () 2554endfunction () 2555 2556# ============================================================================ 2557# common target tools 2558# ============================================================================ 2559 2560# ---------------------------------------------------------------------------- 2561## @brief Whether a given target exists. 2562# 2563# This function should be used instead of the if(TARGET) command of CMake 2564# because target names are mapped by BASIS to target UIDs. 2565# 2566# @param [out] RESULT_VARIABLE Boolean result variable. 2567# @param [in] TARGET_NAME Name which to check whether it is a target. 2568# 2569# @sa basis_make_target_uid() 2570# @sa basis_get_target_uid() 2571macro (basis_exists_target RESULT_VARIABLE TARGET_NAME) 2572 basis_get_target_uid (_UID "${TARGET_NAME}") 2573 if (TARGET ${_UID}) 2574 set (${RESULT_VARIABLE} TRUE) 2575 else () 2576 set (${RESULT_VARIABLE} FALSE) 2577 endif () 2578 unset (_UID) 2579endmacro () 2580 2581# ---------------------------------------------------------------------------- 2582## @brief Get default subdirectory prefix of scripted library modules. 2583# 2584# @param [out] PREFIX Name of variable which is set to the default library 2585# prefix, i.e., subdirectory relative to the library 2586# root directory as used for the @c PREFIX property of 2587# scripted module libraries (see basis_add_script_library()) 2588# or relative to the include directory in case of C++. 2589# Note that this prefix includes a trailing slash to 2590# indicate that the prefix is a subdirectory. 2591# @param [in] LANGUAGE Programming language (case-insenitive), e.g., 2592# @c CXX, @c Python, @c Matlab... 2593macro (basis_library_prefix PREFIX LANGUAGE) 2594 string (TOUPPER "${LANGUAGE}" _LANGUAGE_U) 2595 if (PROJECT_NAMESPACE_${_LANGUAGE_U}) 2596 basis_sanitize_for_regex (_RE "${BASIS_NAMESPACE_DELIMITER_${_LANGUAGE_U}}") 2597 string (REGEX REPLACE "${_RE}" "/" ${PREFIX} "${PROJECT_NAMESPACE_${_LANGUAGE_U}}") 2598 set (${PREFIX} "${${PREFIX}}/") 2599 unset (_RE) 2600 else () 2601 message (FATAL_ERROR "basis_library_prefix(): PROJECT_NAMESPACE_${_LANGUAGE_U} not set!" 2602 " Make sure that the LANGUAGE argument is supported and in" 2603 " uppercase letters only.") 2604 endif () 2605 unset (_LANGUAGE_U) 2606endmacro () 2607 2608# ---------------------------------------------------------------------------- 2609## @brief Get file name of compiled script. 2610# 2611# @param [out] CFILE File path of compiled script file. 2612# @param [in] SOURCE Script source file. 2613# @param [in] ARGV2 Language of script file. If not specified, the language 2614# is derived from the file name extension and shebang of 2615# the script source file. 2616function (basis_get_compiled_file CFILE SOURCE) 2617 if (ARGC GREATER 2) 2618 set (LANGUAGE "${ARGV2}") 2619 else () 2620 basis_get_source_language (LANGUAGE "${SOURCE}") 2621 endif () 2622 set (${CFILE} "" PARENT_SCOPE) 2623 if (SOURCE) 2624 if (LANGUAGE MATCHES "PYTHON") 2625 set (${CFILE} "${SOURCE}c" PARENT_SCOPE) 2626 elseif (LANGUAGE MATCHES "JYTHON") 2627 if (SOURCE MATCHES "(.*)\\.([^.]+)$") 2628 set (${CFILE} "${CMAKE_MATCH_1}$${CMAKE_MATCH_2}.class" PARENT_SCOPE) 2629 endif () 2630 endif () 2631 endif () 2632endfunction () 2633 2634# ---------------------------------------------------------------------------- 2635## @brief Get file path of Jython file compiled from the given Python module. 2636# 2637# Python modules are also compiled using Jython. This macro returns the file 2638# path of the compiled Jython file in the build tree which corresponds to the 2639# specified Python module. 2640# 2641# @param [out] CFILE Path of corresponding compiled Jython file. 2642# @param [in] MODULE Path of input Python module in build tree. 2643macro (basis_get_compiled_jython_file_of_python_module CFILE MODULE) 2644 if (BINARY_PYTHON_LIBRARY_DIR AND BINARY_JYTHON_LIBRARY_DIR) 2645 file (RELATIVE_PATH _GCJFOPM_REL "${BINARY_PYTHON_LIBRARY_DIR}" "${MODULE}") 2646 else () 2647 set (_GCJFOPM_REL) 2648 endif () 2649 if (NOT _GCJFOPM_REL MATCHES "^$|^\\.\\./") 2650 basis_get_compiled_file (${CFILE} "${BINARY_JYTHON_LIBRARY_DIR}/${_GCJFOPM_REL}" JYTHON) 2651 else () 2652 basis_get_compiled_file (${CFILE} "${MODULE}" JYTHON) 2653 endif () 2654 unset (_GCJFOPM_REL) 2655endmacro () 2656 2657# ---------------------------------------------------------------------------- 2658## @brief Whether to compile Python modules for Jython interpreter. 2659# 2660# This macro returns a boolean value stating whether Python modules shall also 2661# be compiled for use by Jython interpreter if BASIS_COMPILE_SCRIPTS is ON. 2662# 2663# @param [out] FLAG Set to either TRUE or FALSE depending on whether Python 2664# modules shall be compiled using Jython or not. 2665macro (basis_compile_python_modules_for_jython FLAG) 2666 if (BASIS_COMPILE_SCRIPTS AND JYTHON_EXECUTABLE) 2667 set (${FLAG} TRUE) 2668 else () 2669 set (${FLAG} FALSE) 2670 endif () 2671 if (DEFINED USE_JythonInterp AND NOT USE_JythonInterp) 2672 set (${FLAG} FALSE) 2673 endif () 2674endmacro () 2675 2676# ---------------------------------------------------------------------------- 2677## @brief Glob source files. 2678# 2679# This function gets a list of source files and globbing expressions, evaluates 2680# the globbing expression, and replaces these by the found source files such 2681# that the resulting list of source files contains only absolute paths of 2682# source files. It is used by basis_add_executable() and basis_add_library() 2683# to get a list of all source files. The syntax for the glob expressions 2684# corresponds to the one used by CMake's 2685# <a href="http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:file"> 2686# file(GLOB)</a> command. Additionally, if the pattern <tt>**</tt> is found 2687# in a glob expression, it is replaced by a single <tt>*</tt> and the 2688# recursive version, i.e., <tt>file(GLOB_RECURSE)</tt>, is used instead. 2689# 2690# @param [in] TARGET_UID UID of build target which builds the globbed source files. 2691# The custom target which re-globs the source files 2692# before each build of this target is named after this 2693# build target with two leading underscores (__). 2694# @param [out] SOURCES List of absolute source paths. 2695# @param [in] ARGN Input file paths and/or globbing expressions. 2696# 2697# @sa basis_add_executable() 2698# @sa basis_add_library() 2699function (basis_add_glob_target TARGET_UID SOURCES) 2700 # prepare globbing expressions 2701 # make paths absolute and turn directories into recursive globbing expressions 2702 set (EXPRESSIONS) 2703 foreach (EXPRESSION IN LISTS ARGN) 2704 if (NOT EXPRESSION MATCHES "^\\$<") # preserve generator expressions 2705 if (NOT IS_ABSOLUTE "${EXPRESSION}") 2706 # prefer configured/generated files in the build tree, but disallow 2707 # globbing within the build tree; glob only files in source tree 2708 if (NOT EXPRESSION MATCHES "[*?]|\\[[0-9]+-[0-9]+\\]" AND 2709 EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}" AND 2710 NOT IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}") 2711 set (EXPRESSION "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}") 2712 else () 2713 set (EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/${EXPRESSION}") 2714 endif () 2715 endif () 2716 if (IS_DIRECTORY "${EXPRESSION}") 2717 set (EXPRESSION "${EXPRESSION}/**") 2718 endif () 2719 endif () 2720 list (APPEND EXPRESSIONS "${EXPRESSION}") 2721 endforeach () 2722 # only if at least one globbing expression is given we need to go through this hassle 2723 if (EXPRESSIONS MATCHES "[*?]|\\[[0-9]+-[0-9]+\\]") 2724 set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}.dir") 2725 set (SOURCES_FILE "${BUILD_DIR}/sources.txt") 2726 # get initial list of source files 2727 execute_process ( 2728 COMMAND "${CMAKE_COMMAND}" 2729 "-DEXPRESSIONS:STRING=${EXPRESSIONS}" 2730 "-DINIT:BOOLEAN=TRUE" 2731 "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}" 2732 -P "${BASIS_MODULE_PATH}/glob.cmake" 2733 RESULT_VARIABLE RETVAL 2734 ) 2735 if (NOT RETVAL EQUAL 0 OR NOT EXISTS "${SOURCES_FILE}") 2736 message (FATAL_ERROR "Target ${TARGET_UID}: Failed to glob source files!") 2737 endif () 2738 # note that including this file here, which is modified whenever a 2739 # source file is added or removed, triggers a re-configuration of the 2740 # build system which is required to re-execute this function. 2741 include ("${SOURCES_FILE}") 2742 set (${SOURCES} "${INITIAL_SOURCES}" PARENT_SCOPE) 2743 # add custom target to re-glob files before each build 2744 set (ERRORMSG "You have either added, removed, or renamed a source file which" 2745 " matches one of the globbing expressions specified for the" 2746 " list of source files from which to build the ${TARGET_UID} target." 2747 " Therefore, the build system must be re-configured. Either try to" 2748 " build again which should trigger CMake and re-configure the build" 2749 " system or run CMake manually.") 2750 basis_list_to_string (ERRORMSG ${ERRORMSG}) 2751 add_custom_target ( 2752 __${TARGET_UID} 2753 COMMAND "${CMAKE_COMMAND}" 2754 "-DEXPRESSIONS:STRING=${EXPRESSIONS}" 2755 "-DINIT:BOOLEAN=FALSE" 2756 "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}" 2757 "-DERRORMSG:STRING=${ERRORMSG}" 2758 -P "${BASIS_MODULE_PATH}/glob.cmake" 2759 COMMENT "Checking if source files for target ${TARGET_UID} were added or removed" 2760 VERBATIM 2761 ) 2762 # otherwise, just return the given absolute source file paths 2763 else () 2764 set (${SOURCES} "${EXPRESSIONS}" PARENT_SCOPE) 2765 endif () 2766endfunction () 2767 2768# ---------------------------------------------------------------------------- 2769## @brief Detect programming language of given source code files. 2770# 2771# This function determines the programming language in which the given source 2772# code files are written. If no common programming language could be determined, 2773# "AMBIGUOUS" is returned. If none of the following programming languages 2774# could be determined, "UNKNOWN" is returned: CXX (i.e., C++), JAVA, MATLAB, 2775# PYTHON, JYTHON, PERL, BASH, BATCH. 2776# 2777# @param [out] LANGUAGE Detected programming language. 2778# @param [in] ARGN List of source code files. 2779function (basis_get_source_language LANGUAGE) 2780 set (LANGUAGE_OUT) 2781 # iterate over source files 2782 foreach (SOURCE_FILE ${ARGN}) 2783 # skip generator expressions 2784 if (NOT SOURCE_FILE MATCHES "^\\$<") 2785 get_filename_component (SOURCE_FILE "${SOURCE_FILE}" ABSOLUTE) 2786 2787 if (IS_DIRECTORY "${SOURCE_FILE}") 2788 2789 file (GLOB_RECURSE SOURCE_FILES "${SOURCE_FILE}/*") 2790 list (APPEND ARGN ${SOURCE_FILES}) 2791 2792 else () 2793 2794 # ------------------------------------------------------------------------ 2795 # determine language based on extension for those without shebang 2796 set (LANG) 2797 # C++ 2798 if (SOURCE_FILE MATCHES "\\.(c|cc|cpp|cxx|h|hh|hpp|hxx|txx|inl)(\\.in)?$") 2799 set (LANG "CXX") 2800 # Java 2801 elseif (SOURCE_FILE MATCHES "\\.java(\\.in)?$") 2802 set (LANG "JAVA") 2803 # MATLAB 2804 elseif (SOURCE_FILE MATCHES "\\.m(\\.in)?$") 2805 set (LANG "MATLAB") 2806 endif () 2807 2808 # ------------------------------------------------------------------------ 2809 # determine language from shebang directive 2810 # 2811 # Note that some scripting languages may use identical file name extensions. 2812 # This is in particular the case for Python and Jython. The only way we 2813 # can distinguish these two is by looking at the shebang directive. 2814 if (NOT LANG) 2815 2816 if (NOT EXISTS "${SOURCE_FILE}" AND EXISTS "${SOURCE_FILE}.in") 2817 set (SOURCE_FILE "${SOURCE_FILE}.in") 2818 endif () 2819 if (EXISTS "${SOURCE_FILE}") 2820 file (STRINGS "${SOURCE_FILE}" FIRST_LINE LIMIT_COUNT 1) 2821 if (FIRST_LINE MATCHES "^#!") 2822 if (FIRST_LINE MATCHES "^#! */usr/bin/env +([^ ]+)") 2823 set (INTERPRETER "${CMAKE_MATCH_1}") 2824 elseif (FIRST_LINE MATCHES "^#! *([^ ]+)") 2825 set (INTERPRETER "${CMAKE_MATCH_1}") 2826 get_filename_component (INTERPRETER "${INTERPRETER}" NAME) 2827 else () 2828 set (INTERPRETER) 2829 endif () 2830 if (INTERPRETER MATCHES "^(python|jython|perl|bash)$") 2831 string (TOUPPER "${INTERPRETER}" LANG) 2832 endif () 2833 endif () 2834 endif () 2835 endif () 2836 2837 # ------------------------------------------------------------------------ 2838 # determine language from further known extensions 2839 if (NOT LANG) 2840 # Python 2841 if (SOURCE_FILE MATCHES "\\.py(\\.in)?$") 2842 set (LANG "PYTHON") 2843 # Perl 2844 elseif (SOURCE_FILE MATCHES "\\.(pl|pm|t)(\\.in)?$") 2845 set (LANG "PERL") 2846 # BASH 2847 elseif (SOURCE_FILE MATCHES "\\.sh(\\.in)?$") 2848 set (LANG "BASH") 2849 # Batch 2850 elseif (SOURCE_FILE MATCHES "\\.bat(\\.in)?$") 2851 set (LANG "BATCH") 2852 # unknown 2853 else () 2854 set (LANGUAGE_OUT "UNKNOWN") 2855 break () 2856 endif () 2857 endif () 2858 2859 # ------------------------------------------------------------------------ 2860 # detect ambiguity 2861 if (LANGUAGE_OUT AND NOT "^${LANG}$" STREQUAL "^${LANGUAGE_OUT}$") 2862 if (LANGUAGE_OUT MATCHES "CXX" AND LANG MATCHES "MATLAB") 2863 # MATLAB Compiler can handle this... 2864 elseif (LANGUAGE_OUT MATCHES "MATLAB" AND LANG MATCHES "CXX") 2865 set (LANG "MATLAB") # language stays MATLAB 2866 elseif (LANGUAGE_OUT MATCHES "PYTHON" AND LANG MATCHES "JYTHON") 2867 # Jython can deal with Python scripts/modules 2868 elseif (LANGUAGE_OUT MATCHES "JYTHON" AND LANG MATCHES "PYTHON") 2869 set (LANG "JYTHON") # language stays JYTHON 2870 else () 2871 # ambiguity 2872 set (LANGUAGE_OUT "AMBIGUOUS") 2873 break () 2874 endif () 2875 endif () 2876 2877 # update current language 2878 set (LANGUAGE_OUT "${LANG}") 2879 endif () 2880 endif () 2881 endforeach () 2882 # return 2883 if (LANGUAGE_OUT) 2884 set (${LANGUAGE} "${LANGUAGE_OUT}" PARENT_SCOPE) 2885 else () 2886 message (FATAL_ERROR "basis_get_source_language called without arguments!") 2887 endif () 2888endfunction () 2889 2890# ---------------------------------------------------------------------------- 2891## @brief Configure .in source files. 2892# 2893# This function configures each source file in the given argument list with 2894# a .in file name suffix and stores the configured file in the build tree 2895# with the same relative directory as the template source file itself. 2896# The first argument names the CMake variable of the list of configured 2897# source files where each list item is the absolute file path of the 2898# corresponding (configured) source file. 2899# 2900# @param [out] LIST_NAME Name of output list. 2901# @param [in] ARGN These arguments are parsed and the following 2902# options recognized. All remaining arguments are 2903# considered to be source file paths. 2904# @par 2905# <table border="0"> 2906# <tr> 2907# @tp @b BINARY_DIRECTORY @endtp 2908# <td>Explicitly specify directory in build tree where configured 2909# source files should be written to.</td> 2910# </tr> 2911# <tr> 2912# @tp @b KEEP_DOT_IN_SUFFIX @endtp 2913# <td>By default, after a source file with the .in extension has been 2914# configured, the .in suffix is removed from the file name. 2915# This can be omitted by giving this option.</td> 2916# </tr> 2917# </table> 2918# 2919# @returns Nothing. 2920function (basis_configure_sources LIST_NAME) 2921 # parse arguments 2922 CMAKE_PARSE_ARGUMENTS (ARGN "KEEP_DOT_IN_SUFFIX" "BINARY_DIRECTORY" "" ${ARGN}) 2923 2924 # ensure that specified BINARY_DIRECTORY is inside build tree of project 2925 if (ARGN_BINARY_DIRECTORY) 2926 get_filename_component (_binpath "${ARGN_BINARY_DIRECTORY}" ABSOLUTE) 2927 file (RELATIVE_PATH _relpath "${PROJECT_BINARY_DIR}" "${_binpath}") 2928 if (_relpath MATCHES "^\\.\\./") 2929 message (FATAL_ERROR "Specified BINARY_DIRECTORY must be inside the build tree!") 2930 endif () 2931 unset (_binpath) 2932 unset (_relpath) 2933 endif () 2934 2935 # configure source files 2936 set (CONFIGURED_SOURCES) 2937 foreach (SOURCE ${ARGN_UNPARSED_ARGUMENTS}) 2938 # The .in suffix is optional, add it here if a .in file exists for this 2939 # source file, but only if the source file itself does not name an actually 2940 # existing source file. 2941 # 2942 # If the source file path is relative, prefer possibly already configured 2943 # sources in build tree such as the test driver source file created by 2944 # create_test_sourcelist() or a manual use of configure_file(). 2945 # 2946 # Note: Make path absolute, otherwise EXISTS check will not work! 2947 if (NOT IS_ABSOLUTE "${SOURCE}") 2948 if (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}") 2949 set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}") 2950 elseif (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in") 2951 set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in") 2952 elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}") 2953 set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}") 2954 elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in") 2955 set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in") 2956 endif () 2957 else () 2958 if (NOT EXISTS "${SOURCE}" AND EXISTS "${SOURCE}.in") 2959 set (SOURCE "${SOURCE}.in") 2960 endif () 2961 endif () 2962 # configure source file if filename ends in .in suffix 2963 if (SOURCE MATCHES "\\.in$") 2964 # if binary directory was given explicitly, use it 2965 if (ARGN_BINARY_DIRECTORY) 2966 get_filename_component (SOURCE_NAME "${SOURCE}" NAME) 2967 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 2968 string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}") 2969 endif () 2970 set (CONFIGURED_SOURCE "${ARGN_BINARY_DIRECTORY}/${SOURCE_NAME}") 2971 # otherwise, 2972 else () 2973 # if source is in project's source tree use relative binary directory 2974 if ("^${SOURCE}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") 2975 basis_get_relative_path (CONFIGURED_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}" "${SOURCE}") 2976 get_filename_component (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURED_SOURCE}" ABSOLUTE) 2977 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 2978 string (REGEX REPLACE "\\.in$" "" CONFIGURED_SOURCE "${CONFIGURED_SOURCE}") 2979 endif () 2980 # otherwise, use current binary directory 2981 else () 2982 get_filename_component (SOURCE_NAME "${SOURCE}" NAME) 2983 if (NOT ARGN_KEEP_DOT_IN_SUFFIX) 2984 string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}") 2985 endif () 2986 set (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE_NAME}") 2987 endif () 2988 endif () 2989 # configure source file 2990 configure_file ("${SOURCE}" "${CONFIGURED_SOURCE}" @ONLY) 2991 if (BASIS_DEBUG) 2992 message ("** Configured source file with .in extension") 2993 endif () 2994 # otherwise, skip configuration of this source file 2995 else () 2996 set (CONFIGURED_SOURCE "${SOURCE}") 2997 if (BASIS_DEBUG) 2998 message ("** Skipped configuration of source file") 2999 endif () 3000 endif () 3001 if (BASIS_DEBUG) 3002 message ("** Source: ${SOURCE}") 3003 message ("** Configured source: ${CONFIGURED_SOURCE}") 3004 endif () 3005 list (APPEND CONFIGURED_SOURCES "${CONFIGURED_SOURCE}") 3006 endforeach () 3007 # return 3008 set (${LIST_NAME} "${CONFIGURED_SOURCES}" PARENT_SCOPE) 3009endfunction () 3010 3011# ---------------------------------------------------------------------------- 3012## @brief Remove one blank line from top of string 3013macro (basis_remove_blank_line STRVAR) 3014 if (${STRVAR} MATCHES "(^|(.*)\n)[ \t]*\n(.*)") 3015 set (${STRVAR} "${CMAKE_MATCH_1}${CMAKE_MATCH_3}") 3016 endif () 3017endmacro () 3018 3019# ---------------------------------------------------------------------------- 3020## @brief Configure and optionally compile script file. 3021# 3022# This function is used to configure script files during the build. It is 3023# called by the build script generated by basis_add_script_target() for each script 3024# target. It is also used to configure the modules of the packages 3025# implemented in supported scripting languages which are located in the 3026# @c PROJECT_LIBRARY_DIR of the source tree. 3027# 3028# In case of executable scripts, this function automatically prepends the 3029# module search paths such that the modules of this software package are found 3030# (and preferred in case of potential name conflicts with other packages). 3031# Moreover, it adds (or replaces) the shebang directive on Unix such that the 3032# configured interpreter version is used. On Windows, it converts the executable 3033# script into a Windows Command instead which executes the proper interpreter 3034# with the code section of the input script. 3035# 3036# @param [in] INPUT Input script file. 3037# @param [in] OUTPUT Configured output script file. 3038# @param [in] ARGN Optional arguments: 3039# @par 3040# <table border=0> 3041# <tr> 3042# @tp @b COMPILE @endtp 3043# <td>Whether to compile module scripts if suitable, i.e., an intermediate 3044# format exists for the specific scripting language. For example, 3045# Python modules can be compiled.</td> 3046# </tr> 3047# @tp @b CONFIGURATION name @endtp 3048# <td>Name of build configuration.</td> 3049# </tr> 3050# <tr> 3051# @tp @b COPYONLY @endtp 3052# <td>Whether to only copy the script file without replacing CMake variables 3053# within the file. This option is passed on to CMake's configure_file() 3054# command used to configure the script file. By default, the option 3055# \@ONLY is used instead.</td> 3056# </tr> 3057# <tr> 3058# @tp @b EXECUTABLE @endtp 3059# <td>Specifies that the given script file is an executable script and not a 3060# module script. Otherwise, if this option is not given and the output 3061# file name contains a file name extension, the given script file is 3062# configured as module script. A script file with an output file name 3063# that has no extension, is always considered to be an executable.</td> 3064# </tr> 3065# <tr> 3066# @tp @b DIRECTORY dir @endtp 3067# <td>Build tree directory of configured script. By default, the directory 3068# of the output script file is used to set the @c __DIR__ variable 3069# used to make absolute file paths relative to the configured build 3070# tree script file in the script configuration file 3071# (see basis_set_script_path()). 3072# </tr> 3073# <tr> 3074# @tp @b DESTINATION dir @endtp 3075# <td>Installation directory for configured script. If this option is given, 3076# the @c BUILD_INSTALL_SCRIPT variable is set to @c TRUE before including 3077# any specified script configuration files (see @p CONFIG_FILE option). 3078# Moreover, the @c __DIR__ variable is set to the specified directory. 3079# Otherwise, if this option is omitted, the @c BUILD_INSTALL_SCRIPT variable 3080# is set to @c FALSE instead and @c __DIR__ is set to the directory of 3081# the configured @p OUTPUT file. Note that the @c BUILD_INSTALL_SCRIPT and 3082# @c __DIR__ variables are in particular used by basis_set_script_path() 3083# to convert the given paths to paths relative to the location of the 3084# configured/installed script.</td> 3085# </tr> 3086# <tr> 3087# @tp @b CACHE_FILE file1 [file2...] @endtp 3088# <td>List of CMake files with dump of variables which should be included 3089# before configuring the script. The cache files can be generated using 3090# the basis_dump_variables() function.</td> 3091# </tr> 3092# <tr> 3093# @tp @b CONFIG_FILE file1 [file2...] @endtp 3094# <td>List of script configuration files to include before the configuration 3095# of the script. See also the documentation of the @p DESTINATION option.</td> 3096# </tr> 3097# <tr> 3098# @tp @b LINK_DEPENDS dep1 [dep2...] @endtp 3099# <td>List of "link" dependencies, i.e., modules and script/module libraries 3100# required by this script. For executable scripts, the paths to these 3101# modules/packages is added to the module search path. If the prefix 3102# "relative " is given before a file path, it is made relative to the 3103# output/installation directory of the script file. All given input paths 3104# must be absolute, however, as the relative location depends on 3105# whether the script will be installed, i.e., the @c DESTINATION 3106# is specified, or not.</td> 3107# </tr> 3108# </table> 3109function (basis_configure_script INPUT OUTPUT) 3110 # rename arguments to avoid conflict with script configuration 3111 set (_INPUT_FILE "${INPUT}") 3112 set (_OUTPUT_FILE "${OUTPUT}") 3113 # -------------------------------------------------------------------------- 3114 # parse arguments 3115 CMAKE_PARSE_ARGUMENTS ( 3116 ARGN 3117 "COMPILE;COPYONLY;EXECUTABLE" 3118 "DIRECTORY;DESTINATION;LANGUAGE;CONFIGURATION" 3119 "CACHE_FILE;CONFIG_FILE;LINK_DEPENDS" 3120 ${ARGN} 3121 ) 3122 if (ARGN_UNPARSED_ARGUMENTS) 3123 message (FATAL_ERROR "Unrecognized arguments given: ${ARGN_UNPARSED_ARGUMENTS}") 3124 endif () 3125 if (NOT ARGN_LANGUAGE) 3126 basis_get_source_language (ARGN_LANGUAGE "${_INPUT_FILE}") 3127 endif () 3128 # -------------------------------------------------------------------------- 3129 # include cache files 3130 foreach (_F IN LISTS ARGN_CACHE_FILE) 3131 get_filename_component (_F "${_F}" ABSOLUTE) 3132 if (NOT EXISTS "${_F}") 3133 message (FATAL_ERROR "Cache file ${_F} does not exist!") 3134 endif () 3135 include ("${_F}") 3136 endforeach () 3137 # -------------------------------------------------------------------------- 3138 # general variables for use in scripts and those intended for use in script 3139 # configurations. The __DIR__ is in particular used by basis_set_script_path() 3140 # to make absolute paths relative to the script file location 3141 if (ARGN_DESTINATION) 3142 if (NOT IS_ABSOLUTE "${ARGN_DESTINATION}") 3143 set (ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}/${ARGN_DESTINATION}") 3144 endif () 3145 set (BUILD_INSTALL_SCRIPT TRUE) 3146 set (__DIR__ "${ARGN_DESTINATION}") 3147 else () 3148 set (BUILD_INSTALL_SCRIPT FALSE) 3149 if (ARGN_DIRECTORY) 3150 if (NOT IS_ABSOLUTE "${ARGN_DIRECTORY}") 3151 message (FATAL_ERROR "Build tree script DIRECTORY must be an absolute path") 3152 endif () 3153 set (__DIR__ "${ARGN_DIRECTORY}") 3154 string (REPLACE "$<${BASIS_GE_CONFIG}>" "${ARGN_CONFIGURATION}" __DIR__ "${__DIR__}") 3155 else () 3156 get_filename_component (__DIR__ "${_OUTPUT_FILE}" PATH) 3157 endif () 3158 endif () 3159 get_filename_component (__NAME__ "${_OUTPUT_FILE}" NAME) 3160 set (__FILE__ "${__DIR__}/${__NAME__}") 3161 set (__CONFIG__ "${ARGN_CONFIGURATION}") 3162 # -------------------------------------------------------------------------- 3163 # replace $<CONFIG> (deprecated $<CONFIGURATION>) in paths of link dependencies 3164 string (REPLACE "$<${BASIS_GE_CONFIG}>" "${ARGN_CONFIGURATION}" ARGN_LINK_DEPENDS "${ARGN_LINK_DEPENDS}") 3165 # -------------------------------------------------------------------------- 3166 # include script configuration files 3167 foreach (_F IN LISTS ARGN_CONFIG_FILE) 3168 get_filename_component (_F "${_F}" ABSOLUTE) 3169 if (NOT EXISTS "${_F}") 3170 message (FATAL_ERROR "Script configuration file ${_F} does not exist!") 3171 endif () 3172 include ("${_F}") 3173 endforeach () 3174 # -------------------------------------------------------------------------- 3175 # configure executable script 3176 if (ARGN_EXECUTABLE) 3177 # Attention: Every line of code added/removed will introduce a mismatch 3178 # between error messages of the interpreter and the original 3179 # source file. To not confuse/mislead developers too much, 3180 # keep number of lines added/removed at a minimum or at least 3181 # try to balance the number of lines added and removed. 3182 # Moreover, blank lines can be used to insert code without 3183 # changing the number of source code lines. 3184 file (READ "${_INPUT_FILE}" SCRIPT) 3185 # (temporarily) remove existing shebang directive 3186 file (STRINGS "${_INPUT_FILE}" FIRST_LINE LIMIT_COUNT 1) 3187 if (FIRST_LINE MATCHES "^#!") 3188 basis_sanitize_for_regex (FIRST_LINE_RE "${FIRST_LINE}") 3189 string (REGEX REPLACE "^${FIRST_LINE_RE}\n?" "" SCRIPT "${SCRIPT}") 3190 set (SHEBANG "${FIRST_LINE}") 3191 endif () 3192 # replace CMake variables used in script 3193 if (NOT ARGN_COPYONLY) 3194 string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY) 3195 endif () 3196 # add code to set module search path 3197 if (ARGN_LANGUAGE MATCHES "[JP]YTHON") 3198 if (ARGN_LINK_DEPENDS) 3199 set (PYTHON_CODE "import sys; import os.path; __dir__ = os.path.dirname(os.path.realpath(__file__))") 3200 list (REVERSE ARGN_LINK_DEPENDS) 3201 foreach (DIR ${ARGN_LINK_DEPENDS}) 3202 if (DIR MATCHES "^relative +(.*)$") 3203 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 3204 endif () 3205 if (DIR MATCHES "\\.(py|class)$") 3206 get_filename_component (DIR "${DIR}" PATH) 3207 endif () 3208 if (IS_ABSOLUTE "${DIR}") 3209 set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath('${DIR}'))") 3210 else () 3211 set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath(os.path.join(__dir__, '${DIR}')))") 3212 endif () 3213 endforeach () 3214 # insert extra Python code near top, but after any future statement 3215 # (http://docs.python.org/2/reference/simple_stmts.html#future) 3216 set (FUTURE_STATEMENTS) 3217 if (SCRIPT MATCHES "^(.*from[ \t]+__future__[ \t]+import[ \t]+[a-z_]+[^\n]*\n)(.*)$") 3218 set (FUTURE_STATEMENTS "${CMAKE_MATCH_1}") 3219 set (SCRIPT "${CMAKE_MATCH_2}") 3220 endif () 3221 basis_remove_blank_line (SCRIPT) # remove a blank line therefore 3222 set (SCRIPT "${FUTURE_STATEMENTS}${PYTHON_CODE} # <-- added by BASIS\n${SCRIPT}") 3223 endif () 3224 elseif (ARGN_LANGUAGE MATCHES "PERL") 3225 if (ARGN_LINK_DEPENDS) 3226 set (PERL_CODE "use Cwd qw(realpath); use File::Basename;") 3227 foreach (DIR ${ARGN_LINK_DEPENDS}) 3228 if (DIR MATCHES "^relative +(.*)$") 3229 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 3230 endif () 3231 if (DIR MATCHES "\\.pm$") 3232 get_filename_component (DIR "${DIR}" PATH) 3233 endif () 3234 if (IS_ABSOLUTE "${DIR}") 3235 set (PERL_CODE "${PERL_CODE} use lib '${DIR}';") 3236 else () 3237 set (PERL_CODE "${PERL_CODE} use lib dirname(realpath(__FILE__)) . '/${DIR}';") 3238 endif () 3239 endforeach () 3240 basis_remove_blank_line (SCRIPT) # remove a blank line therefore 3241 set (SCRIPT "${PERL_CODE} # <-- added by BASIS\n${SCRIPT}") 3242 endif () 3243 elseif (ARGN_LANGUAGE MATCHES "BASH") 3244 basis_library_prefix (PREFIX BASH) 3245 # In case of Bash, set BASIS_BASH_UTILITIES which is required to first source the 3246 # BASIS utilities modules (in particular core.sh). This variable should be set to 3247 # the utilities.sh module of BASIS by default as part of the BASIS installation 3248 # (environment variable) and is here set to the project-specific basis.sh module. 3249 # 3250 # Note that folks at SBIA may submit a Bash script directly to a batch queuing 3251 # system such as the Oracle Grid Engine (SGE) instead of writing a separate submit 3252 # script. To avoid not finding the BASIS utilities in this case only because the 3253 # Bash file was copied by SGE to a temporary file, consider the <PROJECT>_DIR 3254 # environment variable as an alternative. 3255 set (BASH_CODE 3256# Note: Code formatted such that it can be on single line. Use no comments within! 3257"__FILE__=\"$(cd -P -- \"$(dirname -- \"$BASH_SOURCE\")\" && pwd -P)/$(basename -- \"$BASH_SOURCE\")\" 3258if [[ -n \"$SGE_ROOT\" ]] && [[ $__FILE__ =~ $SGE_ROOT/.* ]] && [[ -n \"\${${PROJECT_NAME}_DIR}\" ]] && [[ -f \"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\" ]] 3259then __FILE__=\"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\" 3260fi 3261i=0 3262lnk=\"$__FILE__\" 3263while [[ -h \"$lnk\" ]] && [[ $i -lt 100 ]] 3264do dir=`dirname -- \"$lnk\"` 3265lnk=`readlink -- \"$lnk\"` 3266lnk=`cd \"$dir\" && cd $(dirname -- \"$lnk\") && pwd`/`basename -- \"$lnk\"` 3267let i++ 3268done 3269[[ $i -lt 100 ]] && __FILE__=\"$lnk\" 3270unset -v i dir lnk 3271__DIR__=\"$(dirname -- \"$__FILE__\")\" 3272BASIS_BASH_UTILITIES=\"$__DIR__/${BASH_LIBRARY_DIR}/${PREFIX}basis.sh\"" 3273 ) 3274 string (REPLACE "\n" "; " BASH_CODE "${BASH_CODE}") 3275 # set BASHPATH which is used by import() function provided by core.sh module of BASIS 3276 set (BASHPATH) 3277 foreach (DIR ${ARGN_LINK_DEPENDS}) 3278 if (DIR MATCHES "^relative +(.*)$") 3279 basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}") 3280 endif () 3281 if (DIR MATCHES "\\.sh$") 3282 get_filename_component (DIR "${DIR}" PATH) 3283 endif () 3284 if (IS_ABSOLUTE "${DIR}") 3285 list (APPEND BASHPATH "${DIR}") 3286 else () 3287 list (APPEND BASHPATH "$__DIR__/${DIR}") 3288 endif () 3289 endforeach () 3290 if (BASHPATH) 3291 list (REMOVE_DUPLICATES BASHPATH) 3292 list (APPEND BASHPATH "$BASHPATH") 3293 basis_list_to_delimited_string (BASHPATH ":" NOAUTOQUOTE ${BASHPATH}) 3294 set (BASH_CODE "${BASH_CODE}; BASHPATH=\"${BASHPATH}\"") 3295 endif () 3296 basis_remove_blank_line (SCRIPT) # remove a blank line therefore 3297 set (SCRIPT "${BASH_CODE} # <-- added by BASIS\n${SCRIPT}") 3298 endif () 3299 # replace shebang directive 3300 if (PYTHON_EXECUTABLE AND ARGN_LANGUAGE MATCHES "PYTHON") 3301 if (WIN32) 3302 set (SHEBANG "@setlocal enableextensions & \"${PYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF") 3303 else () 3304 set (SHEBANG "#! ${PYTHON_EXECUTABLE}") 3305 endif () 3306 elseif (JYTHON_EXECUTABLE AND ARGN_LANGUAGE MATCHES "JYTHON") 3307 if (WIN32) 3308 set (SHEBANG "@setlocal enableextensions & \"${JYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF") 3309 else () 3310 # Attention: It is IMPORTANT to not use "#! <interpreter>" even if the <interpreter> 3311 # is given as full path in case of jython. Otherwise, the Jython executable 3312 # fails to execute from within a Python script using the os.system(), 3313 # subprocess.popen(), subprocess.call() or similar function! 3314 # Don't ask me for an explanation, but possibly the used shell otherwise does 3315 # not recognize the shebang as being valid. Using /usr/bin/env helps out here, 3316 # -schuha 3317 set (SHEBANG "#! /usr/bin/env ${JYTHON_EXECUTABLE}") 3318 endif () 3319 elseif (PERL_EXECUTABLE AND ARGN_LANGUAGE MATCHES "PERL") 3320 if (WIN32) 3321 set (SHEBANG "@goto = \"START_OF_BATCH\" ;\n@goto = ();") 3322 set (SCRIPT "${SCRIPT}\n\n__END__\n\n:\"START_OF_BATCH\"\n@\"${PERL_EXECUTABLE}\" -w -S \"%~f0\" %*") 3323 else () 3324 set (SHEBANG "#! ${PERL_EXECUTABLE} -w") 3325 endif () 3326 elseif (BASH_EXECUTABLE AND ARGN_LANGUAGE MATCHES "BASH") 3327 set (SHEBANG "#! ${BASH_EXECUTABLE}") 3328 endif () 3329 # add (modified) shebang directive again 3330 if (SHEBANG) 3331 set (SCRIPT "${SHEBANG}\n${SCRIPT}") 3332 endif () 3333 # write configured script 3334 file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}") 3335 # make script executable on Unix 3336 if (UNIX AND NOT ARGN_DESTINATION) 3337 execute_process (COMMAND /bin/chmod +x "${_OUTPUT_FILE}") 3338 endif () 3339 # -------------------------------------------------------------------------- 3340 # configure module script 3341 else () 3342 # configure module - do not use configure_file() as it will not update the 3343 # file if nothing has changed. the update of the modification 3344 # time is however in particular required for the 3345 # configure_script.cmake build command which uses this 3346 # function to build script targets. otherwise, the custom 3347 # build command is reexecuted only because the output files 3348 # never appear to be more recent than the dependencies 3349 file (READ "${_INPUT_FILE}" SCRIPT) 3350 if (NOT ARGN_COPYONLY) 3351 string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY) 3352 endif () 3353 file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}") 3354 # compile module if requested 3355 if (ARGN_COMPILE) 3356 if (ARGN_LANGUAGE MATCHES "PYTHON" AND PYTHON_EXECUTABLE) 3357 basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" PYTHON) 3358 execute_process (COMMAND "${PYTHON_EXECUTABLE}" -E -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 3359 basis_compile_python_modules_for_jython (RV) 3360 if (RV) 3361 basis_get_compiled_jython_file_of_python_module (CFILE "${_OUTPUT_FILE}") 3362 get_filename_component (CDIR "${CFILE}" PATH) 3363 file (MAKE_DIRECTORY "${CDIR}") 3364 execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 3365 endif () 3366 elseif (ARGN_LANGUAGE MATCHES "JYTHON" AND JYTHON_EXECUTABLE) 3367 basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" JYTHON) 3368 execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')") 3369 endif () 3370 endif () 3371 endif () 3372endfunction () 3373 3374# ---------------------------------------------------------------------------- 3375## @brief Get type name of target. 3376# 3377# @param [out] TYPE The target's type name or NOTFOUND. 3378# @param [in] TARGET_UID The UID of the target. 3379function (_basis_get_target_type TYPE TARGET_UID) 3380 get_target_property (IMPORTED ${TARGET_UID} IMPORTED) 3381 if (IMPORTED) 3382 get_target_property (TYPE_OUT ${TARGET_UID} TYPE) 3383 else () 3384 get_target_property (TYPE_OUT ${TARGET_UID} BASIS_TYPE) 3385 if (NOT TYPE_OUT) 3386 get_target_property (TYPE_OUT ${TARGET_UID} TYPE) 3387 endif () 3388 endif () 3389 set ("${TYPE}" "${TYPE_OUT}" PARENT_SCOPE) 3390endfunction () 3391 3392# ---------------------------------------------------------------------------- 3393## @brief Get type name of target. 3394# 3395# @param [out] TYPE The target's type name or NOTFOUND. 3396# @param [in] TARGET_NAME The name of the target. 3397function (basis_get_target_type TYPE TARGET_NAME) 3398 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 3399 if (TARGET ${TARGET_UID}) 3400 _basis_get_target_type(TYPE_OUT ${TARGET_UID}) 3401 else () 3402 set (TYPE_OUT "NOTFOUND") 3403 endif () 3404 set ("${TYPE}" "${TYPE_OUT}" PARENT_SCOPE) 3405endfunction () 3406 3407# ---------------------------------------------------------------------------- 3408## @brief Get location of build target output file(s). 3409# 3410# This convenience function can be used to get the full path of the output 3411# file(s) generated by a given build target. It is similar to the read-only 3412# @c LOCATION property of CMake targets and should be used instead of 3413# reading this porperty. In case of scripted libraries, this function returns 3414# the path of the root directory of the library that has to be added to the 3415# module search path. 3416# 3417# @note If the target is a binary built from C++ source files and the CMake 3418# generator is an IDE such as Visual Studio or Xcode, the absolute 3419# directory of the target location ends with the generator expression 3420# "/$<${BASIS_GE_CONFIG}>" which is to be substituted by the respective 3421# build configuration. 3422# 3423# @param [out] VAR Path of build target output file. 3424# @param [in] TARGET_NAME Name of build target. 3425# @param [in] PART Which file name component of the @c LOCATION 3426# property to return. See get_filename_component(). 3427# If POST_INSTALL_RELATIVE is given as argument, 3428# @p VAR is set to the path of the installed file 3429# relative to the installation prefix. Similarly, 3430# POST_INSTALL sets @p VAR to the absolute path 3431# of the installed file post installation. 3432# 3433# @returns Path of output file similar to @c LOCATION property of CMake targets. 3434# 3435# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:LOCATION 3436function (basis_get_target_location VAR TARGET_NAME PART) 3437 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 3438 if (TARGET "${TARGET_UID}") 3439 _basis_get_target_name (TARGET_NAME "${TARGET_UID}") 3440 _basis_get_target_type (TYPE "${TARGET_UID}") 3441 get_target_property (IMPORTED ${TARGET_UID} IMPORTED) 3442 # ------------------------------------------------------------------------ 3443 # imported targets 3444 # 3445 # Note: This might not be required though as even custom executable 3446 # and library targets can be imported using CMake's 3447 # add_executable(<NAME> IMPORTED) and add_library(<NAME> <TYPE> IMPORTED) 3448 # commands. Such executable can, for example, also be a BASH 3449 # script built by basis_add_script(). 3450 if (IMPORTED) 3451 # 1. Try IMPORTED_LOCATION_<CMAKE_BUILD_TYPE> 3452 if (CMAKE_BUILD_TYPE) 3453 string (TOUPPER "${CMAKE_BUILD_TYPE}" U) 3454 else () 3455 set (U "NOCONFIG") 3456 endif () 3457 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${U}) 3458 # 2. Try IMPORTED_LOCATION 3459 if (NOT LOCATION) 3460 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION) 3461 endif () 3462 # 3. Prefer Release over all other configurations 3463 if (NOT LOCATION) 3464 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_RELEASE) 3465 endif () 3466 # 4. Just use any of the imported configurations 3467 if (NOT LOCATION) 3468 get_property (CONFIGS TARGET ${TARGET_UID} PROPERTY IMPORTED_CONFIGURATIONS) 3469 foreach (C IN LISTS CONFIGS) 3470 string (TOUPPER "${C}" C) 3471 get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${C}) 3472 if (LOCATION) 3473 break () 3474 endif () 3475 endforeach () 3476 endif () 3477 # make path relative to CMAKE_INSTALL_PREFIX if POST_INSTALL_RELATIVE given 3478 if (LOCATION AND ARGV2 MATCHES "POST_INSTALL_RELATIVE") 3479 file (RELATIVE_PATH LOCATION "${CMAKE_INSTALL_PREFIX}" "${LOCATION}") 3480 endif () 3481 # ------------------------------------------------------------------------ 3482 # non-imported targets 3483 else () 3484 # Attention: The order of the matches/if cases matters here! 3485 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3486 # scripts 3487 if (TYPE MATCHES "^SCRIPT_(EXECUTABLE|MODULE)$") 3488 if (PART MATCHES "POST_INSTALL") 3489 get_target_property (DIRECTORY ${TARGET_UID} INSTALL_DIRECTORY) 3490 else () 3491 get_target_property (DIRECTORY ${TARGET_UID} OUTPUT_DIRECTORY) 3492 if (DIRECTORY AND CMAKE_GENERATOR MATCHES "Visual Studio|Xcode") 3493 set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>") 3494 endif () 3495 endif () 3496 get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME) 3497 elseif (TYPE STREQUAL "^SCRIPT_MODULE$") 3498 if (PART MATCHES "POST_INSTALL") 3499 get_target_property (DIRECTORY ${TARGET_UID} INSTALL_DIRECTORY) 3500 else () 3501 get_target_property (COMPILE ${TARGET_UID} COMPILE) 3502 get_target_property (DIRECTORY ${TARGET_UID} OUTPUT_DIRECTORY) 3503 if (DIRECTORY AND (COMPILE OR CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")) 3504 set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>") 3505 endif () 3506 endif () 3507 get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME) 3508 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3509 # libraries 3510 elseif (TYPE MATCHES "LIBRARY|MODULE|MEX") 3511 if (TYPE MATCHES "STATIC") 3512 if (PART MATCHES "POST_INSTALL") 3513 get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_INSTALL_DIRECTORY) 3514 else () 3515 get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_OUTPUT_DIRECTORY) 3516 endif () 3517 get_target_property (FNAME ${TARGET_UID} ARCHIVE_OUTPUT_NAME) 3518 else () 3519 if (PART MATCHES "POST_INSTALL") 3520 get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_INSTALL_DIRECTORY) 3521 else () 3522 get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_OUTPUT_DIRECTORY) 3523 endif () 3524 get_target_property (FNAME ${TARGET_UID} LIBRARY_OUTPUT_NAME) 3525 endif () 3526 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3527 # executables 3528 else () 3529 if (PART MATCHES "POST_INSTALL") 3530 get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_INSTALL_DIRECTORY) 3531 else () 3532 get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_OUTPUT_DIRECTORY) 3533 endif () 3534 get_target_property (FNAME ${TARGET_UID} RUNTIME_OUTPUT_NAME) 3535 endif () 3536 if (DIRECTORY MATCHES "NOTFOUND") 3537 message (FATAL_ERROR "Failed to get directory of ${TYPE} ${TARGET_UID}!" 3538 " Check implementation of basis_get_target_location()" 3539 " and make sure that the required *INSTALL_DIRECTORY" 3540 " property is set on the target!") 3541 endif () 3542 if (DIRECTORY) 3543 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3544 # get output name of built file (if applicable) 3545 if (NOT FNAME) 3546 get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME) 3547 endif () 3548 if (NOT "^${TYPE}$" STREQUAL "^SCRIPT_LIBRARY$") 3549 get_target_property (PREFIX ${TARGET_UID} PREFIX) 3550 get_target_property (SUFFIX ${TARGET_UID} SUFFIX) 3551 if (FNAME) 3552 set (TARGET_FILE "${FNAME}") 3553 else () 3554 set (TARGET_FILE "${TARGET_NAME}") 3555 endif () 3556 if (PREFIX) 3557 set (TARGET_FILE "${PREFIX}${TARGET_FILE}") 3558 endif () 3559 if (SUFFIX) 3560 set (TARGET_FILE "${TARGET_FILE}${SUFFIX}") 3561 elseif (WIN32 AND "^${TYPE}$" STREQUAL "^EXECUTABLE$") 3562 set (TARGET_FILE "${TARGET_FILE}.exe") 3563 endif () 3564 endif () 3565 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3566 # prepend $<CONFIG> "generator expression" for non-custom binaries 3567 # when built with an IDE such as Visual Studio or Xcode 3568 if ("^${TYPE}$" STREQUAL "^EXECUTABLE$" OR "^${TYPE}$" STREQUAL "^LIBRARY$") 3569 if (NOT PART MATCHES "INSTALL") 3570 if (CMAKE_GENERATOR MATCHES "Visual Studio|Xcode") 3571 set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>") 3572 endif () 3573 endif () 3574 endif () 3575 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3576 # assemble final path 3577 if (PART MATCHES "POST_INSTALL_RELATIVE") 3578 if (IS_ABSOLUTE "${DIRECTORY}") 3579 file (RELATIVE_PATH DIRECTORY "${CMAKE_INSTALL_PREFIX}" "${DIRECTORY}") 3580 if (NOT DIRECTORY) 3581 set (DIRECTORY ".") 3582 endif () 3583 endif () 3584 elseif (PART MATCHES "POST_INSTALL") 3585 if (NOT IS_ABSOLUTE "${DIRECTORY}") 3586 set (DIRECTORY "${CMAKE_INSTALL_PREFIX}/${DIRECTORY}") 3587 endif () 3588 endif () 3589 if (TARGET_FILE) 3590 set (LOCATION "${DIRECTORY}/${TARGET_FILE}") 3591 else () 3592 set (LOCATION "${DIRECTORY}") 3593 endif () 3594 else () 3595 set (LOCATION "${DIRECTORY}") 3596 endif () 3597 endif () 3598 # get filename component 3599 if (LOCATION AND PART MATCHES "(^|_)(PATH|NAME|NAME_WE)$") 3600 get_filename_component (LOCATION "${LOCATION}" "${CMAKE_MATCH_2}") 3601 endif () 3602 else () 3603 message (FATAL_ERROR "basis_get_target_location(): Unknown target ${TARGET_UID}") 3604 endif () 3605 # return 3606 set ("${VAR}" "${LOCATION}" PARENT_SCOPE) 3607endfunction () 3608 3609# ---------------------------------------------------------------------------- 3610## @brief Get link libraries/dependencies of (imported) target. 3611# 3612# This function recursively adds the dependencies of the dependencies as well 3613# and returns them together with the list of the direct link dependencies. 3614# Moreover, for script targets, if any of the dependencies uses the BASIS 3615# utilities for the given language (@c BASIS_UTILITIES property), the 3616# corresponding utilities library is added to the list of dependencies. 3617# Note that therefore the BASIS utilities targets have to be added already, 3618# which is only the case during the finalization of script targets. 3619# 3620# @param [out] LINK_DEPENDS List of all link dependencies. In case of scripts, 3621# the dependencies are the required modules or 3622# paths to required packages, respectively. 3623# @param [in] TARGET_NAME Name of the target. 3624function (basis_get_target_link_libraries LINK_DEPENDS TARGET_NAME) 3625 basis_get_target_uid (TARGET_UID "${TARGET_NAME}") 3626 if (NOT TARGET "${TARGET_UID}") 3627 message (FATAL_ERROR "basis_get_target_link_libraries(): Unknown target: ${TARGET_UID}") 3628 endif () 3629 if (BASIS_DEBUG AND BASIS_VERBOSE) 3630 message ("** basis_get_target_link_libraries():") 3631 message ("** TARGET_NAME: ${TARGET_NAME}") 3632 message ("** CURRENT_DEPENDS: ${ARGN}") 3633 endif () 3634 # get type of target 3635 get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE) 3636 # get direct link dependencies of target 3637 get_target_property (IMPORTED ${TARGET_UID} IMPORTED) 3638 if (IMPORTED) 3639 # 1. Try IMPORTED_LINK_INTERFACE_LIBRARIES_<CMAKE_BUILD_TYPE> 3640 if (CMAKE_BUILD_TYPE) 3641 string (TOUPPER "${CMAKE_BUILD_TYPE}" U) 3642 else () 3643 set (U "NOCONFIG") 3644 endif () 3645 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${U}") 3646 # 2. Try IMPORTED_LINK_INTERFACE_LIBRARIES 3647 if (NOT DEPENDS) 3648 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES") 3649 endif () 3650 # 3. Prefer Release over all other configurations 3651 if (NOT DEPENDS) 3652 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE") 3653 endif () 3654 # 4. Just use any of the imported configurations 3655 if (NOT DEPENDS) 3656 get_property (CONFIGS TARGET "${TARGET_UID}" PROPERTY IMPORTED_CONFIGURATIONS) 3657 foreach (C IN LISTS CONFIGS) 3658 get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${C}") 3659 if (DEPENDS) 3660 break () 3661 endif () 3662 endforeach () 3663 endif () 3664 # otherwise, get LINK_DEPENDS property value 3665 elseif (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$") 3666 get_target_property (DEPENDS ${TARGET_UID} BASIS_LINK_DEPENDS) 3667 else () 3668 get_target_property (DEPENDS ${TARGET_UID} LINK_DEPENDS) 3669 endif () 3670 if (NOT DEPENDS) 3671 set (DEPENDS) 3672 endif () 3673 # prepend BASIS utilities if used (and added) 3674 if (BASIS_TYPE MATCHES "SCRIPT") 3675 set (BASIS_UTILITIES_TARGETS) 3676 foreach (UID IN ITEMS ${TARGET_UID} ${DEPENDS}) 3677 if (TARGET "${UID}") 3678 get_target_property (BASIS_UTILITIES ${UID} BASIS_UTILITIES) 3679 get_target_property (LANGUAGE ${UID} LANGUAGE) 3680 if (BASIS_UTILITIES) 3681 set (BASIS_UTILITIES_TARGET) 3682 if (LANGUAGE MATCHES "[JP]YTHON") 3683 basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.py" NAME) 3684 elseif (LANGUAGE MATCHES "PERL") 3685 basis_get_source_target_name (BASIS_UTILITIES_TARGET "Basis.pm" NAME) 3686 elseif (LANGUAGE MATCHES "BASH") 3687 basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.sh" NAME) 3688 endif () 3689 if (BASIS_UTILITIES_TARGET) 3690 basis_get_target_uid (BASIS_UTILITIES_TARGET ${BASIS_UTILITIES_TARGET}) 3691 endif () 3692 if (TARGET ${BASIS_UTILITIES_TARGET}) 3693 list (APPEND BASIS_UTILITIES_TARGETS ${BASIS_UTILITIES_TARGET}) 3694 endif () 3695 endif () 3696 endif () 3697 endforeach () 3698 if (BASIS_UTILITIES_TARGETS) 3699 list (INSERT DEPENDS 0 ${BASIS_UTILITIES_TARGETS}) 3700 endif () 3701 endif () 3702 # convert target names to UIDs 3703 set (_DEPENDS) 3704 foreach (LIB IN LISTS DEPENDS) 3705 basis_get_target_uid (UID "${LIB}") 3706 if (TARGET ${UID}) 3707 list (APPEND _DEPENDS "${UID}") 3708 else () 3709 list (APPEND _DEPENDS "${LIB}") 3710 endif () 3711 endforeach () 3712 set (DEPENDS "${_DEPENDS}") 3713 unset (_DEPENDS) 3714 # recursively add link dependencies of dependencies 3715 # TODO implement it non-recursively for better performance 3716 foreach (LIB IN LISTS DEPENDS) 3717 if (TARGET ${LIB}) 3718 list (FIND ARGN "${LIB}" IDX) # avoid recursive loop 3719 if (IDX EQUAL -1) 3720 basis_get_target_link_libraries (LIB_DEPENDS ${LIB} ${ARGN} ${DEPENDS}) 3721 list (APPEND DEPENDS ${LIB_DEPENDS}) 3722 endif () 3723 endif () 3724 endforeach () 3725 # remove duplicate entries 3726 if (DEPENDS) 3727 list (REMOVE_DUPLICATES DEPENDS) 3728 endif () 3729 # return 3730 set (${LINK_DEPENDS} "${DEPENDS}" PARENT_SCOPE) 3731endfunction () 3732 3733# ============================================================================ 3734# generator expressions 3735# ============================================================================ 3736 3737# ---------------------------------------------------------------------------- 3738## @brief Process generator expressions in arguments. 3739# 3740# This command evaluates the $<TARGET_FILE:tgt> and related generator 3741# expressions also for custom targets such as scripts and MATLAB Compiler 3742# targets. For other generator expressions whose argument is a target name, 3743# this function replaces the target name by the target UID, i.e., the actual 3744# CMake target name such that the expression can be evaluated by CMake. 3745# The following generator expressions are directly evaluated by this function: 3746# <table border=0> 3747# <tr> 3748# @tp <b><tt>$<TARGET_FILE:tgt></tt></b> @endtp 3749# <td>Absolute file path of built target.</td> 3750# </tr> 3751# <tr> 3752# @tp <b><tt>$<TARGET_FILE_POST_INSTALL:tgt></tt></b> @endtp 3753# <td>Absolute path of target file after installation using the 3754# current @c CMAKE_INSTALL_PREFIX.</td> 3755# </tr> 3756# <tr> 3757# @tp <b><tt>$<TARGET_FILE_POST_INSTALL_RELATIVE:tgt></tt></b> @endtp 3758# <td>Path of target file after installation relative to @c CMAKE_INSTALL_PREFIX.</td> 3759# </tr> 3760# </table> 3761# Additionally, the suffix <tt>_NAME</tt> or <tt>_DIR</tt> can be appended 3762# to the name of each of these generator expressions to get only the basename 3763# of the target file including the extension or the corresponding directory 3764# path, respectively. 3765# 3766# Generator expressions are in particular supported by basis_add_test(). 3767# 3768# @param [out] ARGS Name of output list variable. 3769# @param [in] ARGN List of arguments to process. 3770# 3771# @sa basis_add_test() 3772# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test 3773function (basis_process_generator_expressions ARGS) 3774 set (ARGS_OUT) 3775 foreach (ARG IN LISTS ARGN) 3776 string (REGEX MATCHALL "\\$<.*TARGET.*:.*>" EXPRS "${ARG}") 3777 foreach (EXPR IN LISTS EXPRS) 3778 if (EXPR MATCHES "\\$<(.*):(.*)>") 3779 set (EXPR_NAME "${CMAKE_MATCH_1}") 3780 set (TARGET_NAME "${CMAKE_MATCH_2}") 3781 # TARGET_FILE* expression, including custom targets 3782 if (EXPR_NAME MATCHES "^TARGET_FILE(.*)") 3783 if (NOT CMAKE_MATCH_1) 3784 set (CMAKE_MATCH_1 "ABSOLUTE") 3785 endif () 3786 string (REGEX REPLACE "^_" "" PART "${CMAKE_MATCH_1}") 3787 basis_get_target_location (ARG "${TARGET_NAME}" ${PART}) 3788 # other generator expression supported by CMake 3789 # only replace target name, but do not evaluate expression 3790 else () 3791 basis_get_target_uid (TARGET_UID "${CMAKE_MATCH_2}") 3792 string (REPLACE "${EXPR}" "$<${CMAKE_MATCH_1}:${TARGET_UID}>" ARG "${ARG}") 3793 endif () 3794 if (BASIS_DEBUG AND BASIS_VERBOSE) 3795 message ("** basis_process_generator_expressions():") 3796 message ("** Expression: ${EXPR}") 3797 message ("** Keyword: ${EXPR_NAME}") 3798 message ("** Argument: ${TARGET_NAME}") 3799 message ("** Replaced by: ${ARG}") 3800 endif () 3801 endif () 3802 endforeach () 3803 list (APPEND ARGS_OUT "${ARG}") 3804 endforeach () 3805 set (${ARGS} "${ARGS_OUT}" PARENT_SCOPE) 3806endfunction () 3807 3808 3809## 3810# @brief basis_append_to_each takes an input list and appends a single element to each item in that list and appends it to the output list. 3811# For example, this is useful for adding relative paths to the end of a list of paths. 3812# 3813# @param OUTPUT_LIST Name of list that will be filled with appended names. 3814# @param INPUT_LIST Name of list that contains items to have text appended. 3815# @param ITEM_TO_APPEND text to append to each item in the input list. 3816# 3817function(basis_append_to_each OUTPUT_LIST INPUT_LIST ITEM_TO_APPEND) 3818 foreach(PATH IN LISTS ${INPUT_LIST}) 3819 list(APPEND ${OUTPUT_LIST} ${PATH}${ITEM_TO_APPEND} ) 3820 endforeach() 3821 3822 if(${OUTPUT_LIST}) 3823 set(${OUTPUT_LIST} ${${OUTPUT_LIST}} PARENT_SCOPE) 3824 endif() 3825endfunction() 3826 3827 3828## @} 3829# end of Doxygen group 3830