1# @HEADER
2# ************************************************************************
3#
4#            TriBITS: Tribal Build, Integrate, and Test System
5#                    Copyright 2013 Sandia Corporation
6#
7# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8# the U.S. Government retains certain rights in this software.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions are
12# met:
13#
14# 1. Redistributions of source code must retain the above copyright
15# notice, this list of conditions and the following disclaimer.
16#
17# 2. Redistributions in binary form must reproduce the above copyright
18# notice, this list of conditions and the following disclaimer in the
19# documentation and/or other materials provided with the distribution.
20#
21# 3. Neither the name of the Corporation nor the names of the
22# contributors may be used to endorse or promote products derived from
23# this software without specific prior written permission.
24#
25# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36#
37# ************************************************************************
38# @HEADER
39
40
41INCLUDE(SetCacheOnOffEmpty)
42INCLUDE(MultilineSet)
43INCLUDE(AdvancedOption)
44INCLUDE(AdvancedSet)
45INCLUDE(AssertDefined)
46INCLUDE(PrintVar)
47INCLUDE(MessageWrapper)
48INCLUDE(TribitsListHelpers)
49
50
51#
52# Helper functions
53#
54
55
56#
57# @MACRO: TRIBITS_REPOSITORY_DEFINE_PACKAGES()
58#
59# Define the set of packages for a given `TriBITS Repository`_.  This macro is
60# typically called from inside of a `<repoDir>/PackagesList.cmake`_ file for a
61# given TriBITS repo.
62#
63# Usage::
64#
65#    TRIBITS_REPOSITORY_DEFINE_PACKAGES(
66#       <pkg0>  <pkg0_dir>  <pkg0_classif>
67#       <pkg1>  <pkg1_dir>  <pkg1_classif>
68#       ...
69#       )
70#
71# This macro sets up a 2D array of ``NumPackages`` by ``NumColumns`` listing
72# out the packages for a TriBITS repository.  Each row (with 3 column entries)
73# specifies a package which contains the columns (ordered 0-2):
74#
75# 0. **PACKAGE** (``<pkgi>``): The name of the TriBITS package.  This name
76#    must be unique across all other TriBITS packages in this or any other
77#    TriBITS repo that might be combined into a single TriBITS project
78#    meta-build (see `Globally unique TriBITS package names`_).  The name
79#    should be a valid identifier (e.g. matches the regex
80#    ``[a-zA-Z_][a-zA-Z0-9_]*``).  The package names tend to use mixed case
81#    (e.g. ```SomePackge`` not ``SOMEPACKGE``).
82#
83# 1. **DIR** (``<pkgi_dir>``): The relative directory for the package
84#    ``<packageDir>``.  This directory is relative to the TriBITS repository
85#    base directory ``<repoDir>``.  Under this directory will be a
86#    package-specific ``cmake/`` directory with the file
87#    `<packageDir>/cmake/Dependencies.cmake`_ and a base-level
88#    `<packageDir>/CMakeLists.txt`_ file.  The entire contents of the package
89#    including all of the source code and all of the tests should be contained
90#    under this directory.  The TriBITS testing infrastructure relies on the
91#    mapping of changed files to these base directories when deciding what
92#    packages are modified and need to be retested (along with downstream
93#    packages).  For details, see `checkin-test.py`_.
94#
95# 2. **CLASSIFICATION** (``<pkgi_classif>``): Gives the `SE Package Test
96#    Group`_ `PT`_, `ST`_, or `EX`_ and the maturity level ``EP``, ``RS``,
97#    ``PG``, ``PM``, ``GRS``, ``GPG``, ``GPM``, ``UM``.  These are separated
98#    by a coma with no space in between such as ``"RS,PT"`` for a "Research
99#    Stable", "Primary Tested" package.  No spaces are allowed so that CMake
100#    treats this a one field in the array.  The maturity level can be left off
101#    in which case it is assumed to be ``UM`` for "Unspecified Maturity".
102#    This classification for individual packages can be changed to ``EX`` for
103#    specific platforms by calling `TRIBITS_DISABLE_PACKAGE_ON_PLATFORMS()`_.
104#
105# **IMPORTANT:** The packages must be listed in increasing order of package
106# dependencies.  That is `No circular dependencies of any kind are allowed`_
107# (see the *ADP (Acyclic Dependencies Principle)* in `Software Engineering
108# Packaging Principles`_).  Package ``i`` can only list dependencies (in
109# `<packageDir>/cmake/Dependencies.cmake`_) for packages listed before this
110# package in this list (or in upstream TriBITS repositories).  This avoids an
111# expensive package sorting algorithm and makes it easy to flag packages with
112# circular dependencies or misspelling of package names.
113#
114# NOTE: For some rare use cases, the package directory ``<pkgi_dir>`` is
115# allowed to be specified as an absolute directory but this absolute directory
116# must be a subdirectory of the project source base directory given by
117# `PROJECT_SOURCE_DIR`_.  If not, ``MESSAGE(FATAL_ERROR ...)`` is called and
118# processing stops immediately.
119#
120# NOTE: This macro just sets the variable::
121#
122#   ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS
123#
124# in the current scope.  The advantages of using this macro instead of
125# directly setting this variable are that the macro:
126#
127# * Asserts that the variable ``REPOSITORY_NAME`` is defined and set
128#
129# * Avoids having to hard-code the assumed repository name
130#   ``${REPOSITORY_NAME}``.  This provides more flexibility for how other
131#   TriBITS projects choose to name a given TriBITS repo (i.e. the name of
132#   repo subdirs).
133#
134# * Avoid misspelling the name of the variable
135#   ``${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS``.  If one
136#   misspells the name of the macro, it is an immediate error in CMake.
137#
138MACRO(TRIBITS_REPOSITORY_DEFINE_PACKAGES)
139  ASSERT_DEFINED(REPOSITORY_NAME)
140  SET(${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS "${ARGN}")
141ENDMACRO()
142
143
144#
145# @FUNCTION: TRIBITS_ALLOW_MISSING_EXTERNAL_PACKAGES()
146#
147# Allow listed packages to be missing and automatically excluded from the
148# package dependency data-structures.
149#
150# Usage::
151#
152#   TRIBITS_ALLOW_MISSING_EXTERNAL_PACKAGES(<pkg0> <plg1> ...)
153#
154# If the missing upstream SE package ``<pkgi>`` is optional, then the effect
155# will be to simply ignore the missing package (i.e. it will never be added to
156# package's list and not added to dependency data-structures) and remove it
157# from the dependency lists for downstream SE packages that have an optional
158# dependency on the missing upstream SE package ``<pkgi>``.  However, all
159# downstream SE packages that have a required dependency on the missing
160# upstream SE package ``<pkgi>`` will be hard disabled,
161# i.e. ``${PROJECT_NAME}_ENABLE_{CURRENT_PACKAGE}=OFF`` and a note on the
162# disable will be printed.
163#
164# **WARNING**: This macro just sets the cache variable
165# ``<pkgi>_ALLOW_MISSING_EXTERNAL_PACKAGE=TRUE`` for each SE package
166# ``<pkgi>``.  Therefore, using this function effectively turns off error
167# checking for misspelled package names so it is important to only use it when
168# it absolutely is needed (use cases mentioned below).  Also note that missing
169# packages are silently ignored by default.  Therefore, when doing development
170# involving these packages, it is usually a good idea to set::
171#
172#   -D<pkgi>_ALLOW_MISSING_EXTERNAL_PACKAGE=FALSE
173#
174# so that it will catch errors in the misspelling of package names or source
175# directories.  However, notes on what missing packages are being ignored can
176# printed by configuring with::
177#
178#   -D <Project>_WARN_ABOUT_MISSING_EXTERNAL_PACKAGES=TRUE
179#
180# This macro is typically called in one of two different contexts:
181#
182# * Called from `<packageDir>/cmake/Dependencies.cmake`_ when the upstream
183#   package ``<pkgi>`` is defined in an optional upstream `TriBITS
184#   Repository`_.  This allows the downstream repos and packages to still be
185#   enabled (assuming they don't have required dependencies on the missing
186#   packages) when one or more upstream repos are missing.
187#
188# * Called from `<repoDir>/PackagesList.cmake`_ when the package ``<pkgi>``
189#   might be defined in an optional non-TriBITS repo (see `How to insert a
190#   package into an upstream repo`_).
191#
192# For some meta-projects that composes packages from may different TriBITS
193# repositories, one might need to also call this function from the file
194# `<projectDir>/cmake/ProjectDependenciesSetup.cmake`_.
195#
196FUNCTION(TRIBITS_ALLOW_MISSING_EXTERNAL_PACKAGES)
197  FOREACH(TRIBITS_PACKAGE ${ARGN})
198    ADVANCED_SET(${TRIBITS_PACKAGE}_ALLOW_MISSING_EXTERNAL_PACKAGE TRUE
199      CACHE BOOL
200      "Default set by TRIBITS_ALLOW_MISSING_EXTERNAL_PACKAGES()!"
201      )
202  ENDFOREACH()
203ENDFUNCTION()
204
205
206#
207# Below, we change the value of user cache values like
208# ${PROJECT_NAME}_ENABLE_${PACKAGE_NAME},
209# ${PACKAGE_NAME}_ENABLE_TESTS, and ${PACKAGE_NAME}_ENABLE_EXAMPLES by
210# just setting them to regular variables that live in the top scope
211# instead of putting them back in the cache.  That means that they are
212# used as global variables but we don't want to disturb the cache
213# since that would change the behavior for future invocations of cmake
214# (which is very confusing).  Because of this, these macros must all
215# be called from the top-level ${PROJECT_NAME} CMakeLists.txt file and
216# macros must call macros as not to change the variable scope.
217#
218# I had to do it this way in order to be able to get the right behavior which
219# is:
220#
221# 1) Override the value of these variables in all CMake processing
222#
223# 2) Avoid changing the user cache values because that would be confusing and
224# would make it hard to change package enables/disable later without blowing
225# away the cache
226#
227
228
229#
230# Macro that sets up standard user options a package
231#
232# On completion, the following variables are set:
233#
234# * ${PACKAGE_NAME_IN}_TESTGROUP: Set to PT, ST, or EX
235#
236
237MACRO(TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS  PACKAGE_NAME_IN  PACKAGE_TESTGROUP_IN)
238
239  IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
240    MESSAGE("TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS: ${PACKAGE_NAME_IN} ${PACKAGE_TESTGROUP_IN}")
241    PRINT_VAR(${PACKAGE_NAME_IN}_TESTGROUP)
242  ENDIF()
243
244  SET(PACKAGE_TESTGROUP_LOCAL ${PACKAGE_TESTGROUP_IN})
245
246  # ${PROJECT_NAME}_ELEVATE_ST_TO_PT is deprecated but allowed for backward compatibility
247  IF (${PROJECT_NAME}_ELEVATE_SS_TO_PS)
248    SET(${PROJECT_NAME}_ELEVATE_ST_TO_PT ON)
249  ENDIF()
250
251  IF (${PACKAGE_TESTGROUP_IN} STREQUAL PT OR ${PACKAGE_TESTGROUP_IN} STREQUAL ST)
252    IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
253      MESSAGE("-- " "PT or ST")
254      PRINT_VAR(${PROJECT_NAME}_ELEVATE_ST_TO_PT)
255    ENDIF()
256    IF (${PROJECT_NAME}_ELEVATE_ST_TO_PT)
257      SET(PACKAGE_TESTGROUP_LOCAL PT)
258    ENDIF()
259    IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
260      PRINT_VAR(PACKAGE_TESTGROUP_LOCAL)
261    ENDIF()
262    SET(PACKAGE_ENABLE "")
263  ELSEIF (${PACKAGE_TESTGROUP_IN} STREQUAL EX)
264    IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
265      MESSAGE("-- " "EX")
266    ENDIF()
267    SET(PACKAGE_ENABLE OFF)
268  ELSE()
269    MESSAGE(FATAL_ERROR "Error the package classification '${PACKAGE_TESTGROUP_IN}'"
270      " for the package ${PACKAGE_NAME_IN} is not a valid classification." )
271  ENDIF()
272
273  IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
274    PRINT_VAR(PACKAGE_ENABLE)
275    PRINT_VAR(${PACKAGE_NAME_IN}_TESTGROUP)
276  ENDIF()
277
278  IF ("${${PACKAGE_NAME_IN}_TESTGROUP}" STREQUAL "") # Allow testing override
279    IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
280      MESSAGE("-- " "Setting classification to ${PACKAGE_TESTGROUP_LOCAL}")
281      PRINT_VAR(PACKAGE_TESTGROUP_LOCAL)
282    ENDIF()
283    SET(${PACKAGE_NAME_IN}_TESTGROUP "${PACKAGE_TESTGROUP_LOCAL}")
284  ENDIF()
285
286  IF (TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS_DEBUG)
287    PRINT_VAR(${PACKAGE_NAME_IN}_TESTGROUP)
288  ENDIF()
289
290  MULTILINE_SET(DOCSTR
291    "Enable the package ${PACKAGE_NAME_IN}.  Set to 'ON', 'OFF', or leave"
292    " empty to allow for other logic to decide."
293    )
294  SET_CACHE_ON_OFF_EMPTY( ${PROJECT_NAME}_ENABLE_${PACKAGE_NAME_IN}
295    "${PACKAGE_ENABLE}" ${DOCSTR} )
296
297ENDMACRO()
298
299
300#
301# Function that determines if a package is a primary meta-project package
302#  according to the variables
303#  ${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES[_EXCEPT].
304#
305
306FUNCTION(TRIBITS_IS_PRIMARY_META_PROJECT_PACKAGE  PACKAGE_NAME_IN
307  IS_PRIMARY_META_PROJECT_PACKAGE_OUT
308  )
309
310  SET(IS_PRIMARY_META_PROJECT_PACKAGE TRUE)
311
312  ASSERT_DEFINED(${PACKAGE_NAME_IN}_PARENT_REPOSITORY)
313  SET(PARENT_REPO_NAME ${${PACKAGE_NAME_IN}_PARENT_REPOSITORY})
314  IF (${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES)
315    FIND_LIST_ELEMENT(
316      ${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES_EXCEPT
317      ${PACKAGE_NAME_IN}  PACKAGE_EXCEPTED
318      )
319    IF (PACKAGE_EXCEPTED)
320      IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
321        MESSAGE("-- "
322          "NOTE: ${PACKAGE_NAME_IN} is classified as a primary meta-project packages even"
323          " though ${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES=ON "
324          " because the package is included in the list ${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES_EXCEPT!")
325      ENDIF()
326    ELSE()
327      IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
328        MESSAGE("-- "
329          "NOTE: ${PACKAGE_NAME_IN} is not as a primary meta-project packages"
330          " because ${PARENT_REPO_NAME}_NO_PRIMARY_META_PROJECT_PACKAGES=ON "
331          )
332      ENDIF()
333      SET(IS_PRIMARY_META_PROJECT_PACKAGE FALSE)
334    ENDIF()
335  ENDIF()
336
337  SET(${IS_PRIMARY_META_PROJECT_PACKAGE_OUT} ${IS_PRIMARY_META_PROJECT_PACKAGE}
338    PARENT_SCOPE )
339
340ENDFUNCTION()
341
342
343#
344# Function that determines if it is okay to allow an implicit package enable
345# based on its classification.
346#
347
348FUNCTION(TRIBITS_IMPLICIT_PACKAGE_ENABLE_IS_ALLOWED  UPSTREAM_PACKAGE_NAME_IN  PACKAGE_NAME_IN
349  IMPLICIT_PACKAGE_ENABLE_ALLOWED_OUT
350  )
351
352  IF (${PACKAGE_NAME_IN}_TESTGROUP STREQUAL PT)
353    SET(IMPLICIT_PACKAGE_ENABLE_ALLOWED TRUE)
354  ELSEIF (${PACKAGE_NAME_IN}_TESTGROUP STREQUAL ST
355    AND ${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE
356    )
357    SET(IMPLICIT_PACKAGE_ENABLE_ALLOWED TRUE)
358  ELSE()
359    IF (UPSTREAM_PACKAGE_NAME_IN)
360      MESSAGE("-- " "NOTE: Not Setting ${PROJECT_NAME}_ENABLE_${PACKAGE_NAME_IN}=ON"
361        " even though ${UPSTREAM_PACKAGE_NAME_IN} has an optional dependence on"
362        " ${PACKAGE_NAME_IN} because ${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE=OFF" )
363    ENDIF()
364    SET(IMPLICIT_PACKAGE_ENABLE_ALLOWED FALSE)
365  ENDIF()
366
367  SET(${IMPLICIT_PACKAGE_ENABLE_ALLOWED_OUT} ${IMPLICIT_PACKAGE_ENABLE_ALLOWED}
368    PARENT_SCOPE )
369
370ENDFUNCTION()
371
372
373#
374# Macro that processes ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS into
375# ${PROJECT_NAME}_PACKAGES, ${PROJECT_NAME}_PACKAGE_DIRS, ${PROJECT_NAME}_NUM_PACKAGES,
376# ${PROJECT_NAME}_LAST_PACKAGE_IDX, and ${PROJECT_NAME}_REVERSE_PACKAGES.
377#
378# This macro also sets up the standard package options along with
379# default enables/disables.
380#
381# NOTE: Set TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE=TRUE to see really verbose
382# debug ouptut from this macro.
383#
384
385MACRO(TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS  REPOSITORY_NAME  REPOSITORY_DIR)
386
387  IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
388    MESSAGE("TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS:  '${REPOSITORY_NAME}'  '${REPOSITORY_DIR}'")
389  ENDIF()
390
391  #
392  # Separate out separate lists of package names and directories
393  #
394
395  # Get the total number of packages defined
396
397  ASSERT_DEFINED(${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS)
398  IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
399    PRINT_VAR(${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS)
400  ENDIF()
401  LIST(LENGTH ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS
402    ${REPOSITORY_NAME}_NUM_PACKAGES_AND_FIELDS )
403  MATH(EXPR ${REPOSITORY_NAME}_NUM_PACKAGES
404    "${${REPOSITORY_NAME}_NUM_PACKAGES_AND_FIELDS}/${PLH_NUM_FIELDS_PER_PACKAGE}")
405  IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
406    PRINT_VAR(${REPOSITORY_NAME}_NUM_PACKAGES)
407  ENDIF()
408  MATH(EXPR ${REPOSITORY_NAME}_LAST_PACKAGE_IDX "${${REPOSITORY_NAME}_NUM_PACKAGES}-1")
409
410  # Process each of the packages defined
411
412  IF (${REPOSITORY_NAME}_NUM_PACKAGES GREATER 0)
413
414    FOREACH(PACKAGE_IDX RANGE ${${REPOSITORY_NAME}_LAST_PACKAGE_IDX})
415
416      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
417        MESSAGE("")
418        PRINT_VAR(${PROJECT_NAME}_PACKAGES)
419      ENDIF()
420
421      MATH(EXPR PACKAGE_NAME_IDX "${PACKAGE_IDX}*${PLH_NUM_FIELDS_PER_PACKAGE}+0")
422      LIST(GET ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS
423        ${PACKAGE_NAME_IDX} TRIBITS_PACKAGE )
424      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
425        PRINT_VAR(TRIBITS_PACKAGE)
426      ENDIF()
427
428      MATH(EXPR PACKAGE_DIR_IDX
429        "${PACKAGE_IDX}*${PLH_NUM_FIELDS_PER_PACKAGE}+${PLH_NUM_PACKAGE_DIR_OFFSET}")
430      LIST(GET ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS
431        ${PACKAGE_DIR_IDX} PACKAGE_DIR )
432      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
433        PRINT_VAR(PACKAGE_DIR)
434      ENDIF()
435
436      MATH(EXPR PACKAGE_CLASSIFICATION_IDX
437        "${PACKAGE_IDX}*${PLH_NUM_FIELDS_PER_PACKAGE}+${PLH_NUM_PACKAGE_CLASSIFICATION_OFFSET}")
438      LIST(GET ${REPOSITORY_NAME}_PACKAGES_AND_DIRS_AND_CLASSIFICATIONS
439        ${PACKAGE_CLASSIFICATION_IDX} PACKAGE_CLASSIFICATION )
440      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
441        PRINT_VAR(PACKAGE_CLASSIFICATION)
442      ENDIF()
443
444      # ToDo: Parse out TESTGROUP and MATURITYLEVEL (Trilinos #6042)
445      SET(PACKAGE_TESTGROUP ${PACKAGE_CLASSIFICATION})
446
447      TRIBITS_UPDATE_PS_PT_SS_ST(Package ${TRIBITS_PACKAGE} PACKAGE_TESTGROUP)
448
449      IF (${TRIBITS_PACKAGE}_SOURCE_DIR_OVERRIDE)
450        MESSAGE("-- "
451          "NOTE: ${TRIBITS_PACKAGE}_SOURCE_DIR_OVERRIDE='${${TRIBITS_PACKAGE}_SOURCE_DIR_OVERRIDE}'"
452          " is overriding default path '${PACKAGE_DIR}'")
453        SET(PACKAGE_DIR "${${TRIBITS_PACKAGE}_SOURCE_DIR_OVERRIDE}")
454      ENDIF()
455
456      IF (IS_ABSOLUTE "${PACKAGE_DIR}")
457
458        SET(PACKAGE_ABS_DIR "${PACKAGE_DIR}")
459
460        STRING(LENGTH "${PROJECT_SOURCE_DIR}" PROJECT_SOURCE_DIR_LEN)
461        STRING(LENGTH "${PACKAGE_ABS_DIR}" PACKAGE_ABS_DIR_LEN)
462
463        # See if the package dir is under the project dir
464
465        SET(PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR TRUE)
466
467        IF (PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR)
468          # Determine package abs dir is too short to be under project
469          IF (PACKAGE_ABS_DIR_LEN LESS PROJECT_SOURCE_DIR_LEN)
470            SET(PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR FALSE)
471          ENDIF()
472        ENDIF()
473
474        IF (PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR)
475          # Determine if the package abs base dir base is the project dir
476          STRING(SUBSTRING "${PACKAGE_ABS_DIR}" 0 ${PROJECT_SOURCE_DIR_LEN}
477            PROJECT_SOURCE_DIR_BASE_MATCH)
478          PRINT_VAR(PROJECT_SOURCE_DIR_BASE_MATCH)
479          IF (NOT PROJECT_SOURCE_DIR_BASE_MATCH STREQUAL "${PROJECT_SOURCE_DIR}")
480            SET(PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR FALSE)
481          ENDIF()
482        ENDIF()
483
484        IF (PACKAGE_ABS_DIR_UNDER_PROJECT_SOURCE_DIR)
485          # Get the path of the package dir under the project dir
486          MATH(EXPR PACKAGE_REL_DIR_BEGIN "${PROJECT_SOURCE_DIR_LEN}+1")
487          STRING(SUBSTRING "${PACKAGE_ABS_DIR}" ${PACKAGE_REL_DIR_BEGIN} -1
488            REPOSITORY_AND_PACKAGE_DIR)
489        ELSE()
490          MESSAGE_WRAPPER(FATAL_ERROR
491            "Error: The pacakge '${TRIBITS_PACKAGE}' was given an absolute directory '${PACKAGE_ABS_DIR}' which is *not* under the project's source directory '${PROJECT_SOURCE_DIR}/'!")
492          SET(REPOSITORY_AND_PACKAGE_DIR "ERROR-BAD-PACKAGE-ABS-DIR")
493          # ToDo: We could just put in a relative path but that requries
494          # knowing the common path between the two directory paths but CMake
495          # does not give an easy way to determine that.  I would have to
496          # write that function myself.
497        ENDIF()
498
499      ELSE()
500
501         # PACKAGE_DIR is a relative path
502
503        IF ("${REPOSITORY_DIR}" STREQUAL ".")
504          SET(REPOSITORY_AND_PACKAGE_DIR "${PACKAGE_DIR}")
505        ELSEIF("${PACKAGE_DIR}" STREQUAL ".")
506          SET(REPOSITORY_AND_PACKAGE_DIR "${REPOSITORY_DIR}")
507        ELSE()
508          SET(REPOSITORY_AND_PACKAGE_DIR "${REPOSITORY_DIR}/${PACKAGE_DIR}")
509        ENDIF()
510        SET(PACKAGE_ABS_DIR "${PROJECT_SOURCE_DIR}/${REPOSITORY_AND_PACKAGE_DIR}")
511
512      ENDIF()
513
514      IF (EXISTS ${PACKAGE_ABS_DIR})
515        SET(PACKAGE_EXISTS TRUE)
516      ELSE()
517        SET(PACKAGE_EXISTS FALSE)
518      ENDIF()
519
520      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
521        PRINT_VAR(PROJECT_SOURCE_DIR)
522        PRINT_VAR(REPOSITORY_AND_PACKAGE_DIR)
523        PRINT_VAR(PACKAGE_ABS_DIR)
524        PRINT_VAR(PACKAGE_EXISTS)
525        PRINT_VAR(${PROJECT_NAME}_ASSERT_MISSING_PACKAGES)
526        PRINT_VAR(${TRIBITS_PACKAGE}_ALLOW_MISSING_EXTERNAL_PACKAGE)
527      ENDIF()
528
529      IF (${PROJECT_NAME}_ASSERT_MISSING_PACKAGES
530        AND NOT PACKAGE_EXISTS
531        AND NOT ${TRIBITS_PACKAGE}_ALLOW_MISSING_EXTERNAL_PACKAGE
532        )
533        MESSAGE(
534          "\n***"
535          "\n*** Error, the package ${TRIBITS_PACKAGE} directory ${PACKAGE_ABS_DIR} does not exist!"
536          "\n***\n" )
537        MESSAGE(FATAL_ERROR "Stopping due to above error!")
538      ENDIF()
539
540      IF (PACKAGE_EXISTS OR ${PROJECT_NAME}_IGNORE_PACKAGE_EXISTS_CHECK)
541        LIST(APPEND ${PROJECT_NAME}_PACKAGES ${TRIBITS_PACKAGE})
542        LIST(APPEND ${PROJECT_NAME}_PACKAGE_DIRS "${REPOSITORY_AND_PACKAGE_DIR}")
543        TRIBITS_INSERT_STANDARD_PACKAGE_OPTIONS(${TRIBITS_PACKAGE} ${PACKAGE_TESTGROUP})
544        SET(${TRIBITS_PACKAGE}_SOURCE_DIR "${PROJECT_SOURCE_DIR}/${REPOSITORY_AND_PACKAGE_DIR}")
545        SET(${TRIBITS_PACKAGE}_PARENT_PACKAGE "")
546        SET(${TRIBITS_PACKAGE}_PARENT_REPOSITORY ${REPOSITORY_NAME})
547      ELSE()
548        IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
549          MESSAGE(
550            "\n***"
551            "\n*** NOTE: Excluding package ${TRIBITS_PACKAGE} because ${PACKAGE_ABS_DIR}"
552              " does not exist!"
553            "\n***\n" )
554        ENDIF()
555      ENDIF()
556      # NOTE: The variable ${PROJECT_NAME}_IGNORE_PACKAGE_EXISTS_CHECK only
557      # gets set to TRUE for some unit tests.  Otherwise, in every legitimate
558      # usage of this macro it is always FALSE.
559
560      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
561        PRINT_VAR(${TRIBITS_PACKAGE}_SOURCE_DIR)
562        PRINT_VAR(${TRIBITS_PACKAGE}_PARENT_PACKAGE)
563        PRINT_VAR(${TRIBITS_PACKAGE}_PARENT_REPOSITORY)
564      ENDIF()
565
566      IF (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE)
567        PRINT_VAR(${PROJECT_NAME}_PACKAGES)
568      ENDIF()
569
570    ENDFOREACH()
571
572    # Get the actual number of packages that actually exist
573
574    LIST(LENGTH ${PROJECT_NAME}_PACKAGES ${PROJECT_NAME}_NUM_PACKAGES )
575    MATH(EXPR ${PROJECT_NAME}_LAST_PACKAGE_IDX "${${PROJECT_NAME}_NUM_PACKAGES}-1")
576
577    # Create a reverse list for later use
578
579    SET(${PROJECT_NAME}_REVERSE_PACKAGES ${${PROJECT_NAME}_PACKAGES})
580    LIST(REVERSE ${PROJECT_NAME}_REVERSE_PACKAGES)
581
582  ELSE()
583
584    SET(${REPOSITORY_NAME}_NUM_PACKAGES 0)
585
586  ENDIF()
587
588  IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
589    PRINT_VAR(${REPOSITORY_NAME}_NUM_PACKAGES)
590  ENDIF()
591
592  PRINT_VAR(${PROJECT_NAME}_NUM_PACKAGES)
593
594  # Print the final set of packages in debug mode
595
596  IF (${PROJECT_NAME}_VERBOSE_CONFIGURE)
597    PRINT_VAR(${PROJECT_NAME}_PACKAGES)
598    PRINT_VAR(${PROJECT_NAME}_PACKAGE_DIRS)
599  ENDIF()
600
601ENDMACRO()
602