diff --git a/tribits/core/package_arch/TribitsPackageMacros.cmake b/tribits/core/package_arch/TribitsPackageMacros.cmake index a0c53f512..2886b2b95 100644 --- a/tribits/core/package_arch/TribitsPackageMacros.cmake +++ b/tribits/core/package_arch/TribitsPackageMacros.cmake @@ -407,6 +407,54 @@ macro(tribits_package_assert_call_context) endmacro() +# @MACRO: tribits_disable_optional_dependency() +# +# Macro called to disable an optional dependency in the current package for an +# optional (internal or external) upstream package. +# +# Usage:: +# +# tribits_disable_optional_dependency( "") +# +# This macro can be called from a top-level package's +# ``/CMakeLists.txt`` file to disable an optional dependency that +# may have been enabled by the user or through automated enable/disable logic. +# +# This is most useful in cases where multiple criteria must be considered +# before support for some upstream dependency can really be supported. In +# that case, the dependency can be disabled in the current package and +# telegraphed to all downstream packages. See `How to tweak downstream +# TriBITS "ENABLE" variables during package configuration`_ for more details. +# +macro(tribits_disable_optional_dependency upstreamPackageName reasonStr) + # Assert called in the correct context + if (NOT "${${PACKAGE_NAME}_PARENT_PACKAGE}" STREQUAL "") + message(FATAL_ERROR "ERROR: Calling tribits_disable_optional_dependency() from" + " a subpackage it not allowed. It must be called from the parent package's" + " ${${PACKAGE_NAME}_PARENT_PACKAGE} CMakeLists.txt file") + endif() + if (NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${${PACKAGE_NAME}_SOURCE_DIR}") + message(FATAL_ERROR "ERROR: Calling tribits_disable_optional_dependency() from" + " a subdirectory CMakeLists.txt file under '${CMAKE_CURRENT_SOURCE_DIR}' is not allowed." + " Instead, please call this from the package's base CMakeLists.txt file" + " '${${PACKAGE_NAME}_SOURCE_DIR}/CMakeLists.txt'" ) + endif() + # Get the variable names that are going to be set assert they exist already + set(packageEnableVarName ${PACKAGE_NAME}_ENABLE_${upstreamPackageName}) + assert_defined(${packageEnableVarName}) + string(TOUPPER ${upstreamPackageName} upstreamPackageName_UC) + set(havePackageUpstreamPackageMacroVarName + HAVE_${PACKAGE_NAME_UC}_${upstreamPackageName_UC}) + assert_defined(${havePackageUpstreamPackageMacroVarName}) + # Set the variables to OFF in local and project-level scopes + if (NOT "${reasonStr}" STREQUAL "") + message("-- ${reasonStr}") + endif() + dual_scope_set(${packageEnableVarName} OFF) + dual_scope_set(${havePackageUpstreamPackageMacroVarName} OFF) +endmacro() + + # @MACRO: tribits_add_test_directories() # # Macro called to add a set of test directories for an package. diff --git a/tribits/doc/guides/TribitsGuidesBody.rst b/tribits/doc/guides/TribitsGuidesBody.rst index 662f72389..a196db14e 100644 --- a/tribits/doc/guides/TribitsGuidesBody.rst +++ b/tribits/doc/guides/TribitsGuidesBody.rst @@ -1809,7 +1809,7 @@ are defined before a Package's ``CMakeLists.txt`` file is processed: Set to ``ON`` if the package is enabled and is to be processed or will be set to ``ON`` or ``OFF`` automatically during enable/disable logic. For a - parent package that is not directly enabled but were one of its + parent package that is not directly enabled but where one of its subpackages is enabled, this will get set to ``ON`` (but that is not the same as the parent package being directly enabled and therefore does not imply that all of the required subpackages will be enabled, only that the @@ -1841,6 +1841,10 @@ are defined before a Package's ``CMakeLists.txt`` file is processed: `${PACKAGE_NAME}_LIB_DEFINED_DEPENDENCIES`_ or `${PACKAGE_NAME}_TEST_DEFINED_DEPENDENCIES`_. + **NOTE:** The value of this variable also determines the value of the + macro define variable name + `HAVE__`_. + .. _${PACKAGE_NAME}_ENABLE_TESTS: ``${PACKAGE_NAME}_ENABLE_TESTS`` @@ -1889,6 +1893,13 @@ are defined in the top-level project scope before a Package's #cmakedefine HAVE_EPETRAEXT_TRIUTILS + NOTE: TriBITS automatically sets this variable depending on the value of + `${PACKAGE_NAME}_ENABLE_${OPTIONAL_DEP_PACKAGE_NAME}`_ during the step + "Adjust package and TPLs enables and disables" in `Full Processing of + TriBITS Project Files`_. And tweaking this variable after that must be + done carefully as described in `How to tweak downstream TriBITS "ENABLE" + variables during package configuration`_. + Currently, a Package can refer to its containing Repository and refer to its source and binary directories. This is so that it can refer to repository-level resources (e.g. like the ``Trilinos_version.h`` file for @@ -3348,6 +3359,7 @@ dependency`_ for more discussion and examples. Before getting into specific `Example Enable/Disable Use Cases`_, some of the `TriBITS Dependency Handling Behaviors`_ are first defined below. + TriBITS Dependency Handling Behaviors ------------------------------------- @@ -3768,15 +3780,20 @@ In more detail, these rules/behaviors are: 22) **TriBITS auto-enables/disables done using non-cache local variables**: TriBITS setting (or overrides) of enable/disable cache variables are done by setting local non-cache variables at the top project-level scope - (i.e. the ``/CMakeLists.txt`` file scope). This is done so - they don't get set in the cache and so that the same dependency + (i.e. the ``/CMakeLists.txt`` file scope) and does **not** + touch the value of the cache variables that may be set by the user on + input or the cache variables with documentation set by TriBITS. This is + done so they don't get set in the cache and so that the same dependency enable/disable logic is redone, from scratch, with each re-configure. This results in the same enable/disable logic output as for the initial configure. This is to avoid confusion by the user about why some packages - and TPLs are enabled and some are not on subsequent reconfigures. - However, this implementation choice must be understood when one wants to - go about tweaking these TriBITS enable/disable variables as described in - `How to check for and tweak TriBITS "ENABLE" cache variables`_ and `How to + and TPLs are enabled and some are not on subsequent reconfigures. This is + also desirable behavior as it preserves the user's input values for these + variables to document what was set by the user. However, this + implementation choice (and the tricky relationship between cache and + non-cache CMake variables) must be clearly understood when one wants to go + about tweaking these TriBITS enable/disable variables as described in `How + to check for and tweak TriBITS "ENABLE" cache variables`_ and `How to tweak downstream TriBITS "ENABLE" variables during package configuration`_. @@ -6332,7 +6349,7 @@ enabling/disabling various entities that allow for a default "undefined" empty * ``${PROJECT_NAME}_ENABLE_`` (Packages) * ``TPL_ENABLE_`` (External Packages/TPLs) -* ``_ENABLE_`` (Optional support for a +* ``_ENABLE_`` (Support for a package ```` in a downstream package ````) * ``_ENABLE_TESTS`` (Package tests) @@ -6358,7 +6375,8 @@ following: default defined or not. 2) To tweak the enable/disable of one or more of these variables after user - input but before auto-enable/disable logic: + input but **before** the step "Adjust package and TPLs enables and + disables" in `Full Processing of TriBITS Project Files`_: a) To tweak the enables/disables for a TriBITS Repository (i.e. affecting all TriBITS projects) add enable/disable code to the file @@ -6390,10 +6408,12 @@ possible values of ``ON``, ``OFF`` and empty ``""`` (see the macro ``_ENABLE_`` variable is defined (e.g. ``if (DEFINED _ENABLE_) ... endif()``) does not mean that it has been set to ``ON`` or ``OFF`` yet (or any non-empty values that evaluates to true or false -in CMake). To see if an ``ENABLE`` variable is one of these variables, look -in the CMakeCache.txt file for the type. If the type is ``STRING``, then it -is most likely this type of variable with a default value of empty ``""``. -However, if the cache type is ``BOOL`` then it is likely a standard bool +in CMake). To see if an ``ENABLE`` variable is one of these types, look in +the ``CMakeCache.txt``. If the type of the variable ``_ENABLE_`` is +``STRING`` and you see another variable set with the name +``_ENABLE__-STRINGS``, then it is most likely this special type of +``ENABLE`` variable with a typical default value of empty ``""``. However, if +the cache variable is of type ``BOOL``, then it is likely a standard bool variable that is not allowed to have a value of empty ``""``. Second, note that the value of empty ``""`` evaluates to ``FALSE`` in CMake @@ -6401,11 +6421,11 @@ Second, note that the value of empty ``""`` evaluates to ``FALSE`` in CMake variables evaluates to true, then just use ``if (_ENABLE_) ... endif()``. -Third, note that TriBITS will not define these cache variables until TriBITS -processes the ``Dependencies.cmake`` files on the first configure (see `Full -TriBITS Project Configuration`_). On future reconfigures, these variables are -all defined (but most will have a default value of empty ``""`` stored in the -cache). +Third, note that TriBITS will not define cache variables for these ``ENABLE`` +variables until TriBITS processes the ``Dependencies.cmake`` files on the +first configure (see `Full TriBITS Project Configuration`_). On future +reconfigures, these variables are all defined (but most will have a default +value of empty ``""`` stored in the cache). The reason the files ``RepositoryDependenciesSetup.cmake`` and ``ProjectDependenciesSetup.cmake`` are the best places to put in these tweaks @@ -6418,6 +6438,11 @@ Logic`_). Also, these files get processed in `Reduced Package Dependency Processing`_ as well so they get processed in all contexts where enable/disable logic is applied. +However, if one wants to tweak these variables once packages are starting to +be processed (in step "For each ```` in all enabled top-level +packages" in `Full TriBITS Project Configuration`_), there are fewer +situations where that can be done correctly as described in the next section. + How to tweak downstream TriBITS "ENABLE" variables during package configuration ------------------------------------------------------------------------------- @@ -6426,44 +6451,64 @@ There are cases where one may need to enable or disable some feature that TriBITS may have enabled by default (such as in "Adjust package and TPLs enables and disables" in `Full Processing of TriBITS Project Files`_) and that decision can only be made while processing a package's -`/CMakeLists.txt`_ file. (And therefore the logic for this disable -cannot be performed in the ``ProjectDependenciesSetup.cmake`` or -``RepositoryDependenciesSetup.cmake`` files as described in `How to check for -and tweak TriBITS "ENABLE" cache variables`_ which are processed before the -enabled packages are configured.) Also, there are cases where it is necessary -to make this change visible to downstream packages such as when -```` support of some feature depends on -```` support for that same feature. Examples include -optional support of an upstream package in a downstream package -``_ENABLE_`` or for support for an -optional TPL in a downstream package ``_ENABLE_``. -But other examples may include variables that are not optional TriBITS package -and TPL enables (such as support for a given data-type that may impact -multiple packages). +`/CMakeLists.txt`_ file and not before. (And therefore the logic +for this disable cannot be performed in the ``ProjectDependenciesSetup.cmake`` +or ``RepositoryDependenciesSetup.cmake`` files as described in `How to check +for and tweak TriBITS "ENABLE" cache variables`_.) Also, there are cases +where it is necessary to make this change visible to downstream packages. The +main example is when optional support of an upstream package in a downstream +package ``_ENABLE_`` must be changed in +the package's `/CMakeLists.txt`_ file. But there are other +examples such as support for a given data-type that may impact multiple +downstream packages. When the internal configuration of a package (i.e. while processing its ``/CMakeLists.txt`` file) determines that an optional feature -``_ENABLE_`` must be enabled or disabled with and will change the -value previously set (e.g. during the "Adjust package and TPLs enables and -disables" stage), one cannot use a simple ``set()`` statement. Changing the -value of an ``_ENABLE_`` variable inside a package's -``/CMakeLists.txt`` file using a raw ``set(_ENABLE_ +``_ENABLE_`` must change the value previously set (e.g. that was +set automatically by TriBITS during the "Adjust package and TPLs enables and +disables" stage in `Full Processing of TriBITS Project Files`_), one cannot +use a simple ``set()`` statement. Changing the value of a +``_ENABLE_`` variable inside a package's +``/CMakeLists.txt`` file using a raw ``set(_ENABLE_ )`` statement only changes the variable's value inside the package's scope, but all other packages will see the old value of -``_ENABLE_``. To correctly change the value of one of these +``_ENABLE_``. To correctly change the value of one of these variables, instead use `dual_scope_set()`_ from the top-level -``/CMakeLists.txt`` file. This sets the value in both the -base-level (global) project scope and in the local scope of -``/CMakeLists.txt``. (But this does **not** change the value of a -cache variable ``_ENABLE_`` that may have been set by the user or -some other means; see `TriBITS auto-enables/disables done using non-cache -local variables`_.) Any downstream package (configured after processing -``/CMakeLists.txt``) will see the new value ``_ENABLE_ -STREQUAL ``. It is also strongly recommended that a message or warning -be printed to CMake STDOUT using ``message(["NOTE: "|WARNING] "")`` -when globally changing an ENABLE variable. The user may have set it -explicitly, and they should know exactly why and where their choice is being -overridden. +``/CMakeLists.txt`` file. To perform this disable more robustly +than calling ``dual_scope_set()`` directly, use the provided macro +`tribits_disable_optional_dependency()`_. For example, to disable optional +support for ```` in ```` in +```` package's ``/CMakeLists.txt`` file based +on some criteria, add the CMake code:: + + if () + tribits_disable_optional_dependency( + "NOTE: ${PACKAGE_NAME}_ENABLE_ being set to OFF because of " ) + endif() + +Calling ``dual_scope_set()`` in the package's top-level +``/CMakeLists.txt`` file sets the value in both the local scope of +``/CMakeLists.txt`` (and therefore propagated to all other +``CMakeLists.txt`` files in that package) and in base-level (global) project +scope. (But this does **not** change the value of a cache variable +``_ENABLE_`` that may have been set by the user or some other +means which is the desired behavior; see `TriBITS auto-enables/disables done +using non-cache local variables`_.) In this way, any downstream package +(configured after processing ``/CMakeLists.txt``) will see the new +value for ``_ENABLE_``. + +It is also strongly recommended that a message be printed to CMake STDOUT +using ``message("-- " "NOTE: ")`` when changing the value of one of +these ``_ENABLE_`` variables. The user may have set it +explicitly or TriBITS may have printed automatic logic for setting it by +default, and user needs to know why and where the value is being overridden. + +**NOTE:** However, it is **not** allowed to try to change the value of a +global enable of a upstream or downstream package by trying to change the +value of ``_ENABLE_`` or ``TPL_ENABLE_`` in a +``/CMakeLists.txt`` file. Changing the value of these variables +after the "Adjust package and TPLs enables and disables" stage in `Full +Processing of TriBITS Project Files`_ will result in undefined behavior. How to set up multi-repository support diff --git a/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst b/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst index 532cc7cca..597e2cb2a 100644 --- a/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst +++ b/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst @@ -19,6 +19,7 @@ @FUNCTION: tribits_copy_files_to_binary_dir() + @FUNCTION: tribits_ctest_driver() + @FUNCTION: tribits_determine_if_current_package_needs_rebuilt() + +@MACRO: tribits_disable_optional_dependency() + @MACRO: tribits_disable_package_on_platforms() + @MACRO: tribits_exclude_files() + @MACRO: tribits_extpkg_define_dependencies() +