ProjectTools.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 ProjectTools.cmake
13 # @brief Definition of main project tools.
14 ##############################################################################
15 
16 
17 # ----------------------------------------------------------------------------
18 # include guard
20  return ()
21 else ()
23 endif ()
24 
25 
26 # ============================================================================
27 # basis_name_check
28 # ============================================================================
29 
30 # ---------------------------------------------------------------------------
31 ## @brief Check if a project name fits the BASIS standards.
32 #
33 macro (basis_name_check INPUT_PROJECT_NAME)
34  if (NOT ${INPUT_PROJECT_NAME} MATCHES "^[a-zA-Z][-+_a-zA-Z0-9]*$")
35  message (FATAL_ERROR "Invalid name: ${${INPUT_PROJECT_NAME}}\n"
36  "We suggest that you use upper CamelCase notation. "
37  "(see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms). "
38  "Please choose a name with either only captial letters "
39  "in the case of an acronym or a name with mixed case, "
40  "but starting with a (captial) letter.\n"
41  "Note that numbers, `-`, `+`, and `_` are allowed, "
42  "but not as first character.")
43  endif()
44 endmacro()
45 
46 # ============================================================================
47 # meta-data
48 # ============================================================================
49 
50 ## @brief Auxiliary macro used by basis_project_check_metadata.
51 #
52 # Used by basis_project_check_metadata to check the existence of each project
53 # source directory specified in the given list variable and to report an error
54 # otherwise. As a side effect, this macro makes all relative paths absolute
55 # with respect to PROJECT_SOURCE_DIR or sets the directory variable to the
56 # default value (ARGN).
58  if (${_VAR})
59  set (_PATHS)
60  foreach (_PATH IN LISTS ${_VAR})
61  if (NOT IS_ABSOLUTE "${_PATH}")
62  set (_PATH "${PROJECT_SOURCE_DIR}/${_PATH}")
63  endif ()
64  if (NOT IS_DIRECTORY "${_PATH}")
65  message (FATAL_ERROR "The ${_VAR} is set to the non-existing path\n\t${_PATH}\n"
66  "Check the basis_project() arguments and keep in mind that"
67  " relative paths have to be relative to the top-level directory"
68  " of the project or module, respectively, i.e.\n\t${PROJECT_SOURCE_DIR}\n")
69  endif ()
70  list (APPEND _PATHS "${_PATH}")
71  endforeach ()
72  set (${_VAR} "${_PATHS}")
73  unset (_PATHS)
74  unset (_PATH)
75  else ()
76  set (${_VAR} ${ARGN})
77  endif ()
78 endmacro ()
79 
80 # ----------------------------------------------------------------------------
81 ## @brief Check meta-data and set defaults.
82 #
83 # This command sets PROJECT_IS_SUBPROJECT and PROJECT_IS_SUBMODULE. A project
84 # is a (loosely coupled) "subproject" when it uses the SUBPROJECT option of
85 # basis_project to define the name of the subproject. It then also must specify
86 # the name of the PACKAGE this subproject belongs to. When a project uses the
87 # NAME option instead to declare its name, it can be either an independent
88 # project or a (tighly coupled) "submodule" of another project. A project is
89 # regarded a "submodule" when it is not a subproject but specifies a PACKAGE
90 # it belongs to. Otherwise, when a project has only a NAME but no PACKAGE,
91 # the PACKAGE name is set equal the project NAME and the project is regarded
92 # as neither a subproject nor a submodule. When either a subproject or submodule
93 # is built as part of a top-level project (usually the PACKAGE it belongs to),
94 # the CMake variable PROJECT_IS_MODULE is furthermore set to TRUE by the
95 # basis_add_module and basis_add_subdirectory command, respectively.
96 # The boolean PROJECT_IS_SUBPROJECT and PROJECT_IS_SUBMODULE variables are
97 # used by the BASIS commands to decide to which "namespace" the targets of a
98 # project belong to and what components to install.
99 #
100 # @sa basis_project()
101 # @sa basis_slicer_module()
103  # PROJECT_AUTHOR
104  if (PROJECT_AUTHORS AND PROJECT_AUTHOR)
105  message (FATAL_ERROR "Options AUTHOR and AUTHORS are mutually exclusive!")
106  endif ()
107  if (PROJECT_AUTHOR)
108  set (PROJECT_AUTHORS "${PROJECT_AUTHOR}")
109  endif ()
110  if (NOT PROJECT_AUTHORS AND PROJECT_IS_MODULE)
111  set (PROJECT_AUTHORS "${TOPLEVEL_PROJECT_AUTHORS}")
112  endif ()
113  if (NOT PROJECT_IS_MODULE)
114  set (TOPLEVEL_PROJECT_AUTHORS "${PROJECT_AUTHORS}")
115  endif ()
116  # PROJECT_NAME or PROJECT_SUBPROJECT
117  if (PROJECT_SUBPROJECT AND PROJECT_NAME)
118  message (FATAL_ERROR "Options SUBPROJECT and NAME are mutually exclusive!")
119  elseif (PROJECT_SUBPROJECT)
120  set (PROJECT_NAME "${PROJECT_SUBPROJECT}")
121  set (PROJECT_IS_SUBPROJECT TRUE)
122  else ()
123  set (PROJECT_IS_SUBPROJECT FALSE)
124  endif ()
125  unset (PROJECT_SUBPROJECT)
126  if (NOT PROJECT_NAME)
127  message (FATAL_ERROR "CMake BASIS variable PROJECT_NAME not specified!")
128  endif ()
129  basis_name_check(PROJECT_NAME)
130  string (TOLOWER "${PROJECT_NAME}" PROJECT_NAME_L)
131  string (TOUPPER "${PROJECT_NAME}" PROJECT_NAME_U)
132  basis_sanitize_for_regex(PROJECT_NAME_RE "${PROJECT_NAME}")
133  string (TOLOWER "${PROJECT_NAME_RE}" PROJECT_NAME_RE_L)
134  string (TOUPPER "${PROJECT_NAME_RE}" PROJECT_NAME_RE_U)
135  if (NOT PROJECT_IS_MODULE)
136  set (TOPLEVEL_PROJECT_NAME "${PROJECT_NAME}")
137  set (TOPLEVEL_PROJECT_NAME_L "${PROJECT_NAME_L}")
138  set (TOPLEVEL_PROJECT_NAME_U "${PROJECT_NAME_U}")
139  set (TOPLEVEL_PROJECT_NAME_RE "${PROJECT_NAME_RE}")
140  set (TOPLEVEL_PROJECT_NAME_RE_L "${PROJECT_NAME_RE_L}")
141  set (TOPLEVEL_PROJECT_NAME_RE_U "${PROJECT_NAME_RE_U}")
142  endif ()
143  # PROJECT_PACKAGE_NAME
144  if (PROJECT_PACKAGE AND PROJECT_PACKAGE_NAME)
145  message (FATAL_ERROR "Options PACKAGE_NAME and PACKAGE are mutually exclusive!")
146  endif ()
147  if (PROJECT_PACKAGE)
148  set (PROJECT_PACKAGE_NAME "${PROJECT_PACKAGE}")
149  endif ()
150  if (PROJECT_PACKAGE_NAME AND NOT PROJECT_IS_SUBPROJECT)
151  set (PROJECT_IS_SUBMODULE TRUE)
152  else ()
153  set (PROJECT_IS_SUBMODULE FALSE)
154  endif ()
155  if (NOT PROJECT_PACKAGE_NAME)
156  if (PROJECT_IS_MODULE)
157  set (PROJECT_PACKAGE_NAME "${TOPLEVEL_PROJECT_PACKAGE_NAME}")
158  else ()
159  if (PROJECT_IS_SUBPROJECT)
160  message (FATAL_ERROR "Missing PACKAGE_NAME option for SUBPROJECT ${PROJECT_NAME}!"
161  " Note that the PACKAGE_NAME option is required for subprojects"
162  " in order to enable the independent build. It should be"
163  " set to the name of the top-level project this subproject"
164  " belongs to. Otherwise, the subproject can only be build"
165  " as part of the package it belongs to.")
166  endif ()
167  set (PROJECT_PACKAGE_NAME "${PROJECT_NAME}")
168  endif ()
169  endif ()
170  basis_name_check(PROJECT_PACKAGE_NAME)
171  string (TOLOWER "${PROJECT_PACKAGE_NAME}" PROJECT_PACKAGE_NAME_L)
172  string (TOUPPER "${PROJECT_PACKAGE_NAME}" PROJECT_PACKAGE_NAME_U)
173  basis_sanitize_for_regex(PROJECT_PACKAGE_NAME_RE "${PROJECT_PACKAGE_NAME}")
174  string (TOLOWER "${PROJECT_PACKAGE_NAME_RE}" PROJECT_PACKAGE_NAME_RE_L)
175  string (TOUPPER "${PROJECT_PACKAGE_NAME_RE}" PROJECT_PACKAGE_NAME_RE_U)
176  if (NOT PROJECT_IS_MODULE)
177  set (TOPLEVEL_PROJECT_PACKAGE_NAME "${PROJECT_PACKAGE_NAME}")
178  set (TOPLEVEL_PROJECT_PACKAGE_NAME_L "${PROJECT_PACKAGE_NAME_L}")
179  set (TOPLEVEL_PROJECT_PACKAGE_NAME_U "${PROJECT_PACKAGE_NAME_U}")
180  set (TOPLEVEL_PROJECT_PACKAGE_NAME_RE "${PROJECT_PACKAGE_NAME_RE}")
181  set (TOPLEVEL_PROJECT_PACKAGE_NAME_RE_L "${PROJECT_PACKAGE_NAME_RE_L}")
182  set (TOPLEVEL_PROJECT_PACKAGE_NAME_RE_U "${PROJECT_PACKAGE_NAME_RE_U}")
183  endif ()
184  # PROJECT_PACKAGE_VENDOR
185  if (PROJECT_PROVIDER AND PROJECT_VENDOR AND PROJECT_PACKAGE_VENDOR)
186  message (FATAL_ERROR "Options PACKAGE_VENDOR, VENDOR, and PROVIDER (deprecated) are mutually exclusive!")
187  endif ()
188  if (PROJECT_PROVIDER)
189  message (WARNING "Option PROVIDER is deprecated and should be replaced by VENDOR!"
190  " Consider additionally the new options PROVIDER_NAME and DIVISION_NAME")
191  set (PROJECT_PACKAGE_VENDOR "${PROJECT_PROVIDER}")
192  endif ()
193  if (PROJECT_VENDOR)
194  set (PROJECT_PACKAGE_VENDOR "${PROJECT_VENDOR}")
195  endif ()
196  if (NOT PROJECT_PACKAGE_VENDOR AND PROJECT_IS_MODULE)
197  set (PROJECT_PACKAGE_VENDOR "${TOPLEVEL_PROJECT_PACKAGE_VENDOR}")
198  endif ()
199  string (TOLOWER "${PROJECT_PACKAGE_VENDOR}" PROJECT_PACKAGE_VENDOR_L)
200  string (TOUPPER "${PROJECT_PACKAGE_VENDOR}" PROJECT_PACKAGE_VENDOR_U)
201  if (NOT PROJECT_IS_MODULE)
202  set (TOPLEVEL_PROJECT_PACKAGE_VENDOR "${PROJECT_PACKAGE_VENDOR}")
203  set (TOPLEVEL_PROJECT_PACKAGE_VENDOR_L "${PROJECT_PACKAGE_VENDOR_L}")
204  set (TOPLEVEL_PROJECT_PACKAGE_VENDOR_U "${PROJECT_PACKAGE_VENDOR_U}")
205  endif ()
206  # PROJECT_PACKAGE_WEBSITE
207  if (PROJECT_WEBSITE AND PROJECT_PACKAGE_WEBSITE)
208  message (FATAL_ERROR "Options PACKAGE_WEBSITE and WEBSITE are mutually exclusive!")
209  endif ()
210  if (PROJECT_WEBSITE)
211  set (PROJECT_PACKAGE_WEBSITE "${PROJECT_WEBSITE}")
212  endif ()
213  if (PROJECT_IS_MODULE)
214  if (NOT PROJECT_PACKAGE_WEBSITE)
215  set (PROJECT_PACKAGE_WEBSITE "${TOPLEVEL_PROJECT_PACKAGE_WEBSITE}")
216  endif ()
217  else ()
218  set (TOPLEVEL_PROJECT_PACKAGE_WEBSITE "${PROJECT_PACKAGE_WEBSITE}")
219  endif ()
220  # PROJECT_PACKAGE_LOGO - see also basis_initialize_settings
221  if (PROJECT_IS_MODULE)
222  if (NOT PROJECT_PACKAGE_LOGO)
223  set (PROJECT_PACKAGE_LOGO "${TOPLEVEL_PROJECT_PACKAGE_LOGO}")
224  endif ()
225  else ()
226  set (TOPLEVEL_PROJECT_PACKAGE_LOGO "${PROJECT_PACKAGE_LOGO}")
227  endif ()
228  # PROJECT_PROVIDER_NAME
229  if (NOT PROJECT_PROVIDER_NAME AND PROJECT_IS_MODULE)
230  set (PROJECT_PROVIDER_NAME "${TOPLEVEL_PROJECT_PROVIDER_NAME}")
231  endif ()
232  string (TOLOWER "${PROJECT_PROVIDER_NAME}" PROJECT_PROVIDER_NAME_L)
233  string (TOUPPER "${PROJECT_PROVIDER_NAME}" PROJECT_PROVIDER_NAME_U)
234  if (NOT PROJECT_IS_MODULE)
235  set (TOPLEVEL_PROJECT_PROVIDER_NAME "${PROJECT_PROVIDER_NAME}")
236  set (TOPLEVEL_PROJECT_PROVIDER_NAME_L "${PROJECT_PROVIDER_NAME_L}")
237  set (TOPLEVEL_PROJECT_PROVIDER_NAME_U "${PROJECT_PROVIDER_NAME_U}")
238  endif ()
239  # PROJECT_PROVIDER_WEBSITE
240  if (PROJECT_IS_MODULE)
241  if (NOT PROJECT_PROVIDER_WEBSITE)
242  set (PROJECT_PROVIDER_WEBSITE "${TOPLEVEL_PROJECT_PROVIDER_WEBSITE}")
243  endif ()
244  else ()
245  set (TOPLEVEL_PROJECT_PROVIDER_WEBSITE "${PROJECT_PROVIDER_WEBSITE}")
246  endif ()
247  # PROJECT_PROVIDER_LOGO - see also basis_initialize_settings
248  if (PROJECT_IS_MODULE)
249  if (NOT PROJECT_PROVIDER_LOGO)
250  set (PROJECT_PROVIDER_LOGO "${TOPLEVEL_PROJECT_PROVIDER_LOGO}")
251  endif ()
252  else ()
253  set (TOPLEVEL_PROJECT_PROVIDER_LOGO "${PROJECT_PROVIDER_LOGO}")
254  endif ()
255  # PROJECT_DIVISION_NAME
256  if (NOT PROJECT_DIVISION_NAME AND PROJECT_IS_MODULE)
257  set (PROJECT_DIVISION_NAME "${TOPLEVEL_PROJECT_DIVISION_NAME}")
258  endif ()
259  string (TOLOWER "${PROJECT_DIVISION_NAME}" PROJECT_DIVISION_NAME_L)
260  string (TOUPPER "${PROJECT_DIVISION_NAME}" PROJECT_DIVISION_NAME_U)
261  if (NOT PROJECT_IS_MODULE)
262  set (TOPLEVEL_PROJECT_DIVISION_NAME "${PROJECT_DIVISION_NAME}")
263  set (TOPLEVEL_PROJECT_DIVISION_NAME_L "${PROJECT_DIVISION_NAME_L}")
264  set (TOPLEVEL_PROJECT_DIVISION_NAME_U "${PROJECT_DIVISION_NAME_U}")
265  endif ()
266  # PROJECT_DIVISION_WEBSITE
267  if (PROJECT_IS_MODULE)
268  if (NOT PROJECT_DIVISION_WEBSITE)
269  set (PROJECT_DIVISION_WEBSITE "${TOPLEVEL_PROJECT_DIVISION_WEBSITE}")
270  endif ()
271  else ()
272  set (TOPLEVEL_PROJECT_DIVISION_WEBSITE "${PROJECT_DIVISION_WEBSITE}")
273  endif ()
274  # PROJECT_DIVISION_LOGO - see also basis_initialize_settings
275  if (PROJECT_IS_MODULE)
276  if (NOT PROJECT_DIVISION_LOGO)
277  set (PROJECT_DIVISION_LOGO "${TOPLEVEL_PROJECT_DIVISION_LOGO}")
278  endif ()
279  else ()
280  set (TOPLEVEL_PROJECT_DIVISION_LOGO "${PROJECT_DIVISION_LOGO}")
281  endif ()
282  # PROJECT_SOVERSION -- **BEFORE** setting PROJECT_VERSION!
283  if ("^${PROJECT_SOVERSION}$" STREQUAL "^$")
284  if (PROJECT_IS_MODULE AND "^${PROJECT_VERSION}$" STREQUAL "^$")
285  set (PROJECT_SOVERSION "${TOPLEVEL_PROJECT_SOVERSION}")
286  endif ()
287  else ()
288  if (NOT PROJECT_SOVERSION MATCHES "^[0-9]+(\\.[0-9]+)?$")
289  message (FATAL_ERROR "Project ${PROJECT_NAME} has invalid API version: ${PROJECT_SOVERSION}!")
290  endif ()
291  if (NOT PROJECT_IS_MODULE)
292  set (TOPLEVEL_PROJECT_SOVERSION "${PROJECT_SOVERSION}")
293  endif ()
294  endif ()
295  # PROJECT_VERSION
296  if (NOT "^${PROJECT_VERSION}$" STREQUAL "^$")
297  if (NOT PROJECT_VERSION MATCHES "^[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(rc[0-9]+|[a-z])?$")
298  message (FATAL_ERROR "Project ${PROJECT_NAME} has invalid version: ${PROJECT_VERSION}!")
299  endif ()
300  if (PROJECT_IS_MODULE)
301  if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?$")
302  set (PROJECT_VERSION "${TOPLEVEL_PROJECT_VERSION}")
303  endif ()
304  else ()
305  set (TOPLEVEL_PROJECT_VERSION "${PROJECT_VERSION}")
306  endif ()
307  else ()
308  if (PROJECT_IS_MODULE)
309  set (PROJECT_VERSION "${TOPLEVEL_PROJECT_VERSION}")
310  else ()
311  message (FATAL_ERROR "Project version not specified!")
312  endif ()
313  endif ()
314  # PROJECT_DESCRIPTION
315  if (PROJECT_DESCRIPTION)
316  basis_list_to_string (PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
317  else ()
318  set (PROJECT_DESCRIPTION "")
319  endif ()
320  # PROJECT_COPYRIGHT
321  if (PROJECT_IS_MODULE)
322  if (NOT PROJECT_COPYRIGHT)
323  set (PROJECT_COPYRIGHT "${TOPLEVEL_PROJECT_COPYRIGHT}")
324  endif ()
325  else ()
326  set (TOPLEVEL_PROJECT_COPYRIGHT "${PROJECT_COPYRIGHT}")
327  endif ()
328  # PROJECT_LICENSE
329  if (PROJECT_IS_MODULE)
330  if (NOT PROJECT_LICENSE)
331  set (PROJECT_LICENSE "${TOPLEVEL_PROJECT_LICENSE}")
332  endif ()
333  else ()
334  set (TOPLEVEL_PROJECT_LICENSE "${PROJECT_LICENSE}")
335  endif ()
336  # PROJECT_CONTACT
337  if (PROJECT_IS_MODULE)
338  if (NOT PROJECT_CONTACT)
339  set (PROJECT_CONTACT "${TOPLEVEL_PROJECT_CONTACT}")
340  endif ()
341  else ()
342  set (TOPLEVEL_PROJECT_CONTACT "${PROJECT_CONTACT}")
343  endif ()
344  # PROJECT_LANGUAGES
345  if (PROJECT_IS_MODULE)
346  if (NOT PROJECT_LANGUAGES)
347  set (PROJECT_LANGUAGES "${TOPLEVEL_PROJECT_LANGUAGES}")
348  endif ()
349  else ()
350  if (NOT PROJECT_LANGUAGES)
351  set (PROJECT_LANGUAGES C CXX)
352  endif ()
353  set (TOPLEVEL_PROJECT_LANGUAGES "${PROJECT_LANGUAGES}")
354  endif ()
355  # PROJECT_DEFAULT_MODULES
356  if (PROJECT_IS_MODULE)
357  if (PROJECT_DEFAULT_MODULES)
358  message (FATAL_ERROR "Module ${PROJECT_NAME} specified DEFAULT_MODULES, but a module cannot have itself modules.")
359  else ()
360  set (PROJECT_DEFAULT_MODULES "${TOPLEVEL_PROJECT_DEFAULT_MODULES}")
361  endif ()
362  else ()
363  if (NOT PROJECT_DEFAULT_MODULES)
364  set (PROJECT_DEFAULT_MODULES "")
365  endif ()
366  set (TOPLEVEL_PROJECT_DEFAULT_MODULES "${PROJECT_DEFAULT_MODULES}")
367  endif ()
368  # PROJECT_EXTERNAL_MODULES
369  if (PROJECT_IS_MODULE)
370  if (PROJECT_EXTERNAL_MODULES)
371  message (FATAL_ERROR "Module ${PROJECT_NAME} specified EXTERNAL_MODULES, but a module cannot have itself modules.")
372  else ()
373  set (PROJECT_EXTERNAL_MODULES "${TOPLEVEL_PROJECT_EXTERNAL_MODULES}")
374  endif ()
375  else ()
376  if (NOT PROJECT_EXTERNAL_MODULES)
377  set (PROJECT_EXTERNAL_MODULES "")
378  endif ()
379  set (TOPLEVEL_PROJECT_EXTERNAL_MODULES "${PROJECT_EXTERNAL_MODULES}")
380  endif ()
381  # PROJECT_EXCLUDE_FROM_ALL
382  if (PROJECT_IS_MODULE)
383  if (NOT DEFINED PROJECT_EXCLUDE_FROM_ALL)
384  set (PROJECT_EXCLUDE_FROM_ALL FALSE)
385  endif ()
386  else ()
387  if (PROJECT_EXCLUDE_FROM_ALL)
388  message (FATAL_ERROR "EXCLUDE_FROM_ALL option only valid for project modules.")
389  endif ()
390  endif ()
391  # prefix used for CMake variables in <Pkg>[<Module>]Config.cmake (cf. GenerateConfig.cmake)
392  if (PROJECT_IS_SUBMODULE)
393  set (PROJECT_CONFIG_PREFIX "${PROJECT_PACKAGE_NAME}_${PROJECT_NAME}")
394  elseif (PROJECT_IS_MODULE OR PROJECT_IS_SUBPROJECT)
395  set (PROJECT_CONFIG_PREFIX "${PROJECT_NAME}")
396  else ()
397  set (PROJECT_CONFIG_PREFIX "${PROJECT_PACKAGE_NAME}")
398  endif ()
399  # source tree directories aliases
400  if (PROJECT_INCLUDE_DIR)
401  list (INSERT PROJECT_INCLUDE_DIRS 0 "${PROJECT_INCLUDE_DIR}")
402  endif ()
403  if (PROJECT_CODE_DIR)
404  list (INSERT PROJECT_CODE_DIRS 0 "${PROJECT_CODE_DIR}")
405  endif ()
406  if (PROJECT_TOOLS_DIR)
407  list (INSERT PROJECT_TOOLS_DIRS 0 "${PROJECT_TOOLS_DIR}")
408  endif ()
409  # source tree directories
410  basis_set_if_empty (PROJECT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
411  basis_check_or_set_source_paths (PROJECT_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include")
412  basis_check_or_set_source_paths (PROJECT_CODE_DIRS "${PROJECT_SOURCE_DIR}/src")
413  basis_check_or_set_source_paths (PROJECT_MODULES_DIR "${PROJECT_SOURCE_DIR}/modules")
414  basis_check_or_set_source_paths (PROJECT_TOOLS_DIRS "${PROJECT_SOURCE_DIR}/tools")
415  basis_check_or_set_source_paths (PROJECT_CONFIG_DIR "${PROJECT_SOURCE_DIR}/config")
416  basis_check_or_set_source_paths (PROJECT_DATA_DIR "${PROJECT_SOURCE_DIR}/data")
417  basis_check_or_set_source_paths (PROJECT_DOC_DIR "${PROJECT_SOURCE_DIR}/doc")
418  basis_check_or_set_source_paths (PROJECT_DOCRES_DIR "${PROJECT_DOC_DIR}/static")
419  basis_check_or_set_source_paths (PROJECT_EXAMPLE_DIR "${PROJECT_SOURCE_DIR}/example")
420  basis_check_or_set_source_paths (PROJECT_LIBRARY_DIR "${PROJECT_SOURCE_DIR}/lib")
421  basis_check_or_set_source_paths (PROJECT_TESTING_DIR "${PROJECT_SOURCE_DIR}/test")
422  # PROJECT_HAS_APPLICATIONS
423  set (PROJECT_HAS_APPLICATIONS FALSE)
424  foreach (DIR IN LISTS PROJECT_TOOLS_DIRS)
425  if (EXISTS "${DIR}/CMakeLists.txt")
426  set (PROJECT_HAS_APPLICATIONS TRUE)
427  break()
428  endif ()
429  endforeach ()
430  # extract main source code directories from lists
431  list (GET PROJECT_INCLUDE_DIRS 0 PROJECT_INCLUDE_DIR)
432  list (GET PROJECT_CODE_DIRS 0 PROJECT_CODE_DIR)
433  list (GET PROJECT_TOOLS_DIRS 0 PROJECT_TOOLS_DIR)
434  # make OTHER_DIRS paths absolute and append deprecated SUBDIRS argument
435  set (_OTHER_DIRS)
436  foreach (_PATH IN LISTS PROJECT_OTHER_DIRS PROJECT_SUBDIRS)
437  if (NOT IS_ABSOLUTE "${_PATH}")
438  set (_PATH "${PROJECT_SOURCE_DIR}/${_PATH}")
439  endif ()
440  list (APPEND _OTHER_DIRS "${_PATH}")
441  endforeach ()
442  set (PROJECT_OTHER_DIRS ${_OTHER_DIRS})
443  unset(PROJECT_SUBDIRS)
444  unset(_OTHER_DIRS)
445  unset(_PATH)
446  # let basis_project_begin() know that basis_project() was called
447  set (BASIS_basis_project_CALLED TRUE)
448 endmacro ()
449 
450 # ----------------------------------------------------------------------------
451 ## @brief Sets basic project information including the name, version, and dependencies.
452 #
453 # Any BASIS project has to call this macro in the file BasisProject.cmake
454 # located in the top level directory of the source tree in order to define
455 # the project attributes required by BASIS to setup the build system.
456 # Moreover, if the BASIS project is a module of another BASIS project, this
457 # file and the variables set by this macro are used by the top-level project to
458 # identify its modules and the dependencies among them.
459 #
460 # @param [in] ARGN This list is parsed for the following arguments:
461 #
462 # @par General project meta-data:
463 # @par
464 # <table border="0">
465 # <tr>
466 # @tp @b VERSION major[.minor[.patch]] @endtp
467 # <td>Project version string. (default: 1.0.0)
468 # @n
469 # The version number consists of three components: the major version number,
470 # the minor version number, and the patch number. The format of the version
471 # string is "<major>.<minor>.<patch>", where the minor version number and patch
472 # number default to "0" if not given. Only digits are allowed except of the two
473 # separating dots.
474 # @n
475 # - A change of the major version number indicates changes of the softwares
476 # @api (and @abi) and/or its behavior and/or the change or addition of major
477 # features.
478 # - A change of the minor version number indicates changes that are not only
479 # bug fixes and no major changes. Hence, changes of the @api but not the @abi.
480 # - A change of the patch number indicates changes only related to bug fixes
481 # which did not change the softwares @api. It is the least important component
482 # of the version number.
483 # </td>
484 # </tr>
485 # <tr>
486 # @tp @b SOVERSION major @endtp
487 # <td>Explicit SOVERSION of shared libraries, must be an integer.
488 # A value of 0 indicates that the API is yet unstable.
489 # (default: PROJECT_VERSION_MAJOR)</td>
490 # </tr>
491 # <tr>
492 # @tp @b DESCRIPTION description @endtp
493 # <td>Package description, used for packing. If multiple arguments are given,
494 # they are concatenated using one space character as delimiter.</td>
495 # </tr>
496 # <tr>
497 # @tp @b NAME name @endtp
498 # <td>The name of the project.</td>
499 # </tr>
500 # <tr>
501 # @tp @b SUBPROJECT name @endtp
502 # <td>Use this option instead of @c NAME to indicate that this project is a subproject
503 # of the package named by @c PACKAGE_NAME. This results, for example, in target
504 # UIDs such as "<package>.<name>.<target>" instead of "<package>.<target>".
505 # Moreover, the libraries and shared files of a subproject are installed
506 # in subdirectores whose name equals the name of the subproject. This option
507 # should only be used for projects which are modules of another BASIS project,
508 # where these modules should reside in their own sub-namespace rather than
509 # on the same level as the top-level project.</td>
510 # </tr>
511 # <tr>
512 # @tp @b PACKAGE_NAME name @endtp
513 # <td>Name of the package this project (module) belongs to. Defaults to the
514 # name of the (top-level) project. This option can further be used in case
515 # of a top-level project to specify a different package name for the installation.
516 # In case of a subproject which is a module of another BASIS project, setting
517 # the package name explicitly using this option enables the build of the
518 # subproject as separate project while preserving the directory structure
519 # and other namespace settings. Therefore, this option is required if the
520 # @c SUBPROJECT option is given and the project shall be build independently
521 # as stand-alone package. (default: name of top-level package)</td>
522 # </tr>
523 # <tr>
524 # @tp @b PACKAGE name @endtp
525 # <td>Short alternative for @c PACKAGE_NAME.</td>
526 # </tr>
527 # <tr>
528 # @tp @b PACKAGE_VENDOR name @endtp
529 # <td>Short ID of package vendor (i.e, provider and/or division acronym) this variable is used
530 # for package identification and is the name given to the folder that will be used as the default
531 # installation path location subdirectory.</td>
532 # </tr>
533 # <tr>
534 # @tp @b VENDOR name @endtp
535 # <td>Short alternative for @c PACKAGE_VENDOR.</td>
536 # </tr>
537 # <tr>
538 # @tp @b PACKAGE_WEBSITE url @endtp
539 # <td>URL of project website used for documentation and packaging.
540 # (default: project website of top-level project or empty string)</td>
541 # </tr>
542 # <tr>
543 # @tp @b PACKAGE_LOGO path @endtp
544 # <td>Path to package logo file for this installable package. Used in documentation and packaging.
545 # Relative paths must be relative to @c PROJECT_SOURCE_DIR.
546 # (default: empty string)</td>
547 # </tr>
548 # <tr>
549 # @tp @b WEBSITE url @endtp
550 # <td>Short alternative for @c PACKAGE_WEBSITE.</td>
551 # </tr>
552 # <tr>
553 # @tp @b PROVIDER_NAME name @endtp
554 # <td>The provider/vendor/creator of this package, used for packaging and installation.
555 # (default: provider of top-level project or empty string)</td>
556 # </tr>
557 # <tr>
558 # @tp @b PROVIDER_WEBSITE url @endtp
559 # <td>URL of provider website used for documentation and packaging.
560 # (default: provider website of top-level project or empty string)</td>
561 # </tr>
562 # <tr>
563 # @tp @b PROVIDER_LOGO path @endtp
564 # <td>Path to provider logo file used for documentation and packaging.
565 # Relative paths must be relative to @c PROJECT_SOURCE_DIR.
566 # (default: empty string)</td>
567 # </tr>
568 # <tr>
569 # @tp @b DIVISION_NAME name @endtp
570 # <td>The provider division of this package, used for packaging and installation.
571 # (default: provider division of top-level project or empty string)</td>
572 # </tr>
573 # <tr>
574 # @tp @b DIVISION_WEBSITE url @endtp
575 # <td>URL of provider division website used for documentation and packaging.
576 # (default: provider website of top-level project or empty string)</td>
577 # </tr>
578 # <tr>
579 # @tp @b DIVISION_LOGO path @endtp
580 # <td>Path to provider division logo file used for documentation and packaging.
581 # Relative paths must be relative to @c PROJECT_SOURCE_DIR.
582 # (default: empty string)</td>
583 # </tr>
584 # <tr>
585 # @tp @b LANGUAGES lang1 [lang2...] @endtp
586 # <td>Programming languages used by the project. For example, CXX for C++ or
587 # CXX-11 for C++11. When C++11 is used, the respective compiler flag
588 # such as -std=c++11 is added to the compile flags. Those languages supported
589 # by CMake itself are further passed on to CMake's project command.</td>
590 # </tr>
591 # <tr>
592 # @tp @b DEFAULT_MODULES module1 [module2...] @endtp
593 # <td>List of project modules that should be enabled by default.
594 # The single value "ALL" can be used to enable all modules.<.td>
595 # </tr>
596 # <tr>
597 # @tp @b EXTERNAL_MODULES module1 [module2...] @endtp
598 # <td>List of external project modules. Only required when directory of external
599 # modules may be empty (i.e., not contain a BasisProject.cmake file) as in
600 # case of an uninitialized Git submodule.<.td>
601 # </tr>
602 # <tr>
603 # @tp @b EXCLUDE_FROM_ALL @endtp
604 # <td>Exclude this project module from @c BUILD_ALL_MODULES.</td>
605 # </tr>
606 # <tr>
607 # @tp @b TEMPLATE path @endtp
608 # <td> The TEMPLATE variable stores the directory of the chosen project template along
609 # with the template version so that the correct template is used by basisproject when a project is updated.
610 # Note that this variable is used in BASIS itself to specify the default template to use for the BASIS
611 # installation, i.e., the default used by basisproject if no --template argument is provided.
612 # If the template is part of the BASIS installation, only the template name and version part of the
613 # full path are needed. Otherwise, the full absolute path is used. For example,
614 # @code
615 # basis_project (
616 # # ...
617 # TEMPLATE "sbia/1.8"
618 # # ...
619 # )
620 # # or
621 # basis_project (
622 # # ...
623 # TEMPLATE "/opt/local/share/custom-basis-template/1.0"
624 # # ...
625 # )
626 # @endcode
627 # The installed templates can be found in the share/templates folder of installed BASIS software,
628 # as well as the data/templates foler of the BASIS source tree.</td>
629 # </tr>
630 # </table>
631 #
632 # @par Project dependencies:
633 # Dependencies on other BASIS projects, which can be subprojects of the same
634 # BASIS top-level project, as well as dependencies on external packages such as ITK
635 # have to be defined here using the @p DEPENDS argument option. This will be used
636 # by a top-level project to ensure that the dependencies among its subprojects are
637 # resolved properly. For each external dependency, the BASIS functions
638 # basis_find_package() and basis_use_package() are invoked by
639 # basis_project_initialize(). If an external package is not CMake aware and
640 # additional CMake code shall be executed to include the settings of the external
641 # package (which is usually done in a so-called <tt>Use&lt;Pkg&gt;.cmake</tt> file
642 # if the package would be CMake aware), such code should be added to the
643 # <tt>Settings.cmake</tt> file of the project.
644 # @par
645 # <table border="0">
646 # <tr>
647 # @tp @b DEPENDS dep1 [dep2...] @endtp
648 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
649 # or names of external packages.</td>
650 # </tr>
651 # <tr>
652 # @tp @b OPTIONAL_DEPENDS dep1 [dep2...] @endtp
653 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
654 # or names of external packages which are used only if available.</td>
655 # </tr>
656 # <tr>
657 # @tp @b TOOLS_DEPENDS dep1 [dep2...] @endtp
658 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
659 # or names of external packages required when BUILD_APPLICATIONS is ON.</td>
660 # </tr>
661 # <tr>
662 # @tp @b OPTIONAL_TOOLS_DEPENDS dep1 [dep2...] @endtp
663 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
664 # or names of external packages which are used only if available
665 # when BUILD_APPLICATIONS is ON.</td>
666 # </tr>
667 # <tr>
668 # @tp @b TEST_DEPENDS dep1 [dep2...] @endtp
669 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
670 # or names of external packages which are only required by the tests.</td>
671 # </tr>
672 # <tr>
673 # @tp @b OPTIONAL_TEST_DEPENDS dep1 [dep2...] @endtp
674 # <td>List of dependencies, i.e., either names of other BASIS (sub)projects
675 # or names of external packages which are used only by the tests if available.</td>
676 # </tr>
677 # </table>
678 #
679 # @par Source tree layout:
680 # Relative directory paths have to be relative to the @c PROJECT_SOURCE_DIR, i.e.,
681 # the diretory containing the @c BasisProject.cmake file which calls this command.
682 # If any of the following arguments refer to non-existing directory paths,
683 # the respective paths are simply ignored during the project build configuration.
684 # In case of the paths passed to @p MODULE_DIRS, an error is raised if the directory
685 # does not exist or is missing a BasisProject.cmake file.
686 # @par
687 # <table border="0">
688 # <tr>
689 # @tp @b INCLUDE_DIRS path1 [path2...] @endtp
690 # <td>A list of directories containing the header files of the public interface.
691 # (default: include)</td>
692 # </tr>
693 # <tr>
694 # @tp @b INCLUDE_DIR path @endtp
695 # <td>Alternative option for @p INCLUDE_DIRS which only accepts a single path as argument.</td>
696 # </tr>
697 # <tr>
698 # @tp @b CODE_DIRS path1 [path2...] @endtp
699 # <td>A list of directories containing the source code files. The first diretory path
700 # is used as main source directory from which the subdirectory name of the
701 # corresponding build tree directory is derived. Any configured or generated
702 # source files are written to this build tree source directory.
703 # (default: src)</td>
704 # </tr>
705 # <tr>
706 # @tp @b CODE_DIR path @endtp
707 # <td>Alternative option for @p CODE_DIRS which only accepts a single path as argument.</td>
708 # </tr>
709 # <tr>
710 # @tp @b TOOLS_DIRS path1 [path2...] @endtp
711 # <td>A list of directories containing the source code files of applications.
712 # The first diretory path is used as main source directory from which the
713 # subdirectory name of the corresponding build tree directory is derived.
714 # Any configured or generated source files are written to this build tree
715 # source directory. The source files in the specified directories are only
716 # build when the BUILD_APPLICATIONS option is enabled. This option is
717 # automatically added when any of the directories contains a CMakeLists.txt
718 # file. (default: tools)</td>
719 # </tr>
720 # <tr>
721 # @tp @b TOOLS_DIR path @endtp
722 # <td>Alternative option for @p TOOLS_DIRS which only accepts a single path as argument.</td>
723 # </tr>
724 # <tr>
725 # @tp @b LIBRARY_DIR path @endtp
726 # <td>Directory of public modules written in a scripting language such as Python or Perl. (default: lib)</td>
727 # </tr>
728 # <tr>
729 # @tp @b MODULES_DIR path @endtp
730 # <td>Path to directory containing multiple module subdirectories, each containing
731 # their own BasisProject.cmake file that will each be picked up automatically.
732 # (default: modules)</td>
733 # </tr>
734 # <tr>
735 # @tp @b MODULE_DIRS path1 [path2...] @endtp
736 # <td>A list of individual module directories, each containing a BasisProject.cmake file.
737 # This list differs from @c MODULES_DIR in that each listed directory is the
738 # root directory of a single module, whereas @c MODULES_DIR is the comman
739 # directory of multiple modules contained in their own respective subdirectory.
740 # (default: "")</td>
741 # </tr>
742 # <tr>
743 # @tp @b CONFIG_DIR path @endtp
744 # <td>Directory in which BASIS looks for custom CMake/BASIS configuration files. (default: config)</td>
745 # </tr>
746 # <tr>
747 # @tp @b DATA_DIR path @endtp
748 # <td>Directory which contains auxiliary data required by the software programs. (default: data)</td>
749 # </tr>
750 # <tr>
751 # @tp @b DOC_DIR path @endtp
752 # <td>Directory containing the software documentation (source) files. (default: doc)</td>
753 # </tr>
754 # <tr>
755 # @tp @b DOCRES_DIR path @endtp
756 # <td>Directory where the documentation ressource files such as the project logo are located. (default: @p DOC_DIR/config)</td>
757 # </tr>
758 # <tr>
759 # @tp @b EXAMPLE_DIR path @endtp
760 # <td>Directory with some example files demonstrating the usage of the software. (default: example)</td>
761 # </tr>
762 # <tr>
763 # @tp @b TESTING_DIR path @endtp
764 # <td>The root diretory of the testing source tree containing test data and implementations. (default: test)</td>
765 # </tr>
766 # <tr>
767 # @tp @b OTHER_DIRS path... @endtp
768 # <td>List of other project directories with CMakeLists.txt files in them. (default: none)</td>
769 # </tr>
770 # </table>
771 #
772 # @returns Sets the following non-cached CMake variables.
773 # See documentation of the corresponding parameters above for details.
774 # @retval PROJECT_NAME See @c NAME and @p SUBPROJECT.
775 # @retval PROJECT_PACKAGE_NAME See @c PACKAGE_NAME.
776 # @retval PROJECT_PACKAGE_VENDOR See @c PACKAGE_VENDOR.
777 # @retval PROJECT_PACKAGE_WEBSITE See @c PACKAGE_WEBSITE.
778 # @retval PROJECT_PACKAGE_LOGO See @c PACKAGE_LOGO. Value is an absolute path.
779 # @retval PROJECT_PROVIDER_NAME See @c PROVIDER_NAME.
780 # @retval PROJECT_PROVIDER_WEBSITE See @c PROVIDER_WEBSITE.
781 # @retval PROJECT_PROVIDER_LOGO See @c PROVIDER_LOGO. Value is an absolute path.
782 # @retval PROJECT_DIVISION_NAME See @c DIVISION_NAME.
783 # @retval PROJECT_DIVISION_WEBSITE See @c DIVISION_WEBSITE.
784 # @retval PROJECT_DIVISION_LOGO See @c DIVISION_LOGO. Value is an absolute path.
785 # @retval PROJECT_VERSION See @c VERSION.
786 # @retval PROJECT_SOVERSION See @c SOVERSION.
787 # @retval PROJECT_DESCRIPTION See @c DESCRIPTION.
788 # @retval PROJECT_LANGUAGES See @c LANGUAGES.
789 # @retval PROJECT_DEPENDS See @c DEPENDS.
790 # @retval PROJECT_OPTIONAL_DEPENDS See @c OPTIONAL_DEPENDS.
791 # @retval PROJECT_TOOLS_DEPENDS See @c TOOLS_DEPENDS.
792 # @retval PROJECT_OPTIONAL_TOOLS_DEPENDS See @c OPTIONAL_TOOLS_DEPENDS.
793 # @retval PROJECT_TEST_DEPENDS See @c TEST_DEPENDS.
794 # @retval PROJECT_OPTIONAL_TEST_DEPENDS See @c OPTIONAL_TEST_DEPENDS.
795 # @retval PROJECT_IS_SUBPROJECT @c TRUE if @c SUBPROJECT used instead of NAME or @c FALSE otherwise.
796 # @retval PROJECT_IS_SUBMODULE @c TRUE when project @c NAME and @c PACKAGE name is given, @c FALSE otherwise.
797 # @retval PROJECT_DEFAULT_MODULES See @c DEFAULT_MODULES.
798 # @retval PROJECT_EXTERNAL_MODULES See @c EXTERNAL_MODULES.
799 #
800 # @retval PROJECT_CODE_DIRS See @c CODE_DIRS.
801 # @retval PROJECT_CODE_DIR First element of @c PROJECT_CODE_DIRS list.
802 # @retval PROJECT_TOOLS_DIRS See @c TOOLS_DIRS.
803 # @retval PROJECT_TOOLS_DIR First element of @c PROJECT_TOOLS_DIRS list.
804 # @retval PROJECT_CONFIG_DIR See @c CONFIG_DIR.
805 # @retval PROJECT_DATA_DIR See @c DATA_DIR.
806 # @retval PROJECT_DOC_DIR See @c DOC_DIR.
807 # @retval PROJECT_DOCRES_DIR See @c DOCRES_DIR.
808 # @retval PROJECT_EXAMPLE_DIR See @c EXAMPLE_DIR.
809 # @retval PROJECT_INCLUDE_DIRS See @c INCLUDE_DIRS.
810 # @retval PROJECT_INCLUDE_DIR First element of @c PROJECT_INCLUDE_DIRS list.
811 # @retval PROJECT_LIBRARY_DIR See @c LIBRARY_DIR.
812 # @retval PROJECT_MODULE_DIRS See @c MODULE_DIRS.
813 # @retval PROJECT_MODULES_DIR See @c MODULES_DIR.
814 # @retval PROJECT_TESTING_DIR See @c TESTING_DIR.
815 # @retval PROJECT_OTHER_DIRS See @c OTHER_DIRS.
816 #
817 # @retval PROJECT_HAS_APPLICATIONS Whether any of the PROJECT_TOOLS_DIRS has a CMakeLists.txt file.
818 #
819 # @ingroup CMakeAPI
820 #
821 # @see BasisSettings.cmake
822 macro (basis_project)
823  # @see BasisSettings.cmake for parameter lists.
824  # @see basis_project_check_metadata() above for implementation details
825  CMAKE_PARSE_ARGUMENTS (
826  PROJECT
827  "${BASIS_METADATA_LIST_SWITCH}"
828  "${BASIS_METADATA_LIST_SINGLE}"
829  "${BASIS_METADATA_LIST_MULTI}"
830  ${ARGN}
831  )
833 endmacro ()
834 
835 
836 ## @addtogroup CMakeUtilities
837 # @{
838 
839 
840 # ============================================================================
841 # initialization
842 # ============================================================================
843 
844 # ----------------------------------------------------------------------------
845 ## @brief Ensure certain requirements on build tree.
846 #
847 # Requirements:
848 # - Root of build tree must not be root of source tree.
849 #
850 # @param [in] ARGN Not used.
851 #
852 # @returns Nothing.
853 function (basis_buildtree_asserts)
854  string (TOLOWER "${CMAKE_SOURCE_DIR}" SOURCE_ROOT)
855  string (TOLOWER "${CMAKE_BINARY_DIR}" BUILD_ROOT)
856  if ("^${BUILD_ROOT}$" STREQUAL "^${SOURCE_ROOT}$")
857  message(FATAL_ERROR "This project should not be configured & build in the "
858  "source directory:\n"
859  " ${CMAKE_SOURCE_DIR}\n"
860  "You must run CMake in a separate build directory.")
861  endif()
862 endfunction ()
863 
864 # ----------------------------------------------------------------------------
865 ## @brief Ensure certain requirements on install tree.
866 #
867 # Requirements:
868 # - Prefix must be an absolute path.
869 # - Install tree must be different from source and build tree.
870 #
871 # @param [in] ARGN Not used.
872 #
873 # @returns Nothing.
874 function (basis_installtree_asserts)
875  if (NOT IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}")
876  message (FATAL_ERROR "CMAKE_INSTALL_PREFIX must be an absolute path!")
877  endif ()
878  string (TOLOWER "${CMAKE_SOURCE_DIR}" SOURCE_ROOT)
879  string (TOLOWER "${CMAKE_BINARY_DIR}" BUILD_ROOT)
880  string (TOLOWER "${CMAKE_INSTALL_PREFIX}" INSTALL_ROOT)
881  if ("^${BUILD_ROOT}$" STREQUAL "^${INSTALL_ROOT}$" OR "^${SOURCE_ROOT}$" STREQUAL "^${INSTALL_ROOT}$")
882  message (FATAL_ERROR "The current CMAKE_INSTALL_PREFIX points at the source or build tree:\n"
883  " ${CMAKE_INSTALL_PREFIX}\n"
884  "This is not permitted by this project. "
885  "Please choose another installation prefix."
886  )
887  endif()
888 endfunction ()
889 
890 # ----------------------------------------------------------------------------
891 # @brief Obtain module info from BasisProject.cmake file
892 #
893 # Use function scope to avoid overwriting of this project's variables.
894 function (basis_get_module_info MODULE_NAME F)
895  # clean path without // to fix issue with UNC paths on Windows
896  get_filename_component (F "${F}" ABSOLUTE)
897  # include BasisProject.cmake file
898  set (PROJECT_IS_MODULE TRUE)
899  get_filename_component (PROJECT_SOURCE_DIR "${F}" PATH)
900  set (BASIS_basis_project_CALLED FALSE)
901  include ("${F}")
902  # make sure that basis_project() was called
903  if (NOT BASIS_basis_project_CALLED)
904  message (FATAL_ERROR "basis_module_info(): Missing basis_project() command in ${F}!")
905  endif ()
906  # remember dependencies
907  foreach (V IN ITEMS DEPENDS OPTIONAL_DEPENDS TOOLS_DEPENDS OPTIONAL_TOOLS_DEPENDS TEST_DEPENDS OPTIONAL_TEST_DEPENDS)
908  set (${V})
909  foreach (D ${PROJECT_${V}})
910  basis_tokenize_dependency ("${D}" PKG VER CMPS)
911  if ("^${PKG}$" STREQUAL "^${TOPLEVEL_PROJECT_NAME}$")
912  list (APPEND ${V} ${CMPS})
913  else ()
914  list (APPEND ${V} "${PKG}")
915  endif ()
916  endforeach ()
917  endforeach ()
918  # do not use MODULE instead of PROJECT_NAME in this function as it is not
919  # set in the scope of this function but its parent scope only
920  set (${PROJECT_NAME}_DEPENDS "${DEPENDS}" PARENT_SCOPE)
921  set (${PROJECT_NAME}_OPTIONAL_DEPENDS "${OPTIONAL_DEPENDS}" PARENT_SCOPE)
922  set (${PROJECT_NAME}_TOOLS_DEPENDS "${TOOLS_DEPENDS}" PARENT_SCOPE)
923  set (${PROJECT_NAME}_OPTIONAL_TOOLS_DEPENDS "${OPTIONAL_TOOLS_DEPENDS}" PARENT_SCOPE)
924  set (${PROJECT_NAME}_TEST_DEPENDS "${TEST_DEPENDS}" PARENT_SCOPE)
925  set (${PROJECT_NAME}_OPTIONAL_TEST_DEPENDS "${OPTIONAL_TEST_DEPENDS}" PARENT_SCOPE)
926  set (${PROJECT_NAME}_DECLARED TRUE PARENT_SCOPE)
927  set (${PROJECT_NAME}_MISSING FALSE PARENT_SCOPE)
928  set (${PROJECT_NAME}_IS_SUBPROJECT "${PROJECT_IS_SUBPROJECT}" PARENT_SCOPE)
929  set (${PROJECT_NAME}_IS_SUBMODULE "${PROJECT_IS_SUBMODULE}" PARENT_SCOPE)
930  set (${PROJECT_NAME}_CONFIG_PREFIX "${PROJECT_CONFIG_PREFIX}" PARENT_SCOPE)
931  # remember source directories - used by basis_add_doxygen_doc()
932  set (${PROJECT_NAME}_INCLUDE_DIRS "${PROJECT_INCLUDE_DIRS}" PARENT_SCOPE)
933  set (${PROJECT_NAME}_CODE_DIRS "${PROJECT_CODE_DIRS}" PARENT_SCOPE)
934  # remember if module depends on Slicer - used by basis_find_packages()
935  if (PROJECT_IS_SLICER_MODULE)
936  foreach (_D IN LISTS BASIS_SLICER_METADATA_LIST)
937  if (DEFINED PROJECT_${_D})
938  set (${PROJECT_NAME}_${_D} "${PROJECT_${_D}}" PARENT_SCOPE)
939  endif ()
940  endforeach ()
941  set (${PROJECT_NAME}_IS_SLICER_MODULE TRUE PARENT_SCOPE)
942  else ()
943  set (${PROJECT_NAME}_IS_SLICER_MODULE FALSE PARENT_SCOPE)
944  endif ()
945  # whether to always exclude module from BUILD_ALL_MODULES
946  set (${PROJECT_NAME}_EXCLUDE_FROM_ALL "${PROJECT_EXCLUDE_FROM_ALL}" PARENT_SCOPE)
947  # module name
948  set (${MODULE_NAME} "${PROJECT_NAME}" PARENT_SCOPE)
949 endfunction ()
950 
951 # ----------------------------------------------------------------------------
952 ## @brief Manually add project module to list of modules
953 macro (basis_add_module_info MODULE_NAME F)
954  # clean path without // to fix issue with UNC paths on Windows
955  get_filename_component (F "${F}" ABSOLUTE)
957  list (APPEND PROJECT_MODULES ${_MODULE})
958  get_filename_component (${_MODULE}_BASE ${F} PATH)
959  basis_get_relative_path (${_MODULE}_BASE_REL "${CMAKE_CURRENT_SOURCE_DIR}" "${${_MODULE}_BASE}")
960  set (MODULE_${_MODULE}_SOURCE_DIR "${${_MODULE}_BASE}")
961  set (MODULE_${_MODULE}_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${${_MODULE}_BASE_REL}")
962  set (${MODULE_NAME} ${_MODULE})
963  unset(_MODULE)
964 endmacro ()
965 
966 # ----------------------------------------------------------------------------
967 ## @brief Initialize project modules.
968 #
969 # Most parts of this macro were copied from the ITK4 project
970 # (http://www.vtk.org/Wiki/ITK_Release_4), in particular, the top-level
971 # CMakeLists.txt file. This file does not state any specific license, but
972 # the ITK package itself is released under the Apache License Version 2.0,
973 # January 2004 (http://www.apache.org/licenses/).
974 macro (basis_project_modules)
975  # --------------------------------------------------------------------------
976  # reset variables
977  set (PROJECT_MODULES)
980  # --------------------------------------------------------------------------
981  # load module DAG
982 
983  # glob BasisProject.cmake files in modules subdirectory
985  file (GLOB_RECURSE MODULE_INFO_FILES "${PROJECT_MODULES_DIR}/*/BasisProject.cmake")
986  endif ()
987 
988  # add each manually specified module
989  foreach (_PATH IN LISTS PROJECT_MODULE_DIRS)
990  if (NOT IS_ABSOLUTE ${_PATH})
991  set (_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${_PATH}")
992  endif ()
993  if (EXISTS "${_PATH}/BasisProject.cmake")
994  list (APPEND MODULE_INFO_FILES "${_PATH}/BasisProject.cmake")
995  else ()
996  get_filename_component(MODULE "${_PATH}" NAME)
997  list(FIND PROJECT_EXTERNAL_MODULES "${MODULE}" IDX)
998  if (IDX EQUAL -1)
999  message (FATAL_ERROR "Check your top-level ${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake"
1000  " file because the module ${_PATH}/BasisProject.cmake"
1001  " file does not appear to exist.")
1002  endif ()
1003  endif ()
1004  endforeach ()
1005  unset (_PATH)
1006 
1007  set (PROJECT_MODULES)
1008  foreach (F IN LISTS MODULE_INFO_FILES)
1009  # import module info into current scope
1010  basis_add_module_info (MODULE ${F})
1011  # help modules to find each other using basis_find_package()
1012  set (${MODULE}_DIR "${MODULE_${MODULE}_BINARY_DIR}")
1013  # only set EXCLUDE_<MODULE>_FROM_ALL when not specified on command-line using -D switch
1014  if (NOT DEFINED EXCLUDE_${MODULE}_FROM_ALL)
1015  set (EXCLUDE_${MODULE}_FROM_ALL "${${MODULE}_EXCLUDE_FROM_ALL}")
1016  endif ()
1017  endforeach()
1018 
1019  # add non-existing external modules to list
1020  foreach (MODULE IN LISTS PROJECT_EXTERNAL_MODULES)
1021  if (NOT ${MODULE}_DECLARED)
1022  list (APPEND PROJECT_MODULES "${MODULE}")
1023  set (${MODULE}_DEPENDS)
1024  set (${MODULE}_OPTIONAL_DEPENDS)
1025  set (${MODULE}_TOOLS_DEPENDS)
1026  set (${MODULE}_OPTIONAL_TOOLS_DEPENDS)
1027  set (${MODULE}_TEST_DEPENDS)
1028  set (${MODULE}_OPTIONAL_TEST_DEPENDS)
1029  set (${MODULE}_DECLARED TRUE)
1030  set (${MODULE}_MISSING TRUE)
1031  endif ()
1032  endforeach ()
1033 
1034  # validate the module DAG to identify cyclic dependencies
1035  macro (basis_module_check MODULE NEEDED_BY STACK)
1036  if (${MODULE}_DECLARED)
1037  if (${MODULE}_CHECK_STARTED AND NOT ${MODULE}_CHECK_FINISHED)
1038  # we reached a module while traversing its own dependencies recursively
1039  set (MSG "")
1040  foreach (M ${STACK})
1041  set (MSG " ${M} =>${MSG}")
1042  if ("${M}" STREQUAL "${MODULE}")
1043  break ()
1044  endif ()
1045  endforeach ()
1046  message (FATAL_ERROR "Module dependency cycle detected:\n ${MSG} ${MODULE}")
1047  elseif (NOT ${MODULE}_CHECK_STARTED)
1048  # traverse dependencies of this module
1049  set (${MODULE}_CHECK_STARTED TRUE)
1050  foreach (D IN LISTS ${MODULE}_DEPENDS
1051  ${MODULE}_OPTIONAL_DEPENDS
1052  ${MODULE}_TOOLS_DEPENDS
1053  ${MODULE}_OPTIONAL_TOOLS_DEPENDS
1054  ${MODULE}_TEST_DEPENDS
1055  ${MODULE}_OPTIONAL_TEST_DEPENDS)
1056  basis_module_check (${D} ${MODULE} "${MODULE};${STACK}")
1057  endforeach ()
1058  set (${MODULE}_CHECK_FINISHED TRUE)
1059  endif ()
1060  endif ()
1061  endmacro ()
1062 
1063  foreach (MODULE ${PROJECT_MODULES})
1064  basis_module_check ("${MODULE}" "" "")
1065  endforeach ()
1066 
1067  # check if list of PROJECT_DEFAULT_MODULES contains invalid module name
1068  if (NOT "^${PROJECT_DEFAULT_MODULES}$" STREQUAL "^ALL$")
1069  foreach (MODULE IN LISTS PROJECT_DEFAULT_MODULES)
1070  list (FIND PROJECT_MODULES "${MODULE}" IDX)
1071  if (IDX EQUAL -1)
1072  message (FATAL_ERROR "List of DEFAULT_MODULES specified in BasisProject.cmake file"
1073  " contains non-existing module ${MODULE}.")
1074  endif ()
1075  endforeach ()
1076  endif ()
1077 
1078  # --------------------------------------------------------------------------
1079  # determine list of enabled modules
1080 
1081  # provide an option for all modules
1082  if (PROJECT_MODULES)
1083  option (BUILD_ALL_MODULES "Request to build all modules." OFF)
1084  endif ()
1085 
1086  # provide an option for each module
1087  foreach (MODULE ${PROJECT_MODULES})
1088  if ("^${PROJECT_DEFAULT_MODULES}$" STREQUAL "^ALL$")
1089  set (MODULE_${MODULE}_DEFAULT ON)
1090  else ()
1091  list (FIND PROJECT_DEFAULT_MODULES "${MODULE}" IDX)
1092  if (IDX EQUAL -1)
1093  set (MODULE_${MODULE}_DEFAULT OFF)
1094  else ()
1095  set (MODULE_${MODULE}_DEFAULT ON)
1096  endif ()
1097  endif ()
1098  if (${MODULE}_MISSING AND NOT MODULE_${MODULE}_DEFAULT)
1099  set (MODULE_${MODULE} NOTFOUND CACHE STRING "Request to build the module ${MODULE}.")
1100  set_property (CACHE MODULE_${MODULE} PROPERTY STRINGS "NOTFOUND;ON")
1101  else ()
1102  option (MODULE_${MODULE} "Request to build the module ${MODULE}." ${MODULE_${MODULE}_DEFAULT})
1103  set_property (CACHE MODULE_${MODULE} PROPERTY TYPE BOOL)
1104  endif ()
1105  unset (MODULE_${MODULE}_DEFAULT)
1106  endforeach ()
1107 
1108  # follow dependencies
1109  macro (basis_module_enable MODULE NEEDED_BY)
1110  if (${MODULE}_DECLARED)
1111  if (NOT "${NEEDED_BY}" STREQUAL "")
1112  list (APPEND ${MODULE}_NEEDED_BY "${NEEDED_BY}")
1113  endif ()
1114  if (NOT ${MODULE}_ENABLED)
1115  if ("${NEEDED_BY}" STREQUAL "")
1116  set (${MODULE}_NEEDED_BY)
1117  endif ()
1118  set (${MODULE}_ENABLED TRUE)
1119  foreach (D IN LISTS ${MODULE}_DEPENDS)
1120  basis_module_enable (${D} ${MODULE})
1121  endforeach ()
1122  if (BUILD_APPLICATIONS)
1123  foreach (D IN LISTS ${MODULE}_TOOLS_DEPENDS)
1124  basis_module_enable (${D} ${MODULE})
1125  endforeach ()
1126  endif ()
1127  if (BUILD_TESTING)
1128  foreach (D IN LISTS ${MODULE}_TEST_DEPENDS)
1129  basis_module_enable (${D} ${MODULE})
1130  endforeach ()
1131  endif ()
1132  endif ()
1133  endif ()
1134  endmacro ()
1135 
1136  foreach (MODULE ${PROJECT_MODULES})
1137  # EXCLUDE_<MODULE>_FROM_ALL can be set on command-line via cmake -D switch
1138  # in conjunction with -D BUILD_ALL_MODULES=ON. the default value of
1139  # EXCLUDE_<MODULE>_FROM_ALL is set from the EXCLUDE_FROM_ALL basis_project option.
1140  if (MODULE_${MODULE} OR (BUILD_ALL_MODULES AND NOT EXCLUDE_${MODULE}_FROM_ALL))
1141  basis_module_enable ("${MODULE}" "")
1142  endif ()
1143  endforeach ()
1144 
1145  # build final list of enabled modules
1148  foreach (MODULE ${PROJECT_MODULES})
1149  if (${MODULE}_DECLARED)
1150  if (${MODULE}_ENABLED)
1151  list (APPEND PROJECT_MODULES_ENABLED ${MODULE})
1152  else ()
1153  list (APPEND PROJECT_MODULES_DISABLED ${MODULE})
1154  endif ()
1155  endif ()
1156  endforeach ()
1157  list (SORT PROJECT_MODULES_ENABLED) # Deterministic order.
1158  list (SORT PROJECT_MODULES_DISABLED) # Deterministic order.
1159 
1160  # order list to satisfy dependencies
1161  include (${BASIS_MODULE_PATH}/TopologicalSort.cmake)
1162  foreach (MODULE ${PROJECT_MODULES})
1163  set (${MODULE}_USES
1164  ${${MODULE}_DEPENDS}
1165  ${${MODULE}_OPTIONAL_DEPENDS}
1166  ${${MODULE}_TOOLS_DEPENDS}
1167  ${${MODULE}_OPTIONAL_TOOLS_DEPENDS}
1168  ${${MODULE}_TEST_DEPENDS}
1169  ${${MODULE}_OPTIONAL_TEST_DEPENDS}
1170  )
1171  endforeach ()
1172  set (PROJECT_MODULES_SORTED "${PROJECT_MODULES}")
1173  topological_sort (PROJECT_MODULES_SORTED "" "_USES")
1174  foreach (MODULE ${PROJECT_MODULES})
1175  unset (${MODULE}_USES)
1176  endforeach ()
1177 
1178  # remove disabled modules and external dependencies
1179  set (L)
1180  foreach (MODULE IN LISTS PROJECT_MODULES_SORTED)
1181  if (${MODULE}_DECLARED)
1182  list (FIND PROJECT_MODULES_ENABLED "${MODULE}" IDX)
1183  if (NOT IDX EQUAL -1)
1184  list (APPEND L "${MODULE}")
1185  endif ()
1186  endif ()
1187  endforeach ()
1188  set (PROJECT_MODULES_ENABLED "${L}")
1189  unset (L)
1190 
1191  # turn options ON for modules that are required by other modules
1192  foreach (MODULE ${PROJECT_MODULES})
1193  if (DEFINED MODULE_${MODULE} # there was an option for the user
1194  AND NOT MODULE_${MODULE} # user did not set it to ON themself
1195  AND NOT ${MODULE}_IN_ALL # BUILD_ALL_MODULES was not set ON
1196  AND ${MODULE}_NEEDED_BY) # module is needed by other module(s)
1197  set (MODULE_${MODULE} ON CACHE BOOL "Request building module ${MODULE}." FORCE)
1198  message ("Enabled module ${MODULE}, needed by [${${MODULE}_NEEDED_BY}].")
1199  endif ()
1200  endforeach ()
1201 
1202  # report what will be built
1203  if (PROJECT_MODULES_ENABLED)
1204  message (STATUS "Enabled modules [${PROJECT_MODULES_ENABLED}].")
1205  endif ()
1206 
1207  # check that all enabled external modules do exist
1208  foreach (MODULE IN LISTS PROJECT_EXTERNAL_MODULES)
1209  if (MODULE_${MODULE} AND ${MODULE}_MISSING)
1210  set (msg "External module ${MODULE} is enabled but missing.")
1211  if (EXISTS "${PROJECT_SOURCE_DIR}/.gitmodules")
1212  set (msg "${msg} If the module is a Git submodule, ensure that it"
1213  " is properly initialized, i.e.,\n"
1214  "\tgit submodule update --init -- <module_dir>\n")
1215  endif ()
1216  basis_list_to_string(msg ${msg})
1217  message (FATAL_ERROR "${msg}")
1218  endif ()
1219  endforeach ()
1220 
1221  # undefine locally used variables
1222  unset (F)
1223  unset (MODULE)
1224  unset (IDX)
1225  unset (M)
1226  unset (MSG)
1227  unset (D)
1228  unset (PKG)
1229  unset (VER)
1230  unset (CMPS)
1231 
1232 endmacro ()
1233 
1234 # ----------------------------------------------------------------------------
1235 ## @brief Check if named project module depends on the specified package
1236 #
1237 # @param[out] result Name of boolean return variable.
1238 # @param[in] module Name of project module.
1239 # @param[in] package Name of (external) package.
1240 #
1241 # @returns Sets @p result variable to either @c TRUE or @c FALSE.
1242 function (basis_check_if_module_depends_on_package result module package)
1243  if (ARGN)
1244  cmake_parse_arguments(ARGN "REQUIRED;OPTIONAL" "" "" ${ARGN})
1245  if (ARGN_UNPARSED_ARGUMENTS)
1246  message(FATAL_ERROR "Too many arguments: ${ARGN_UNPARSED_ARGUMENTS}")
1247  endif ()
1248  else ()
1249  set(ARGN_REQUIRED TRUE)
1250  set(ARGN_OPTIONAL TRUE)
1251  endif ()
1252  basis_tokenize_dependency ("${package}" pkg_name pkg_version pkg_comps)
1253  set(depends)
1254  if (ARGN_REQUIRED)
1255  list(APPEND depends ${${module}_DEPENDS})
1256  if (BUILD_APPLICATIONS)
1257  list(APPEND depends ${${module}_TOOLS_DEPENDS})
1258  endif ()
1259  if (BUILD_TESTING)
1260  list(APPEND depends ${${module}_TEST_DEPENDS})
1261  endif ()
1262  endif ()
1263  if (ARGN_OPTIONAL)
1264  set(depends ${${module}_OPTIONAL_DEPENDS})
1265  if (BUILD_APPLICATIONS)
1266  list(APPEND depends ${${module}_OPTIONAL_TOOLS_DEPENDS})
1267  endif ()
1268  if (BUILD_TESTING)
1269  list(APPEND depends ${${module}_OPTIONAL_TEST_DEPENDS})
1270  endif ()
1271  endif ()
1272  set(pkg_found FALSE)
1273  foreach (dep IN LISTS depends)
1274  basis_tokenize_dependency ("${dep}" dep_name dep_version dep_comps)
1275  if ("^${dep_name}$" STREQUAL "^${pkg_name}$")
1276  if (pkg_comps)
1277  foreach (comp IN LISTS pkg_comps)
1278  list(FIND dep_comps ${comp} idx)
1279  if (NOT idx EQUAL -1)
1280  set(pkg_found TRUE)
1281  break()
1282  endif ()
1283  endforeach ()
1284  if (pkg_found)
1285  break()
1286  endif ()
1287  else ()
1288  set(pkg_found TRUE)
1289  break()
1290  endif ()
1291  endif ()
1292  endforeach ()
1293  set(${result} ${pkg_found} PARENT_SCOPE)
1294 endfunction ()
1295 
1296 # ----------------------------------------------------------------------------
1297 ## @brief Check if any of the named/enabled modules depends on the specified package
1298 #
1299 # @param[out] result Name of boolean return variable.
1300 # @param[in] package Name of (external) package.
1301 # @param[in] ARGN Names of project modules. If none specified,
1302 # the list of enabled modules is used instead.
1303 #
1304 # @returns Sets @p result variable to either @c TRUE or @c FALSE.
1305 function (basis_check_if_package_is_needed_by_modules result package)
1306  if (ARGN)
1307  set(modules ${ARGN})
1308  else ()
1309  set(modules ${PROJECT_MODULES_ENABLED})
1310  endif ()
1311  set(pkg_found FALSE)
1312  foreach (module IN LISTS modules)
1313  basis_check_if_module_depends_on_package(pkg_found ${module} ${package})
1314  if (pkg_found)
1315  break()
1316  endif ()
1317  endforeach ()
1318  set(${result} ${pkg_found} PARENT_SCOPE)
1319 endfunction ()
1320 
1321 # ----------------------------------------------------------------------------
1322 ## @brief Configure public header files.
1323 function (basis_configure_public_headers)
1324  # --------------------------------------------------------------------------
1325  # settings
1326 
1327  # log file which lists the configured header files
1328  set (CMAKE_FILE "${BINARY_INCLUDE_DIR}/${PROJECT_NAME}PublicHeaders.cmake")
1329 
1330  # ----------------------------------------------------------------------------
1331  # header files to configure excluding the .in suffix
1332  set (
1333  EXTENSIONS
1334  ".h"
1335  ".hh"
1336  ".hpp"
1337  ".hxx"
1338  ".inl"
1339  ".txx"
1340  ".inc"
1341  )
1342 
1343  # --------------------------------------------------------------------------
1344  # clean up last run before the error because a file was added/removed
1345  file (REMOVE "${CMAKE_FILE}.tmp")
1346  file (REMOVE "${CMAKE_FILE}.updated")
1347  if (EXISTS "${CMAKE_FILE}")
1348  # required to be able to remove now obsolete files from the build tree
1349  file (RENAME "${CMAKE_FILE}" "${CMAKE_FILE}.tmp")
1350  endif ()
1351 
1352  # --------------------------------------------------------------------------
1353  # configure public header files
1354  message (STATUS "Configuring public header files...")
1355 
1356  if (NOT PROJECT_INCLUDE_DIRS)
1357  message (FATAL_ERROR "Missing argument PROJECT_INCLUDE_DIRS!")
1358  endif ()
1359 
1360  # configure all .in files with substitution
1361  set (CONFIGURED_HEADERS)
1362  foreach (INCLUDE_DIR IN LISTS PROJECT_INCLUDE_DIRS)
1363  set (PATTERN)
1364  foreach (E IN LISTS EXTENSIONS)
1365  list (APPEND PATTERN "${INCLUDE_DIR}/*${E}.in")
1366  endforeach ()
1367  file (GLOB_RECURSE FILES RELATIVE "${INCLUDE_DIR}" ${PATTERN})
1368  foreach (HEADER IN LISTS FILES)
1369  get_filename_component (SOURCE "${INCLUDE_DIR}/${HEADER}" ABSOLUTE)
1370  string (REGEX REPLACE "\\.in$" "" HEADER "${HEADER}")
1371  configure_file ("${SOURCE}" "${BINARY_INCLUDE_DIR}/${HEADER}" @ONLY)
1372  list (APPEND CONFIGURED_HEADERS "${SOURCE}")
1373  endforeach ()
1374  endforeach ()
1375 
1376  # regular headers are copied separately via
1377  # execute_process to avoid a full configure step
1378  # However, all headers should be checked for changes.
1379 
1380  execute_process (
1381  COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
1382  -D "PROJECT_INCLUDE_DIRS=${PROJECT_INCLUDE_DIRS}"
1383  -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
1384  -D "EXTENSIONS=${EXTENSIONS}"
1385  -D "CMAKE_FILE=${CMAKE_FILE}"
1386  -D "CONFIGURED_HEADERS=${CONFIGURED_HEADERS}"
1387  -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
1388  RESULT_VARIABLE RT
1389  )
1390 
1391  if (RT EQUAL 0)
1392  execute_process (
1393  COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
1394  )
1395  else ()
1396  message (FATAL_ERROR "Failed to configure public header files!")
1397  endif ()
1398 
1399  if (NOT EXISTS "${CMAKE_FILE}")
1400  message (FATAL_ERROR "File ${CMAKE_FILE} not generated as it should have been!")
1401  endif ()
1402 
1403  # remove header files from build tree which were copied there before but
1404  # are part of a now disabled module or were simply removed from the source tree
1405  if (EXISTS "${CMAKE_FILE}.tmp")
1406  execute_process (
1407  # Compare current list of headers to list of previously configured files.
1408  # If the lists differ, this command removes files which have been removed
1409  # from the directory tree with root PROJECT_INCLUDE_DIR also from the
1410  # tree with root directory BINARY_INCLUDE_DIR.
1411  COMMAND "${CMAKE_COMMAND}" ${COMMON_ARGS}
1412  -D "PROJECT_INCLUDE_DIRS=${PROJECT_INCLUDE_DIRS}"
1413  -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
1414  -D "CMAKE_FILE=${CMAKE_FILE}.tmp"
1415  -D "REFERENCE_FILE=${CMAKE_FILE}"
1416  -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
1417  VERBATIM
1418  )
1419  file (REMOVE "${CMAKE_FILE}.tmp")
1420  if (NOT RT EQUAL 0)
1421  message (FATAL_ERROR "Failed to remove obsolete header files from build tree."
1422  " Remove the ${BINARY_INCLUDE_DIR} directory and re-run CMake.")
1423  endif ()
1424  endif ()
1425 
1426  message (STATUS "Configuring public header files... - done")
1427 
1428  # We need a list of the configured files to add them as dependency of the
1429  # custom build targets such that these get re-build whenever a file changed.
1430  # Additionally, including this file here which is modified whenever a
1431  # header file is added or removed triggeres a re-configuration of the
1432  # build system which is required to re-execute this function and adjust
1433  # these custom build targets.
1434  include ("${CMAKE_FILE}")
1435 
1436  # --------------------------------------------------------------------------
1437  # check if any header was added or removed (always out-of-date)
1438 
1439  # error message displayed when a file was added or removed which requires
1440  # a reconfiguration of the build system
1441  set (ERRORMSG "You have either added, removed, or renamed a public header file"
1442  " with a .in suffix in the file name. Therefore, the build system"
1443  " needs to be re-configured. Either try to build again which will"
1444  " trigger CMake and re-configure the build system or run CMake manually.")
1445  basis_list_to_string (ERRORMSG ${ERRORMSG})
1446 
1447  # custom command which globs the files in the project's include directory
1448  set (COMMENT "Checking if public header files were added or removed")
1449  if (PROJECT_IS_MODULE)
1450  set (COMMENT "${COMMENT} to ${PROJECT_NAME} module")
1451  endif ()
1452  add_custom_command (
1453  OUTPUT "${CMAKE_FILE}.tmp"
1454  COMMAND "${CMAKE_COMMAND}"
1455  -D "PROJECT_INCLUDE_DIRS=${PROJECT_INCLUDE_DIRS}"
1456  -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
1457  -D "EXTENSIONS=${EXTENSIONS}"
1458  -D "CMAKE_FILE=${CMAKE_FILE}.tmp"
1459  -D "PREVIEW=TRUE" # do not actually configure the files
1460  -D "CONFIGURED_HEADERS=${CONFIGURED_HEADERS}"
1461  -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
1462  COMMENT "${COMMENT}"
1463  VERBATIM
1464  )
1465 
1466  # custom target to detect whether a file was added or removed
1467  basis_make_target_uid (CHECK_HEADERS_TARGET headers_check)
1468  add_custom_target (
1469  ${CHECK_HEADERS_TARGET} ALL
1470  # trigger execution of custom command that generates the list
1471  # of current files in the project's include directory
1472  DEPENDS "${CMAKE_FILE}.tmp"
1473  # Compare current list of headers to list of previously configured files.
1474  # If the lists differ, the build of this target fails with the given error message.
1475  COMMAND "${CMAKE_COMMAND}"
1476  -D "PROJECT_INCLUDE_DIRS=${PROJECT_INCLUDE_DIRS}"
1477  -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
1478  -D "CMAKE_FILE=${CMAKE_FILE}"
1479  -D "REFERENCE_FILE=${CMAKE_FILE}.tmp"
1480  -D "ERRORMSG=${ERRORMSG}"
1481  -D "REMOVE_FILES_IF_DIFFERENT=TRUE" # triggers reconfigure on next build
1482  -P "${BASIS_MODULE_PATH}/CheckPublicHeaders.cmake"
1483  # remove temporary file again to force its regeneration
1484  COMMAND "${CMAKE_COMMAND}" -E remove "${CMAKE_FILE}.tmp"
1485  VERBATIM
1486  )
1487  if (PROJECT_IS_MODULE)
1488  if (NOT TARGET headers_check)
1489  add_custom_target (headers_check ALL)
1490  endif ()
1491  add_dependencies (headers_check ${CHECK_HEADERS_TARGET})
1492  endif ()
1493 
1494  # --------------------------------------------------------------------------
1495  # add build command to re-configure public header files
1496  if (PUBLIC_HEADERS)
1497  set (COMMENT "Configuring public header files")
1498  if (PROJECT_IS_MODULE)
1499  set (COMMENT "${COMMENT} of ${PROJECT_NAME} module")
1500  endif ()
1501  add_custom_command (
1502  OUTPUT "${CMAKE_FILE}.updated" # do not use same file as included
1503  # before otherwise CMake will re-configure
1504  # the build system next time
1505  COMMAND "${CMAKE_COMMAND}"
1506  -D "PROJECT_INCLUDE_DIRS=${PROJECT_INCLUDE_DIRS}"
1507  -D "BINARY_INCLUDE_DIR=${BINARY_INCLUDE_DIR}"
1508  -D "EXTENSIONS=${EXTENSIONS}"
1509  -P "${BASIS_MODULE_PATH}/ConfigureIncludeFiles.cmake"
1510  COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_FILE}.updated"
1511  DEPENDS ${PUBLIC_HEADERS}
1512  COMMENT "${COMMENT}"
1513  VERBATIM
1514  )
1515  basis_make_target_uid (CONFIGURE_HEADERS_TARGET headers)
1516  add_custom_target (
1517  ${CONFIGURE_HEADERS_TARGET} ALL
1518  DEPENDS ${CHECK_HEADERS_TARGET} "${CMAKE_FILE}.updated"
1519  SOURCES ${PUBLIC_HEADERS}
1520  )
1521  if (PROJECT_IS_MODULE)
1522  if (NOT TARGET headers)
1523  add_custom_target (headers ALL)
1524  endif ()
1525  add_dependencies (headers ${CONFIGURE_HEADERS_TARGET})
1526  endif ()
1527  endif ()
1528 endfunction ()
1529 
1530 # ----------------------------------------------------------------------------
1531 ## @brief Add library targets for the public modules in @c PROJECT_LIBRARY_DIR.
1532 #
1533 # This function configures ("builds") the library modules in the
1534 # @c PROJECT_LIBRARY_DIR that are written in a scripting language such as
1535 # Python or Perl. The names of the added library targets can be modified using
1536 # the <tt>BASIS_&lt;LANG&gt;_LIBRARY_TARGET</tt> variables, which are set to their
1537 # default values in the @c BasisSettings.cmake file.
1538 function (basis_configure_script_libraries)
1539  # Python
1540  if (PythonInterp_FOUND)
1541  set (PYTHON_EXT .py .py.in)
1542  set (PYTHON_LIB_DIRS)
1543  if (PYTHON_VERSION_MAJOR)
1544  list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/python${PYTHON_VERSION_MAJOR}")
1545  endif ()
1546  list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/python")
1547  list (APPEND PYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
1548  else ()
1549  set (PYTHON_LIB_DIRS)
1550  endif ()
1551  # Jython
1552  if (JythonInterp_FOUND)
1553  set (JYTHON_EXT .py .py.in)
1554  set (JYTHON_LIB_DIRS)
1555  if (JYTHON_VERSION_MAJOR)
1556  list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/jython${JYTHON_VERSION_MAJOR}")
1557  endif ()
1558  list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}/jython")
1559  list (APPEND JYTHON_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
1560  else ()
1561  set (JYTHON_LIB_DIRS)
1562  endif ()
1563  # Perl
1564  if (Perl_FOUND)
1565  set (PERL_EXT .pm .pm.in)
1566  set (PERL_LIB_DIRS)
1567  if (PERL_VERSION_MAJOR)
1568  list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}/perl${PERL_VERSION_MAJOR}")
1569  endif ()
1570  list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}/perl")
1571  list (APPEND PERL_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
1572  else ()
1573  set (PERL_LIB_DIRS)
1574  endif ()
1575  # MATLAB
1576  if (MATLAB_FOUND)
1577  set (MATLAB_EXT .m .m.in)
1578  set (MATLAB_LIB_DIRS)
1579  if (MATLAB_RELEASE)
1580  list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab/${MATLAB_RELEASE}")
1581  endif ()
1582  if (MATLAB_VERSION_MAJOR)
1583  list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab${MATLAB_VERSION_MAJOR}")
1584  endif ()
1585  list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}/matlab")
1586  list (APPEND MATLAB_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
1587  else ()
1588  set (MATLAB_LIB_DIRS)
1589  endif ()
1590  # Bash
1591  if (BASH_FOUND)
1592  set (BASH_EXT .sh .sh.in)
1593  set (BASH_LIB_DIRS)
1594  if (BASH_VERSION_MAJOR)
1595  list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}/bash${BASH_VERSION_MAJOR}")
1596  endif ()
1597  list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}/bash")
1598  list (APPEND BASH_LIB_DIRS "${PROJECT_LIBRARY_DIR}")
1599  else ()
1600  set (BASH_LIB_DIRS)
1601  endif ()
1602  # add library targets
1603  set (TARGETS)
1604  foreach (LANGUAGE IN ITEMS PYTHON JYTHON PERL MATLAB BASH)
1605  foreach (LIB_DIR IN LISTS ${LANGUAGE}_LIB_DIRS)
1606  set (EXPRESSIONS)
1607  foreach (MODULE_EXT IN LISTS ${LANGUAGE}_EXT)
1608  list (APPEND EXPRESSIONS "${LIB_DIR}/**${MODULE_EXT}")
1609  endforeach ()
1610  file (GLOB_RECURSE SOURCES ${EXPRESSIONS})
1611  if (SOURCES)
1612  basis_get_source_language (SOURCE_LANGUAGE ${SOURCES}) # in particular required to
1613  # not falsely build Jython modules
1614  # as Python library
1615  if (SOURCE_LANGUAGE MATCHES "UNKNOWN|AMBIGUOUS")
1616  message (WARNING "Failed to auto-detect scripting language of modules in ${LIB_DIR}!"
1617  " Skipping source files matching one of the extensions [${${LANGUAGE}_EXT}].")
1618  elseif (SOURCE_LANGUAGE MATCHES "${LANGUAGE}")
1619  if (DEFINED ${LANGUAGE}_LIBRARY_TARGET)
1620  message (FATAL_ERROR "Variable ${LANGUAGE}_LIBRARY_TARGET is obsolete, use BASIS_${LANGUAGE}_LIBRARY_TARGET instead!")
1621  endif ()
1622  set (TARGET_NAME "${BASIS_${LANGUAGE}_LIBRARY_TARGET}")
1623  if (NOT TARGET_NAME)
1624  message (FATAL_ERROR "Variable BASIS_${LANGUAGE}_LIBRARY_TARGET not set (cf. BasisSettings module)!")
1625  endif ()
1626  basis_add_library (${TARGET_NAME} ${EXPRESSIONS} LANGUAGE ${LANGUAGE})
1627  basis_set_target_properties (
1628  ${TARGET_NAME}
1629  PROPERTIES
1630  SOURCE_DIRECTORY "${LIB_DIR}"
1631  LIBRARY_OUTPUT_DIRECTORY "${BINARY_${LANGUAGE}_LIBRARY_DIR}"
1632  LIBRARY_INSTALL_DIRECTORY "${INSTALL_${LANGUAGE}_SITE_DIR}"
1633  PREFIX ""
1634  )
1635  list (APPEND TARGETS ${TARGET_NAME})
1636  break ()
1637  endif ()
1638  endif ()
1639  endforeach ()
1640  endforeach ()
1641  if (TARGETS)
1642  basis_make_target_uid (LIBRARY_TARGET lib)
1643  if (NOT TARGET ${LIBRARY_TARGET})
1644  add_custom_target (${LIBRARY_TARGET} ALL)
1645  endif ()
1646  basis_add_dependencies (${LIBRARY_TARGET} ${TARGETS})
1647  endif ()
1648 endfunction ()
1649 
1650 # ----------------------------------------------------------------------------
1651 ## @brief Configure root documentation files.
1652 #
1653 # The root documentation files are located in the top-level directory of the
1654 # project's source tree. These are, in particular, the
1655 # * @c AUTHORS.txt or AUTHORS.md file with information on the authors of the software,
1656 # * @c COPYING.txt or COPYING.md file with copyright and licensing information,
1657 # * @c README.txt or README.md file,
1658 # * @c INSTALL.txt or INSTALL.md file with build and installation instructions,
1659 # * @c WELCOME.txt or WELCOME.md file with text used as welcome text of the installer.
1660 # where the top-level project requires all of these files except of the
1661 # @c WELCOME.txt or WELCOME.md file which defaults to the readme file. Modules of a project
1662 # usually do not include any of these files. Otherwise, the content of the
1663 # module's documentation file is appended to the corresponding file of the
1664 # top-level project.
1665 macro (basis_configure_root_documentation_files)
1666  foreach (F AUTHORS COPYING README INSTALL WELCOME)
1667 
1668  if (EXISTS "${PROJECT_SOURCE_DIR}/${F}.txt")
1669  set (PROJECT_${F}_FILE "${PROJECT_SOURCE_DIR}/${F}.txt")
1670  set (DOC_EXT ".txt")
1671  elseif (EXISTS "${PROJECT_SOURCE_DIR}/${F}.md")
1672  set (PROJECT_${F}_FILE "${PROJECT_SOURCE_DIR}/${F}.md")
1673  set (DOC_EXT ".md")
1674  endif ()
1675 
1676  if (EXISTS "${PROJECT_SOURCE_DIR}/${F}${DOC_EXT}")
1677  set (PROJECT_${F}_FILE "${PROJECT_SOURCE_DIR}/${F}${DOC_EXT}")
1678  if (PROJECT_IS_MODULE)
1679  file (READ "${PROJECT_${F}_FILE}" T)
1680  file (
1681  APPEND "${TOPLEVEL_PROJECT_${F}_FILE}"
1682  "\n\n\n"
1683  "------------------------------------------------------------------------------\n"
1684  "${PROJECT_NAME} Module\n"
1685  "------------------------------------------------------------------------------\n"
1686  "${T}"
1687  )
1688  else ()
1689  set (TOPLEVEL_PROJECT_${F}_FILE "${PROJECT_BINARY_DIR}/${F}${DOC_EXT}")
1690  # do not use configure_file() to copy the file, otherwise CMake will
1691  # update the build system only because we modified this file in the if-clause
1692  execute_process (COMMAND "${CMAKE_COMMAND}" -E copy "${PROJECT_${F}_FILE}" "${TOPLEVEL_PROJECT_${F}_FILE}")
1693  # use extension on Windows, but leave it out on Unix
1694  get_filename_component (N "${F}" NAME_WE)
1695  get_filename_component (E "${F}" EXT)
1696  if (WIN32)
1697  if (NOT E)
1698  set (E "${DOC_EXT}")
1699  endif ()
1700  else ()
1701  if ("${E}" STREQUAL "${DOC_EXT}")
1702  set (E "")
1703  endif ()
1704  endif ()
1705  set (N "${N}${E}")
1706  # install file
1707  if (F MATCHES "COPYING")
1708  install (
1709  FILES "${PROJECT_BINARY_DIR}/${F}${DOC_EXT}"
1710  DESTINATION "${INSTALL_DOC_DIR}"
1711  RENAME "${N}"
1712  OPTIONAL
1713  )
1714  endif ()
1715  endif ()
1716  endif ()
1717  endforeach ()
1718  set (PROJECT_LICENSE_FILE "${PROJECT_COPYING_FILE}") # compatibility with Slicer
1719 endmacro ()
1720 
1721 # ----------------------------------------------------------------------------
1722 ## @brief Get build time stamp.
1723 #
1724 # The build time stamp is used as an alternative to the version and revision
1725 # information in @c PROJECT_RELEASE if version is invalid, i.e., set to 0.0.0
1726 # as is the case for development branches, and now revision from a revision
1727 # control system is available.
1728 function (basis_get_build_timestamp TIMESTAMP)
1729  if (WIN32)
1730  execute_process (
1731  COMMAND "${BASIS_MODULE_PATH}/buildtimestamp.cmd"
1732  RESULT_VARIABLE RT
1733  OUTPUT_VARIABLE BUILD_TIMESTAMP
1734  ERROR_QUIET
1735  OUTPUT_STRIP_TRAILING_WHITESPACE
1736  )
1737  else ()
1738  execute_process (
1739  COMMAND "date" -u "+%Y.%m.%d (%H:%M UTC)"
1740  RESULT_VARIABLE RT
1741  OUTPUT_VARIABLE BUILD_TIMESTAMP
1742  ERROR_QUIET
1743  OUTPUT_STRIP_TRAILING_WHITESPACE
1744  )
1745  endif ()
1746  if (RT EQUAL 0)
1747  set (${TIMESTAMP} "${BUILD_TIMESTAMP}" PARENT_SCOPE)
1748  else ()
1749  set (${TIMESTAMP} PARENT_SCOPE)
1750  endif ()
1751 endfunction ()
1752 
1753 # ----------------------------------------------------------------------------
1754 ## @brief Find standard project logo files with standardized @c PROJECT_${LOGO_TYPE}_LOGO variable names
1755 # This is an internal function not designed for general use.
1756 #
1757 # @param OUTPUT_VARIABLE the name of the variable that will contain the final
1758 # @param SPECIFIED_LOGO the value that is already set for the logo
1759 # @param DEFAULT_NAME the default filename of the logo
1760 #
1761 function (basis_find_logo OUTPUT_VARIABLE SPECIFIED_LOGO DEFAULT_NAME)
1762  # check for the default logo file locations
1763  if (NOT SPECIFIED_LOGO)
1764  if (EXISTS "${PROJECT_DOCRES_DIR}/${DEFAULT_NAME}")
1765  set (${OUTPUT_VARIABLE} "${PROJECT_DOCRES_DIR}/${DEFAULT_NAME}")
1766  elseif (EXISTS "${PROJECT_DOC_DIR}/${DEFAULT_NAME}")
1767  set (${OUTPUT_VARIABLE} "${PROJECT_DOC_DIR}/${DEFAULT_NAME}")
1768  endif ()
1769  endif()
1770 
1771  # if no logo is specified at all, skip this
1772  if (${OUTPUT_VARIABLE})
1773  if (NOT IS_ABSOLUTE "${SPECIFIED_LOGO}")
1774  if (EXISTS "${PROJECT_DOCRES_DIR}/${SPECIFIED_LOGO}")
1775  set (${OUTPUT_VARIABLE} "${PROJECT_DOCRES_DIR}/${SPECIFIED_LOGO}")
1776  elseif (EXISTS "${PROJECT_DOC_DIR}/${SPECIFIED_LOGO}")
1777  set (${OUTPUT_VARIABLE} "${PROJECT_DOC_DIR}/${SPECIFIED_LOGO}")
1778  else ()
1779  set (${OUTPUT_VARIABLE} "${PROJECT_SOURCE_DIR}/${SPECIFIED_LOGO}")
1780  endif ()
1781  endif ()
1782 
1783  if (EXISTS "${${OUTPUT_VARIABLE}}")
1784  set(${OUTPUT_VARIABLE} "${${OUTPUT_VARIABLE}}" PARENT_SCOPE)
1785  else()
1786  message (AUTHOR_WARNING "Problem:\n${OUTPUT_VARIABLE} file specified in the BasisProject.cmake"
1787  " basis_project() call of the project ${PROJECT_NAME} was not found.\n"
1788  "Solutions:"
1789  "\n\t1. Add a logo file to one of the appropriate locations detailed below."
1790  "\n\t2. Correct the path if the logo exists."
1791  "\n\t3. Remove the line specifying the logo to look for if it does not exist."
1792  "\n\nExpected to find file:\n\t${SPECIFIED_LOGO}\n\n"
1793  "Directories checked:\n\t${PROJECT_DOCRES_DIR}\n\t${PROJECT_DOC_DIR}\n\t${PROJECT_SOURCE_DIR}\n\n")
1794  endif ()
1795  endif ()
1796 endfunction()
1797 
1798 # ----------------------------------------------------------------------------
1799 ## @brief Initialize project, calls CMake's project() command.
1800 #
1801 # @sa basis_project(), basis_project_begin()
1802 #
1803 # @returns Sets the following non-cached CMake variables:
1804 # @retval PROJECT_REVISION Revision number of Subversion controlled
1805 # source tree or 0 if the source tree is
1806 # not under revision control.
1807 # @retval PROJECT_RELEASE A string of project version and revision
1808 # that can be used for the output of
1809 # version information. The format of this
1810 # string is either one of the following:
1811 # - "v1.0 (r42)"
1812 # - "v1.0.5 (r50)"
1813 # - "v1.0" (if revision unknown)
1814 # - "r42" (if version is 0.0.0)
1815 # - "" (otherwise)
1816 macro (basis_project_initialize)
1817  # --------------------------------------------------------------------------
1818  # CMake version and policies
1819  cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)
1820 
1821  # Add policies introduced with CMake versions newer than the one specified
1822  # above. These policies would otherwise trigger a policy not set warning by
1823  # newer CMake versions.
1824 
1825  if (POLICY CMP0016)
1826  cmake_policy (SET CMP0016 NEW)
1827  endif ()
1828 
1829  if (POLICY CMP0017)
1830  cmake_policy (SET CMP0017 NEW)
1831  endif ()
1832 
1833  if (POLICY CMP0048)
1834  # PROJECT_VERSION et al. variables are set by basis_project instead
1835  cmake_policy (SET CMP0048 OLD)
1836  endif ()
1837 
1838  # --------------------------------------------------------------------------
1839  # reset
1840 
1841  # only set if not set by top-level project before configuring a module
1842  basis_set_if_empty (PROJECT_IS_MODULE FALSE)
1843  # set only by basis_use_package() to TRUE such that functions such as
1844  # the overwritten (basis_)link_directories() command or add_library()
1845  # know that these directories/targets belong to an external project which
1846  # is part of the same superbuild. otherwise, it shall be FALSE.
1847  set (BUNDLE_PROJECT FALSE)
1848 
1849  # hide it here to avoid that it shows up in the GUI on error
1850  set (CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "" FORCE)
1851 
1852  # --------------------------------------------------------------------------
1853  # project meta-data
1854  if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
1855  set (BASIS_basis_project_CALLED FALSE)
1856  set (PROJECT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
1857  include ("${CMAKE_CURRENT_SOURCE_DIR}/BasisProject.cmake")
1858  if (NOT BASIS_basis_project_CALLED)
1859  message (FATAL_ERROR "Missing basis_project() command in BasisProject.cmake!")
1860  endif ()
1861  else ()
1862  message (FATAL_ERROR "Missing BasisProject.cmake file!")
1863  endif ()
1864 
1865  # --------------------------------------------------------------------------
1866  # project()
1867  set (LANGUAGES)
1868  foreach (lang IN LISTS PROJECT_LANGUAGES)
1869  if (lang MATCHES "^(C|CXX)$")
1870  list (APPEND LANGUAGES ${lang})
1871  elseif (lang MATCHES "^CXX-?[0-9][0-9x]+$")
1872  list (APPEND LANGUAGES CXX)
1873  endif ()
1874  endforeach ()
1875 
1876  project ("${PROJECT_NAME}" ${LANGUAGES})
1877 
1878  # work-around for issue with CMAKE_PROJECT_NAME always being set to 'Project'
1879  if ("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
1880  set_property (CACHE CMAKE_PROJECT_NAME PROPERTY VALUE "${PROJECT_NAME}")
1881  endif ()
1882 
1883  # C++ standard
1884  if (PROJECT_LANGUAGES MATCHES "CXX-?([0-9][0-9x]*)")
1885  set (CXX_VERSION ${CMAKE_MATCH_1})
1886  if (CMAKE_VERSION VERSION_LESS 3.1)
1887  # no automatic C++ standard compiler flag support before CMake 3.1
1888  if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
1889  include(CheckCXXCompilerFlag)
1890  CHECK_CXX_COMPILER_FLAG("-std=c++${CXX_VERSION}" COMPILER_SUPPORTS_CXX${CXX_VERSION})
1891  if (CXX_VERSION STREQUAL "11" AND NOT COMPILER_SUPPORTS_CXX${CXX_VERSION})
1892  CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX${CXX_VERSION})
1893  endif ()
1894  if (COMPILER_SUPPORTS_CXX${CXX_VERSION})
1895  if (NOT CMAKE_CXX_FLAGS MATCHES "-std=c\\+\\+${CXX_VERSION}")
1896  if (CMAKE_CXX_FLAGS)
1897  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ")
1898  endif ()
1899  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-std=c++${CXX_VERSION}")
1900  endif ()
1901  else ()
1902  message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++${CXX_VERSION} support. Please use a different C++ compiler.")
1903  endif ()
1904  endif ()
1905  else ()
1906  # default values for C++ standard related target properties
1907  set (CMAKE_CXX_STANDARD ${CXX_VERSION})
1908  set (CMAKE_CXX_STANDARD_REQUIRED TRUE)
1909  set (CMAKE_CXX_EXTENSIONS FALSE)
1910  endif ()
1911  unset (CXX_VERSION)
1912  endif ()
1913 
1914  # get revision of project
1915  #
1916  # Note: Use revision when branch, i.e., either trunk, a branch, or a tag
1917  # has been modified last. For tags, this should in particular
1918  # correspond to the revision when the tag was created.
1919  basis_is_git_repository (PROJECT_IS_GIT_REPOSITORY "${PROJECT_SOURCE_DIR}")
1920  if (BASIS_REVISION_INFO)
1921  if (PROJECT_IS_GIT_REPOSITORY)
1922  basis_git_get_revision ("${PROJECT_SOURCE_DIR}" PROJECT_REVISION 7)
1923  else ()
1924  basis_svn_get_last_changed_revision ("${PROJECT_SOURCE_DIR}" PROJECT_REVISION)
1925  endif ()
1926  else ()
1927  set (PROJECT_REVISION 0)
1928  endif ()
1929 
1930  # extract version numbers from version string
1931  basis_version_numbers (
1932  "${PROJECT_VERSION}"
1933  PROJECT_VERSION_MAJOR
1934  PROJECT_VERSION_MINOR
1935  PROJECT_VERSION_PATCH
1936  )
1937 
1938  if (NOT DEFINED PROJECT_SOVERSION OR PROJECT_SOVERSION STREQUAL "")
1939  set (PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}")
1940  endif ()
1941 
1942  # version information string
1943  if (PROJECT_VERSION MATCHES "^0+(\\.0+)?(\\.0+)?")
1944  if (PROJECT_REVISION)
1945  if (PROJECT_IS_GIT_REPOSITORY)
1946  set (PROJECT_RELEASE "${PROJECT_REVISION}")
1947  else ()
1948  set (PROJECT_RELEASE "r${PROJECT_REVISION}")
1949  endif ()
1950  else ()
1951  basis_get_build_timestamp (BUILD_TIMESTAMP)
1952  if (BUILD_TIMESTAMP)
1953  set (PROJECT_RELEASE "b${BUILD_TIMESTAMP}")
1954  else ()
1955  set (PROJECT_RELEASE "")
1956  endif ()
1957  endif ()
1958  else ()
1959  set (PROJECT_RELEASE "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
1960  if (PROJECT_VERSION_PATCH)
1961  set (PROJECT_RELEASE "${PROJECT_RELEASE}.${PROJECT_VERSION_PATCH}")
1962  endif ()
1963  if (PROJECT_VERSION MATCHES "^[0-9]+(\\.[0-9]+)(\\.[0-9]+)([a-zA-Z][a-zA-Z0-9]*)")
1964  set (PROJECT_RELEASE "${PROJECT_RELEASE}${CMAKE_MATCH_3}") # add rc, beta, alpha prefix
1965  endif ()
1966  if (PROJECT_REVISION)
1967  if (PROJECT_IS_GIT_REPOSITORY)
1968  set (PROJECT_RELEASE "${PROJECT_RELEASE} (${PROJECT_REVISION})")
1969  else ()
1970  set (PROJECT_RELEASE "${PROJECT_RELEASE} (r${PROJECT_REVISION})")
1971  endif ()
1972  endif ()
1973  endif ()
1974 
1975  set (PROJECT_VERSION_AND_REVISION "${PROJECT_RELEASE}") # backwards compatibility to BASIS < 1.3
1976 
1977  # version number for use in Perl modules
1978  set (PROJECT_VERSION_PERL "${PROJECT_VERSION_MAJOR}")
1979  if (PROJECT_VERSION_MAJOR LESS 10)
1980  set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.0${PROJECT_VERSION_MINOR}")
1981  else ()
1982  set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}.${PROJECT_VERSION_MINOR}")
1983  endif ()
1984  if (PROJECT_VERSION_PATCH LESS 10)
1985  set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_0${PROJECT_VERSION_PATCH}")
1986  else ()
1987  set (PROJECT_VERSION_PERL "${PROJECT_VERSION_PERL}_${PROJECT_VERSION_PATCH}")
1988  endif ()
1989 
1990  # print project information
1991  if (NOT PROJECT_IS_MODULE)
1992  message (STATUS "${PROJECT_NAME} ${PROJECT_RELEASE}")
1993  endif ()
1994 
1995  # --------------------------------------------------------------------------
1996  # reset project properties - *after* PROJECT_NAME was set
1997 
1998  # The following variables are used across BASIS macros and functions. They
1999  # in particular remember information added by one function or macro which
2000  # is required by another function or macro.
2001  #
2002  # These variables need to be properties such that they can be set in
2003  # subdirectories. Moreover, they have to be assigned with the project's
2004  # root source directory such that a top-level project's properties are restored
2005  # after this subproject is finalized such that the top-level project itself can
2006  # be finalized properly.
2007  #
2008  # Attention: In particular the IMPORTED_* properties are already used
2009  # during the import of targets when including the use files of
2010  # external packages. Hence, this property has to be reset before.
2011 
2012  # see basis_add_imported_target()
2013  basis_set_project_property (PROPERTY IMPORTED_TARGETS "")
2014  basis_set_project_property (PROPERTY IMPORTED_TYPES "")
2015  basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "")
2016  basis_set_project_property (PROPERTY IMPORTED_RANKS "")
2017  # see basis_include_directories()
2018  basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS "")
2019  # see basis_link_directories()
2020  basis_set_project_property (PROPERTY PROJECT_LINK_DIRS "")
2021  basis_set_project_property (PROPERTY BUNDLE_LINK_DIRS "")
2022  # see add_executable(), add_library()
2023  basis_set_project_property (PROPERTY TARGETS "")
2024  # see basis_finalize_targets()
2025  basis_set_project_property (PROPERTY FINALIZED_TARGETS "")
2026  # see basis_add_*() functions
2027  basis_set_project_property (PROPERTY EXPORT_TARGETS "")
2028  basis_set_project_property (PROPERTY INSTALL_EXPORT_TARGETS "")
2029  basis_set_project_property (PROPERTY CUSTOM_EXPORT_TARGETS "")
2030  basis_set_project_property (PROPERTY TEST_EXPORT_TARGETS "")
2031  basis_set_project_property (PROPERTY PROJECT_USES_CXX_UTILITIES FALSE)
2032  basis_set_project_property (PROPERTY PROJECT_USES_PYTHON_UTILITIES FALSE)
2033  basis_set_project_property (PROPERTY PROJECT_USES_PERL_UTILITIES FALSE)
2034  basis_set_project_property (PROPERTY PROJECT_USES_BASH_UTILITIES FALSE)
2035  # yet unused
2036  basis_set_project_property (PROPERTY PROJECT_USES_JAVA_UTILITIES FALSE)
2037  basis_set_project_property (PROPERTY PROJECT_USES_MATLAB_UTILITIES FALSE)
2038 
2039  # --------------------------------------------------------------------------
2040  # configure BASIS directory structure
2041  include ("${BASIS_MODULE_PATH}/DirectoriesSettings.cmake")
2042  # configure file used for the generation of the corresponding documentation
2043  configure_file (
2044  "${BASIS_MODULE_PATH}/Directories.cmake.in"
2045  "${BINARY_CONFIG_DIR}/Directories.cmake"
2046  @ONLY
2047  )
2048 endmacro ()
2049 
2050 # ----------------------------------------------------------------------------
2051 ## @brief Initialize project settings.
2052 macro (basis_initialize_settings)
2053  # --------------------------------------------------------------------------
2054  # include project specific settings
2055  #
2056  # This file enables the project to modify the default behavior of BASIS,
2057  # but only if BASIS allows so as the BASIS project settings are included
2058  # afterwards.
2059  if (EXISTS "${PROJECT_CONFIG_DIR}/Settings.cmake.in")
2060  configure_file (
2061  "${PROJECT_CONFIG_DIR}/Settings.cmake.in"
2062  "${BINARY_CONFIG_DIR}/Settings.cmake"
2063  @ONLY
2064  )
2065  include ("${BINARY_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE)
2066  else ()
2067  include ("${PROJECT_CONFIG_DIR}/Settings.cmake" NO_POLICY_SCOPE OPTIONAL)
2068  endif ()
2069 
2070  # --------------------------------------------------------------------------
2071  # project logos
2072  basis_find_logo(PROJECT_PACKAGE_LOGO "${PROJECT_PACKAGE_LOGO}" "logo.png")
2073  basis_find_logo(PROJECT_PROVIDER_LOGO "${PROJECT_PROVIDER_LOGO}" "provider_logo.png")
2074  basis_find_logo(PROJECT_DIVISION_LOGO "${PROJECT_DIVISION_LOGO}" "division_logo.png")
2075 
2076  # --------------------------------------------------------------------------
2077  # configure project specific BASIS settings
2078  set (_TOPLEVEL_NAMESPACE_CMAKE "${PROJECT_PACKAGE_NAME_L}")
2079  # default namespaces used for supported programming languages
2080  foreach (_L IN LISTS BASIS_LANGUAGES_U)
2081  if (_L MATCHES "PERL")
2082  set (_NAMESPACE_${_L} "${PROJECT_PACKAGE_NAME}")
2083  else ()
2084  set (_NAMESPACE_${_L} "${PROJECT_PACKAGE_NAME_L}")
2085  endif ()
2086  endforeach ()
2087  if (PROJECT_IS_SUBPROJECT)
2088  foreach (_L IN LISTS BASIS_LANGUAGES_U)
2089  if (_L MATCHES "PERL")
2090  set (_NAMESPACE_${_L} "${_NAMESPACE_${_L}}${BASIS_NAMESPACE_DELIMITER_${_L}}${PROJECT_NAME}")
2091  else ()
2092  set (_NAMESPACE_${_L} "${_NAMESPACE_${_L}}${BASIS_NAMESPACE_DELIMITER_${_L}}${PROJECT_NAME_L}")
2093  endif ()
2094  endforeach ()
2095  endif ()
2096  # package configuration
2097  set (_TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX "${TOPLEVEL_PROJECT_PACKAGE_NAME}")
2098  if (PROJECT_IS_MODULE OR PROJECT_IS_SUBMODULE)
2099  set (_PROJECT_PACKAGE_CONFIG_PREFIX "${_TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX}${PROJECT_NAME}")
2100  else ()
2101  set (_PROJECT_PACKAGE_CONFIG_PREFIX "${_TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX}")
2102  endif ()
2103  if (PROJECT_PACKAGE_VENDOR)
2104  set (_TOPLEVEL_PROJECT_PACKAGE_UID "${PROJECT_PACKAGE_VENDOR}-${PROJECT_PACKAGE_NAME}-${PROJECT_VERSION}")
2105  else ()
2106  set (_TOPLEVEL_PROJECT_PACKAGE_UID "${PROJECT_PACKAGE_NAME}-${PROJECT_VERSION}")
2107  endif ()
2108  # configure settings file which contains the documentation of these variables
2109  configure_file (
2110  "${BASIS_MODULE_PATH}/ProjectSettings.cmake.in"
2111  "${BINARY_CONFIG_DIR}/ProjectSettings.cmake"
2112  @ONLY
2113  )
2114  # unset local variables
2115  unset (_TOPLEVEL_NAMESPACE_CMAKE)
2116  foreach (_L IN LISTS BASIS_LANGUAGES_U)
2117  unset (_NAMESPACE_${_L})
2118  endforeach ()
2119  unset (_TOPLEVEL_PROJECT_PACKAGE_UID)
2120  unset (_TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX)
2121  unset (_PROJECT_PACKAGE_CONFIG_PREFIX)
2122  unset (_L)
2123  # include configured project specific BASIS settings
2124  include ("${BINARY_CONFIG_DIR}/ProjectSettings.cmake" NO_POLICY_SCOPE)
2125 endmacro ()
2126 
2127 # ----------------------------------------------------------------------------
2128 ## @brief Find packages this project depends on.
2129 macro (basis_find_packages)
2130  set (BASIS_SET_TARGET_PROPERTIES_IMPORT TRUE) # see set_target_properties()
2131 
2132  # --------------------------------------------------------------------------
2133  # add project config directory to CMAKE_MODULE_PATH
2134  set (CMAKE_MODULE_PATH "${PROJECT_CONFIG_DIR}" ${CMAKE_MODULE_PATH})
2135 
2136  # --------------------------------------------------------------------------
2137  # required dependencies
2138  foreach (P IN LISTS PROJECT_DEPENDS)
2139  basis_find_package ("${P}" REQUIRED)
2140  basis_use_package ("${P}" REQUIRED)
2141  endforeach ()
2142 
2143  # --------------------------------------------------------------------------
2144  # optional dependencies
2145  foreach (P IN LISTS PROJECT_OPTIONAL_DEPENDS)
2146  basis_find_package ("${P}")
2147  basis_use_package ("${P}")
2148  endforeach ()
2149 
2150  # --------------------------------------------------------------------------
2151  # application dependencies
2152  if (BUILD_APPLICATIONS)
2153  # required application dependencies
2154  foreach (P IN LISTS PROJECT_TOOLS_DEPENDS)
2155  basis_find_package ("${P}" REQUIRED NO_NOTFOUND_ERROR)
2156  basis_tokenize_dependency ("${P}" PKG VER CMPS)
2157  string (TOUPPER "${PKG}" PKG_U)
2158  if (NOT ${PKG}_FOUND AND NOT ${PKG_U}_FOUND)
2159  set (msg "Could not find package ${PKG}! It is required by the applications"
2160  " of ${PROJECT_NAME}. Please ensure that the package is installed"
2161  " in a standard system location or set DEPENDS_${PKG}_DIR to the"
2162  " installation prefix (i.e., top-level directory of the installation).")
2163  if (DEFINED ${PKG}_DIR OR DEFINED ${PKG_U}_DIR)
2164  string (TOLOWER "${PKG}" PKG_L)
2165  set (msg "${msg}\nThe DEPENDS_${PKG}_DIR variable can alternatively be set"
2166  " to the directory containing a ${PKG}Config.cmake or ${PKG_L}-config.cmake"
2167  " file. If no such file exists, contact either the developer of"
2168  " this project or CMake BASIS to provide a Find${PKG}.cmake file.")
2169  endif ()
2170  set (msg "${msg}\nTo disable the build of the applications, set BUILD_APPLICATIONS to OFF.")
2171  basis_list_to_string(msg ${msg})
2172  message (FATAL_ERROR "\n${msg}\n")
2173  endif ()
2174  basis_use_package ("${P}" REQUIRED)
2175  unset (PKG_U)
2176  unset (PKG)
2177  unset (VER)
2178  unset (CMPS)
2179  endforeach ()
2180  # optional application dependencies
2181  foreach (P IN LISTS PROJECT_OPTIONAL_TOOLS_DEPENDS)
2182  basis_find_package ("${P}")
2183  basis_use_package ("${P}")
2184  endforeach ()
2185  endif ()
2186 
2187  # --------------------------------------------------------------------------
2188  # test dependencies
2189  if (BUILD_TESTING)
2190  # required test dependencies
2191  foreach (P IN LISTS PROJECT_TEST_DEPENDS)
2192  basis_find_package ("${P}" REQUIRED NO_NOTFOUND_ERROR)
2193  basis_tokenize_dependency ("${P}" PKG VER CMPS)
2194  string (TOUPPER "${PKG}" PKG_U)
2195  if (NOT ${PKG}_FOUND AND NOT ${PKG_U}_FOUND)
2196  set (msg "Could not find package ${PKG}! It is required by the tests"
2197  " of ${PROJECT_NAME}. Please ensure that the package is installed"
2198  " in a standard system location or set DEPENDS_${PKG}_DIR to the"
2199  " installation prefix (i.e., top-level directory of the installation).")
2200  if (DEFINED ${PKG}_DIR OR DEFINED ${PKG_U}_DIR)
2201  string (TOLOWER "${PKG}" PKG_L)
2202  set (msg "${msg}\nThe DEPENDS_${PKG}_DIR variable can alternatively be set"
2203  " to the directory containing a ${PKG}Config.cmake or ${PKG_L}-config.cmake"
2204  " file. If no such file exists, contact either the developer of"
2205  " this project or CMake BASIS to provide a Find${PKG}.cmake file.")
2206  endif ()
2207  set (msg "${msg}\nTo disable the build of the tests, set BUILD_TESTING to OFF.")
2208  basis_list_to_string(msg ${msg})
2209  message (FATAL_ERROR "\n${msg}\n")
2210  endif ()
2211  basis_use_package ("${P}" REQUIRED)
2212  unset (PKG_U)
2213  unset (PKG)
2214  unset (VER)
2215  unset (CMPS)
2216  endforeach ()
2217  # optional test dependencies
2218  foreach (P IN LISTS PROJECT_OPTIONAL_TEST_DEPENDS)
2219  basis_find_package ("${P}")
2220  basis_use_package ("${P}")
2221  endforeach ()
2222  endif ()
2223 
2224  unset (P)
2225 
2226  # --------------------------------------------------------------------------
2227  # Depends.cmake
2228  #
2229  # This file is in particular of interest if an additional dependency is
2230  # required or may optionally be used if certain modules are enabled or
2231  # an optional dependency was found.
2232  include ("${PROJECT_CONFIG_DIR}/Depends.cmake" OPTIONAL)
2233 
2234  set (BASIS_SET_TARGET_PROPERTIES_IMPORT FALSE) # see set_target_properties()
2235 endmacro ()
2236 
2237 # ============================================================================
2238 # finalization
2239 # ============================================================================
2240 
2241 # ----------------------------------------------------------------------------
2242 ## @brief Add installation rules for public header files.
2243 macro (basis_install_public_headers)
2244  # subdirectory of basis.h header file
2245  basis_library_prefix (_BASIS_H_PREFIX CXX)
2246  # install public header files from source tree
2247  foreach (INCLUDE_DIR IN LISTS PROJECT_INCLUDE_DIRS)
2248  basis_install_directory ("${INCLUDE_DIR}" "${INSTALL_INCLUDE_DIR}" PATTERN "*.in" EXCLUDE)
2249  endforeach ()
2250 
2251  # install configured public header files, excluding BASIS utilities
2252  file (GLOB_RECURSE _CONFIGURED_PUBLIC_HEADERS "${BINARY_INCLUDE_DIR}/*")
2253  list (REMOVE_ITEM _CONFIGURED_PUBLIC_HEADERS "${BINARY_INCLUDE_DIR}/${_BASIS_H_PREFIX}basis.h")
2254  if (_CONFIGURED_PUBLIC_HEADERS)
2255  basis_install_directory (
2256  "${BINARY_INCLUDE_DIR}" "${INSTALL_INCLUDE_DIR}"
2257  REGEX "/${_BASIS_H_PREFIX}basis\\.h$" EXCLUDE # BASIS utilities header only installed
2258  # below if included by any other public header
2259  PATTERN "*.cmake" EXCLUDE # e.g., <Name>PublicHeaders.cmake file,
2260  PATTERN "*.cmake.*" EXCLUDE # see basis_configure_public_headers()
2261  )
2262  endif ()
2263  # "parse" public header files to check if C++ BASIS utilities are included
2264  if (NOT BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
2265  # get list of all public header files of project
2266  set (_PUBLIC_HEADERS)
2267  if (NOT BASIS_CONFIGURE_INCLUDES)
2268  foreach (INCLUDE_DIR IN LISTS PROJECT_INCLUDE_DIRS)
2269  file (GLOB_RECURSE __PUBLIC_HEADERS "${INCLUDE_DIR}/*.h")
2270  list (APPEND _PUBLIC_HEADERS "${__PUBLIC_HEADERS}")
2271  endforeach ()
2272  unset (__PUBLIC_HEADERS)
2273  endif ()
2274  list (APPEND _PUBLIC_HEADERS ${_CONFIGURED_PUBLIC_HEADERS})
2275  # check include statements of each public header file
2276  foreach (_A IN LISTS _PUBLIC_HEADERS)
2277  basis_utilities_check (_B "${_A}" CXX)
2278  if (_B)
2279  set (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES TRUE)
2280  break ()
2281  endif ()
2282  endforeach ()
2283  unset (_PUBLIC_HEADERS)
2284  unset (_A)
2285  unset (_B)
2286  endif ()
2287  unset (_CONFIGURED_PUBLIC_HEADERS)
2288  # install public header of BASIS utilities (optional)
2289  if (BASIS_INSTALL_PUBLIC_HEADERS_OF_CXX_UTILITIES)
2290  install (
2291  FILES "${BINARY_INCLUDE_DIR}/${_BASIS_H_DIR}/basis.h"
2292  DESTINATION "${INSTALL_INCLUDE_DIR}/${_BASIS_H_PREFIX}"
2293  COMPONENT "${BASIS_LIBRARY_COMPONENT}"
2294  )
2295  endif ()
2296 endmacro ()
2297 
2298 
2299 ## @}
2300 # end of Doxygen group
2301 
2302 # ============================================================================
2303 # root CMakeLists.txt implementation
2304 # ============================================================================
2305 
2306 # ----------------------------------------------------------------------------
2307 ## @brief Add subdirectory or ignore it if it does not exist.
2308 macro (basis_add_subdirectory SUBDIR)
2309  get_filename_component(_SUBDIR "${SUBDIR}" ABSOLUTE)
2310  if (EXISTS "${_SUBDIR}/CMakeLists.txt")
2311  if (EXISTS "${_SUBDIR}/BasisProject.cmake")
2312  basis_add_module_info (MODULE "${_SUBDIR}/BasisProject.cmake")
2313  list(APPEND PROJECT_MODULES_ENABLED ${MODULE})
2314  basis_add_module (${MODULE})
2315  unset(MODULE)
2316  else ()
2317  add_subdirectory ("${_SUBDIR}")
2318  endif ()
2319  elseif (BASIS_VERBOSE)
2320  message (WARNING "Skipping subdirectory ${SUBDIR}.")
2321  endif ()
2322  unset(_SUBDIR)
2323 endmacro ()
2324 
2325 # ----------------------------------------------------------------------------
2326 ## @brief Add a project module.
2327 macro (basis_add_module MODULE)
2328  if (PROJECT_IS_MODULE)
2329  message (FATAL_ERROR "A module cannot have submodules by itself!")
2330  endif ()
2331  set (PROJECT_IS_MODULE TRUE)
2332  # Set up modules, checking the super build special case first.
2333  # By default the else case with add_subdirectory() will be called.
2334  #
2335  # Note: - MODULE_${MODULE}_SOURCE_DIR is the location of the module source code.
2336  # - MODULE_${MODULE}_BINARY_DIR is the build directory for the module.
2337  # - ${MODULE}_INCLUDE_DIRS are the locations of public header files.
2338  if (BASIS_SUPERBUILD_MODULES)
2339  message (STATUS "Configuring super-build of module ${MODULE}...")
2340  basis_super_build (${MODULE}) # automatically uses: "${MODULE_${MODULE}_SOURCE_DIR}" "${MODULE_${MODULE}_BINARY_DIR}"
2341  message (STATUS "Configuring super-build of module ${MODULE}... - done")
2342  else ()
2343  message (STATUS "Configuring module ${MODULE}...")
2344  add_subdirectory ("${MODULE_${MODULE}_SOURCE_DIR}" "${MODULE_${MODULE}_BINARY_DIR}")
2345  message (STATUS "Configuring module ${MODULE}... - done")
2346  endif ()
2347  set (PROJECT_IS_MODULE FALSE)
2348  include ("${BINARY_LIBCONF_DIR}/${TOPLEVEL_PROJECT_PACKAGE_CONFIG_PREFIX}${MODULE}Config.cmake")
2349 endmacro ()
2350 
2351 # ----------------------------------------------------------------------------
2352 ## @brief Use a previously added project module.
2353 macro (basis_use_module MODULE)
2354  set (NO_${MODULE}_IMPORTS TRUE)
2355  include ("${${${MODULE}_CONFIG_PREFIX}_USE_FILE}")
2356  add_definitions(-DHAVE_${PROJECT_PACKAGE_NAME}_${MODULE})
2357 endmacro ()
2358 
2359 # ----------------------------------------------------------------------------
2360 ## @brief Marks the begining of a BASIS project.
2361 #
2362 # This macro initializes a BASIS project. It replaces CMake's project() command.
2363 # At first, the project is initialized and the BASIS settings configured using
2364 # the project information given in the <tt>BasisProject.cmake</tt> file which
2365 # must be located in the same directory.
2366 #
2367 # @sa BasisProject.cmake, basis_project(), basis_project_end(), basis_project_impl()
2368 #
2369 # @ingroup CMakeAPI
2370 macro (basis_project_begin)
2371 
2372  # --------------------------------------------------------------------------
2373  # set CMAKE_INSTALL_PREFIX to cached invalid value to have
2374  # basis_initialize_settings() set it to BASIS's default rather than CMake's
2375  # default even if this is not the first configure run because a previous
2376  # one was interrupted by an error such as a requird package that was not found
2377  if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
2378  set (CMAKE_INSTALL_PREFIX "" CACHE INTERNAL "Installation prefix." FORCE)
2379  endif ()
2380 
2381  # --------------------------------------------------------------------------
2382  # initialize project
2383  basis_project_initialize ()
2384 
2385  # --------------------------------------------------------------------------
2386  # load information of modules
2387  if (NOT PROJECT_IS_MODULE)
2388  basis_project_modules ()
2389  endif ()
2390 
2391  if (BASIS_DEBUG)
2392  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterDetectionOfModules.cmake")
2393  endif ()
2394 
2395  # --------------------------------------------------------------------------
2396  # initialize Slicer module
2397  if (BASIS_SUPPORT_SLICER_MODULES)
2398  basis_slicer_module_initialize ()
2399  endif ()
2400 
2401  # --------------------------------------------------------------------------
2402  # Python
2403 
2404  # In case of a Slicer Extension, the UseSlicer.cmake file of Slicer (>= 4.0)
2405  # will set PYTHON_EXECUTABLE and requires us not to set this variable before
2406  # the UseSlicer.cmake file has been included. Hence, we set this variable
2407  # here only if it has not been set by Slicer, but before any PythonInterp
2408  # dependency declared by this package such that the Python interpreter
2409  # configured while building BASIS is used to avoid conflicts of different
2410  # versions used to compile the Python utilities (if BASIS_COMPILE_SCRIPTS
2411  # was set to ON) and the one used to configure/build this package.
2412  #
2413  # Note: The PYTHON_EXECUTABLE variable has to be cached such that
2414  # PythonInterp.cmake does not look for the interpreter itself.
2415  if (BASIS_PYTHON_EXECUTABLE)
2416  set (
2417  PYTHON_EXECUTABLE
2418  "${BASIS_PYTHON_EXECUTABLE}"
2419  CACHE PATH
2420  "The Python interpreter."
2421  )
2422  mark_as_advanced (PYTHON_EXECUTABLE)
2423  endif ()
2424  # Note that PERL_EXECUTABLE and BASH_EXECUTABLE are set in BASISUse.cmake.
2425 
2426  # --------------------------------------------------------------------------
2427  # find packages
2428 
2429  # any package use file must be included after PROJECT_NAME was set as the
2430  # imported targets are added to the <Project>_IMPORTED_TARGETS property
2431  # using basis_set_project_property() in add_executable() and add_library()
2432  basis_use_package (BASIS)
2433  basis_find_packages ()
2434 
2435  if (BASIS_DEBUG)
2436  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFindDependencies.cmake")
2437  endif ()
2438 
2439  # --------------------------------------------------------------------------
2440  # get interpreter versions - set to invalid version if not available
2441  if (PYTHON_EXECUTABLE AND NOT PYTHON_VERSION_STRING)
2442  basis_get_python_version ()
2443  if (PYTHON_VERSION_MAJOR EQUAL 0 OR (PYTHON_VERSION_MAJOR EQUAL 1 AND PYTHON_VERSION_MINOR EQUAL 4))
2444  message (WARNING "Failed to determine Python version! Check if you can run \"${PYTHON_EXECUTABLE} -E\" in a Terminal.")
2445  endif ()
2446  endif ()
2447 
2448  if (JYTHON_EXECUTABLE AND NOT JYTHON_VERSION_STRING)
2449  basis_get_jython_version ()
2450  if (JYTHON_VERSION_MAJOR EQUAL 0)
2451  message (WARNING "Failed to determine Jython version! Check if you can run \"${JYTHON_EXECUTABLE}\".")
2452  endif ()
2453  endif ()
2454 
2455  if (PERL_EXECUTABLE AND NOT PERL_VERSION_STRING)
2456  basis_get_perl_version ()
2457  if (PERL_VERSION_MAJOR EQUAL 0)
2458  message (WARNING "Failed to determine Perl version! Check if you can run \"${PERL_EXECUTABLE}\".")
2459  endif ()
2460  endif ()
2461 
2462  if (BASH_EXECUTABLE AND NOT BASH_VERSION_STRING)
2463  basis_get_bash_version ()
2464  if (BASH_VERSION_MAJOR EQUAL 0)
2465  message (WARNING "Failed to determine Bash version! Check if you can run \"${BASH_EXECUTABLE}\".")
2466  endif ()
2467  endif ()
2468 
2469  if (MATLAB_EXECUTABLE AND NOT MATLAB_VERSION_STRING)
2470  basis_get_matlab_version ()
2471  if (MATLAB_VERSION_MAJOR EQUAL 0)
2472  message (WARNING "Failed to determine MATLAB version! Check if you can run \"${MATLAB_EXECUTABLE} -nodesktop -nosplash -r 'version,quit force'\" and try again.")
2473  endif ()
2474  endif ()
2475 
2476  # --------------------------------------------------------------------------
2477  # initialize settings
2478  basis_initialize_settings ()
2479 
2480  # --------------------------------------------------------------------------
2481  # assertions
2482  basis_buildtree_asserts ()
2483  basis_installtree_asserts ()
2484 
2485  # --------------------------------------------------------------------------
2486  # default script configuration - see basis_configure_script()
2487  set (BASIS_SCRIPT_CONFIG_FILE "${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake")
2488  configure_file ("${BASIS_MODULE_PATH}/ScriptConfig.cmake.in" "${BASIS_SCRIPT_CONFIG_FILE}" @ONLY)
2489  if (EXISTS "${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in")
2490  configure_file ("${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in" "${BINARY_CONFIG_DIR}/ScriptConfig.cmake" @ONLY)
2491  endif ()
2492 
2493  # --------------------------------------------------------------------------
2494  # root documentation files
2495  basis_configure_root_documentation_files ()
2496 
2497  # --------------------------------------------------------------------------
2498  # enable testing
2499  if (NOT PROJECT_IS_MODULE)
2500  include ("${BASIS_MODULE_PATH}/BasisTest.cmake")
2501  basis_disable_testing_if_no_tests ()
2502  endif ()
2503 
2504  # --------------------------------------------------------------------------
2505  # public header files and script libraries
2506 
2507  # dump currently defined CMake variables such that these can be used to
2508  # configure the .in public header and module files during the build step
2509  basis_include_directories (BEFORE "${BINARY_INCLUDE_DIR}"
2510  "${PROJECT_INCLUDE_DIRS}"
2511  "${PROJECT_CODE_DIRS}")
2512 
2513  if (BASIS_CONFIGURE_PUBLIC_HEADERS)
2514  basis_configure_public_headers ()
2515  endif ()
2516  if (IS_DIRECTORY "${PROJECT_LIBRARY_DIR}")
2517  basis_configure_script_libraries ()
2518  endif ()
2519 
2520  # --------------------------------------------------------------------------
2521  # subdirectories
2522 
2523  set(PROJECT_SUBDIRS)
2524  foreach (_SUBDIR IN LISTS PROJECT_CODE_DIRS)
2525  if (EXISTS "${_SUBDIR}/CMakeLists.txt")
2526  list (APPEND PROJECT_SUBDIRS "${_SUBDIR}")
2527  endif ()
2528  endforeach ()
2529  if (BUILD_APPLICATIONS)
2530  foreach (_SUBDIR IN LISTS PROJECT_TOOLS_DIRS)
2531  if (EXISTS "${_SUBDIR}/CMakeLists.txt")
2532  list (APPEND PROJECT_SUBDIRS "${_SUBDIR}")
2533  endif ()
2534  endforeach ()
2535  endif ()
2536  if (EXISTS "${PROJECT_DATA_DIR}/CMakeLists.txt")
2537  list (APPEND PROJECT_SUBDIRS "${PROJECT_DATA_DIR}")
2538  endif ()
2539  if (EXISTS "${PROJECT_TESTING_DIR}/CMakeLists.txt" AND BUILD_TESTING)
2540  list (APPEND PROJECT_SUBDIRS "${PROJECT_TESTING_DIR}")
2541  endif ()
2542  if (EXISTS "${PROJECT_EXAMPLE_DIR}/CMakeLists.txt" AND BUILD_EXAMPLE)
2543  list (APPEND PROJECT_SUBDIRS "${PROJECT_EXAMPLE_DIR}")
2544  endif ()
2545  foreach (_SUBDIR IN LISTS PROJECT_OTHER_DIRS)
2546  if (EXISTS "${_SUBDIR}/CMakeLists.txt")
2547  list (APPEND PROJECT_SUBDIRS "${_SUBDIR}")
2548  endif ()
2549  endforeach ()
2550  unset(_SUBDIR)
2551 
2552  if (BASIS_DEBUG)
2553  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterInitialization.cmake")
2554  endif ()
2555 endmacro ()
2556 
2557 # ----------------------------------------------------------------------------
2558 ## @brief Marks the end of a BASIS project.
2559 #
2560 # This macro performs all the steps needed to finalize the configuration of
2561 # a BASIS project, including in particular also the addition of custom build
2562 # targets which perform the actual build of custom build targets such as
2563 # the ones build using the MATLAB Compiler. This command must be the last
2564 # in the root CMakeLists.txt file of each project.
2565 #
2566 # @sa basis_project_begin(), basis_project_impl()
2567 #
2568 # @ingroup CMakeAPI
2569 macro (basis_project_end)
2570 
2571  if (BASIS_DEBUG)
2572  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesBeforeFinalization.cmake")
2573  endif ()
2574 
2575  # --------------------------------------------------------------------------
2576  # copy project properties of modules
2577  if (NOT PROJECT_IS_MODULE)
2578  # copy properties of modules
2579  foreach (M IN LISTS PROJECT_MODULES_ENABLED)
2580  foreach (P IN ITEMS TARGETS
2581  FINALIZED_TARGETS
2582  IMPORTED_TARGETS
2583  IMPORTED_TYPES
2584  IMPORTED_LOCATIONS
2585  IMPORTED_RANKS
2586  PROJECT_INCLUDE_DIRS
2587  PROJECT_LINK_DIRS
2588  BUNDLE_LINK_DIRS)
2589  basis_get_project_property (V ${M} ${P})
2590  basis_set_project_property (APPEND PROPERTY ${P} ${V})
2591  endforeach ()
2592  endforeach ()
2593  foreach (L IN ITEMS CXX PYTHON PERL BASH)
2594  foreach (M IN LISTS PROJECT_MODULES_ENABLED)
2595  basis_get_project_property (P ${M} PROJECT_USES_${L}_UTILITIES)
2596  if (P)
2597  basis_set_project_property (PROPERTY PROJECT_USES_${L}_UTILITIES TRUE)
2598  break ()
2599  endif ()
2600  endforeach ()
2601  endforeach ()
2602  endif ()
2603 
2604  # ----------------------------------------------------------------------------
2605  # finalize custom targets
2606  #
2607  # Note: Must be done *after* the TARGETS project properties of the modules
2608  # were copied as basis_finalize_targets() iterates over this list.
2609 
2610  # add missing build commands for custom targets
2611  basis_finalize_targets ()
2612  if (NOT PROJECT_IS_MODULE OR PROJECT_IS_SUBPROJECT)
2613  # configure the BASIS utilities
2614  basis_configure_utilities ()
2615  # add build target for missing __init__.py files of Python package
2616  if (BASIS_PYTHON_TEMPLATES_DIR)
2617  if (PythonInterp_FOUND OR JythonInterp_FOUND)
2618  basis_add_init_py_target ()
2619  endif ()
2620  endif ()
2621  endif ()
2622 
2623  # ----------------------------------------------------------------------------
2624  # build/install package documentation
2625  #
2626  # This is done after all files which may be interesting for inclusion
2627  # in the documentation are generated. In particular, this has to be done
2628  # after the configuration of the BASIS utilities.
2629  if (EXISTS "${PROJECT_DOC_DIR}/CMakeLists.txt" AND BUILD_DOCUMENTATION)
2630  add_subdirectory ("${PROJECT_DOC_DIR}")
2631  endif ()
2632 
2633  # --------------------------------------------------------------------------
2634  # generate configuration files
2635  include ("${BASIS_MODULE_PATH}/GenerateConfig.cmake")
2636 
2637  if (NOT BASIS_BUILD_ONLY)
2638 
2639  # --------------------------------------------------------------------------
2640  # write convenience file to setup MATLAB environment
2641  if (MATLAB_FOUND)
2642  basis_create_addpaths_mfile ()
2643  endif ()
2644 
2645  # --------------------------------------------------------------------------
2646  # add installation rules for public headers
2647  basis_install_public_headers ()
2648 
2649  # --------------------------------------------------------------------------
2650  # change log
2651  if (NOT PROJECT_IS_MODULE)
2652  basis_add_changelog ()
2653  endif ()
2654 
2655  # --------------------------------------------------------------------------
2656  # package software
2657  if (NOT PROJECT_IS_MODULE OR PROJECT_IS_SUBPROJECT)
2658  include ("${BASIS_MODULE_PATH}/BasisPack.cmake")
2659  endif ()
2660 
2661  # --------------------------------------------------------------------------
2662  # add installation rule to register package with CMake
2663  if (BASIS_REGISTER
2664  AND NOT PROJECT_IS_MODULE
2665  AND NOT PROJECT_IS_SUBMODULE
2666  AND PROJECT_VERSION VERSION_GREATER 0.0.0)
2667  basis_register_package ()
2668  endif ()
2669 
2670  # --------------------------------------------------------------------------
2671  # uninstaller
2672  if (NOT PROJECT_IS_MODULE)
2673  # add uninstall target
2674  basis_add_uninstall ()
2675  # Attention: add_uninstall must be called last in a separate file via an
2676  # add_subdirectory call. This ensures that the code is executed
2677  # at the end of the root cmake_install.cmake file.
2678  add_subdirectory ("${BASIS_MODULE_PATH}/uninstall" "${PROJECT_BINARY_DIR}/uninstall")
2679  endif ()
2680 
2681  endif ()
2682 
2683  if (BASIS_DEBUG)
2684  basis_dump_variables ("${PROJECT_BINARY_DIR}/VariablesAfterFinalization.cmake")
2685  endif ()
2686 
2687 endmacro ()
2688 
2689 # ----------------------------------------------------------------------------
2690 ## @brief Implementation of root <tt>CMakeLists.txt</tt> file of BASIS project.
2691 #
2692 # This macro implements the entire logic of the top-level
2693 # <tt>CMakeLists.txt</tt> file. At first, the project is initialized and the
2694 # BASIS settings configured using the project information given in the
2695 # <tt>BasisProject.cmake</tt> file which must be located in the same directory.
2696 # The, the code in the <tt>CMakeLists.txt</tt> files in the subdirectories is
2697 # executed in order. At the end, the configuration of the build system is
2698 # finalized, including in particular also the addition of custom build targets
2699 # which perform the actual build of custom build targets such as the ones build
2700 # using the MATLAB Compiler.
2701 #
2702 # @sa BasisProject.cmake, basis_project(), basis_project_begin(), basis_project_end()
2703 #
2704 # @ingroup CMakeAPI
2705 macro (basis_project_impl)
2706  # initialize project
2707  basis_project_begin ()
2708  # process modules
2709  if (NOT PROJECT_IS_MODULE)
2710  foreach (MODULE IN LISTS PROJECT_MODULES_ENABLED)
2711  basis_add_module (${MODULE})
2712  basis_use_module (${MODULE})
2713  endforeach ()
2714  endif ()
2715  # process subdirectories
2716  foreach (SUBDIR IN LISTS PROJECT_SUBDIRS)
2717  basis_add_subdirectory (${SUBDIR})
2718  endforeach ()
2719  # finalize project
2720  basis_project_end ()
2721 endmacro ()
string OPTIONAL
Definition: argparse.py:128
string PROJECT
Project name.
Definition: utilities.sh:79
cmake _MODULE
function basis_get_relative_path(out REL, in BASE, in PATH)
Get path relative to a given base directory.
cmake PROJECT_DOCRES_DIR
Absolute path to directory of documentation ressource files in source tree.
cmake PROJECT_EXAMPLE_DIR
Absolute path to directory of example in source tree.
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
cmake PROJECT_INCLUDE_DIRS
Absolute paths to directories of public header files in source tree.
cmake PROJECT_DOC_DIR
Absolute path to directory of documentation files in source tree.
function basis_get_module_info(in MODULE_NAME, in F, in ARGN)
cmake PROJECT_MODULES_DIR
Absolute path to directory containing project modules in subdirectories.
cmake PROJECT_LIBRARY_DIR
Absolute path to directory of public scripted packages.
cmake PROJECT_DATA_DIR
Absolute path to directory of auxiliary data in source tree.
cmake BINARY_INCLUDE_DIR
Absolute path to output directory for configured public header files.
option BUILD_TESTING
Request build of tests.
Definition: BasisTest.cmake:24
cmake PROJECT_MODULE_DIRS
Absolute paths to root directories of project modules.
macro basis_sanitize_for_regex(out OUT, in STR)
Sanitize string variable for use in regular expression.
macro basis_set_if_empty(out VAR, in ARGN)
Set value of variable only if variable is not set already.
macro basis_module_enable(in MODULE, in NEEDED_BY)
function basis_installtree_asserts(in ARGN)
Ensure certain requirements on install tree.
cmake NAME
cmake PROJECT_MODULES_ENABLED
function basis_buildtree_asserts(in ARGN)
Ensure certain requirements on build tree.
function basis_add_doxygen_doc(in TARGET_NAME, in ARGN)
Add documentation to be generated by Doxygen.
macro basis_check_or_set_source_paths(in _VAR)
Auxiliary macro used by basis_project_check_metadata.
macro basis_name_check(in INPUT_PROJECT_NAME)
Check if a project name fits the BASIS standards.
cmake PROJECT_CONFIG_DIR
Absolute path to directory of BASIS project configuration in source tree.
cmake __BASIS_PROJECTTOOLS_INCLUDED
function basis_list_to_string(out STR, in ARGN)
Concatenates all list elements into a single string.
macro basis_project_modules()
Initialize project modules.
macro basis_add_module_info(in MODULE_NAME, in F)
Manually add project module to list of modules.
option BUILD_ALL_MODULES
macro basis_find_package(in PACKAGE, in ARGN)
Find external software package or other project module.
cmake PROJECT_MODULES_SORTED
cmake DIR
macro basis_project(in ARGN)
Sets basic project information including the name, version, and dependencies.
cmake PROJECT_CODE_DIRS
Absolute paths to directories of project sources in source tree.
cmake PROJECT_TESTING_DIR
Absolute path to directory of testing tree in source tree.
cmake msg
cmake CXX
cmake PROJECT_SUBDIRS
Names of additional project subdirectories at root level.
cmake PROJECT_MODULES_DISABLED
function basis_tokenize_dependency(in DEP, out PKG, out VER, out CMP)
Tokenize dependency specification.
if(oldcoutbuf)
macro basis_find_packages()
Find packages this project depends on.
function get_filename_component(inout ARGN)
Fixes CMake&#39;s get_filename_component() command.
macro basis_project_check_metadata()
Check meta-data and set defaults.