CommonTools.cmake
Go to the documentation of this file.
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 
19  return ()
20 else ()
22 endif ()
23 
24 
25 include (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.
47 macro (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)
82 endmacro ()
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.
109 function (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)
128 endfunction ()
129 
130 ## @brief Get installation prefix given path of <PKG>Config directory
131 function (_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)
154 endfunction ()
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_&lt;PACKAGE&gt;</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_&lt;PACKAGE&gt;</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_&lt;PACKAGE&gt;</tt> option. Note
175 # that when <tt>USE_&lt;PACKAGE&gt;</tt> is defined, no <tt>WITH_&lt;PACKAGE&gt;</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., &lt;Package&gt;[-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 &lt;PACKAGE&gt;_FOUND Whether the given package was found.
195 # @retval &lt;PACKAGE&gt;_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
205 macro (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)
899 endmacro ()
900 
901 # ----------------------------------------------------------------------------
902 ## @brief Use found package.
903 #
904 # This macro includes the package's use file if the variable @c &lt;Pkg&gt;_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 &lt;Pkg&gt;_INCLUDES, @c &lt;Pkg&gt;_INCLUDE_DIRS, or @c &lt;Pkg&gt;_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 &lt;PKG&gt;_INCLUDES is defined, but not @c &lt;Pkg&gt;_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 # &lt;Package&gt;[-major[.minor[.patch[.tweak]]]].
930 # A version specification is simply ignored by this macro.
931 #
932 # @ingroup CMakeAPI
933 macro (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 (BASIS_DEBUG)
1027  message ("** Include package use file of external package.")
1028  endif ()
1029  if ("^${PKG}$" STREQUAL "^BASIS$")
1030  include ("${${PKG}_USE_FILE}" NO_POLICY_SCOPE)
1031  else ()
1032  include ("${${PKG}_USE_FILE}")
1033  endif ()
1034  else ()
1035  if (BASIS_DEBUG)
1036  message ("** Use variables which were set by basis_find_package().")
1037  endif ()
1038  # OpenCV
1039  if ("^${PKG}$" STREQUAL "^OpenCV$")
1040  # the cv.h may be found as part of PerlLibs, the include path of
1041  # which is added at first by BASISConfig.cmake
1042  if (OpenCV_INCLUDE_DIRS)
1043  basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIRS})
1044  elseif (OpenCV_INCLUDE_DIR)
1045  basis_include_directories (BEFORE ${OpenCV_INCLUDE_DIR})
1046  endif ()
1047  # generic
1048  else ()
1049  if (${PKG}_INCLUDE_DIRS)
1050  basis_include_directories (${${PKG}_INCLUDE_DIRS})
1051  elseif (${PKG}_INCLUDES)
1052  basis_include_directories (${${PKG}_INCLUDES})
1053  elseif (${PKG}_INCLUDE_PATH)
1054  basis_include_directories (${${PKG}_INCLUDE_PATH})
1055  elseif (${PKG}_INCLUDE_DIR)
1056  basis_include_directories (${${PKG}_INCLUDE_DIR})
1057  endif ()
1058  endif ()
1059  endif ()
1060  add_definitions(-DHAVE_${PKG})
1061  set (BASIS_USE_${PKG}_INCLUDED TRUE)
1062  elseif (ARGC GREATER 1 AND "^${ARGV1}$" STREQUAL "^REQUIRED$")
1063  if (BASIS_DEBUG)
1064  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFind${PKG}.cmake")
1065  endif ()
1066  message (FATAL_ERROR "Package ${PACKAGE} not found!")
1067  endif ()
1068  # reset switch that identifies currently imported targets and link directories
1069  # as belonging to an external project which is part of the same superbuild
1070  set (BUNDLE_PROJECT FALSE)
1071  endforeach ()
1072 endmacro ()
1073 
1074 # ============================================================================
1075 # basis_get_filename_component / basis_get_relative_path
1076 # ============================================================================
1077 
1078 # ----------------------------------------------------------------------------
1079 ## @brief Fixes CMake's
1080 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component">
1081 # get_filename_component()</a> command.
1082 #
1083 # The get_filename_component() command of CMake returns the entire portion
1084 # after the first period (.) [including the period] as extension. However,
1085 # only the component following the last period (.) [including the period]
1086 # should be considered to be the extension.
1087 #
1088 # @note Consider the use of the basis_get_filename_component() macro as
1089 # an alias to emphasize that this function is different from CMake's
1090 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component">
1091 # get_filename_component()</a> command.
1092 #
1093 # @todo Fix issue http://public.kitware.com/Bug/view.php?id=15743 which
1094 # affects also basis_get_relative_path.
1095 #
1096 # @param [in,out] ARGN Arguments as accepted by get_filename_component().
1097 #
1098 # @returns Sets the variable named by the first argument to the requested
1099 # component of the given file path.
1100 #
1101 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_filename_component
1102 # @sa basis_get_filename_component()
1103 function (get_filename_component)
1104  if (ARGC LESS 3)
1105  message (FATAL_ERROR "[basis_]get_filename_component(): At least three arguments required!")
1106  elseif (ARGC GREATER 4)
1107  message (FATAL_ERROR "[basis_]get_filename_component(): Too many arguments!")
1108  endif ()
1109  list (GET ARGN 0 VAR)
1110  list (GET ARGN 1 STR)
1111  list (GET ARGN 2 CMD)
1112  if (CMD MATCHES "^EXT")
1113  _get_filename_component (${VAR} "${STR}" ${CMD})
1114  string (REGEX MATCHALL "\\.[^.]*" PARTS "${${VAR}}")
1115  list (LENGTH PARTS LEN)
1116  if (LEN GREATER 1)
1117  math (EXPR LEN "${LEN} - 1")
1118  list (GET PARTS ${LEN} ${VAR})
1119  endif ()
1120  elseif (CMD MATCHES "NAME_WE")
1121  _get_filename_component (${VAR} "${STR}" NAME)
1122  string (REGEX REPLACE "\\.[^.]*$" "" ${VAR} ${${VAR}})
1123  else ()
1124  _get_filename_component (${VAR} "${STR}" ${CMD})
1125  endif ()
1126  if (ARGC EQUAL 4)
1127  if (NOT "^${ARGV3}$" STREQUAL "^CACHE$")
1128  message (FATAL_ERROR "[basis_]get_filename_component(): Invalid fourth argument: ${ARGV3}!")
1129  else ()
1130  set (${VAR} "${${VAR}}" CACHE STRING "")
1131  endif ()
1132  else ()
1133  set (${VAR} "${${VAR}}" PARENT_SCOPE)
1134  endif ()
1135 endfunction ()
1136 
1137 # ----------------------------------------------------------------------------
1138 ## @brief Alias for the overwritten get_filename_component() function.
1139 #
1140 # @sa get_filename_component()
1141 #
1142 # @ingroup CMakeAPI
1143 macro (basis_get_filename_component)
1144  get_filename_component (${ARGN})
1145 endmacro ()
1146 
1147 # ----------------------------------------------------------------------------
1148 ## @brief Get path relative to a given base directory.
1149 #
1150 # Unlike the file(RELATIVE_PATH ...) command of CMake which if @p PATH and
1151 # @p BASE are the same directory returns an empty string, this function
1152 # returns a dot (.) in this case instead.
1153 #
1154 # @param [out] REL @c PATH relative to @c BASE.
1155 # @param [in] BASE Path of base directory. If a relative path is given, it
1156 # is made absolute using basis_get_filename_component()
1157 # with ABSOLUTE as last argument.
1158 # @param [in] PATH Absolute or relative path. If a relative path is given
1159 # it is made absolute using basis_get_filename_component()
1160 # with ABSOLUTE as last argument.
1161 #
1162 # @returns Sets the variable named by the first argument to the relative path.
1163 #
1164 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:file
1165 #
1166 # @ingroup CMakeAPI
1167 function (basis_get_relative_path REL BASE PATH)
1168  if (BASE MATCHES "^$")
1169  message (FATAL_ERROR "Empty string given where (absolute) base directory path expected!")
1170  endif ()
1171  if (PATH MATCHES "^$")
1172  set (PATH ".")
1173  endif ()
1174  # Attention: http://public.kitware.com/Bug/view.php?id=15743
1175  basis_get_filename_component (PATH "${PATH}" ABSOLUTE)
1176  basis_get_filename_component (BASE "${BASE}" ABSOLUTE)
1177  if (NOT PATH)
1178  message (FATAL_ERROR "basis_get_relative_path(): No PATH given!")
1179  endif ()
1180  if (NOT BASE)
1181  message (FATAL_ERROR "basis_get_relative_path(): No BASE given!")
1182  endif ()
1183  file (RELATIVE_PATH P "${BASE}" "${PATH}")
1184  if ("${P}" STREQUAL "")
1185  set (P ".")
1186  endif ()
1187  set (${REL} "${P}" PARENT_SCOPE)
1188 endfunction ()
1189 
1190 ## @brief Create a string from a list of variables indicating if they are defined and their values.
1191 #
1192 # Useful for debug and user errors, for example:
1193 # @code
1194 # set(VAR1 "I'm a string")
1195 # set(VAR2 2)
1196 # basis_variable_value_status(VAR_INFO_STRING VAR1 VAR2 VAR3)
1197 # message(STATUS ${VAR_INFO_STRING})
1198 # @endcode
1199 #
1200 # @param[out] VAR_INFO_STRING The output string variable that will set with the debug string.
1201 # @param[in] ARGN List of variables to be put into a string along with their value.
1202 function(basis_variable_value_status VAR_INFO_STRING)
1203  set (OUTPUT_STRING)
1204  foreach (VARIABLE_NAME IN ITEMS ${ARGN})
1205  if (DEFINED ${VARIABLE_NAME})
1206  set (OUTPUT_STRING "${OUTPUT_STRING}\n variable name: ${VARIABLE_NAME} value: ${${VARIABLE_NAME}}")
1207  else ()
1208  set (OUTPUT_STRING "${OUTPUT_STRING}\n variable name: ${VARIABLE_NAME} value is not defined")
1209  endif ()
1210  endforeach ()
1211  set (${VAR_INFO_STRING} ${OUTPUT_STRING} PARENT_SCOPE)
1212 endfunction()
1213 
1214 ## @brief Checks for a list of variables required later in the script.
1215 #
1216 # Produces a clear error message explaining the problem and how to fix it if they are not present.
1217 #
1218 # @code
1219 # basis_variable_check(
1220 # REQUIRED
1221 # LIBRARY1_INCLUDE_DIRS
1222 # LIBRARY2_INCLUDE_DIRS
1223 # LIBRARY2_LIBRARIES
1224 # OPTIONAL
1225 # LIBRARY3_INCLUDE_DIRS
1226 # LIBRARY3_LIBRARIES
1227 # OPTIONAL_PATH
1228 #
1229 # )
1230 # @endcode
1231 #
1232 # @param [in] ARGN This argument list is parsed and the following
1233 # arguments are extracted.
1234 # @par
1235 # <table border="0">
1236 # <tr>
1237 # @tp @b REQUIRED var... @endtp
1238 # <td>List of variables that MUST be set to run this script correctly.
1239 # Will produce a FATAL_ERROR message explaining which variables
1240 # are misisng and exit the cmake script.</td>
1241 # </tr>
1242 # <tr>
1243 # @tp @b OPTIONAL var... @endtp
1244 # <td>List of variables need not be set to run this script correctly.</td>
1245 # </tr>
1246 # <tr>
1247 # @tp @b PATH_EXISTS var... @endtp
1248 # <td>List of path variables that MUST be set to a location that exists.</td>
1249 # </tr>
1250 # <tr>
1251 # @tp @b OPTIONAL_PATH_EXISTS var... @endtp
1252 # <td>List of path variables that are optional, but once set must be empty
1253 # or provide a path to location that exists.</td>
1254 # </tr>
1255 # </table>
1256 function(basis_variable_check)
1257 
1258  set(options ) # currently none
1259  set(oneValueArgs ) # currently none
1260  set(multiValueArgs REQUIRED OPTIONAL PATH_EXISTS OPTIONAL_PATH_EXISTS )
1261  cmake_parse_arguments(VARIABLE_CONFIGURATION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
1262 
1263 
1264  #-------------------------------------------
1265  # Create the error strings for missing REQUIRED variables
1266  set(MISSING_REQUIRED_VARIABLES)
1267  foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_REQUIRED)
1268  if(NOT ${VARIABLE_NAME})
1269  list(APPEND MISSING_REQUIRED_VARIABLES ${VARIABLE_NAME})
1270  endif()
1271  endforeach()
1272  if(MISSING_REQUIRED_VARIABLES)
1273  basis_variable_value_status(MISSING_REQUIRED_VARIABLES_STATUS ${MISSING_REQUIRED_VARIABLES})
1274  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}")
1275  endif(MISSING_REQUIRED_VARIABLES)
1276 
1277 
1278  #-------------------------------------------
1279  # Create and print the warning strings for missing OPTIONAL variables
1280  set(MISSING_OPTIONAL_VARIABLES)
1281  foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_OPTIONAL)
1282  if(NOT ${VARIABLE_NAME})
1283  list(APPEND MISSING_OPTIONAL_VARIABLES ${VARIABLE_NAME})
1284  endif()
1285  endforeach()
1286  if(MISSING_OPTIONAL_VARIABLES)
1287  basis_variable_value_status(MISSING_OPTIONAL_VARIABLES_STATUS ${MISSING_OPTIONAL_VARIABLES})
1288  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}")
1289  message(AUTHOR_WARNING "${MISSING_VARIABLES_WARNING}")
1290  endif(MISSING_OPTIONAL_VARIABLES)
1291 
1292 
1293 
1294  #-------------------------------------------
1295  # Create the error strings for missing or nonexistant REQUIRED PATH variables
1296  set(MISSING_PATH_EXISTS)
1297  foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_PATH_EXISTS)
1298  if(NOT DEFINED ${VARIABLE_NAME} OR NOT EXISTS ${${VARIABLE_NAME}})
1299  list(APPEND MISSING_PATH_EXISTS ${VARIABLE_NAME})
1300  endif()
1301  endforeach()
1302  if(MISSING_PATH_EXISTS)
1303  basis_variable_value_status(MISSING_PATH_EXISTS_STATUS ${MISSING_PATH_EXISTS})
1304  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}")
1305  endif(MISSING_PATH_EXISTS)
1306 
1307 
1308 
1309  #-------------------------------------------
1310  # Create the error strings for missing or nonexistant OPTIONAL PATH variables
1311  set(MISSING_OPTIONAL_PATH_EXISTS)
1312  foreach(VARIABLE_NAME IN LISTS VARIABLE_CONFIGURATION_OPTIONAL_PATH_EXISTS)
1313  if(DEFINED ${VARIABLE_NAME} AND NOT ${${VARIABLE_NAME}} STREQUAL "" AND NOT EXISTS ${${VARIABLE_NAME}})
1314  # add VARIABLE_NAME to error list if a nonempty path is defined, but does not point to a real location
1315  list(APPEND MISSING_OPTIONAL_PATH_EXISTS ${VARIABLE_NAME})
1316  endif()
1317  endforeach()
1318  if(MISSING_OPTIONAL_PATH_EXISTS)
1319  basis_variable_value_status(MISSING_OPTIONAL_PATH_EXISTS_STATUS ${MISSING_OPTIONAL_PATH_EXISTS})
1320  #debug:
1321  #message(STATUS "MISSING_OPTIONAL_PATH_EXISTS: ${MISSING_OPTIONAL_PATH_EXISTS}")
1322  #message(STATUS "MISSING_OPTIONAL_PATH_EXISTS_STATUS: ${MISSING_OPTIONAL_PATH_EXISTS_STATUS}")
1323  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}")
1324  endif(MISSING_OPTIONAL_PATH_EXISTS)
1325 
1326  #-------------------------------------------
1327  # Print all fatal errors at once, because the script will halt
1328  if(MISSING_VARIABLES_ERROR OR PATH_EXISTS_ERROR OR OPTIONAL_PATH_EXISTS_ERROR)
1329  message(FATAL_ERROR "${MISSING_VARIABLES_ERROR}${PATH_EXISTS_ERROR}${OPTIONAL_PATH_EXISTS_ERROR}\n")
1330  endif(MISSING_VARIABLES_ERROR OR PATH_EXISTS_ERROR OR OPTIONAL_PATH_EXISTS_ERROR)
1331 
1332 endfunction(basis_variable_check)
1333 
1334 
1335 
1336 # ============================================================================
1337 # name / version
1338 # ============================================================================
1339 
1340 # ----------------------------------------------------------------------------
1341 ## @brief Convert string to lowercase only or mixed case.
1342 #
1343 # Strings in all uppercase or all lowercase are converted to all lowercase
1344 # letters because these are usually used for acronymns. All other strings
1345 # are returned unmodified with the one exception that the first letter has
1346 # to be uppercase for mixed case strings.
1347 #
1348 # This function is in particular used to normalize the project name for use
1349 # in installation directory paths and namespaces.
1350 #
1351 # @param [out] OUT String in CamelCase.
1352 # @param [in] STR String.
1353 function (basis_normalize_name OUT STR)
1354  # strings in all uppercase or all lowercase such as acronymns are an
1355  # exception and shall be converted to all lowercase instead
1356  string (TOLOWER "${STR}" L)
1357  string (TOUPPER "${STR}" U)
1358  if ("${STR}" STREQUAL "${L}" OR "${STR}" STREQUAL "${U}")
1359  set (${OUT} "${L}" PARENT_SCOPE)
1360  # change first letter to uppercase
1361  else ()
1362  string (SUBSTRING "${U}" 0 1 A)
1363  string (SUBSTRING "${STR}" 1 -1 B)
1364  set (${OUT} "${A}${B}" PARENT_SCOPE)
1365  endif ()
1366 endfunction ()
1367 
1368 # ----------------------------------------------------------------------------
1369 ## @brief Extract version numbers from version string.
1370 #
1371 # @param [in] VERSION Version string in the format "MAJOR[.MINOR[.PATCH]]".
1372 # @param [out] MAJOR Major version number if given or 0.
1373 # @param [out] MINOR Minor version number if given or 0.
1374 # @param [out] PATCH Patch number if given or 0.
1375 #
1376 # @returns See @c [out] parameters.
1377 function (basis_version_numbers VERSION MAJOR MINOR PATCH)
1378  if (VERSION MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?")
1379  if (CMAKE_MATCH_1)
1380  set (VERSION_MAJOR ${CMAKE_MATCH_1})
1381  else ()
1382  set (VERSION_MAJOR 0)
1383  endif ()
1384  if (CMAKE_MATCH_2)
1385  set (VERSION_MINOR ${CMAKE_MATCH_2})
1386  string (REGEX REPLACE "^\\." "" VERSION_MINOR "${VERSION_MINOR}")
1387  else ()
1388  set (VERSION_MINOR 0)
1389  endif ()
1390  if (CMAKE_MATCH_3)
1391  set (VERSION_PATCH ${CMAKE_MATCH_3})
1392  string (REGEX REPLACE "^\\." "" VERSION_PATCH "${VERSION_PATCH}")
1393  else ()
1394  set (VERSION_PATCH 0)
1395  endif ()
1396  else ()
1397  set (VERSION_MAJOR 0)
1398  set (VERSION_MINOR 0)
1399  set (VERSION_PATCH 0)
1400  endif ()
1401  set ("${MAJOR}" "${VERSION_MAJOR}" PARENT_SCOPE)
1402  set ("${MINOR}" "${VERSION_MINOR}" PARENT_SCOPE)
1403  set ("${PATCH}" "${VERSION_PATCH}" PARENT_SCOPE)
1404 endfunction ()
1405 
1406 # ============================================================================
1407 # set
1408 # ============================================================================
1409 
1410 # ----------------------------------------------------------------------------
1411 ## @brief Set flag given mutually exclusive
1412 # ARGN_&lt;FLAG&gt; and ARGN_NO&lt;FLAG&gt; function arguments.
1413 #
1414 # @param [in] PREFIX Prefix of function arguments. Set to the first argument
1415 # of the CMAKE_PARSE_ARGUMENTS() command.
1416 # @param [out] FLAG Name of flag.
1417 # @param [in] DEFAULT Default flag value if neither <tt>ARGN_&lt;FLAG;gt;</tt>
1418 # nor <tt>ARGN_NO&lt;FLAG;gt;</tt> evaluates to true.
1419 macro (basis_set_flag PREFIX FLAG DEFAULT)
1420  if (${PREFIX}_${FLAG} AND ${PREFIX}_NO${FLAG})
1421  message (FATAL_ERROR "Options ${FLAG} and NO${FLAG} are mutually exclusive!")
1422  endif ()
1423  if (${PREFIX}_${FLAG})
1424  set (${FLAG} TRUE)
1425  elseif (${PREFIX}_NO${FLAG})
1426  set (${FLAG} FALSE)
1427  else ()
1428  set (${FLAG} ${DEFAULT})
1429  endif ()
1430 endmacro ()
1431 
1432 # ----------------------------------------------------------------------------
1433 ## @brief Determine if cache entry exists.
1434 #
1435 # @param [out] VAR Name of boolean result variable.
1436 # @param [in] ENTRY Name of cache entry.
1437 macro (basis_is_cached VAR ENTRY)
1438  if (DEFINED ${ENTRY})
1439  get_property (${VAR} CACHE ${ENTRY} PROPERTY TYPE SET)
1440  else ()
1441  set (${VAR} FALSE)
1442  endif ()
1443 endmacro ()
1444 
1445 # ----------------------------------------------------------------------------
1446 ## @brief Set type of variable.
1447 #
1448 # If the variable is cached, the type is updated, otherwise, a cache entry
1449 # of the given type with the current value of the variable is added.
1450 #
1451 # @param [in] VAR Name of variable.
1452 # @param [in] TYPE Desired type of variable.
1453 # @param [in] ARGN Optional DOC string used if variable was not cached before.
1454 macro (basis_set_or_update_type VAR TYPE)
1455  basis_is_cached (_CACHED ${VAR})
1456  if (_CACHED)
1457  set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE})
1458  else ()
1459  set (${VAR} "${${VAR}}" CACHE ${TYPE} "${ARGN}" FORCE)
1460  endif ()
1461  unset (_CACHED)
1462 endmacro ()
1463 
1464 # ----------------------------------------------------------------------------
1465 ## @brief Change type of cached variable.
1466 #
1467 # If the variable is not cached, nothing is done.
1468 macro (basis_update_type_of_variable VAR TYPE)
1469  basis_is_cached (_CACHED ${VAR})
1470  if (_CACHED)
1471  set_property (CACHE ${VAR} PROPERTY TYPE ${TYPE})
1472  endif ()
1473  unset (_CACHED)
1474 endmacro ()
1475 
1476 # ----------------------------------------------------------------------------
1477 ## @brief Set variable value.
1478 #
1479 # If the variable is cached, this function will update the cache value,
1480 # otherwise, it simply sets the CMake variable uncached to the given value(s).
1481 macro (basis_set_or_update_value VAR)
1482  basis_is_cached (_CACHED ${VAR})
1483  if (_CACHED)
1484  if (ARGC GREATER 1)
1485  set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN})
1486  else ()
1487  set (${VAR} "" CACHE INTERNAL "" FORCE)
1488  endif ()
1489  else ()
1490  set (${VAR} ${ARGN})
1491  endif ()
1492  unset (_CACHED)
1493 endmacro ()
1494 
1495 # ----------------------------------------------------------------------------
1496 ## @brief Update cache variable.
1497 macro (basis_update_value VAR)
1498  basis_is_cached (_CACHED ${VAR})
1499  if (_CACHED)
1500  set_property (CACHE ${VAR} PROPERTY VALUE ${ARGN})
1501  endif ()
1502  unset (_CACHED)
1503 endmacro ()
1504 
1505 # ----------------------------------------------------------------------------
1506 ## @brief Set value of variable only if variable is not set already.
1507 #
1508 # @param [out] VAR Name of variable.
1509 # @param [in] ARGN Arguments to set() command excluding variable name.
1510 #
1511 # @returns Sets @p VAR if its value was not valid before.
1512 macro (basis_set_if_empty VAR)
1513  if (NOT ${VAR})
1514  set (${VAR} ${ARGN})
1515  endif ()
1516 endmacro ()
1517 
1518 # ----------------------------------------------------------------------------
1519 ## @brief Set value of variable only if variable is not defined yet.
1520 #
1521 # @param [out] VAR Name of variable.
1522 # @param [in] ARGN Arguments to set() command excluding variable name.
1523 #
1524 # @returns Sets @p VAR if it was not defined before.
1525 macro (basis_set_if_not_set VAR)
1526  if (NOT DEFINED "${VAR}")
1527  set ("${VAR}" ${ARGN})
1528  endif ()
1529 endmacro ()
1530 
1531 # ----------------------------------------------------------------------------
1532 ## @brief Set value of variable to either 0 or 1 based on option value
1533 #
1534 # This function can be used to convert option values from TRUE/ON to 1 and
1535 # FALSE/OFF to 0 such that they can be used to configure a config.h.in header.
1536 #
1537 # @param [out] VAR Name of configuration header variable.
1538 # @param [in] OPT Value of CMake option.
1539 macro (basis_set_config_option VAR OPT)
1540  if (${OPT})
1541  set ("${VAR}" 1)
1542  else ()
1543  set ("${VAR}" 0)
1544  endif ()
1545 endmacro ()
1546 
1547 # ----------------------------------------------------------------------------
1548 ## @brief Set path relative to script file.
1549 #
1550 # This function can be used in script configurations. It takes a variable
1551 # name and a path as input arguments. If the given path is relative, it makes
1552 # it first absolute using @c PROJECT_SOURCE_DIR. Then the path is made
1553 # relative to the directory of the built script file. A CMake variable of the
1554 # given name is set to the specified relative path. Optionally, a third
1555 # argument, the path used for building the script for the install tree
1556 # can be passed as well. If a relative path is given as this argument,
1557 # it is made absolute by prefixing it with @c CMAKE_INSTALL_PREFIX instead.
1558 #
1559 # @note This function may only be used in script configurations such as
1560 # in particular the ScriptConfig.cmake.in file. It requires that the
1561 # variables @c __DIR__ and @c BUILD_INSTALL_SCRIPT are set properly.
1562 # These variables are set by the basis_configure_script() function.
1563 # Moreover, it makes use of the global @c CMAKE_INSTALL_PREFIX and
1564 # @c PROJECT_SOURCE_DIR variables.
1565 #
1566 # @param [out] VAR Name of the variable.
1567 # @param [in] PATH Path to directory or file.
1568 # @param [in] ARGV3 Path to directory or file inside install tree.
1569 # If this argument is not given, PATH is used for both
1570 # the build and install tree version of the script.
1571 #
1572 # @ingroup CMakeAPI
1573 function (basis_set_script_path VAR PATH)
1574  if (NOT __DIR__)
1575  message (FATAL_ERROR "__DIR__ not set! Note that basis_set_script_path() may"
1576  " only be used in script configurations (e.g., ScriptConfig.cmake.in).")
1577  endif ()
1578  if (ARGC GREATER 3)
1579  message (FATAL_ERROR "Too many arguments given for function basis_set_script_path()")
1580  endif ()
1581  if (ARGC EQUAL 3 AND BUILD_INSTALL_SCRIPT)
1582  set (PREFIX "${CMAKE_INSTALL_PREFIX}")
1583  set (PATH "${ARGV2}")
1584  else ()
1585  set (PREFIX "${PROJECT_SOURCE_DIR}")
1586  endif ()
1587  if (NOT IS_ABSOLUTE "${PATH}")
1588  set (PATH "${PREFIX}/${PATH}")
1589  endif ()
1590  basis_get_relative_path (PATH "${__DIR__}" "${PATH}")
1591  if (NOT PATH)
1592  set (${VAR} "." PARENT_SCOPE)
1593  else ()
1594  string (REGEX REPLACE "/+$" "" PATH "${PATH}")
1595  set (${VAR} "${PATH}" PARENT_SCOPE)
1596  endif ()
1597 endfunction ()
1598 
1599 # ============================================================================
1600 # set/get any property
1601 # ============================================================================
1602 
1603 # ----------------------------------------------------------------------------
1604 ## @brief Convert list into regular expression.
1605 #
1606 # This function is in particular used to convert a list of property names
1607 # such as &lt;CONFIG&gt;_OUTPUT_NAME, e.g., the list @c BASIS_PROPERTIES_ON_TARGETS,
1608 # into a regular expression which can be used in pattern matches.
1609 #
1610 # @param [out] REGEX Name of variable for resulting regular expression.
1611 # @param [in] ARGN List of patterns which may contain placeholders in the
1612 # form of "<this is a placeholder>". These are replaced
1613 # by the regular expression "[^ ]+".
1614 macro (basis_list_to_regex REGEX)
1615  string (REGEX REPLACE "<[^>]+>" "[^ ]+" ${REGEX} "${ARGN}")
1616  string (REGEX REPLACE ";" "|" ${REGEX} "${${REGEX}}")
1617  set (${REGEX} "^(${${REGEX}})$")
1618 endmacro ()
1619 
1620 # ----------------------------------------------------------------------------
1621 ## @brief Output current CMake variables to file.
1622 function (basis_dump_variables RESULT_FILE)
1623  set (DUMP)
1624  get_cmake_property (VARIABLE_NAMES VARIABLES)
1625  foreach (V IN LISTS VARIABLE_NAMES)
1626  if (NOT V MATCHES "^_|^RESULT_FILE$|^ARGC$|^ARGV[0-9]?$|^ARGN_")
1627  set (VALUE "${${V}}")
1628  # sanitize value for use in set() command
1629  string (REPLACE "\\" "\\\\" VALUE "${VALUE}") # escape backspaces
1630  string (REPLACE "\"" "\\\"" VALUE "${VALUE}") # escape double quotes
1631  # Escape ${VAR} by \${VAR} such that CMake does not evaluate it.
1632  # Escape $STR{VAR} by \$STR{VAR} such that CMake does not report a
1633  # syntax error b/c it expects either ${VAR}, $ENV{VAR}, or $CACHE{VAR}.
1634  # Escape @VAR@ by \@VAR\@ such that CMake does not evaluate it.
1635  string (REGEX REPLACE "([^\\])\\\$([^ ]*){" "\\1\\\\\$\\2{" VALUE "${VALUE}")
1636  string (REGEX REPLACE "([^\\])\\\@([^ ]*)\@" "\\1\\\\\@\\2\\\\\@" VALUE "${VALUE}")
1637  # append variable to output file
1638  set (DUMP "${DUMP}set (${V} \"${VALUE}\")\n")
1639  endif ()
1640  endforeach ()
1641  file (WRITE "${RESULT_FILE}" "# CMake variables dump created by BASIS\n${DUMP}")
1642 endfunction ()
1643 
1644 # ----------------------------------------------------------------------------
1645 ## @brief Write CMake script file which sets the named variable to the
1646 # specified (list of) values.
1647 function (basis_write_list FILENAME VARIABLE)
1648  file (WRITE "${FILENAME}" "# Automatically generated. Do not edit this file!\nset (${VARIABLE}\n")
1649  foreach (V IN LISTS ARGN)
1650  file (APPEND "${FILENAME}" " \"${V}\"\n")
1651  endforeach ()
1652  file (APPEND "${FILENAME}" ")\n")
1653 endfunction ()
1654 
1655 # ----------------------------------------------------------------------------
1656 ## @brief Set a named property in a given scope.
1657 #
1658 # This function replaces CMake's
1659 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property">
1660 # set_property()</a> command.
1661 #
1662 # @param [in] SCOPE The argument for the @p SCOPE parameter of
1663 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property">
1664 # set_property()</a>.
1665 # @param [in] ARGN Arguments as accepted by.
1666 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property">
1667 # set_property()</a>.
1668 #
1669 # @returns Sets the specified property.
1670 #
1671 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property
1672 #
1673 # @ingroup CMakeAPI
1674 if (BASIS_USE_TARGET_UIDS)
1675  function (basis_set_property SCOPE)
1676  if (SCOPE MATCHES "^TARGET$|^TEST$")
1677  # map target/test names to UIDs
1678  list (LENGTH ARGN ARGN_LENGTH)
1679  if (ARGN_LENGTH EQUAL 0)
1680  message (FATAL_ERROR "basis_set_property(${SCOPE}): Expected arguments after SCOPE!")
1681  endif ()
1682  set (IDX 0)
1683  set (ARG)
1684  while (IDX LESS ARGN_LENGTH)
1685  list (GET ARGN ${IDX} ARG)
1686  if (ARG MATCHES "^APPEND$")
1687  math (EXPR IDX "${IDX} + 1")
1688  list (GET ARGN ${IDX} ARG)
1689  if (NOT ARG MATCHES "^PROPERTY$")
1690  message (FATAL_ERROR "basis_set_properties(${SCOPE}): Expected PROPERTY keyword after APPEND!")
1691  endif ()
1692  break ()
1693  elseif (ARG MATCHES "^PROPERTY$")
1694  break ()
1695  else ()
1696  if (SCOPE MATCHES "^TEST$")
1697  basis_get_test_uid (UID "${ARG}")
1698  else ()
1699  basis_get_target_uid (UID "${ARG}")
1700  endif ()
1701  list (INSERT ARGN ${IDX} "${UID}")
1702  math (EXPR IDX "${IDX} + 1")
1703  list (REMOVE_AT ARGN ${IDX}) # after insert to avoid index out of range
1704  endif ()
1705  endwhile ()
1706  if (IDX EQUAL ARGN_LENGTH)
1707  message (FATAL_ERROR "basis_set_properties(${SCOPE}): Missing PROPERTY keyword!")
1708  endif ()
1709  math (EXPR IDX "${IDX} + 1")
1710  list (GET ARGN ${IDX} ARG)
1711  # property name matches DEPENDS
1712  if (ARG MATCHES "DEPENDS")
1713  math (EXPR IDX "${IDX} + 1")
1714  while (IDX LESS ARGN_LENGTH)
1715  list (GET ARGN ${IDX} ARG)
1716  if (SCOPE MATCHES "^TEST$")
1717  basis_get_test_uid (UID "${ARG}")
1718  else ()
1719  basis_get_target_uid (UID "${ARG}")
1720  endif ()
1721  list (INSERT ARGN ${IDX} "${UID}")
1722  math (EXPR IDX "${IDX} + 1")
1723  list (REMOVE_AT ARGN ${IDX}) # after insert to avoid index out of range
1724  endwhile ()
1725  endif ()
1726  endif ()
1727  if (BASIS_DEBUG)
1728  message ("** basis_set_property():")
1729  message ("** Scope: ${SCOPE}")
1730  message ("** Arguments: [${ARGN}]")
1731  endif ()
1732  set_property (${SCOPE} ${ARGN})
1733  endfunction ()
1734 else ()
1735  macro (basis_set_property)
1736  set_property (${ARGV})
1737  endmacro ()
1738 endif ()
1739 
1740 # ----------------------------------------------------------------------------
1741 ## @brief Get a property.
1742 #
1743 # This function replaces CMake's
1744 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property">
1745 # get_property()</a> command.
1746 #
1747 # @param [out] VAR Property value.
1748 # @param [in] SCOPE The argument for the @p SCOPE argument of
1749 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property">
1750 # get_property()</a>.
1751 # @param [in] ELEMENT The argument for the @p ELEMENT argument of
1752 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property">
1753 # get_property()</a>.
1754 # @param [in] ARGN Arguments as accepted by
1755 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property">
1756 # get_property()</a>.
1757 #
1758 # @returns Sets @p VAR to the value of the requested property.
1759 #
1760 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_property
1761 #
1762 # @ingroup CMakeAPI
1763 if (BASIS_USE_TARGET_UIDS)
1764  function (basis_get_property VAR SCOPE ELEMENT)
1765  if (SCOPE MATCHES "^TARGET$")
1766  basis_get_target_uid (ELEMENT "${ELEMENT}")
1767  elseif (SCOPE MATCHES "^TEST$")
1768  basis_get_test_uid (ELEMENT "${ELEMENT}")
1769  endif ()
1770  get_property (VALUE ${SCOPE} ${ELEMENT} ${ARGN})
1771  set ("${VAR}" "${VALUE}" PARENT_SCOPE)
1772  endfunction ()
1773 else ()
1774  macro (basis_get_property)
1775  get_property (${ARGV})
1776  endmacro ()
1777 endif ()
1778 
1779 # ----------------------------------------------------------------------------
1780 ## @brief Set project-global property.
1781 #
1782 # Set property associated with current project/module. The property is in
1783 # fact just a cached variable whose name is prefixed by the project's name.
1784 function (basis_set_project_property)
1785  CMAKE_PARSE_ARGUMENTS (
1786  ARGN
1787  "APPEND"
1788  "PROJECT"
1789  "PROPERTY"
1790  ${ARGN}
1791  )
1792 
1793  if (NOT ARGN_PROJECT)
1794  set (ARGN_PROJECT "${PROJECT_NAME}")
1795  endif ()
1796  if (NOT ARGN_PROPERTY)
1797  message (FATAL_ERROR "Missing PROPERTY argument!")
1798  endif ()
1799 
1800  list (GET ARGN_PROPERTY 0 PROPERTY_NAME)
1801  list (REMOVE_AT ARGN_PROPERTY 0) # remove property name from values
1802 
1803  if (ARGN_APPEND)
1804  basis_get_project_property (CURRENT ${ARGN_PROJECT} ${PROPERTY_NAME})
1805  if (NOT "${CURRENT}" STREQUAL "")
1806  list (INSERT ARGN_PROPERTY 0 "${CURRENT}")
1807  endif ()
1808  endif ()
1809 
1810  set (
1811  ${ARGN_PROJECT}_${PROPERTY_NAME}
1812  "${ARGN_PROPERTY}"
1813  CACHE INTERNAL
1814  "Property ${PROPERTY_NAME} of project ${ARGN_PROJECT}."
1815  FORCE
1816  )
1817 endfunction ()
1818 
1819 # ----------------------------------------------------------------------------
1820 ## @brief Get project-global property value.
1821 #
1822 # Example:
1823 # @code
1824 # basis_get_project_property(TARGETS)
1825 # basis_get_project_property(TARGETS ${PROJECT_NAME})
1826 # basis_get_project_property(TARGETS ${PROJECT_NAME} TARGETS)
1827 # basis_get_project_property(TARGETS PROPERTY TARGETS)
1828 # @endcode
1829 #
1830 # @param [out] VARIABLE Name of result variable.
1831 # @param [in] ARGN See the example uses. The optional second argument
1832 # is either the name of the project similar to CMake's
1833 # get_target_property() command or the keyword PROPERTY
1834 # followed by the name of the property.
1835 function (basis_get_project_property VARIABLE)
1836  if (ARGC GREATER 3)
1837  message (FATAL_ERROR "Too many arguments!")
1838  endif ()
1839  if (ARGC EQUAL 1)
1840  set (ARGN_PROJECT "${PROJECT_NAME}")
1841  set (ARGN_PROPERTY "${VARIABLE}")
1842  elseif (ARGC EQUAL 2)
1843  if (ARGV1 MATCHES "^PROPERTY$")
1844  message (FATAL_ERROR "Expected argument after PROPERTY keyword!")
1845  endif ()
1846  set (ARGN_PROJECT "${ARGV1}")
1847  set (ARGN_PROPERTY "${VARIABLE}")
1848  else ()
1849  if (ARGV1 MATCHES "^PROPERTY$")
1850  set (ARGN_PROJECT "${PROJECT_NAME}")
1851  else ()
1852  set (ARGN_PROJECT "${ARGV1}")
1853  endif ()
1854  set (ARGN_PROPERTY "${ARGV2}")
1855  endif ()
1856  set (${VARIABLE} "${${ARGN_PROJECT}_${ARGN_PROPERTY}}" PARENT_SCOPE)
1857 endfunction ()
1858 
1859 # ============================================================================
1860 # list / string manipulations
1861 # ============================================================================
1862 
1863 # ----------------------------------------------------------------------------
1864 ## @brief Sanitize string variable for use in regular expression.
1865 #
1866 # @note This function may not work for all cases, but is used in particular
1867 # to sanitize project names, target names, namespace identifiers,...
1868 #
1869 # This takes all of the dollar signs, and other special characters and
1870 # adds escape characters such as backslash as necessary.
1871 #
1872 # @param [out] OUT String that can be used in regular expression.
1873 # @param [in] STR String to sanitize.
1874 macro (basis_sanitize_for_regex OUT STR)
1875  string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" ${OUT} "${STR}")
1876 endmacro ()
1877 
1878 # ----------------------------------------------------------------------------
1879 ## @brief Concatenates all list elements into a single string.
1880 #
1881 # The list elements are concatenated without any delimiter in between.
1882 # Use basis_list_to_delimited_string() to specify a delimiter such as a
1883 # whitespace character or comma (,) as delimiter.
1884 #
1885 # @param [out] STR Output string.
1886 # @param [in] ARGN Input list.
1887 #
1888 # @returns Sets @p STR to the resulting string.
1889 #
1890 # @sa basis_list_to_delimited_string()
1891 function (basis_list_to_string STR)
1892  set (OUT)
1893  foreach (ELEM IN LISTS ARGN)
1894  set (OUT "${OUT}${ELEM}")
1895  endforeach ()
1896  set ("${STR}" "${OUT}" PARENT_SCOPE)
1897 endfunction ()
1898 
1899 # ----------------------------------------------------------------------------
1900 ## @brief Concatenates all list elements into a single delimited string.
1901 #
1902 # @param [out] STR Output string.
1903 # @param [in] DELIM Delimiter used to separate list elements.
1904 # Each element which contains the delimiter as substring
1905 # is surrounded by double quotes (") in the output string.
1906 # @param [in] ARGN Input list. If this list starts with the argument
1907 # @c NOAUTOQUOTE, the automatic quoting of list elements
1908 # which contain the delimiter is disabled.
1909 #
1910 # @returns Sets @p STR to the resulting string.
1911 #
1912 # @see basis_join
1913 #
1914 # @todo consider replacing basis_list_to_delimited_string with basis_join
1915 function (basis_list_to_delimited_string STR DELIM)
1916  set (OUT)
1917  set (AUTOQUOTE TRUE)
1918  if (ARGN)
1919  list (GET ARGN 0 FIRST)
1920  if (FIRST MATCHES "^NOAUTOQUOTE$")
1921  list (REMOVE_AT ARGN 0)
1922  set (AUTOQUOTE FALSE)
1923  endif ()
1924  endif ()
1925  basis_sanitize_for_regex (DELIM_RE "${DELIM}")
1926  foreach (ELEM ${ARGN})
1927  if (OUT)
1928  set (OUT "${OUT}${DELIM}")
1929  endif ()
1930  if (AUTOQUOTE AND ELEM MATCHES "${DELIM_RE}")
1931  set (OUT "${OUT}\"${ELEM}\"")
1932  else ()
1933  set (OUT "${OUT}${ELEM}")
1934  endif ()
1935  endforeach ()
1936  set ("${STR}" "${OUT}" PARENT_SCOPE)
1937 endfunction ()
1938 
1939 # ----------------------------------------------------------------------------
1940 ## @brief Concatenates all list elements into a single delimited string.
1941 #
1942 # @param [in] VALUES Input list string.
1943 # @param [in] DELIMITER Delimiter glue used to separate list elements.
1944 # Each element which contains the delimiter as substring
1945 # is surrounded by double quotes (") in the output string.
1946 # @param [out] OUTPUT Output string variable name.
1947 #
1948 # @code
1949 # set( letters "" "\;a" b c "d\;d" )
1950 # basis_join("${letters}" ":" output)
1951 # message("${output}") # :;a:b:c:d;d
1952 # @endcode
1953 #
1954 # @returns Sets @p OUTPUT to the resulting string.
1955 #
1956 # @see basis_list_to_delimited_string
1957 function(basis_join VALUES DELIMITER OUTPUT)
1958  string (REGEX REPLACE "([^\\]|^);" "\\1${DELIMITER}" _TMP_STR "${VALUES}")
1959  string (REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping
1960  set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
1961 endfunction()
1962 
1963 # ----------------------------------------------------------------------------
1964 ## @brief Splits a string at space characters into a list.
1965 #
1966 # @todo Probably this can be done in a better way...
1967 # Difficulty is, that string(REPLACE) does always replace all
1968 # occurrences. Therefore, we need a regular expression which matches
1969 # the entire string. More sophisticated regular expressions should do
1970 # a better job, though.
1971 #
1972 # @param [out] LST Output list.
1973 # @param [in] STR Input string.
1974 #
1975 # @returns Sets @p LST to the resulting CMake list.
1976 function (basis_string_to_list LST STR)
1977  set (TMP "${STR}")
1978  set (OUT)
1979  # 1. extract elements such as "a string with spaces"
1980  while (TMP MATCHES "\"[^\"]*\"")
1981  string (REGEX REPLACE "^(.*)\"([^\"]*)\"(.*)$" "\\1\\3" TMP "${TMP}")
1982  if (OUT)
1983  set (OUT "${CMAKE_MATCH_2};${OUT}")
1984  else (OUT)
1985  set (OUT "${CMAKE_MATCH_2}")
1986  endif ()
1987  endwhile ()
1988  # 2. extract other elements separated by spaces (excluding first and last)
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  # 3. extract first and last elements (if not done yet)
1998  if (TMP MATCHES "^[^\" ]+")
1999  set (OUT "${CMAKE_MATCH_0};${OUT}")
2000  endif ()
2001  if (NOT "${CMAKE_MATCH_0}" STREQUAL "${TMP}" AND TMP MATCHES "[^\" ]+$")
2002  set (OUT "${OUT};${CMAKE_MATCH_0}")
2003  endif ()
2004  # return resulting list
2005  set (${LST} "${OUT}" PARENT_SCOPE)
2006 endfunction ()
2007 
2008 # ----------------------------------------------------------------------------
2009 ## @brief Compare two lists.
2010 #
2011 # @param [out] RESULT Result of comparison.
2012 # @param [in] LIST1 Name of variable holding the first list.
2013 # @param [in] LIST2 Name of varaible holding the second list.
2014 #
2015 # @retval 0 The two lists are not identical.
2016 # @retval 1 Both lists have identical elements (not necessarily in the same order).
2017 macro (basis_compare_lists RESULT LIST1 LIST2)
2018  set (_L1 "${${LIST1}}")
2019  set (_L2 "${${LIST2}}")
2020  list (SORT _L1)
2021  list (SORT _L2)
2022  if ("${_L1}" STREQUAL "${_L2}")
2023  set (RESULT TRUE)
2024  else ()
2025  set (RESULT FALSE)
2026  endif ()
2027  unset (_L1)
2028  unset (_L2)
2029 endmacro ()
2030 
2031 # ============================================================================
2032 # name <=> UID
2033 # ============================================================================
2034 
2035 # ----------------------------------------------------------------------------
2036 ## @brief Derive target name from source file name.
2037 #
2038 # @param [out] TARGET_NAME Target name.
2039 # @param [in] SOURCE_FILE Source file.
2040 # @param [in] ARGN Third argument to get_filename_component().
2041 # If not specified, the given path is only sanitized.
2042 #
2043 # @returns Target name derived from @p SOURCE_FILE.
2044 function (basis_get_source_target_name TARGET_NAME SOURCE_FILE)
2045  # remove ".in" suffix from file name
2046  string (REGEX REPLACE "\\.in$" "" OUT "${SOURCE_FILE}")
2047  # get name component
2048  if (ARGC GREATER 2)
2049  get_filename_component (OUT "${OUT}" ${ARGV2})
2050  endif ()
2051  # replace special characters
2052  string (REGEX REPLACE "[./\\]" "_" OUT "${OUT}")
2053  # return
2054  set (${TARGET_NAME} "${OUT}" PARENT_SCOPE)
2055 endfunction ()
2056 
2057 # ----------------------------------------------------------------------------
2058 ## @brief Strip of top-level package name from target UID if present.
2059 #
2060 # If @c BASIS_USE_FULLY_QUALIFIED_TARGET_UID is @c ON, the top-level package
2061 # name is always preserved and this operation does nothing.
2062 #
2063 # @param[in,out] TARGET_UID "Global" target name, i.e., actual CMake target name.
2064 #
2065 # @returns Sets @p TARGET_UID to the (stripped) UID.
2066 function (basis_strip_target_uid TARGET_UID)
2067  if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS)
2068  basis_sanitize_for_regex (RE "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}")
2069  string (REGEX REPLACE "^\\.*${RE}\\." "" UID "${${TARGET_UID}}")
2070  set ("${TARGET_UID}" "${UID}" PARENT_SCOPE)
2071  endif ()
2072 endfunction ()
2073 
2074 # ----------------------------------------------------------------------------
2075 ## @brief Make target UID from given target name.
2076 #
2077 # This function is intended for internal use only.
2078 #
2079 # @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name.
2080 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions.
2081 #
2082 # @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME.
2083 #
2084 # @sa basis_make_target_uid()
2085 function (_basis_make_target_uid TARGET_UID TARGET_NAME)
2086  if (TARGET_NAME MATCHES "^\\.+(.*)$")
2087  set (${TARGET_UID} "${CMAKE_MATCH_1}" PARENT_SCOPE)
2088  else ()
2089  set (UID "${PROJECT_NAMESPACE_CMAKE}.${TARGET_NAME}")
2090  basis_strip_target_uid (UID)
2091  set (${TARGET_UID} "${UID}" PARENT_SCOPE)
2092  endif ()
2093 endfunction ()
2094 
2095 # ----------------------------------------------------------------------------
2096 ## @brief Make target UID from given target name.
2097 #
2098 # This function is intended for use by the basis_add_*() functions only.
2099 #
2100 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2101 # always just sets the @p TARGET_UID to the given @p TARGET_NAME.
2102 #
2103 # @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name.
2104 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions.
2105 #
2106 # @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME.
2107 #
2108 # @sa basis_get_target_uid()
2109 if (BASIS_USE_TARGET_UIDS)
2110  function (basis_make_target_uid TARGET_UID TARGET_NAME)
2111  _basis_make_target_uid (UID "${TARGET_NAME}")
2112  set ("${TARGET_UID}" "${UID}" PARENT_SCOPE)
2113  endfunction ()
2114 else ()
2115  function (basis_make_target_uid TARGET_UID TARGET_NAME)
2116  if (TARGET_NAME MATCHES "^\\.+(.*)$")
2117  set ("${TARGET_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2118  else ()
2119  set ("${TARGET_UID}" "${TARGET_NAME}" PARENT_SCOPE)
2120  endif ()
2121  endfunction ()
2122 endif ()
2123 
2124 # ----------------------------------------------------------------------------
2125 ## @brief Get "global" target name, i.e., actual CMake target name.
2126 #
2127 # In order to ensure that CMake target names are unique across modules of
2128 # a BASIS project, the target name given to the BASIS CMake functions is
2129 # converted by basis_make_target_uid() into a so-called target UID which is
2130 # used as actual CMake target name. This function can be used to get for a
2131 # given target name or UID the closest match of a known target UID.
2132 #
2133 # The individual parts of the target UID, i.e, package name,
2134 # module name, and target name are separated by a dot (.).
2135 # If @c BASIS_USE_FULLY_QUALIFIED_UIDS is set to @c OFF, the common part of
2136 # all target UIDs is removed by this function from the target UID.
2137 # When the target is exported, however, this common part will be
2138 # prefixed again. This is done by the basis_export_targets() function.
2139 #
2140 # Note that names of imported targets are not prefixed in any case.
2141 #
2142 # The counterpart basis_get_target_name() can be used to convert the target UID
2143 # back to the target name without namespace prefix.
2144 #
2145 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2146 # always just sets the @p TARGET_UID to the given @p TARGET_NAME.
2147 #
2148 # @note At the moment, BASIS does not support modules which themselves have
2149 # modules again. This would require a more nested namespace hierarchy
2150 # and makes things unnecessarily complicated.
2151 #
2152 # @param [out] TARGET_UID "Global" target name, i.e., actual CMake target name.
2153 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions.
2154 #
2155 # @returns Sets @p TARGET_UID to the UID of the build target @p TARGET_NAME.
2156 #
2157 # @sa basis_get_target_name()
2158 if (BASIS_USE_TARGET_UIDS)
2159  function (basis_get_target_uid TARGET_UID TARGET_NAME)
2160  # in case of a leading namespace separator, do not modify target name
2161  if (TARGET_NAME MATCHES "^\\.+(.*)$")
2162  set (UID "${CMAKE_MATCH_1}")
2163  # otherwise,
2164  else ()
2165  set (UID "${TARGET_NAME}")
2166  basis_sanitize_for_regex (BASE_RE "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}")
2167  # try prepending namespace or parts of it until target is known,
2168  # first assuming the simplified UIDs without the common prefix
2169  # of this package which applies to targets of this package
2170  if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS AND NOT TARGET "${UID}")
2171  string (REGEX REPLACE "^${BASE_RE}\\." "" PREFIX "${PROJECT_NAMESPACE_CMAKE}")
2172  while (PREFIX)
2173  if (TARGET "${PREFIX}.${TARGET_NAME}")
2174  set (UID "${PREFIX}.${TARGET_NAME}")
2175  break ()
2176  else ()
2177  if (PREFIX MATCHES "(.*)\\.[^.]+")
2178  set (PREFIX "${CMAKE_MATCH_1}")
2179  else ()
2180  break ()
2181  endif ()
2182  endif ()
2183  endwhile ()
2184  endif ()
2185  # and then with the fully qualified UIDs for imported targets
2186  if (NOT TARGET "${UID}")
2187  set (PREFIX "${PROJECT_NAMESPACE_CMAKE}")
2188  while (PREFIX)
2189  if (TARGET "${PREFIX}.${TARGET_NAME}")
2190  set (UID "${PREFIX}.${TARGET_NAME}")
2191  break ()
2192  else ()
2193  if (PREFIX MATCHES "(.*)\\.[^.]+")
2194  set (PREFIX "${CMAKE_MATCH_1}")
2195  else ()
2196  break ()
2197  endif ()
2198  endif ()
2199  endwhile ()
2200  endif ()
2201  endif ()
2202  # strip off top-level namespace part (optional)
2203  if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS)
2204  string (REGEX REPLACE "^${BASE_RE}\\." "" UID "${UID}")
2205  endif ()
2206  # return
2207  set ("${TARGET_UID}" "${UID}" PARENT_SCOPE)
2208  endfunction ()
2209 else ()
2210  function (basis_get_target_uid TARGET_UID TARGET_NAME)
2211  if (TARGET_NAME MATCHES "^\\.+(.*)$")
2212  set (${TARGET_UID} "${CMAKE_MATCH_1}" PARENT_SCOPE)
2213  else ()
2214  set ("${TARGET_UID}" "${TARGET_NAME}" PARENT_SCOPE)
2215  endif ()
2216  endfunction ()
2217 endif ()
2218 
2219 # ----------------------------------------------------------------------------
2220 ## @brief Get fully-qualified target name.
2221 #
2222 # This function always returns a fully-qualified target UID, no matter if
2223 # the option @c BASIS_USE_TARGET_UIDS or @c BASIS_USE_FULLY_QUALIFIED_UIDS
2224 # is @c OFF. Note that if @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c ON, the
2225 # returned target UID may not be the actual name of a CMake target.
2226 #
2227 # @param [out] TARGET_UID Fully-qualified target UID.
2228 # @param [in] TARGET_NAME Target name used as argument to BASIS CMake functions.
2229 #
2230 # @sa basis_get_target_uid()
2231 function (basis_get_fully_qualified_target_uid TARGET_UID TARGET_NAME)
2232  if (BASIS_USE_TARGET_UIDS)
2233  basis_get_target_uid (UID "${TARGET_NAME}")
2234  if (NOT BASIS_USE_FULLY_QUALIFIED_UIDS)
2235  if (TARGET "${UID}")
2236  get_target_property (IMPORTED "${UID}" IMPORTED)
2237  if (NOT IMPORTED)
2238  set (UID "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${UID}")
2239  endif ()
2240  else ()
2241  set (UID "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${UID}")
2242  endif ()
2243  endif ()
2244  else ()
2245  if (TARGET "${TARGET_NAME}")
2246  get_target_property (IMPORTED "${TARGET_NAME}" IMPORTED)
2247  else ()
2248  set (IMPORTED FALSE)
2249  endif ()
2250  if (IMPORTED)
2251  set (UID "${TARGET_NAME}")
2252  else ()
2253  set (UID "${PROJECT_NAMESPACE_CMAKE}.${TARGET_NAME}")
2254  endif ()
2255  endif ()
2256  set (${TARGET_UID} "${UID}" PARENT_SCOPE)
2257 endfunction ()
2258 
2259 # ----------------------------------------------------------------------------
2260 ## @brief Get namespace of build target without check of UID.
2261 #
2262 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2263 # always just sets the @p TARGET_NS to an empty string.
2264 #
2265 # @param [out] TARGET_NS Namespace part of target UID.
2266 # @param [in] TARGET_UID Target UID.
2267 if (BASIS_USE_TARGET_UIDS)
2268  function (_basis_get_target_namespace TARGET_NS TARGET_UID)
2269  if (UID MATCHES "^(.*)\\.")
2270  set ("${TARGET_NS}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2271  else ()
2272  set ("${TARGET_NS}" "" PARENT_SCOPE)
2273  endif ()
2274  endfunction ()
2275 else ()
2276  function (_basis_get_target_namespace TARGET_NS TARGET_UID)
2277  set ("${TARGET_NS}" "" PARENT_SCOPE)
2278  endfunction ()
2279 endif ()
2280 
2281 # ----------------------------------------------------------------------------
2282 ## @brief Get namespace of build target.
2283 #
2284 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2285 # always just sets the @p TARGET_NS to an empty string.
2286 #
2287 # @param [out] TARGET_NS Namespace part of target UID.
2288 # @param [in] TARGET_UID Target UID/name.
2289 if (BASIS_USE_TARGET_UIDS)
2290  function (basis_get_target_namespace TARGET_NS TARGET_UID)
2291  basis_get_fully_qualified_target_uid (UID "${TARGET_UID}")
2292  _basis_get_target_namespace (NS "${UID}")
2293  set ("${TARGET_NS}" "${NS}" PARENT_SCOPE)
2294  endfunction ()
2295 else ()
2296  function (basis_get_target_namespace TARGET_NS TARGET_UID)
2297  set ("${TARGET_NS}" "" PARENT_SCOPE)
2298  endfunction ()
2299 endif ()
2300 
2301 # ----------------------------------------------------------------------------
2302 ## @brief Get "local" target name, i.e., BASIS target name without check of UID.
2303 #
2304 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2305 # always just sets the @p TARGET_NAME to the given @p TARGET_UID.
2306 #
2307 # @param [out] TARGET_NAME Target name used as argument to BASIS functions.
2308 # @param [in] TARGET_UID "Global" target name, i.e., actual CMake target name.
2309 #
2310 # @returns Sets @p TARGET_NAME to the name of the build target with UID @p TARGET_UID.
2311 #
2312 # @sa basis_get_target_name(), basis_get_target_uid()
2313 if (BASIS_USE_TARGET_UIDS)
2314  function (_basis_get_target_name TARGET_NAME TARGET_UID)
2315  # strip off namespace of current project
2316  basis_sanitize_for_regex (RE "${PROJECT_NAMESPACE_CMAKE}")
2317  string (REGEX REPLACE "^${RE}\\." "" NAME "${UID}")
2318  # return
2319  set (${TARGET_NAME} "${NAME}" PARENT_SCOPE)
2320  endfunction ()
2321 else ()
2322  function (_basis_get_target_name TARGET_NAME TARGET_UID)
2323  set (${TARGET_NAME} "${TARGET_UID}" PARENT_SCOPE)
2324  endfunction ()
2325 endif ()
2326 
2327 # ----------------------------------------------------------------------------
2328 ## @brief Get "local" target name, i.e., BASIS target name.
2329 #
2330 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2331 # always just sets the @p TARGET_NAME to the given @p TARGET_UID.
2332 #
2333 # @param [out] TARGET_NAME Target name used as argument to BASIS functions.
2334 # @param [in] TARGET_UID "Global" target name, i.e., actual CMake target name.
2335 #
2336 # @returns Sets @p TARGET_NAME to the name of the build target with UID @p TARGET_UID.
2337 #
2338 # @sa basis_get_target_uid()
2339 if (BASIS_USE_TARGET_UIDS)
2340  function (basis_get_target_name TARGET_NAME TARGET_UID)
2341  basis_get_fully_qualified_target_uid (UID "${TARGET_UID}")
2342  _basis_get_target_name (NAME "${UID}")
2343  set (${TARGET_NAME} "${NAME}" PARENT_SCOPE)
2344  endfunction ()
2345 else ()
2346  function (basis_get_target_name TARGET_NAME TARGET_UID)
2347  set (${TARGET_NAME} "${TARGET_UID}" PARENT_SCOPE)
2348  endfunction ()
2349 endif ()
2350 
2351 # ----------------------------------------------------------------------------
2352 ## @brief Checks whether a given name is a valid target name.
2353 #
2354 # Displays fatal error message when target name is invalid.
2355 #
2356 # @param [in] TARGET_NAME Desired target name.
2357 #
2358 # @returns Nothing.
2359 function (basis_check_target_name TARGET_NAME)
2360  # reserved target name ?
2361  foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES)
2362  if ("^${TARGET_NAME}$" STREQUAL "^${PATTERN}$")
2363  message (FATAL_ERROR "Target name \"${TARGET_NAME}\" is reserved and cannot be used.")
2364  endif ()
2365  endforeach ()
2366  # invalid target name ?
2367  if (NOT TARGET_NAME MATCHES "^\\.?[a-zA-Z]([a-zA-Z0-9_+.]|-)*$|^__init__(_py)?$")
2368  message (FATAL_ERROR "Target name '${TARGET_NAME}' is invalid.\nChoose a target name"
2369  " which only contains alphanumeric characters,"
2370  " '_', '-', or '+', and starts with a letter."
2371  " The only exception from this rule is __init__[_py] for"
2372  " a __init__.py script.\n")
2373  endif ()
2374 
2375  # unique ?
2376  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
2377  if (TARGET "${TARGET_UID}")
2378  message (FATAL_ERROR "There exists already a target named ${TARGET_UID}."
2379  " Target names must be unique.")
2380  endif ()
2381 endfunction ()
2382 
2383 # ----------------------------------------------------------------------------
2384 ## @brief Make test UID from given test name.
2385 #
2386 # This function is intended for use by the basis_add_test() only.
2387 #
2388 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2389 # always just sets the @p TEST_UID to the given @p TEST_NAME.
2390 #
2391 # @param [out] TEST_UID "Global" test name, i.e., actual CTest test name.
2392 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions.
2393 #
2394 # @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME.
2395 #
2396 # @sa basis_get_test_uid()
2397 function (basis_make_test_uid TEST_UID TEST_NAME)
2398  basis_make_target_uid (UID "${TEST_NAME}")
2399  set ("${TEST_UID}" "${UID}" PARENT_SCOPE)
2400 endfunction ()
2401 
2402 # ----------------------------------------------------------------------------
2403 ## @brief Get "global" test name, i.e., actual CTest test name.
2404 #
2405 # In order to ensure that CTest test names are unique across BASIS projects,
2406 # the test name used by a developer of a BASIS project is converted by this
2407 # function into another test name which is used as actual CTest test name.
2408 #
2409 # The function basis_get_test_name() can be used to convert the unique test
2410 # name, the test UID, back to the original test name passed to this function.
2411 #
2412 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2413 # always just sets the @p TEST_UID to the given @p TEST_NAME.
2414 #
2415 # @param [out] TEST_UID "Global" test name, i.e., actual CTest test name.
2416 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions.
2417 #
2418 # @returns Sets @p TEST_UID to the UID of the test @p TEST_NAME.
2419 #
2420 # @sa basis_get_test_name()
2421 if (BASIS_USE_TARGET_UIDS)
2422  function (basis_get_test_uid TEST_UID TEST_NAME)
2423  if (TEST_NAME MATCHES "^\\.+(.*)$")
2424  set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2425  else ()
2426  set (UID "${PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}")
2427  basis_strip_target_uid (UID ${UID})
2428  set ("${TEST_UID}" "${UID}" PARENT_SCOPE)
2429  endif ()
2430  endfunction ()
2431 else ()
2432  function (basis_get_test_uid TEST_UID TEST_NAME)
2433  if (TEST_NAME MATCHES "^\\.+(.*)$")
2434  set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2435  else ()
2436  set ("${TEST_UID}" "${TEST_NAME}" PARENT_SCOPE)
2437  endif ()
2438  endfunction ()
2439 endif ()
2440 
2441 # ----------------------------------------------------------------------------
2442 ## @brief Get "global" test name, i.e., actual CTest test name.
2443 #
2444 # This function always returns a fully-qualified test UID, no matter if
2445 # the option @c BASIS_USE_FULLY_QUALIFIED_UIDS is @c OFF. Note that
2446 # if this option is @c ON, the returned test UID may not be the
2447 # actual name of a CMake test.
2448 #
2449 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2450 # always just sets the @p TEST_UID to the given @p TEST_NAME.
2451 #
2452 # @param [out] TEST_UID Fully-qualified test UID.
2453 # @param [in] TEST_NAME Test name used as argument to BASIS CMake functions.
2454 #
2455 # @sa basis_get_test_uid()
2456 if (BASIS_USE_TARGET_UIDS)
2457  function (basis_get_fully_qualified_test_uid TEST_UID TEST_NAME)
2458  if (TEST_NAME MATCHES "^\\.+(.*)$")
2459  set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2460  else ()
2461  set ("${TEST_UID}" "${TOPLEVEL_PROJECT_NAMESPACE_CMAKE}.${TEST_NAME}" PARENT_SCOPE)
2462  endif ()
2463  endfunction ()
2464 else ()
2465  function (basis_get_fully_qualified_test_uid TEST_UID TEST_NAME)
2466  if (TEST_NAME MATCHES "^\\.+(.*)$")
2467  set ("${TEST_UID}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
2468  else ()
2469  set ("${TEST_UID}" "${TEST_NAME}" PARENT_SCOPE)
2470  endif ()
2471  endfunction ()
2472 endif ()
2473 
2474 # ----------------------------------------------------------------------------
2475 ## @brief Get namespace of test.
2476 #
2477 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2478 # always just sets the @p TEST_NS to an empty string.
2479 #
2480 # @param [out] TEST_NS Namespace part of test UID. If @p TEST_UID is
2481 # no UID, i.e., does not contain a namespace part,
2482 # the namespace of this project is returned.
2483 # @param [in] TEST_UID Test UID/name.
2484 if (BASIS_USE_TARGET_UIDS)
2485  function (basis_get_test_namespace TEST_NS TEST_UID)
2486  if (TEST_UID MATCHES "^(.*)\\.")
2487  set (${TEST_NS} "${CMAKE_MATCH_1}" PARENT_SCOPE)
2488  else ()
2489  set (${TEST_NS} "" PARENT_SCOPE)
2490  endif ()
2491  endfunction ()
2492 else ()
2493  function (basis_get_test_namespace TEST_NS TEST_UID)
2494  set ("${TEST_UID}" "" PARENT_SCOPE)
2495  endfunction ()
2496 endif ()
2497 
2498 # ----------------------------------------------------------------------------
2499 ## @brief Get "local" test name, i.e., BASIS test name.
2500 #
2501 # If @c BASIS_USE_TARGET_UIDS is set to @c OFF, this operation
2502 # always just sets the @p TEST_NAME to the given @p TEST_UID.
2503 #
2504 # @param [out] TEST_NAME Test name used as argument to BASIS functions.
2505 # @param [in] TEST_UID "Global" test name, i.e., actual CTest test name.
2506 #
2507 # @returns Sets @p TEST_NAME to the name of the test with UID @p TEST_UID.
2508 #
2509 # @sa basis_get_test_uid()
2510 if (BASIS_USE_TARGET_UIDS)
2511  function (basis_get_test_name TEST_NAME TEST_UID)
2512  if (TEST_UID MATCHES "([^.]+)$")
2513  set (${TEST_NAME} "${CMAKE_MATCH_1}" PARENT_SCOPE)
2514  else ()
2515  set (${TEST_NAME} "" PARENT_SCOPE)
2516  endif ()
2517  endfunction ()
2518 else ()
2519  function (basis_get_test_name TEST_NAME TEST_UID)
2520  set ("${TEST_NAME}" "${TEST_UID}" PARENT_SCOPE)
2521  endfunction ()
2522 endif ()
2523 
2524 # ----------------------------------------------------------------------------
2525 ## @brief Checks whether a given name is a valid test name.
2526 #
2527 # Displays fatal error message when test name is invalid.
2528 #
2529 # @param [in] TEST_NAME Desired test name.
2530 #
2531 # @returns Nothing.
2532 function (basis_check_test_name TEST_NAME)
2533  # reserved test name ?
2534  foreach (PATTERN IN LISTS BASIS_RESERVED_TARGET_NAMES)
2535  if ("^${TARGET_NAME}$" STREQUAL "^${PATTERN}$")
2536  message (FATAL_ERROR "Test name \"${TARGET_NAME}\" is reserved and cannot be used.")
2537  endif ()
2538  endforeach ()
2539  # invalid test name ?
2540  if (NOT TEST_NAME MATCHES "^\\.?[a-zA-Z]([a-zA-Z0-9_+.]|-)*$")
2541  message (FATAL_ERROR "Test name ${TEST_NAME} is invalid.\nChoose a test name "
2542  " which only contains alphanumeric characters,"
2543  " '_', '-', or '+', and starts with a letter.\n")
2544  endif ()
2545 endfunction ()
2546 
2547 # ============================================================================
2548 # common target tools
2549 # ============================================================================
2550 
2551 # ----------------------------------------------------------------------------
2552 ## @brief Whether a given target exists.
2553 #
2554 # This function should be used instead of the if(TARGET) command of CMake
2555 # because target names are mapped by BASIS to target UIDs.
2556 #
2557 # @param [out] RESULT_VARIABLE Boolean result variable.
2558 # @param [in] TARGET_NAME Name which to check whether it is a target.
2559 #
2560 # @sa basis_make_target_uid()
2561 # @sa basis_get_target_uid()
2562 macro (basis_exists_target RESULT_VARIABLE TARGET_NAME)
2563  basis_get_target_uid (_UID "${TARGET_NAME}")
2564  if (TARGET ${_UID})
2565  set (${RESULT_VARIABLE} TRUE)
2566  else ()
2567  set (${RESULT_VARIABLE} FALSE)
2568  endif ()
2569  unset (_UID)
2570 endmacro ()
2571 
2572 # ----------------------------------------------------------------------------
2573 ## @brief Get default subdirectory prefix of scripted library modules.
2574 #
2575 # @param [out] PREFIX Name of variable which is set to the default library
2576 # prefix, i.e., subdirectory relative to the library
2577 # root directory as used for the @c PREFIX property of
2578 # scripted module libraries (see basis_add_script_library())
2579 # or relative to the include directory in case of C++.
2580 # Note that this prefix includes a trailing slash to
2581 # indicate that the prefix is a subdirectory.
2582 # @param [in] LANGUAGE Programming language (case-insenitive), e.g.,
2583 # @c CXX, @c Python, @c Matlab...
2584 macro (basis_library_prefix PREFIX LANGUAGE)
2585  string (TOUPPER "${LANGUAGE}" _LANGUAGE_U)
2586  if (PROJECT_NAMESPACE_${_LANGUAGE_U})
2587  basis_sanitize_for_regex (_RE "${BASIS_NAMESPACE_DELIMITER_${_LANGUAGE_U}}")
2588  string (REGEX REPLACE "${_RE}" "/" ${PREFIX} "${PROJECT_NAMESPACE_${_LANGUAGE_U}}")
2589  set (${PREFIX} "${${PREFIX}}/")
2590  unset (_RE)
2591  else ()
2592  message (FATAL_ERROR "basis_library_prefix(): PROJECT_NAMESPACE_${_LANGUAGE_U} not set!"
2593  " Make sure that the LANGUAGE argument is supported and in"
2594  " uppercase letters only.")
2595  endif ()
2596  unset (_LANGUAGE_U)
2597 endmacro ()
2598 
2599 # ----------------------------------------------------------------------------
2600 ## @brief Get file name of compiled script.
2601 #
2602 # @param [out] CFILE File path of compiled script file.
2603 # @param [in] SOURCE Script source file.
2604 # @param [in] ARGV2 Language of script file. If not specified, the language
2605 # is derived from the file name extension and shebang of
2606 # the script source file.
2607 function (basis_get_compiled_file CFILE SOURCE)
2608  if (ARGC GREATER 2)
2609  set (LANGUAGE "${ARGV2}")
2610  else ()
2611  basis_get_source_language (LANGUAGE "${SOURCE}")
2612  endif ()
2613  set (${CFILE} "" PARENT_SCOPE)
2614  if (SOURCE)
2615  if (LANGUAGE MATCHES "PYTHON")
2616  set (${CFILE} "${SOURCE}c" PARENT_SCOPE)
2617  elseif (LANGUAGE MATCHES "JYTHON")
2618  if (SOURCE MATCHES "(.*)\\.([^.]+)$")
2619  set (${CFILE} "${CMAKE_MATCH_1}$${CMAKE_MATCH_2}.class" PARENT_SCOPE)
2620  endif ()
2621  endif ()
2622  endif ()
2623 endfunction ()
2624 
2625 # ----------------------------------------------------------------------------
2626 ## @brief Get file path of Jython file compiled from the given Python module.
2627 #
2628 # Python modules are also compiled using Jython. This macro returns the file
2629 # path of the compiled Jython file in the build tree which corresponds to the
2630 # specified Python module.
2631 #
2632 # @param [out] CFILE Path of corresponding compiled Jython file.
2633 # @param [in] MODULE Path of input Python module in build tree.
2634 macro (basis_get_compiled_jython_file_of_python_module CFILE MODULE)
2635  if (BINARY_PYTHON_LIBRARY_DIR AND BINARY_JYTHON_LIBRARY_DIR)
2636  file (RELATIVE_PATH _GCJFOPM_REL "${BINARY_PYTHON_LIBRARY_DIR}" "${MODULE}")
2637  else ()
2638  set (_GCJFOPM_REL)
2639  endif ()
2640  if (NOT _GCJFOPM_REL MATCHES "^$|^\\.\\./")
2641  basis_get_compiled_file (${CFILE} "${BINARY_JYTHON_LIBRARY_DIR}/${_GCJFOPM_REL}" JYTHON)
2642  else ()
2643  basis_get_compiled_file (${CFILE} "${MODULE}" JYTHON)
2644  endif ()
2645  unset (_GCJFOPM_REL)
2646 endmacro ()
2647 
2648 # ----------------------------------------------------------------------------
2649 ## @brief Whether to compile Python modules for Jython interpreter.
2650 #
2651 # This macro returns a boolean value stating whether Python modules shall also
2652 # be compiled for use by Jython interpreter if BASIS_COMPILE_SCRIPTS is ON.
2653 #
2654 # @param [out] FLAG Set to either TRUE or FALSE depending on whether Python
2655 # modules shall be compiled using Jython or not.
2656 macro (basis_compile_python_modules_for_jython FLAG)
2657  if (BASIS_COMPILE_SCRIPTS AND JYTHON_EXECUTABLE)
2658  set (${FLAG} TRUE)
2659  else ()
2660  set (${FLAG} FALSE)
2661  endif ()
2662  if (DEFINED USE_JythonInterp AND NOT USE_JythonInterp)
2663  set (${FLAG} FALSE)
2664  endif ()
2665 endmacro ()
2666 
2667 # ----------------------------------------------------------------------------
2668 ## @brief Glob source files.
2669 #
2670 # This function gets a list of source files and globbing expressions, evaluates
2671 # the globbing expression, and replaces these by the found source files such
2672 # that the resulting list of source files contains only absolute paths of
2673 # source files. It is used by basis_add_executable() and basis_add_library()
2674 # to get a list of all source files. The syntax for the glob expressions
2675 # corresponds to the one used by CMake's
2676 # <a href="http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:file">
2677 # file(GLOB)</a> command. Additionally, if the pattern <tt>**</tt> is found
2678 # in a glob expression, it is replaced by a single <tt>*</tt> and the
2679 # recursive version, i.e., <tt>file(GLOB_RECURSE)</tt>, is used instead.
2680 #
2681 # @param [in] TARGET_UID UID of build target which builds the globbed source files.
2682 # The custom target which re-globs the source files
2683 # before each build of this target is named after this
2684 # build target with two leading underscores (__).
2685 # @param [out] SOURCES List of absolute source paths.
2686 # @param [in] ARGN Input file paths and/or globbing expressions.
2687 #
2688 # @sa basis_add_executable()
2689 # @sa basis_add_library()
2690 function (basis_add_glob_target TARGET_UID SOURCES)
2691  # prepare globbing expressions
2692  # make paths absolute and turn directories into recursive globbing expressions
2693  set (EXPRESSIONS)
2694  foreach (EXPRESSION IN LISTS ARGN)
2695  if (NOT EXPRESSION MATCHES "^\\$<") # preserve generator expressions
2696  if (NOT IS_ABSOLUTE "${EXPRESSION}")
2697  # prefer configured/generated files in the build tree, but disallow
2698  # globbing within the build tree; glob only files in source tree
2699  if (NOT EXPRESSION MATCHES "[*?]|\\[[0-9]+-[0-9]+\\]" AND
2700  EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}" AND
2701  NOT IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}")
2702  set (EXPRESSION "${CMAKE_CURRENT_BINARY_DIR}/${EXPRESSION}")
2703  else ()
2704  set (EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/${EXPRESSION}")
2705  endif ()
2706  endif ()
2707  if (IS_DIRECTORY "${EXPRESSION}")
2708  set (EXPRESSION "${EXPRESSION}/**")
2709  endif ()
2710  endif ()
2711  list (APPEND EXPRESSIONS "${EXPRESSION}")
2712  endforeach ()
2713  # only if at least one globbing expression is given we need to go through this hassle
2714  if (EXPRESSIONS MATCHES "[*?]|\\[[0-9]+-[0-9]+\\]")
2715  set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}.dir")
2716  set (SOURCES_FILE "${BUILD_DIR}/sources.txt")
2717  # get initial list of source files
2718  execute_process (
2719  COMMAND "${CMAKE_COMMAND}"
2720  "-DEXPRESSIONS:STRING=${EXPRESSIONS}"
2721  "-DINIT:BOOLEAN=TRUE"
2722  "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}"
2723  -P "${BASIS_MODULE_PATH}/glob.cmake"
2724  RESULT_VARIABLE RETVAL
2725  )
2726  if (NOT RETVAL EQUAL 0 OR NOT EXISTS "${SOURCES_FILE}")
2727  message (FATAL_ERROR "Target ${TARGET_UID}: Failed to glob source files!")
2728  endif ()
2729  # note that including this file here, which is modified whenever a
2730  # source file is added or removed, triggers a re-configuration of the
2731  # build system which is required to re-execute this function.
2732  include ("${SOURCES_FILE}")
2733  set (${SOURCES} "${INITIAL_SOURCES}" PARENT_SCOPE)
2734  # add custom target to re-glob files before each build
2735  set (ERRORMSG "You have either added, removed, or renamed a source file which"
2736  " matches one of the globbing expressions specified for the"
2737  " list of source files from which to build the ${TARGET_UID} target."
2738  " Therefore, the build system must be re-configured. Either try to"
2739  " build again which should trigger CMake and re-configure the build"
2740  " system or run CMake manually.")
2741  basis_list_to_string (ERRORMSG ${ERRORMSG})
2742  add_custom_target (
2743  __${TARGET_UID}
2744  COMMAND "${CMAKE_COMMAND}"
2745  "-DEXPRESSIONS:STRING=${EXPRESSIONS}"
2746  "-DINIT:BOOLEAN=FALSE"
2747  "-DSOURCES_FILE:FILEPATH=${SOURCES_FILE}"
2748  "-DERRORMSG:STRING=${ERRORMSG}"
2749  -P "${BASIS_MODULE_PATH}/glob.cmake"
2750  COMMENT "Checking if source files for target ${TARGET_UID} were added or removed"
2751  VERBATIM
2752  )
2753  # otherwise, just return the given absolute source file paths
2754  else ()
2755  set (${SOURCES} "${EXPRESSIONS}" PARENT_SCOPE)
2756  endif ()
2757 endfunction ()
2758 
2759 # ----------------------------------------------------------------------------
2760 ## @brief Detect programming language of given source code files.
2761 #
2762 # This function determines the programming language in which the given source
2763 # code files are written. If no common programming language could be determined,
2764 # "AMBIGUOUS" is returned. If none of the following programming languages
2765 # could be determined, "UNKNOWN" is returned: CXX (i.e., C++), JAVA, MATLAB,
2766 # PYTHON, JYTHON, PERL, BASH, BATCH.
2767 #
2768 # @param [out] LANGUAGE Detected programming language.
2769 # @param [in] ARGN List of source code files.
2770 function (basis_get_source_language LANGUAGE)
2771  set (LANGUAGE_OUT)
2772  # iterate over source files
2773  foreach (SOURCE_FILE ${ARGN})
2774  # skip generator expressions
2775  if (NOT SOURCE_FILE MATCHES "^\\$<")
2776  get_filename_component (SOURCE_FILE "${SOURCE_FILE}" ABSOLUTE)
2777 
2778  if (IS_DIRECTORY "${SOURCE_FILE}")
2779 
2780  file (GLOB_RECURSE SOURCE_FILES "${SOURCE_FILE}/*")
2781  list (APPEND ARGN ${SOURCE_FILES})
2782 
2783  else ()
2784 
2785  # ------------------------------------------------------------------------
2786  # determine language based on extension for those without shebang
2787  set (LANG)
2788  # C++
2789  if (SOURCE_FILE MATCHES "\\.(c|cc|cpp|cxx|h|hh|hpp|hxx|txx|inl)(\\.in)?$")
2790  set (LANG "CXX")
2791  # Java
2792  elseif (SOURCE_FILE MATCHES "\\.java(\\.in)?$")
2793  set (LANG "JAVA")
2794  # MATLAB
2795  elseif (SOURCE_FILE MATCHES "\\.m(\\.in)?$")
2796  set (LANG "MATLAB")
2797  endif ()
2798 
2799  # ------------------------------------------------------------------------
2800  # determine language from shebang directive
2801  #
2802  # Note that some scripting languages may use identical file name extensions.
2803  # This is in particular the case for Python and Jython. The only way we
2804  # can distinguish these two is by looking at the shebang directive.
2805  if (NOT LANG)
2806 
2807  if (NOT EXISTS "${SOURCE_FILE}" AND EXISTS "${SOURCE_FILE}.in")
2808  set (SOURCE_FILE "${SOURCE_FILE}.in")
2809  endif ()
2810  if (EXISTS "${SOURCE_FILE}")
2811  file (STRINGS "${SOURCE_FILE}" FIRST_LINE LIMIT_COUNT 1)
2812  if (FIRST_LINE MATCHES "^#!")
2813  if (FIRST_LINE MATCHES "^#! */usr/bin/env +([^ ]+)")
2814  set (INTERPRETER "${CMAKE_MATCH_1}")
2815  elseif (FIRST_LINE MATCHES "^#! *([^ ]+)")
2816  set (INTERPRETER "${CMAKE_MATCH_1}")
2817  get_filename_component (INTERPRETER "${INTERPRETER}" NAME)
2818  else ()
2819  set (INTERPRETER)
2820  endif ()
2821  if (INTERPRETER MATCHES "^(python|jython|perl|bash)$")
2822  string (TOUPPER "${INTERPRETER}" LANG)
2823  endif ()
2824  endif ()
2825  endif ()
2826  endif ()
2827 
2828  # ------------------------------------------------------------------------
2829  # determine language from further known extensions
2830  if (NOT LANG)
2831  # Python
2832  if (SOURCE_FILE MATCHES "\\.py(\\.in)?$")
2833  set (LANG "PYTHON")
2834  # Perl
2835  elseif (SOURCE_FILE MATCHES "\\.(pl|pm|t)(\\.in)?$")
2836  set (LANG "PERL")
2837  # BASH
2838  elseif (SOURCE_FILE MATCHES "\\.sh(\\.in)?$")
2839  set (LANG "BASH")
2840  # Batch
2841  elseif (SOURCE_FILE MATCHES "\\.bat(\\.in)?$")
2842  set (LANG "BATCH")
2843  # unknown
2844  else ()
2845  set (LANGUAGE_OUT "UNKNOWN")
2846  break ()
2847  endif ()
2848  endif ()
2849 
2850  # ------------------------------------------------------------------------
2851  # detect ambiguity
2852  if (LANGUAGE_OUT AND NOT "^${LANG}$" STREQUAL "^${LANGUAGE_OUT}$")
2853  if (LANGUAGE_OUT MATCHES "CXX" AND LANG MATCHES "MATLAB")
2854  # MATLAB Compiler can handle this...
2855  elseif (LANGUAGE_OUT MATCHES "MATLAB" AND LANG MATCHES "CXX")
2856  set (LANG "MATLAB") # language stays MATLAB
2857  elseif (LANGUAGE_OUT MATCHES "PYTHON" AND LANG MATCHES "JYTHON")
2858  # Jython can deal with Python scripts/modules
2859  elseif (LANGUAGE_OUT MATCHES "JYTHON" AND LANG MATCHES "PYTHON")
2860  set (LANG "JYTHON") # language stays JYTHON
2861  else ()
2862  # ambiguity
2863  set (LANGUAGE_OUT "AMBIGUOUS")
2864  break ()
2865  endif ()
2866  endif ()
2867 
2868  # update current language
2869  set (LANGUAGE_OUT "${LANG}")
2870  endif ()
2871  endif ()
2872  endforeach ()
2873  # return
2874  if (LANGUAGE_OUT)
2875  set (${LANGUAGE} "${LANGUAGE_OUT}" PARENT_SCOPE)
2876  else ()
2877  message (FATAL_ERROR "basis_get_source_language called without arguments!")
2878  endif ()
2879 endfunction ()
2880 
2881 # ----------------------------------------------------------------------------
2882 ## @brief Configure .in source files.
2883 #
2884 # This function configures each source file in the given argument list with
2885 # a .in file name suffix and stores the configured file in the build tree
2886 # with the same relative directory as the template source file itself.
2887 # The first argument names the CMake variable of the list of configured
2888 # source files where each list item is the absolute file path of the
2889 # corresponding (configured) source file.
2890 #
2891 # @param [out] LIST_NAME Name of output list.
2892 # @param [in] ARGN These arguments are parsed and the following
2893 # options recognized. All remaining arguments are
2894 # considered to be source file paths.
2895 # @par
2896 # <table border="0">
2897 # <tr>
2898 # @tp @b BINARY_DIRECTORY @endtp
2899 # <td>Explicitly specify directory in build tree where configured
2900 # source files should be written to.</td>
2901 # </tr>
2902 # <tr>
2903 # @tp @b KEEP_DOT_IN_SUFFIX @endtp
2904 # <td>By default, after a source file with the .in extension has been
2905 # configured, the .in suffix is removed from the file name.
2906 # This can be omitted by giving this option.</td>
2907 # </tr>
2908 # </table>
2909 #
2910 # @returns Nothing.
2911 function (basis_configure_sources LIST_NAME)
2912  # parse arguments
2913  CMAKE_PARSE_ARGUMENTS (ARGN "KEEP_DOT_IN_SUFFIX" "BINARY_DIRECTORY" "" ${ARGN})
2914 
2915  # ensure that specified BINARY_DIRECTORY is inside build tree of project
2916  if (ARGN_BINARY_DIRECTORY)
2917  get_filename_component (_binpath "${ARGN_BINARY_DIRECTORY}" ABSOLUTE)
2918  file (RELATIVE_PATH _relpath "${PROJECT_BINARY_DIR}" "${_binpath}")
2919  if (_relpath MATCHES "^\\.\\./")
2920  message (FATAL_ERROR "Specified BINARY_DIRECTORY must be inside the build tree!")
2921  endif ()
2922  unset (_binpath)
2923  unset (_relpath)
2924  endif ()
2925 
2926  # configure source files
2927  set (CONFIGURED_SOURCES)
2928  foreach (SOURCE ${ARGN_UNPARSED_ARGUMENTS})
2929  # The .in suffix is optional, add it here if a .in file exists for this
2930  # source file, but only if the source file itself does not name an actually
2931  # existing source file.
2932  #
2933  # If the source file path is relative, prefer possibly already configured
2934  # sources in build tree such as the test driver source file created by
2935  # create_test_sourcelist() or a manual use of configure_file().
2936  #
2937  # Note: Make path absolute, otherwise EXISTS check will not work!
2938  if (NOT IS_ABSOLUTE "${SOURCE}")
2939  if (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}")
2940  set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}")
2941  elseif (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in")
2942  set (SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE}.in")
2943  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}")
2944  set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}")
2945  elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in")
2946  set (SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.in")
2947  endif ()
2948  else ()
2949  if (NOT EXISTS "${SOURCE}" AND EXISTS "${SOURCE}.in")
2950  set (SOURCE "${SOURCE}.in")
2951  endif ()
2952  endif ()
2953  # configure source file if filename ends in .in suffix
2954  if (SOURCE MATCHES "\\.in$")
2955  # if binary directory was given explicitly, use it
2956  if (ARGN_BINARY_DIRECTORY)
2957  get_filename_component (SOURCE_NAME "${SOURCE}" NAME)
2958  if (NOT ARGN_KEEP_DOT_IN_SUFFIX)
2959  string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}")
2960  endif ()
2961  set (CONFIGURED_SOURCE "${ARGN_BINARY_DIRECTORY}/${SOURCE_NAME}")
2962  # otherwise,
2963  else ()
2964  # if source is in project's source tree use relative binary directory
2965  if ("^${SOURCE}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
2966  basis_get_relative_path (CONFIGURED_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}" "${SOURCE}")
2967  get_filename_component (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURED_SOURCE}" ABSOLUTE)
2968  if (NOT ARGN_KEEP_DOT_IN_SUFFIX)
2969  string (REGEX REPLACE "\\.in$" "" CONFIGURED_SOURCE "${CONFIGURED_SOURCE}")
2970  endif ()
2971  # otherwise, use current binary directory
2972  else ()
2973  get_filename_component (SOURCE_NAME "${SOURCE}" NAME)
2974  if (NOT ARGN_KEEP_DOT_IN_SUFFIX)
2975  string (REGEX REPLACE "\\.in$" "" SOURCE_NAME "${SOURCE_NAME}")
2976  endif ()
2977  set (CONFIGURED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE_NAME}")
2978  endif ()
2979  endif ()
2980  # configure source file
2981  configure_file ("${SOURCE}" "${CONFIGURED_SOURCE}" @ONLY)
2982  if (BASIS_DEBUG)
2983  message ("** Configured source file with .in extension")
2984  endif ()
2985  # otherwise, skip configuration of this source file
2986  else ()
2987  set (CONFIGURED_SOURCE "${SOURCE}")
2988  if (BASIS_DEBUG)
2989  message ("** Skipped configuration of source file")
2990  endif ()
2991  endif ()
2992  if (BASIS_DEBUG)
2993  message ("** Source: ${SOURCE}")
2994  message ("** Configured source: ${CONFIGURED_SOURCE}")
2995  endif ()
2996  list (APPEND CONFIGURED_SOURCES "${CONFIGURED_SOURCE}")
2997  endforeach ()
2998  # return
2999  set (${LIST_NAME} "${CONFIGURED_SOURCES}" PARENT_SCOPE)
3000 endfunction ()
3001 
3002 # ----------------------------------------------------------------------------
3003 ## @brief Remove one blank line from top of string
3004 macro (basis_remove_blank_line STRVAR)
3005  if (${STRVAR} MATCHES "(^|(.*)\n)[ \t]*\n(.*)")
3006  set (${STRVAR} "${CMAKE_MATCH_1}${CMAKE_MATCH_3}")
3007  endif ()
3008 endmacro ()
3009 
3010 # ----------------------------------------------------------------------------
3011 ## @brief Configure and optionally compile script file.
3012 #
3013 # This function is used to configure script files during the build. It is
3014 # called by the build script generated by basis_add_script_target() for each script
3015 # target. It is also used to configure the modules of the packages
3016 # implemented in supported scripting languages which are located in the
3017 # @c PROJECT_LIBRARY_DIR of the source tree.
3018 #
3019 # In case of executable scripts, this function automatically prepends the
3020 # module search paths such that the modules of this software package are found
3021 # (and preferred in case of potential name conflicts with other packages).
3022 # Moreover, it adds (or replaces) the shebang directive on Unix such that the
3023 # configured interpreter version is used. On Windows, it converts the executable
3024 # script into a Windows Command instead which executes the proper interpreter
3025 # with the code section of the input script.
3026 #
3027 # @param [in] INPUT Input script file.
3028 # @param [in] OUTPUT Configured output script file.
3029 # @param [in] ARGN Optional arguments:
3030 # @par
3031 # <table border=0>
3032 # <tr>
3033 # @tp @b COMPILE @endtp
3034 # <td>Whether to compile module scripts if suitable, i.e., an intermediate
3035 # format exists for the specific scripting language. For example,
3036 # Python modules can be compiled.</td>
3037 # </tr>
3038 # @tp @b CONFIGURATION name @endtp
3039 # <td>Name of build configuration.</td>
3040 # </tr>
3041 # <tr>
3042 # @tp @b COPYONLY @endtp
3043 # <td>Whether to only copy the script file without replacing CMake variables
3044 # within the file. This option is passed on to CMake's configure_file()
3045 # command used to configure the script file. By default, the option
3046 # \@ONLY is used instead.</td>
3047 # </tr>
3048 # <tr>
3049 # @tp @b EXECUTABLE @endtp
3050 # <td>Specifies that the given script file is an executable script and not a
3051 # module script. Otherwise, if this option is not given and the output
3052 # file name contains a file name extension, the given script file is
3053 # configured as module script. A script file with an output file name
3054 # that has no extension, is always considered to be an executable.</td>
3055 # </tr>
3056 # <tr>
3057 # @tp @b DIRECTORY dir @endtp
3058 # <td>Build tree directory of configured script. By default, the directory
3059 # of the output script file is used to set the @c __DIR__ variable
3060 # used to make absolute file paths relative to the configured build
3061 # tree script file in the script configuration file
3062 # (see basis_set_script_path()).
3063 # </tr>
3064 # <tr>
3065 # @tp @b DESTINATION dir @endtp
3066 # <td>Installation directory for configured script. If this option is given,
3067 # the @c BUILD_INSTALL_SCRIPT variable is set to @c TRUE before including
3068 # any specified script configuration files (see @p CONFIG_FILE option).
3069 # Moreover, the @c __DIR__ variable is set to the specified directory.
3070 # Otherwise, if this option is omitted, the @c BUILD_INSTALL_SCRIPT variable
3071 # is set to @c FALSE instead and @c __DIR__ is set to the directory of
3072 # the configured @p OUTPUT file. Note that the @c BUILD_INSTALL_SCRIPT and
3073 # @c __DIR__ variables are in particular used by basis_set_script_path()
3074 # to convert the given paths to paths relative to the location of the
3075 # configured/installed script.</td>
3076 # </tr>
3077 # <tr>
3078 # @tp @b CACHE_FILE file1 [file2...] @endtp
3079 # <td>List of CMake files with dump of variables which should be included
3080 # before configuring the script. The cache files can be generated using
3081 # the basis_dump_variables() function.</td>
3082 # </tr>
3083 # <tr>
3084 # @tp @b CONFIG_FILE file1 [file2...] @endtp
3085 # <td>List of script configuration files to include before the configuration
3086 # of the script. See also the documentation of the @p DESTINATION option.</td>
3087 # </tr>
3088 # <tr>
3089 # @tp @b LINK_DEPENDS dep1 [dep2...] @endtp
3090 # <td>List of "link" dependencies, i.e., modules and script/module libraries
3091 # required by this script. For executable scripts, the paths to these
3092 # modules/packages is added to the module search path. If the prefix
3093 # "relative " is given before a file path, it is made relative to the
3094 # output/installation directory of the script file. All given input paths
3095 # must be absolute, however, as the relative location depends on
3096 # whether the script will be installed, i.e., the @c DESTINATION
3097 # is specified, or not.</td>
3098 # </tr>
3099 # </table>
3100 function (basis_configure_script INPUT OUTPUT)
3101  # rename arguments to avoid conflict with script configuration
3102  set (_INPUT_FILE "${INPUT}")
3103  set (_OUTPUT_FILE "${OUTPUT}")
3104  # --------------------------------------------------------------------------
3105  # parse arguments
3106  CMAKE_PARSE_ARGUMENTS (
3107  ARGN
3108  "COMPILE;COPYONLY;EXECUTABLE"
3109  "DIRECTORY;DESTINATION;LANGUAGE;CONFIGURATION"
3110  "CACHE_FILE;CONFIG_FILE;LINK_DEPENDS"
3111  ${ARGN}
3112  )
3113  if (ARGN_UNPARSED_ARGUMENTS)
3114  message (FATAL_ERROR "Unrecognized arguments given: ${ARGN_UNPARSED_ARGUMENTS}")
3115  endif ()
3116  if (NOT ARGN_LANGUAGE)
3117  basis_get_source_language (ARGN_LANGUAGE "${_INPUT_FILE}")
3118  endif ()
3119  # --------------------------------------------------------------------------
3120  # include cache files
3121  foreach (_F IN LISTS ARGN_CACHE_FILE)
3122  get_filename_component (_F "${_F}" ABSOLUTE)
3123  if (NOT EXISTS "${_F}")
3124  message (FATAL_ERROR "Cache file ${_F} does not exist!")
3125  endif ()
3126  include ("${_F}")
3127  endforeach ()
3128  # --------------------------------------------------------------------------
3129  # general variables for use in scripts and those intended for use in script
3130  # configurations. The __DIR__ is in particular used by basis_set_script_path()
3131  # to make absolute paths relative to the script file location
3132  if (ARGN_DESTINATION)
3133  if (NOT IS_ABSOLUTE "${ARGN_DESTINATION}")
3134  set (ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}/${ARGN_DESTINATION}")
3135  endif ()
3136  set (BUILD_INSTALL_SCRIPT TRUE)
3137  set (__DIR__ "${ARGN_DESTINATION}")
3138  else ()
3139  set (BUILD_INSTALL_SCRIPT FALSE)
3140  if (ARGN_DIRECTORY)
3141  if (NOT IS_ABSOLUTE "${ARGN_DIRECTORY}")
3142  message (FATAL_ERROR "Build tree script DIRECTORY must be an absolute path")
3143  endif ()
3144  set (__DIR__ "${ARGN_DIRECTORY}")
3145  string (REPLACE "$<${BASIS_GE_CONFIG}>" "${ARGN_CONFIGURATION}" __DIR__ "${__DIR__}")
3146  else ()
3147  get_filename_component (__DIR__ "${_OUTPUT_FILE}" PATH)
3148  endif ()
3149  endif ()
3150  get_filename_component (__NAME__ "${_OUTPUT_FILE}" NAME)
3151  set (__FILE__ "${__DIR__}/${__NAME__}")
3152  set (__CONFIG__ "${ARGN_CONFIGURATION}")
3153  # --------------------------------------------------------------------------
3154  # replace $<CONFIG> (deprecated $<CONFIGURATION>) in paths of link dependencies
3155  string (REPLACE "$<${BASIS_GE_CONFIG}>" "${ARGN_CONFIGURATION}" ARGN_LINK_DEPENDS "${ARGN_LINK_DEPENDS}")
3156  # --------------------------------------------------------------------------
3157  # include script configuration files
3158  foreach (_F IN LISTS ARGN_CONFIG_FILE)
3159  get_filename_component (_F "${_F}" ABSOLUTE)
3160  if (NOT EXISTS "${_F}")
3161  message (FATAL_ERROR "Script configuration file ${_F} does not exist!")
3162  endif ()
3163  include ("${_F}")
3164  endforeach ()
3165  # --------------------------------------------------------------------------
3166  # configure executable script
3167  if (ARGN_EXECUTABLE)
3168  # Attention: Every line of code added/removed will introduce a mismatch
3169  # between error messages of the interpreter and the original
3170  # source file. To not confuse/mislead developers too much,
3171  # keep number of lines added/removed at a minimum or at least
3172  # try to balance the number of lines added and removed.
3173  # Moreover, blank lines can be used to insert code without
3174  # changing the number of source code lines.
3175  file (READ "${_INPUT_FILE}" SCRIPT)
3176  # (temporarily) remove existing shebang directive
3177  file (STRINGS "${_INPUT_FILE}" FIRST_LINE LIMIT_COUNT 1)
3178  if (FIRST_LINE MATCHES "^#!")
3179  basis_sanitize_for_regex (FIRST_LINE_RE "${FIRST_LINE}")
3180  string (REGEX REPLACE "^${FIRST_LINE_RE}\n?" "" SCRIPT "${SCRIPT}")
3181  set (SHEBANG "${FIRST_LINE}")
3182  endif ()
3183  # replace CMake variables used in script
3184  if (NOT ARGN_COPYONLY)
3185  string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY)
3186  endif ()
3187  # add code to set module search path
3188  if (ARGN_LANGUAGE MATCHES "[JP]YTHON")
3189  if (ARGN_LINK_DEPENDS)
3190  set (PYTHON_CODE "import sys; import os.path; __dir__ = os.path.dirname(os.path.realpath(__file__))")
3191  list (REVERSE ARGN_LINK_DEPENDS)
3192  foreach (DIR ${ARGN_LINK_DEPENDS})
3193  if (DIR MATCHES "^relative +(.*)$")
3194  basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}")
3195  endif ()
3196  if (DIR MATCHES "\\.(py|class)$")
3197  get_filename_component (DIR "${DIR}" PATH)
3198  endif ()
3199  if (IS_ABSOLUTE "${DIR}")
3200  set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath('${DIR}'))")
3201  else ()
3202  set (PYTHON_CODE "${PYTHON_CODE}; sys.path.insert(0, os.path.realpath(os.path.join(__dir__, '${DIR}')))")
3203  endif ()
3204  endforeach ()
3205  # insert extra Python code near top, but after any future statement
3206  # (http://docs.python.org/2/reference/simple_stmts.html#future)
3207  set (FUTURE_STATEMENTS)
3208  if (SCRIPT MATCHES "^(.*from[ \t]+__future__[ \t]+import[ \t]+[a-z_]+[^\n]*\n)(.*)$")
3209  set (FUTURE_STATEMENTS "${CMAKE_MATCH_1}")
3210  set (SCRIPT "${CMAKE_MATCH_2}")
3211  endif ()
3212  basis_remove_blank_line (SCRIPT) # remove a blank line therefore
3213  set (SCRIPT "${FUTURE_STATEMENTS}${PYTHON_CODE} # <-- added by BASIS\n${SCRIPT}")
3214  endif ()
3215  elseif (ARGN_LANGUAGE MATCHES "PERL")
3216  if (ARGN_LINK_DEPENDS)
3217  set (PERL_CODE "use Cwd qw(realpath); use File::Basename;")
3218  foreach (DIR ${ARGN_LINK_DEPENDS})
3219  if (DIR MATCHES "^relative +(.*)$")
3220  basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}")
3221  endif ()
3222  if (DIR MATCHES "\\.pm$")
3223  get_filename_component (DIR "${DIR}" PATH)
3224  endif ()
3225  if (IS_ABSOLUTE "${DIR}")
3226  set (PERL_CODE "${PERL_CODE} use lib '${DIR}';")
3227  else ()
3228  set (PERL_CODE "${PERL_CODE} use lib dirname(realpath(__FILE__)) . '/${DIR}';")
3229  endif ()
3230  endforeach ()
3231  basis_remove_blank_line (SCRIPT) # remove a blank line therefore
3232  set (SCRIPT "${PERL_CODE} # <-- added by BASIS\n${SCRIPT}")
3233  endif ()
3234  elseif (ARGN_LANGUAGE MATCHES "BASH")
3235  basis_library_prefix (PREFIX BASH)
3236  # In case of Bash, set BASIS_BASH_UTILITIES which is required to first source the
3237  # BASIS utilities modules (in particular core.sh). This variable should be set to
3238  # the utilities.sh module of BASIS by default as part of the BASIS installation
3239  # (environment variable) and is here set to the project-specific basis.sh module.
3240  #
3241  # Note that folks at SBIA may submit a Bash script directly to a batch queuing
3242  # system such as the Oracle Grid Engine (SGE) instead of writing a separate submit
3243  # script. To avoid not finding the BASIS utilities in this case only because the
3244  # Bash file was copied by SGE to a temporary file, consider the <PROJECT>_DIR
3245  # environment variable as an alternative.
3246  set (BASH_CODE
3247 # Note: Code formatted such that it can be on single line. Use no comments within!
3248 "__FILE__=\"$(cd -P -- \"$(dirname -- \"$BASH_SOURCE\")\" && pwd -P)/$(basename -- \"$BASH_SOURCE\")\"
3249 if [[ -n \"$SGE_ROOT\" ]] && [[ $__FILE__ =~ $SGE_ROOT/.* ]] && [[ -n \"\${${PROJECT_NAME}_DIR}\" ]] && [[ -f \"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\" ]]
3250 then __FILE__=\"\${${PROJECT_NAME}_DIR}/bin/${__NAME__}\"
3251 fi
3252 i=0
3253 lnk=\"$__FILE__\"
3254 while [[ -h \"$lnk\" ]] && [[ $i -lt 100 ]]
3255 do dir=`dirname -- \"$lnk\"`
3256 lnk=`readlink -- \"$lnk\"`
3257 lnk=`cd \"$dir\" && cd $(dirname -- \"$lnk\") && pwd`/`basename -- \"$lnk\"`
3258 let i++
3259 done
3260 [[ $i -lt 100 ]] && __FILE__=\"$lnk\"
3261 unset -v i dir lnk
3262 __DIR__=\"$(dirname -- \"$__FILE__\")\"
3263 BASIS_BASH_UTILITIES=\"$__DIR__/${BASH_LIBRARY_DIR}/${PREFIX}basis.sh\""
3264  )
3265  string (REPLACE "\n" "; " BASH_CODE "${BASH_CODE}")
3266  # set BASHPATH which is used by import() function provided by core.sh module of BASIS
3267  set (BASHPATH)
3268  foreach (DIR ${ARGN_LINK_DEPENDS})
3269  if (DIR MATCHES "^relative +(.*)$")
3270  basis_get_relative_path (DIR "${__DIR__}" "${CMAKE_MATCH_1}")
3271  endif ()
3272  if (DIR MATCHES "\\.sh$")
3273  get_filename_component (DIR "${DIR}" PATH)
3274  endif ()
3275  if (IS_ABSOLUTE "${DIR}")
3276  list (APPEND BASHPATH "${DIR}")
3277  else ()
3278  list (APPEND BASHPATH "$__DIR__/${DIR}")
3279  endif ()
3280  endforeach ()
3281  if (BASHPATH)
3282  list (REMOVE_DUPLICATES BASHPATH)
3283  list (APPEND BASHPATH "$BASHPATH")
3284  basis_list_to_delimited_string (BASHPATH ":" NOAUTOQUOTE ${BASHPATH})
3285  set (BASH_CODE "${BASH_CODE}; BASHPATH=\"${BASHPATH}\"")
3286  endif ()
3287  basis_remove_blank_line (SCRIPT) # remove a blank line therefore
3288  set (SCRIPT "${BASH_CODE} # <-- added by BASIS\n${SCRIPT}")
3289  endif ()
3290  # replace shebang directive
3291  if (PYTHON_EXECUTABLE AND ARGN_LANGUAGE MATCHES "PYTHON")
3292  if (WIN32)
3293  set (SHEBANG "@setlocal enableextensions & \"${PYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF")
3294  else ()
3295  set (SHEBANG "#! ${PYTHON_EXECUTABLE}")
3296  endif ()
3297  elseif (JYTHON_EXECUTABLE AND ARGN_LANGUAGE MATCHES "JYTHON")
3298  if (WIN32)
3299  set (SHEBANG "@setlocal enableextensions & \"${JYTHON_EXECUTABLE}\" -x \"%~f0\" %* & goto :EOF")
3300  else ()
3301  # Attention: It is IMPORTANT to not use "#! <interpreter>" even if the <interpreter>
3302  # is given as full path in case of jython. Otherwise, the Jython executable
3303  # fails to execute from within a Python script using the os.system(),
3304  # subprocess.popen(), subprocess.call() or similar function!
3305  # Don't ask me for an explanation, but possibly the used shell otherwise does
3306  # not recognize the shebang as being valid. Using /usr/bin/env helps out here,
3307  # -schuha
3308  set (SHEBANG "#! /usr/bin/env ${JYTHON_EXECUTABLE}")
3309  endif ()
3310  elseif (PERL_EXECUTABLE AND ARGN_LANGUAGE MATCHES "PERL")
3311  if (WIN32)
3312  set (SHEBANG "@goto = \"START_OF_BATCH\" ;\n@goto = ();")
3313  set (SCRIPT "${SCRIPT}\n\n__END__\n\n:\"START_OF_BATCH\"\n@\"${PERL_EXECUTABLE}\" -w -S \"%~f0\" %*")
3314  else ()
3315  set (SHEBANG "#! ${PERL_EXECUTABLE} -w")
3316  endif ()
3317  elseif (BASH_EXECUTABLE AND ARGN_LANGUAGE MATCHES "BASH")
3318  set (SHEBANG "#! ${BASH_EXECUTABLE}")
3319  endif ()
3320  # add (modified) shebang directive again
3321  if (SHEBANG)
3322  set (SCRIPT "${SHEBANG}\n${SCRIPT}")
3323  endif ()
3324  # write configured script
3325  file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}")
3326  # make script executable on Unix
3327  if (UNIX AND NOT ARGN_DESTINATION)
3328  execute_process (COMMAND /bin/chmod +x "${_OUTPUT_FILE}")
3329  endif ()
3330  # --------------------------------------------------------------------------
3331  # configure module script
3332  else ()
3333  # configure module - do not use configure_file() as it will not update the
3334  # file if nothing has changed. the update of the modification
3335  # time is however in particular required for the
3336  # configure_script.cmake build command which uses this
3337  # function to build script targets. otherwise, the custom
3338  # build command is reexecuted only because the output files
3339  # never appear to be more recent than the dependencies
3340  file (READ "${_INPUT_FILE}" SCRIPT)
3341  if (NOT ARGN_COPYONLY)
3342  string (CONFIGURE "${SCRIPT}" SCRIPT @ONLY)
3343  endif ()
3344  file (WRITE "${_OUTPUT_FILE}" "${SCRIPT}")
3345  # compile module if requested
3346  if (ARGN_COMPILE)
3347  if (ARGN_LANGUAGE MATCHES "PYTHON" AND PYTHON_EXECUTABLE)
3348  basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" PYTHON)
3349  execute_process (COMMAND "${PYTHON_EXECUTABLE}" -E -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')")
3350  basis_compile_python_modules_for_jython (RV)
3351  if (RV)
3352  basis_get_compiled_jython_file_of_python_module (CFILE "${_OUTPUT_FILE}")
3353  get_filename_component (CDIR "${CFILE}" PATH)
3354  file (MAKE_DIRECTORY "${CDIR}")
3355  execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')")
3356  endif ()
3357  elseif (ARGN_LANGUAGE MATCHES "JYTHON" AND JYTHON_EXECUTABLE)
3358  basis_get_compiled_file (CFILE "${_OUTPUT_FILE}" JYTHON)
3359  execute_process (COMMAND "${JYTHON_EXECUTABLE}" -c "import py_compile; py_compile.compile('${_OUTPUT_FILE}', '${CFILE}')")
3360  endif ()
3361  endif ()
3362  endif ()
3363 endfunction ()
3364 
3365 # ----------------------------------------------------------------------------
3366 ## @brief Get type name of target.
3367 #
3368 # @param [out] TYPE The target's type name or NOTFOUND.
3369 # @param [in] TARGET_UID The UID of the target.
3370 function (_basis_get_target_type TYPE TARGET_UID)
3371  get_target_property (IMPORTED ${TARGET_UID} IMPORTED)
3372  if (IMPORTED)
3373  get_target_property (TYPE_OUT ${TARGET_UID} TYPE)
3374  else ()
3375  get_target_property (TYPE_OUT ${TARGET_UID} BASIS_TYPE)
3376  if (NOT TYPE_OUT)
3377  get_target_property (TYPE_OUT ${TARGET_UID} TYPE)
3378  endif ()
3379  endif ()
3380  set ("${TYPE}" "${TYPE_OUT}" PARENT_SCOPE)
3381 endfunction ()
3382 
3383 # ----------------------------------------------------------------------------
3384 ## @brief Get type name of target.
3385 #
3386 # @param [out] TYPE The target's type name or NOTFOUND.
3387 # @param [in] TARGET_NAME The name of the target.
3388 function (basis_get_target_type TYPE TARGET_NAME)
3389  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
3390  if (TARGET ${TARGET_UID})
3391  _basis_get_target_type(TYPE_OUT ${TARGET_UID})
3392  else ()
3393  set (TYPE_OUT "NOTFOUND")
3394  endif ()
3395  set ("${TYPE}" "${TYPE_OUT}" PARENT_SCOPE)
3396 endfunction ()
3397 
3398 # ----------------------------------------------------------------------------
3399 ## @brief Get location of build target output file(s).
3400 #
3401 # This convenience function can be used to get the full path of the output
3402 # file(s) generated by a given build target. It is similar to the read-only
3403 # @c LOCATION property of CMake targets and should be used instead of
3404 # reading this porperty. In case of scripted libraries, this function returns
3405 # the path of the root directory of the library that has to be added to the
3406 # module search path.
3407 #
3408 # @note If the target is a binary built from C++ source files and the CMake
3409 # generator is an IDE such as Visual Studio or Xcode, the absolute
3410 # directory of the target location ends with the generator expression
3411 # "/$<${BASIS_GE_CONFIG}>" which is to be substituted by the respective
3412 # build configuration.
3413 #
3414 # @param [out] VAR Path of build target output file.
3415 # @param [in] TARGET_NAME Name of build target.
3416 # @param [in] PART Which file name component of the @c LOCATION
3417 # property to return. See get_filename_component().
3418 # If POST_INSTALL_RELATIVE is given as argument,
3419 # @p VAR is set to the path of the installed file
3420 # relative to the installation prefix. Similarly,
3421 # POST_INSTALL sets @p VAR to the absolute path
3422 # of the installed file post installation.
3423 #
3424 # @returns Path of output file similar to @c LOCATION property of CMake targets.
3425 #
3426 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:LOCATION
3427 function (basis_get_target_location VAR TARGET_NAME PART)
3428  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
3429  if (TARGET "${TARGET_UID}")
3430  _basis_get_target_name (TARGET_NAME "${TARGET_UID}")
3431  _basis_get_target_type (TYPE "${TARGET_UID}")
3432  get_target_property (IMPORTED ${TARGET_UID} IMPORTED)
3433  # ------------------------------------------------------------------------
3434  # imported targets
3435  #
3436  # Note: This might not be required though as even custom executable
3437  # and library targets can be imported using CMake's
3438  # add_executable(<NAME> IMPORTED) and add_library(<NAME> <TYPE> IMPORTED)
3439  # commands. Such executable can, for example, also be a BASH
3440  # script built by basis_add_script().
3441  if (IMPORTED)
3442  # 1. Try IMPORTED_LOCATION_<CMAKE_BUILD_TYPE>
3443  if (CMAKE_BUILD_TYPE)
3444  string (TOUPPER "${CMAKE_BUILD_TYPE}" U)
3445  else ()
3446  set (U "NOCONFIG")
3447  endif ()
3448  get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${U})
3449  # 2. Try IMPORTED_LOCATION
3450  if (NOT LOCATION)
3451  get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION)
3452  endif ()
3453  # 3. Prefer Release over all other configurations
3454  if (NOT LOCATION)
3455  get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_RELEASE)
3456  endif ()
3457  # 4. Just use any of the imported configurations
3458  if (NOT LOCATION)
3459  get_property (CONFIGS TARGET ${TARGET_UID} PROPERTY IMPORTED_CONFIGURATIONS)
3460  foreach (C IN LISTS CONFIGS)
3461  string (TOUPPER "${C}" C)
3462  get_target_property (LOCATION ${TARGET_UID} IMPORTED_LOCATION_${C})
3463  if (LOCATION)
3464  break ()
3465  endif ()
3466  endforeach ()
3467  endif ()
3468  # make path relative to CMAKE_INSTALL_PREFIX if POST_INSTALL_RELATIVE given
3469  if (LOCATION AND ARGV2 MATCHES "POST_INSTALL_RELATIVE")
3470  file (RELATIVE_PATH LOCATION "${CMAKE_INSTALL_PREFIX}" "${LOCATION}")
3471  endif ()
3472  # ------------------------------------------------------------------------
3473  # non-imported targets
3474  else ()
3475  # Attention: The order of the matches/if cases matters here!
3476  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3477  # scripts
3478  if (TYPE MATCHES "^SCRIPT_(EXECUTABLE|MODULE)$")
3479  if (PART MATCHES "POST_INSTALL")
3480  get_target_property (DIRECTORY ${TARGET_UID} INSTALL_DIRECTORY)
3481  else ()
3482  get_target_property (DIRECTORY ${TARGET_UID} OUTPUT_DIRECTORY)
3483  if (DIRECTORY AND CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
3484  set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>")
3485  endif ()
3486  endif ()
3487  get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME)
3488  elseif (TYPE STREQUAL "^SCRIPT_MODULE$")
3489  if (PART MATCHES "POST_INSTALL")
3490  get_target_property (DIRECTORY ${TARGET_UID} INSTALL_DIRECTORY)
3491  else ()
3492  get_target_property (COMPILE ${TARGET_UID} COMPILE)
3493  get_target_property (DIRECTORY ${TARGET_UID} OUTPUT_DIRECTORY)
3494  if (DIRECTORY AND (COMPILE OR CMAKE_GENERATOR MATCHES "Visual Studio|Xcode"))
3495  set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>")
3496  endif ()
3497  endif ()
3498  get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME)
3499  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3500  # libraries
3501  elseif (TYPE MATCHES "LIBRARY|MODULE|MEX")
3502  if (TYPE MATCHES "STATIC")
3503  if (PART MATCHES "POST_INSTALL")
3504  get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_INSTALL_DIRECTORY)
3505  else ()
3506  get_target_property (DIRECTORY ${TARGET_UID} ARCHIVE_OUTPUT_DIRECTORY)
3507  endif ()
3508  get_target_property (FNAME ${TARGET_UID} ARCHIVE_OUTPUT_NAME)
3509  else ()
3510  if (PART MATCHES "POST_INSTALL")
3511  get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_INSTALL_DIRECTORY)
3512  else ()
3513  get_target_property (DIRECTORY ${TARGET_UID} LIBRARY_OUTPUT_DIRECTORY)
3514  endif ()
3515  get_target_property (FNAME ${TARGET_UID} LIBRARY_OUTPUT_NAME)
3516  endif ()
3517  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3518  # executables
3519  else ()
3520  if (PART MATCHES "POST_INSTALL")
3521  get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_INSTALL_DIRECTORY)
3522  else ()
3523  get_target_property (DIRECTORY ${TARGET_UID} RUNTIME_OUTPUT_DIRECTORY)
3524  endif ()
3525  get_target_property (FNAME ${TARGET_UID} RUNTIME_OUTPUT_NAME)
3526  endif ()
3527  if (DIRECTORY MATCHES "NOTFOUND")
3528  message (FATAL_ERROR "Failed to get directory of ${TYPE} ${TARGET_UID}!"
3529  " Check implementation of basis_get_target_location()"
3530  " and make sure that the required *INSTALL_DIRECTORY"
3531  " property is set on the target!")
3532  endif ()
3533  if (DIRECTORY)
3534  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3535  # get output name of built file (if applicable)
3536  if (NOT FNAME)
3537  get_target_property (FNAME ${TARGET_UID} OUTPUT_NAME)
3538  endif ()
3539  if (NOT "^${TYPE}$" STREQUAL "^SCRIPT_LIBRARY$")
3540  get_target_property (PREFIX ${TARGET_UID} PREFIX)
3541  get_target_property (SUFFIX ${TARGET_UID} SUFFIX)
3542  if (FNAME)
3543  set (TARGET_FILE "${FNAME}")
3544  else ()
3545  set (TARGET_FILE "${TARGET_NAME}")
3546  endif ()
3547  if (PREFIX)
3548  set (TARGET_FILE "${PREFIX}${TARGET_FILE}")
3549  endif ()
3550  if (SUFFIX)
3551  set (TARGET_FILE "${TARGET_FILE}${SUFFIX}")
3552  elseif (WIN32 AND "^${TYPE}$" STREQUAL "^EXECUTABLE$")
3553  set (TARGET_FILE "${TARGET_FILE}.exe")
3554  endif ()
3555  endif ()
3556  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3557  # prepend $<CONFIG> "generator expression" for non-custom binaries
3558  # when built with an IDE such as Visual Studio or Xcode
3559  if ("^${TYPE}$" STREQUAL "^EXECUTABLE$" OR "^${TYPE}$" STREQUAL "^LIBRARY$")
3560  if (NOT PART MATCHES "INSTALL")
3561  if (CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
3562  set (DIRECTORY "${DIRECTORY}/$<${BASIS_GE_CONFIG}>")
3563  endif ()
3564  endif ()
3565  endif ()
3566  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3567  # assemble final path
3568  if (PART MATCHES "POST_INSTALL_RELATIVE")
3569  if (IS_ABSOLUTE "${DIRECTORY}")
3570  file (RELATIVE_PATH DIRECTORY "${CMAKE_INSTALL_PREFIX}" "${DIRECTORY}")
3571  if (NOT DIRECTORY)
3572  set (DIRECTORY ".")
3573  endif ()
3574  endif ()
3575  elseif (PART MATCHES "POST_INSTALL")
3576  if (NOT IS_ABSOLUTE "${DIRECTORY}")
3577  set (DIRECTORY "${CMAKE_INSTALL_PREFIX}/${DIRECTORY}")
3578  endif ()
3579  endif ()
3580  if (TARGET_FILE)
3581  set (LOCATION "${DIRECTORY}/${TARGET_FILE}")
3582  else ()
3583  set (LOCATION "${DIRECTORY}")
3584  endif ()
3585  else ()
3586  set (LOCATION "${DIRECTORY}")
3587  endif ()
3588  endif ()
3589  # get filename component
3590  if (LOCATION AND PART MATCHES "(^|_)(PATH|NAME|NAME_WE)$")
3591  get_filename_component (LOCATION "${LOCATION}" "${CMAKE_MATCH_2}")
3592  endif ()
3593  else ()
3594  message (FATAL_ERROR "basis_get_target_location(): Unknown target ${TARGET_UID}")
3595  endif ()
3596  # return
3597  set ("${VAR}" "${LOCATION}" PARENT_SCOPE)
3598 endfunction ()
3599 
3600 # ----------------------------------------------------------------------------
3601 ## @brief Get link libraries/dependencies of (imported) target.
3602 #
3603 # This function recursively adds the dependencies of the dependencies as well
3604 # and returns them together with the list of the direct link dependencies.
3605 # Moreover, for script targets, if any of the dependencies uses the BASIS
3606 # utilities for the given language (@c BASIS_UTILITIES property), the
3607 # corresponding utilities library is added to the list of dependencies.
3608 # Note that therefore the BASIS utilities targets have to be added already,
3609 # which is only the case during the finalization of script targets.
3610 #
3611 # @param [out] LINK_DEPENDS List of all link dependencies. In case of scripts,
3612 # the dependencies are the required modules or
3613 # paths to required packages, respectively.
3614 # @param [in] TARGET_NAME Name of the target.
3615 function (basis_get_target_link_libraries LINK_DEPENDS TARGET_NAME)
3616  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
3617  if (NOT TARGET "${TARGET_UID}")
3618  message (FATAL_ERROR "basis_get_target_link_libraries(): Unknown target: ${TARGET_UID}")
3619  endif ()
3620  if (BASIS_DEBUG AND BASIS_VERBOSE)
3621  message ("** basis_get_target_link_libraries():")
3622  message ("** TARGET_NAME: ${TARGET_NAME}")
3623  message ("** CURRENT_DEPENDS: ${ARGN}")
3624  endif ()
3625  # get type of target
3626  get_target_property (BASIS_TYPE ${TARGET_UID} BASIS_TYPE)
3627  # get direct link dependencies of target
3628  get_target_property (IMPORTED ${TARGET_UID} IMPORTED)
3629  if (IMPORTED)
3630  # 1. Try IMPORTED_LINK_INTERFACE_LIBRARIES_<CMAKE_BUILD_TYPE>
3631  if (CMAKE_BUILD_TYPE)
3632  string (TOUPPER "${CMAKE_BUILD_TYPE}" U)
3633  else ()
3634  set (U "NOCONFIG")
3635  endif ()
3636  get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${U}")
3637  # 2. Try IMPORTED_LINK_INTERFACE_LIBRARIES
3638  if (NOT DEPENDS)
3639  get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES")
3640  endif ()
3641  # 3. Prefer Release over all other configurations
3642  if (NOT DEPENDS)
3643  get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE")
3644  endif ()
3645  # 4. Just use any of the imported configurations
3646  if (NOT DEPENDS)
3647  get_property (CONFIGS TARGET "${TARGET_UID}" PROPERTY IMPORTED_CONFIGURATIONS)
3648  foreach (C IN LISTS CONFIGS)
3649  get_target_property (DEPENDS ${TARGET_UID} "IMPORTED_LINK_INTERFACE_LIBRARIES_${C}")
3650  if (DEPENDS)
3651  break ()
3652  endif ()
3653  endforeach ()
3654  endif ()
3655  # otherwise, get LINK_DEPENDS property value
3656  elseif (BASIS_TYPE MATCHES "^EXECUTABLE$|^(SHARED|STATIC|MODULE)_LIBRARY$")
3657  get_target_property (DEPENDS ${TARGET_UID} BASIS_LINK_DEPENDS)
3658  else ()
3659  get_target_property (DEPENDS ${TARGET_UID} LINK_DEPENDS)
3660  endif ()
3661  if (NOT DEPENDS)
3662  set (DEPENDS)
3663  endif ()
3664  # prepend BASIS utilities if used (and added)
3665  if (BASIS_TYPE MATCHES "SCRIPT")
3666  set (BASIS_UTILITIES_TARGETS)
3667  foreach (UID IN ITEMS ${TARGET_UID} ${DEPENDS})
3668  if (TARGET "${UID}")
3669  get_target_property (BASIS_UTILITIES ${UID} BASIS_UTILITIES)
3670  get_target_property (LANGUAGE ${UID} LANGUAGE)
3671  if (BASIS_UTILITIES)
3672  set (BASIS_UTILITIES_TARGET)
3673  if (LANGUAGE MATCHES "[JP]YTHON")
3674  basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.py" NAME)
3675  elseif (LANGUAGE MATCHES "PERL")
3676  basis_get_source_target_name (BASIS_UTILITIES_TARGET "Basis.pm" NAME)
3677  elseif (LANGUAGE MATCHES "BASH")
3678  basis_get_source_target_name (BASIS_UTILITIES_TARGET "basis.sh" NAME)
3679  endif ()
3680  if (BASIS_UTILITIES_TARGET)
3681  basis_get_target_uid (BASIS_UTILITIES_TARGET ${BASIS_UTILITIES_TARGET})
3682  endif ()
3683  if (TARGET ${BASIS_UTILITIES_TARGET})
3684  list (APPEND BASIS_UTILITIES_TARGETS ${BASIS_UTILITIES_TARGET})
3685  endif ()
3686  endif ()
3687  endif ()
3688  endforeach ()
3689  if (BASIS_UTILITIES_TARGETS)
3690  list (INSERT DEPENDS 0 ${BASIS_UTILITIES_TARGETS})
3691  endif ()
3692  endif ()
3693  # convert target names to UIDs
3694  set (_DEPENDS)
3695  foreach (LIB IN LISTS DEPENDS)
3696  basis_get_target_uid (UID "${LIB}")
3697  if (TARGET ${UID})
3698  list (APPEND _DEPENDS "${UID}")
3699  else ()
3700  list (APPEND _DEPENDS "${LIB}")
3701  endif ()
3702  endforeach ()
3703  set (DEPENDS "${_DEPENDS}")
3704  unset (_DEPENDS)
3705  # recursively add link dependencies of dependencies
3706  # TODO implement it non-recursively for better performance
3707  foreach (LIB IN LISTS DEPENDS)
3708  if (TARGET ${LIB})
3709  list (FIND ARGN "${LIB}" IDX) # avoid recursive loop
3710  if (IDX EQUAL -1)
3711  basis_get_target_link_libraries (LIB_DEPENDS ${LIB} ${ARGN} ${DEPENDS})
3712  list (APPEND DEPENDS ${LIB_DEPENDS})
3713  endif ()
3714  endif ()
3715  endforeach ()
3716  # remove duplicate entries
3717  if (DEPENDS)
3718  list (REMOVE_DUPLICATES DEPENDS)
3719  endif ()
3720  # return
3721  set (${LINK_DEPENDS} "${DEPENDS}" PARENT_SCOPE)
3722 endfunction ()
3723 
3724 # ============================================================================
3725 # generator expressions
3726 # ============================================================================
3727 
3728 # ----------------------------------------------------------------------------
3729 ## @brief Process generator expressions in arguments.
3730 #
3731 # This command evaluates the $&lt;TARGET_FILE:tgt&gt; and related generator
3732 # expressions also for custom targets such as scripts and MATLAB Compiler
3733 # targets. For other generator expressions whose argument is a target name,
3734 # this function replaces the target name by the target UID, i.e., the actual
3735 # CMake target name such that the expression can be evaluated by CMake.
3736 # The following generator expressions are directly evaluated by this function:
3737 # <table border=0>
3738 # <tr>
3739 # @tp <b><tt>$&lt;TARGET_FILE:tgt&gt;</tt></b> @endtp
3740 # <td>Absolute file path of built target.</td>
3741 # </tr>
3742 # <tr>
3743 # @tp <b><tt>$&lt;TARGET_FILE_POST_INSTALL:tgt&gt;</tt></b> @endtp
3744 # <td>Absolute path of target file after installation using the
3745 # current @c CMAKE_INSTALL_PREFIX.</td>
3746 # </tr>
3747 # <tr>
3748 # @tp <b><tt>$&lt;TARGET_FILE_POST_INSTALL_RELATIVE:tgt&gt;</tt></b> @endtp
3749 # <td>Path of target file after installation relative to @c CMAKE_INSTALL_PREFIX.</td>
3750 # </tr>
3751 # </table>
3752 # Additionally, the suffix <tt>_NAME</tt> or <tt>_DIR</tt> can be appended
3753 # to the name of each of these generator expressions to get only the basename
3754 # of the target file including the extension or the corresponding directory
3755 # path, respectively.
3756 #
3757 # Generator expressions are in particular supported by basis_add_test().
3758 #
3759 # @param [out] ARGS Name of output list variable.
3760 # @param [in] ARGN List of arguments to process.
3761 #
3762 # @sa basis_add_test()
3763 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test
3764 function (basis_process_generator_expressions ARGS)
3765  set (ARGS_OUT)
3766  foreach (ARG IN LISTS ARGN)
3767  string (REGEX MATCHALL "\\$<.*TARGET.*:.*>" EXPRS "${ARG}")
3768  foreach (EXPR IN LISTS EXPRS)
3769  if (EXPR MATCHES "\\$<(.*):(.*)>")
3770  set (EXPR_NAME "${CMAKE_MATCH_1}")
3771  set (TARGET_NAME "${CMAKE_MATCH_2}")
3772  # TARGET_FILE* expression, including custom targets
3773  if (EXPR_NAME MATCHES "^TARGET_FILE(.*)")
3774  if (NOT CMAKE_MATCH_1)
3775  set (CMAKE_MATCH_1 "ABSOLUTE")
3776  endif ()
3777  string (REGEX REPLACE "^_" "" PART "${CMAKE_MATCH_1}")
3778  basis_get_target_location (ARG "${TARGET_NAME}" ${PART})
3779  # other generator expression supported by CMake
3780  # only replace target name, but do not evaluate expression
3781  else ()
3782  basis_get_target_uid (TARGET_UID "${CMAKE_MATCH_2}")
3783  string (REPLACE "${EXPR}" "$<${CMAKE_MATCH_1}:${TARGET_UID}>" ARG "${ARG}")
3784  endif ()
3785  if (BASIS_DEBUG AND BASIS_VERBOSE)
3786  message ("** basis_process_generator_expressions():")
3787  message ("** Expression: ${EXPR}")
3788  message ("** Keyword: ${EXPR_NAME}")
3789  message ("** Argument: ${TARGET_NAME}")
3790  message ("** Replaced by: ${ARG}")
3791  endif ()
3792  endif ()
3793  endforeach ()
3794  list (APPEND ARGS_OUT "${ARG}")
3795  endforeach ()
3796  set (${ARGS} "${ARGS_OUT}" PARENT_SCOPE)
3797 endfunction ()
3798 
3799 
3800 ##
3801 # @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.
3802 # For example, this is useful for adding relative paths to the end of a list of paths.
3803 #
3804 # @param OUTPUT_LIST Name of list that will be filled with appended names.
3805 # @param INPUT_LIST Name of list that contains items to have text appended.
3806 # @param ITEM_TO_APPEND text to append to each item in the input list.
3807 #
3808 function(basis_append_to_each OUTPUT_LIST INPUT_LIST ITEM_TO_APPEND)
3809  foreach(PATH IN LISTS ${INPUT_LIST})
3810  list(APPEND ${OUTPUT_LIST} ${PATH}${ITEM_TO_APPEND} )
3811  endforeach()
3812 
3813  if(${OUTPUT_LIST})
3814  set(${OUTPUT_LIST} ${${OUTPUT_LIST}} PARENT_SCOPE)
3815  endif()
3816 endfunction()
3817 
3818 
3819 ## @}
3820 # end of Doxygen group
cmake CMAKE_FIND_LIBRARY_SUFFIXES
Definition: FindGMock.cmake:80
cmake __BASIS_COMMONTOOLS_INCLUDED
option BASIS_DEBUG
Request debugging messages from BASIS functions.
macro find_package()
Overloaded find_package() command.
if(oldcoutbuf)