diff --git a/test/core/ExamplesUnitTests/TribitsExampleApp2_Tests.cmake b/test/core/ExamplesUnitTests/TribitsExampleApp2_Tests.cmake index 25f6adb56..01c0025c6 100644 --- a/test/core/ExamplesUnitTests/TribitsExampleApp2_Tests.cmake +++ b/test/core/ExamplesUnitTests/TribitsExampleApp2_Tests.cmake @@ -103,16 +103,8 @@ function(TribitsExampleApp2 tribitsExProj2TestNameBaseBase if (fullOrComponents STREQUAL "FULL") set(tribitsExProjUseComponentsArg "") elseif (fullOrComponents STREQUAL "COMPONENTS") - if (tribitsExProj2TestNameBaseBase STREQUAL "TribitsExampleProject2_find_package") - # ToDo: Remove this special case once the test - # TribitsExampleProject2_find_package enables all the packages! - set(tribitsExProjUseComponentsArg - -DTribitsExApp2_USE_COMPONENTS="Package1") - set(fullDepsRegex "Full Deps: Package1{tpl1}") - else() - set(tribitsExProjUseComponentsArg - -DTribitsExApp2_USE_COMPONENTS="Package1,Package2,Package3") - endif() + set(tribitsExProjUseComponentsArg + -DTribitsExApp2_USE_COMPONENTS="Package1,Package2,Package3") else() message(FATAL_ERROR "Invalid value of fullOrComponents='${fullOrComponents}'!") endif() @@ -141,6 +133,7 @@ function(TribitsExampleApp2 tribitsExProj2TestNameBaseBase ${tribitsExProjUseComponentsArg} ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleApp2 PASS_REGULAR_EXPRESSION_ALL + "TribitsExProj2_PACKAGE_LIST = Package3[;]Package2[;]Package1" "-- Configuring done" "-- Generating done" "-- Build files have been written to: .*/${testName}/app_build" diff --git a/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake b/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake index e51c87a7c..c71f82307 100644 --- a/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake +++ b/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake @@ -88,7 +88,7 @@ endmacro() ######################################################################## -function(TribitsExampleProject2_find_tpl_parts sharedOrStatic findingTplsMethod) +function(TribitsExampleProject2_find_tpl_parts sharedOrStatic findingTplsMethod) TribitsExampleProject2_test_setup_header() @@ -104,6 +104,13 @@ function(TribitsExampleProject2_find_tpl_parts sharedOrStatic findingTplsMethod) "${tplInstallBaseDir}/install_tpl4${tplInstallBaseDir}/install_tpl3${tplInstallBaseDir}/install_tpl2${tplInstallBaseDir}/install_tpl1" ) + set(allTplsNoPrefindArgs + "-DTpl1_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl2_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl3_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl4_ALLOW_PACKAGE_PREFIND=OFF" + ) + if (findingTplsMethod STREQUAL "TPL_LIBRARY_AND_INCLUDE_DIRS") set(tplLibAndIncDirsArgs "-DTpl1_INCLUDE_DIRS=${tplInstallBaseDir}/install_tpl1/include" @@ -126,13 +133,13 @@ function(TribitsExampleProject2_find_tpl_parts sharedOrStatic findingTplsMethod) elseif (findingTplsMethod STREQUAL "CMAKE_PREFIX_PATH_CACHE") set(testNameSuffix "_CMAKE_PREFIX_PATH_CACHE") set(cmakePrefixPathCacheArg "-DCMAKE_PREFIX_PATH=${cmakePrefixPath}") - set(tplLibAndIncDirsArgs "-DTpl1_ALLOW_PACKAGE_PREFIND=OFF") + set(tplLibAndIncDirsArgs "${allTplsNoPrefindArgs}") set(searchingTplLibAndINcDirsRegexes "") elseif (findingTplsMethod STREQUAL "CMAKE_PREFIX_PATH_ENV") set(testNameSuffix "_CMAKE_PREFIX_PATH_ENV") string(REPLACE "" ":" cmakePrefixPathEnv "${cmakePrefixPath}") set(cmakePrefixPathEnvArg ENVIRONMENT CMAKE_PREFIX_PATH=${cmakePrefixPathEnv}) - set(tplLibAndIncDirsArgs "-DTpl1_ALLOW_PACKAGE_PREFIND=OFF") + set(tplLibAndIncDirsArgs "${allTplsNoPrefindArgs}") set(searchingTplLibAndINcDirsRegexes "") else() message(FATAL_ERROR @@ -282,7 +289,7 @@ TribitsExampleProject2_find_tpl_parts(SHARED CMAKE_PREFIX_PATH_ENV) ######################################################################## -function(TribitsExampleProject2_find_tpl_parts_no_optional_packages_tpls sharedOrStatic) +function(TribitsExampleProject2_find_tpl_parts_no_optional_packages_tpls sharedOrStatic) TribitsExampleProject2_test_setup_header() @@ -312,6 +319,9 @@ function(TribitsExampleProject2_find_tpl_parts_no_optional_packages_tpls sharedO -DCMAKE_BUILD_TYPE=DEBUG "-DCMAKE_PREFIX_PATH=${cmakePrefixPath}" -DTpl1_ALLOW_PACKAGE_PREFIND=OFF + -DTpl2_ALLOW_PACKAGE_PREFIND=OFF + -DTpl3_ALLOW_PACKAGE_PREFIND=OFF + -DTpl4_ALLOW_PACKAGE_PREFIND=OFF -DTribitsExProj2_ENABLE_ALL_OPTIONAL_PACKAGES=OFF -DPackage3_ENABLE_Package2=OFF -DTribitsExProj2_ENABLE_TESTS=ON @@ -395,7 +405,7 @@ TribitsExampleProject2_find_tpl_parts_no_optional_packages_tpls(SHARED) ######################################################################## -function(TribitsExampleProject2_explicit_tpl_vars sharedOrStatic) +function(TribitsExampleProject2_explicit_tpl_vars sharedOrStatic) TribitsExampleProject2_test_setup_header() @@ -504,61 +514,79 @@ TribitsExampleProject2_explicit_tpl_vars(SHARED) ######################################################################## -function(TribitsExampleProject2_find_package_test sharedOrStatic) +function(TribitsExampleProject2_find_package sharedOrStatic) TribitsExampleProject2_test_setup_header() - set(testNameBase TribitsExampleProject2_find_package_${sharedOrStatic}) + set(testNameBase ${CMAKE_CURRENT_FUNCTION}_${sharedOrStatic}) set(testName ${PACKAGE_NAME}_${testNameBase}) set(testDir "${CMAKE_CURRENT_BINARY_DIR}/${testName}") + set(tplInstallBaseDir "${TribitsExampleProject2_Tpls_install_${sharedOrStatic}_DIR}") + tribits_add_advanced_test( ${testNameBase} OVERALL_WORKING_DIRECTORY TEST_NAME OVERALL_NUM_MPI_PROCS 1 - - ENVIRONMENT - "CMAKE_PREFIX_PATH=${TribitsExampleProject2_Tpls_install_${sharedOrStatic}_DIR}/install_tpl1" + LIST_SEPARATOR "" TEST_0 - MESSAGE "Configure TribitsExampleProject2 against pre-installed Tpl1" + MESSAGE "Configure TribitsExampleProject2 against pre-installed TPLs" CMND ${CMAKE_COMMAND} ARGS ${TribitsExampleProject2_COMMON_CONFIG_ARGS} -DCMAKE_BUILD_TYPE=DEBUG + -DTPL_ENABLE_Tpl3=ON + -DTPL_ENABLE_Tpl4=ON + -DTribitsExProj2_ENABLE_ALL_PACKAGES=ON -DTribitsExProj2_ENABLE_TESTS=ON -DCMAKE_INSTALL_PREFIX=install - -DTribitsExProj2_ENABLE_Package1=ON + -D CMAKE_PREFIX_PATH="${tplInstallBaseDir}/install_tpl1${tplInstallBaseDir}/install_tpl2${tplInstallBaseDir}/install_tpl3${tplInstallBaseDir}/install_tpl4" ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject2 ALWAYS_FAIL_ON_NONZERO_RETURN PASS_REGULAR_EXPRESSION_ALL - "Using find_package[(]Tpl1 [.][.][.][)] [.][.][.]" - "Found Tpl1_DIR='.*TribitsExampleProject2_Tpls_install_${sharedOrStatic}/install_tpl1/lib/cmake/Tpl1'" - "TPL_Tpl1_LIBRARIES='Tpl1::all_libs'" - "TPL_Tpl1_INCLUDE_DIRS=''" + "-- Using find_package[(]Tpl1 [.][.][.][)] [.][.][.]" + "-- Found Tpl1_DIR='.*TribitsExampleProject2_Tpls_install_${sharedOrStatic}/install_tpl1/lib/cmake/Tpl1'" + "-- Generating Tpl1::all_libs and Tpl1Config.cmake" + "-- Found Tpl2_DIR='.*TribitsExampleProject2_Tpls_install_${sharedOrStatic}/install_tpl2/lib/cmake/Tpl2'" + "-- Generating Tpl2::all_libs and Tpl2Config.cmake" + "-- Found Tpl3_DIR='.*TribitsExampleProject2_Tpls_install_${sharedOrStatic}/install_tpl3/lib/cmake/Tpl3'" + "-- Generating Tpl3::all_libs and Tpl3Config.cmake" + "-- Found Tpl4_DIR='.*TribitsExampleProject2_Tpls_install_${sharedOrStatic}/install_tpl4/lib/cmake/Tpl4'" + "-- Generating Tpl4::all_libs and Tpl4Config.cmake" "-- Configuring done" "-- Generating done" TEST_1 - MESSAGE "Build Package1 and tests" + MESSAGE "Build Packages and tests" CMND make ALWAYS_FAIL_ON_NONZERO_RETURN PASS_REGULAR_EXPRESSION_ALL "package1-prg" + "package2-prg" + "package3-prg" TEST_2 - MESSAGE "Run tests for Package1" + MESSAGE "Run tests" CMND ${CMAKE_CTEST_COMMAND} ARGS -VV ALWAYS_FAIL_ON_NONZERO_RETURN PASS_REGULAR_EXPRESSION_ALL "Test.*Package1_Prg.*Passed" - "100% tests passed, 0 tests failed" + "Test.*Package2_Prg.*Passed" + "Test.*Package3_Prg.*Passed" + "100% tests passed, 0 tests failed out of 3" TEST_3 - MESSAGE "Install Package1" + MESSAGE "Install" CMND make ARGS install PASS_REGULAR_EXPRESSION_ALL "Tpl1Config.cmake" "Tpl1ConfigVersion.cmake" + "Tpl2Config.cmake" + "Tpl2ConfigVersion.cmake" + "Tpl3Config.cmake" + "Tpl3ConfigVersion.cmake" + "Tpl4Config.cmake" + "Tpl4ConfigVersion.cmake" ALWAYS_FAIL_ON_NONZERO_RETURN ${ENV_PATH_HACK_FOR_TPL1_${sharedOrStatic}_ARG} @@ -566,7 +594,7 @@ function(TribitsExampleProject2_find_package_test sharedOrStatic) ADDED_TEST_NAME_OUT ${testNameBase}_NAME ) # NOTE: The above test ensures that find_package() works with manual - # building of the target . + # building of the target. if (${testNameBase}_NAME) set(${testNameBase}_NAME ${${testNameBase}_NAME} PARENT_SCOPE) @@ -578,8 +606,8 @@ function(TribitsExampleProject2_find_package_test sharedOrStatic) endfunction() -TribitsExampleProject2_find_package_test(STATIC) -TribitsExampleProject2_find_package_test(SHARED) +TribitsExampleProject2_find_package(STATIC) +TribitsExampleProject2_find_package(SHARED) ######################################################################## @@ -680,6 +708,9 @@ tribits_add_advanced_test( ${testNameBase} # find_package(Tpl1) will not find Tpl1Config.cmake just because # CMAKE_INSTALL_PREFIX is in the search path. # + # This test also sets Tpl1_EXTRACT_INFO_AFTER_FIND_PACKAGE=ON so we can test + # that path through FindTPLTpl1.cmake. + # # NOTE: Updated versions of TriBITS will not find TriBITS-generated files # like Tpl1Config.cmake because they are placed under a different subdir # /external_pacakges/. diff --git a/tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake b/tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake new file mode 100644 index 000000000..474f42c5e --- /dev/null +++ b/tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake @@ -0,0 +1,132 @@ +# @HEADER +# ************************************************************************ +# +# TriBITS: Tribal Build, Integrate, and Test System +# Copyright 2013 Sandia Corporation +# +# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +# the U.S. Government retains certain rights in this software. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Corporation nor the names of the +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ************************************************************************ +# @HEADER + + +# @FUNCTION: tribits_external_package_create_imported_all_libs_target_and_config_file() +# +# Call from a ``FindTPL.cmake`` module that calls inner +# ``find_package()`` for external package that uses modern CMake +# IMPORTED targets. +# +# Usage:: +# +# tribits_external_package_create_imported_all_libs_target_and_config_file( +# +# INNER_FIND_PACKAGE_NAME +# IMPORTED_TARGETS_FOR_ALL_LIBS ... ) +# +# This function is called in a TriBITS ``FindTPL.cmake`` wrapper +# module after it calls ``find_package()`` and then creates the +# IMPORTED target ``::all_libs`` from the list of IMPORTED targets +# `` ...`` which are defined from the call +# ``find_package()``. This function also takes care of +# generating the correct ``Config.cmake`` file under the directory:: +# +# ${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR} +# +# The generated ``Config.cmake`` file calls +# ``find_dependency()`` (with no other argument) and then, again, +# defines the correct imported library dependency. +# +# For more details, see `Creating FindTPL*.cmake using find_package() with +# IMPORTED targets`_. +# +function(tribits_external_package_create_imported_all_libs_target_and_config_file + tplName + ) + + # Parse arguments + cmake_parse_arguments( + PARSE_ARGV 1 + PARSE "" "" # prefix, options, one_value_keywords + "INNER_FIND_PACKAGE_NAME;IMPORTED_TARGETS_FOR_ALL_LIBS" #multi_value_keywords + ) + tribits_check_for_unparsed_arguments(PARSE) + tribits_assert_parse_arg_one_value(PARSE INNER_FIND_PACKAGE_NAME) + tribits_assert_parse_arg_one_or_more_values(PARSE IMPORTED_TARGETS_FOR_ALL_LIBS) + + # Create imported target ::all_libs + add_library(${tplName}::all_libs INTERFACE IMPORTED GLOBAL) + foreach (importedTarget IN LISTS PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS) + target_link_libraries(${tplName}::all_libs INTERFACE ${importedTarget}) + endforeach() + + # Create Config.cmake file + tribits_external_package_create_package_config_file_with_imported_targets( + ${tplName} + INNER_FIND_PACKAGE_NAME ${PARSE_INNER_FIND_PACKAGE_NAME} + IMPORTED_TARGETS_FOR_ALL_LIBS ${PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS} ) + +endfunction() + + +function(tribits_external_package_create_package_config_file_with_imported_targets + tplName + ) + + # Parse arguments + cmake_parse_arguments( + PARSE_ARGV 1 + PARSE "" "" # prefix, options, one_value_keywords + "INNER_FIND_PACKAGE_NAME;IMPORTED_TARGETS_FOR_ALL_LIBS" #multi_value_keywords + ) + tribits_check_for_unparsed_arguments(PARSE) + tribits_assert_parse_arg_one_value(PARSE INNER_FIND_PACKAGE_NAME) + tribits_assert_parse_arg_one_or_more_values(PARSE IMPORTED_TARGETS_FOR_ALL_LIBS) + set(externalPkg ${PARSE_INNER_FIND_PACKAGE_NAME}) + + # Create Config.cmake file + set(configFileStr "") + string(APPEND configFileStr + "include(CMakeFindDependencyMacro)\n" + "set(${externalPkg}_DIR \"${${externalPkg}_DIR}\")\n" + "find_dependency(${externalPkg})\n" + "add_library(${tplName}::all_libs INTERFACE IMPORTED GLOBAL)\n" + ) + foreach (importedTarget IN LISTS PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS) + string(APPEND configFileStr + "target_link_libraries(${tplName}::all_libs INTERFACE ${importedTarget})\n") + endforeach() + set(buildDirExternalPkgsDir + "${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR}") + set(tplConfigFile + "${buildDirExternalPkgsDir}/${tplName}/${tplName}Config.cmake") + file(WRITE "${tplConfigFile}" "${configFileStr}") + +endfunction() diff --git a/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake b/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake index 62b51f257..d5b2b6eb1 100644 --- a/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake +++ b/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake @@ -61,9 +61,9 @@ cmake_policy(SET CMP0057 NEW) # Support if ( ... IN_LIST ... ) # ````: Full file path for the ``Config.cmake`` # file that will be written out. # -# This function just calls -# ``tribits_external_package_write_config_file_str()`` and writes that text to -# the file ```` so see that function for more details. +# This function just calls `tribits_external_package_write_config_file_str()`_ +# and writes that text to the file ```` so see that function +# for more details. # function(tribits_external_package_write_config_file tplName tplConfigFile) tribits_external_package_write_config_file_str(${tplName} tplConfigFileStr) @@ -172,30 +172,81 @@ endfunction() # tribits_external_package_write_config_file_str( # ) # -# The arguments are: +# The function arguments are: # # ````: Name of the external package/TPL # # ````: Name of variable that will contain the string # for the config file on output. # -# This function reads from the variables ``TPL__INCLUDE_DIRS`` -# ``TPL__LIBRARIES``, and ``_LIB_ENABLED_DEPENDENCIES`` +# This function reads from the (cache) variables +# +# * ``TPL__INCLUDE_DIRS`` +# * ``TPL__LIBRARIES`` +# * ``_LIB_ENABLED_DEPENDENCIES`` +# # (which must already be set) and uses that information to produce the # contents of the ``Config.cmake`` which is returned as a string # variable that contains IMPORTED targets to represent these libraries and # include directories as well as ``find_dependency()`` calls for upstream -# packages listed in ``_LIB_ENABLED_DEPENDENCIES`` +# packages listed in ``_LIB_ENABLED_DEPENDENCIES``. +# +# The arguments in ``TPL__LIBRARIES`` are handled in special ways in +# order to create the namespaced IMPORTED targets ``::`` and +# the ``::all_libs`` target that depends on these. The types of +# arguments that are handled and how the are interpreted: +# +# ``/[lib].`` +# +# Arguments that are absolute file paths are treated as libraries and an +# imported target name ```` is derived from the file name (of the +# form ``lib.`` removing beginning ``lib`` and file +# extension ``.``). The IMPORTED target +# ``::`` is created and the file path is set using the +# ``IMPORTED_LOCATION`` target property. +# +# ``-l`` +# +# Arguments of the form ``-l`` are used to create IMPORTED +# targets with the name ``::`` using the +# ``IMPORTED_LIBNAME`` target property. +# +# ```` +# +# Arguments that are a raw name that matches the regex +# ``^[a-zA-Z_][a-zA-Z0-9_-]*$`` are interpreted to be a library name +# ```` and is used to create an IMPORTED targets +# ``::`` using the ``IMPORTED_LIBNAME`` target property. +# +# ``-L`` +# +# Link directories. These are pulled off and added to the +# ``::all_libs`` using ``target_link_options()``. (The order of +# these options is maintained.) +# +# ``-`` +# +# Any other option that starts with ``-`` is assumed to +# be a link argument where the order does not matter in relation to the +# libraries (but the order of these extra options are maintained w.r.t. each +# other). +# +# ```` +# +# Any other argument that does not match one of the above patterns is +# regarded as an error. # -# ToDo: Flesh out more documentation for behavior as more features are added -# for handling: +# For more details on the handling of individual ``TPL__LIBRARIES`` +# arguments, see `tribits_tpl_libraries_entry_type()`_. # -# * ``TPL__LIBRARIES`` containing ``-l`` and ``-L`` arguments ... +# The list of directories given in ``TPL__INCLUDE_DIRS`` is added to +# the ``::all_libs`` target using ``target_include_directories()``. # -# * ``TPL__LIBRARIES`` containing arguments other than library files -# * or ``-l`` and ``-L`` arguments and files. +# Finally, for every ```` listed in +# ``_LIB_ENABLED_DEPENDENCIES``, a link dependency is created using +# ``target_link_library(::all_libs INTERFACE )``. # -function(tribits_external_package_write_config_file_str tplName tplConfigFileStrOut) +function(tribits_external_package_write_config_file_str tplName tplConfigFileStrOut) # A) Set up beginning of config file text set(configFileStr "") @@ -402,30 +453,36 @@ function(tribits_external_package_process_libraries_list tplName) endfunction() +# @FUNCTION: tribits_tpl_libraries_entry_type() +# # Returns the type of the library entry in the list TPL__LIBRARIES # +# Usage:: +# +# tribits_tpl_libraries_entry_type( ) +# # Arguments: # -# ``libentry`` [in]: Element of ``TPL__LIBRARIES`` +# ```` [in]: Element of ``TPL__LIBRARIES`` # -# ``libEntryTypeOut`` [out]: Variable set on output to the type of entry. +# ```` [out]: Variable set on output to the type of entry. # # The types of entries set on ``libEntryTypeOut`` include: # -# ``FULL_LIB_PATH``: A full library path +# * ``FULL_LIB_PATH``: A full library path # -# ``LIB_NAME_LINK_OPTION``: A library name link option of the form -# ``-l`` +# * ``LIB_NAME_LINK_OPTION``: A library name link option of the form +# ``-l`` # -# ``LIB_NAME``: A library name of the form ```` +# * ``LIB_NAME``: A library name of the form ```` # -# ``LIB_DIR_LINK_OPTION``: A library directory search option of the form -# ``-L`` +# * ``LIB_DIR_LINK_OPTION``: A library directory search option of the form +# ``-L`` # -# ``GENERAL_LINK_OPTION``: Some other general link option that starts with -# ``-`` but is not ``-l`` or ``-L``. +# * ``GENERAL_LINK_OPTION``: Some other general link option that starts with +# ``-`` but is not ``-l`` or ``-L``. # -# ``UNSUPPORTED_LIB_ENTRY``: An unsupported lib option +# * ``UNSUPPORTED_LIB_ENTRY``: An unsupported lib option # function(tribits_tpl_libraries_entry_type libentry libEntryTypeOut) string(SUBSTRING "${libentry}" 0 1 firstCharLibEntry) diff --git a/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake b/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake index 84f242a1c..221e8fb90 100644 --- a/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake +++ b/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake @@ -39,6 +39,7 @@ # Standard TriBITS Includes +include(TribitsExternalPackageFindTplHelpers) include(TribitsExternalPackageWriteConfigFile) include(TribitsTplFindIncludeDirsAndLibraries) include(TribitsGeneralMacros) diff --git a/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake b/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake index d3ebe2795..3a514943d 100644 --- a/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake +++ b/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake @@ -99,8 +99,9 @@ include(Split) # to disable the prefind call to ``find_package()`` even if it would be # allowed otherwise. # -# See `How to use find_package() for a TriBITS TPL`_ for details in how to use -# this function to create a ``FindTPL.cmake`` module file. +# See `Creating FindTPL*.cmake using find_package() without IMPORTED targets`_ +# for details in how to use this function to create a +# ``FindTPL.cmake`` module file. # function(tribits_tpl_allow_pre_find_package TPL_NAME ALLOW_PACKAGE_PREFIND_OUT) @@ -157,10 +158,12 @@ endfunction() # @FUNCTION: tribits_tpl_find_include_dirs_and_libraries() # -# Function that sets up cache variables for users to specify where to find a -# `TriBITS TPL`_'s headers and libraries. This function is typically called -# inside of a ``FindTPL.cmake`` module file (see -# `${TPL_NAME}_FINDMOD`_). +# This function reads (cache) variables that specify where to find a `TriBITS +# TPL`_'s headers and libraries and then creates IMPORTED targets, the +# ``::all_libs`` target, and writes the file +# ``Config.cmake`` into the standard location in the build directory. +# This function is typically called inside of a ``FindTPL.cmake`` +# module file (see `${TPL_NAME}_FINDMOD`_). # # Usage:: # @@ -190,22 +193,23 @@ endfunction() # ``MUST_FIND_ALL_HEADERS`` # # If set, then all of the header files listed in ``REQUIRED_HEADERS`` must -# be found in order for ``TPL__INCLUDE_DIRS`` to be defined. +# be found (unless ``TPL__INCLUDE_DIRS`` is already set). # # ``REQUIRED_LIBS_NAMES`` # # List of libraries that are searched for when looking for the TPL's # libraries using ``find_library()``. This list can be overridden by the -# user by setting ``_LIBRARY_DIRS`` (see below). +# user by setting ``_LIBRARY_NAMES`` (see below). # # ``MUST_FIND_ALL_LIBS`` # # If set, then all of the library files listed in ``REQUIRED_LIBS_NAMES`` -# must be found or the TPL is considered not found! If the global cache -# var ``_MUST_FIND_ALL_TPL_LIBS`` is set to ``TRUE``, then this -# is turned on as well. WARNING: The default is not to require finding -# all of the listed libs. This is to maintain backward compatibility with -# some older ``FindTPL.cmake`` modules. +# must be found or the TPL is considered not found (unless +# ``TPL__LIBRARIES`` is already set). If the global cache var +# ``_MUST_FIND_ALL_TPL_LIBS`` is set to ``TRUE``, then this is +# turned on as well. WARNING: The default is not to require finding all +# of the listed libs. (This is to maintain backward compatibility with +# some older ``FindTPL.cmake`` modules.) # # ``NO_PRINT_ENABLE_SUCCESS_FAIL`` # @@ -214,50 +218,69 @@ endfunction() # This function implements the TPL find behavior described in `Enabling # support for an optional Third-Party Library (TPL)`_. # -# The following (cache) variables, if set, will be used by that this function: +# The following (cache) variables, if set, will be used by this function: # # ``_INCLUDE_DIRS`` (type ``PATH``) # # List of paths to search first for header files defined in -# ``REQUIRED_HEADERS``. +# ``REQUIRED_HEADERS ...``. # # ``_LIBRARY_DIRS`` (type ``PATH``) # # The list of directories to search first for libraries defined in -# ``REQUIRED_LIBS_NAMES``. If, for some reason, no libraries should be -# linked in for this particular configuration, then setting -# ``_LIBRARY_DIRS=OFF`` will +# ``REQUIRED_LIBS_NAMES ...``. If, for some reason, +# no libraries should be linked in for this particular configuration, then +# setting ``_LIBRARY_DIRS=OFF`` or is empty will no special paths +# will be searched. # # ``_LIBRARY_NAMES`` (type ``STRING``) # # List of library names to be looked for instead of what is specified in -# ``REQUIRED_LIBS_NAMES``. +# ``REQUIRED_LIBS_NAMES ...``. # -# This function sets global variables to return state so it can be called from -# anywhere in the call stack. The following cache variables are defined that -# are intended for the user to set and/or use: +# ``_LIB_ENABLED_DEPENDENCIES`` +# +# List of direct upstream external package/TPL dependencies that also +# define ``::all_libs`` targets. +# +# An addition, the function will avoid calling the find operations if the +# following (cache) variables are set on input: # # ``TPL__INCLUDE_DIRS`` (type ``PATH``) # # A list of common-separated full directory paths that contain the TPL's -# header files. If this variable is set before calling this function, -# then no headers are searched for and this variable will be assumed to -# have the correct list of header paths. +# header files. # # ``TPL__LIBRARIES`` (type ``FILEPATH``) # # A list of commons-separated full library names (i.e. output from -# ``find_library()``) for all of the libraries found for the TPL. If this -# variable is set before calling this function, then no libraries are -# searched for and this variable will be assumed to have the correct list -# of libraries to link to. +# ``find_library()``) for all of the libraries for the TPL. +# +# This function produces the following: # # ``TPL__NOT_FOUND`` (type ``BOOL``) # # Will be set to ``ON`` if all of the parts of the TPL could not be found. # -# ToDo: Document the behavior of this function for finding headers and -# libraries and when a find is successful and when it is not. +# ``::`` +# +# Namespaced IMPORTED target for every library found or specified in +# ``TPL__LIBRARIES``. These IMPORTED targets will have the +# ``::all_libs`` for the upstream external packages/TPLs +# listed in ``_LIB_ENABLED_DEPENDENCIES``. +# +# ``::all_libs`` +# +# INTERFACE target that depends on all of the created IMPORTED targets. +# +# ``/external_packages//Config.cmake`` +# +# A package configure file that contains all of the generated IMPORTED +# targets ``::`` and the ``::all_libs`` target. +# This fill will also call ``find_dependency()`` to pull in +# ``Config.cmake`` files for upstream TPLs that are +# listed in ``_LIB_ENABLED_DEPENDENCIES``. (For more +# information, see `tribits_external_package_write_config_file()`_.) # # Note, if ``TPL_TENTATIVE_ENABLE_=ON``, then if all of the parts of # the TPL can't be found, then ``TPL_ENABLE_`` will be (forced) set @@ -358,7 +381,7 @@ function(tribits_tpl_find_include_dirs_and_libraries TPL_NAME) else() - set(${TPL_NAME}_LIBRARY_DIRS) # Just to ignore below! + set(${TPL_NAME}_LIBRARY_DIRS "") # Just to ignore below! endif() diff --git a/tribits/doc/guides/TribitsGuidesBody.rst b/tribits/doc/guides/TribitsGuidesBody.rst index fd4094662..327960df2 100644 --- a/tribits/doc/guides/TribitsGuidesBody.rst +++ b/tribits/doc/guides/TribitsGuidesBody.rst @@ -2,12 +2,12 @@ Background ========== In order to easily find the most appropriate documentation, see the `TriBITS -Developer and User Roles`_ guide. This guide describes the different roles +Developer and User Roles`_ guide. This guide describes the different roles that users of TriBITS may play and offers links to relevant sections of the -documentation. Additionally, the reader may wish to review the `CMake Language -Overview and Gotchas`_ section which is meant for users that are new to both +documentation. Additionally, the reader may wish to review the `CMake Language +Overview and Gotchas`_ section which is meant for users that are new to both CMake and TriBITS. This section gives a brief overview of getting started with -CMake and provides some warnings about non-obvious CMake behavior that often +CMake and provides some warnings about non-obvious CMake behavior that often trips up new users of TriBITS. @@ -21,7 +21,7 @@ Project User`_, 2) `TriBITS Project Developer`_, 3) `TriBITS Project Architect`_, 4) `TriBITS System Developer`_, and 5) `TriBITS System Architect`_. Each of these roles builds on the necessary knowledge of the lower-level roles. - + .. _TriBITS Project User: .. _TriBITS Project Users: @@ -119,12 +119,12 @@ project. As a result, many people can come into a project that uses TriBITS and quickly start to contribute by adding new source files, adding new libraries, adding new tests, and even adding new TriBITS packages and TPLs; all without really having learned anything about CMake. Often one can use existing -example CMake code as a guide and be successful using basic functionality. As long -as nothing out of the ordinary happens, many people can get along just fine in this +example CMake code as a guide and be successful using basic functionality. As long +as nothing out of the ordinary happens, many people can get along just fine in this mode for a time. -However, we have observed that most mistakes and problems that people run into when -using TriBITS are due to lack of basic knowledge of the CMake language. One can find +However, we have observed that most mistakes and problems that people run into when +using TriBITS are due to lack of basic knowledge of the CMake language. One can find basic tutorials and references on the CMake language in various locations online for free. One can also purchase the `official CMake reference book`_. Also, documentation for any built-in CMake command is available locally by running:: @@ -143,15 +143,15 @@ greater understanding of how TriBITS works. .. _Official CMake reference book: http://www.cmake.org/cmake/help/book.html The CMake language is used to write CMake projects with TriBITS. In fact the -core TriBITS functionality itself is implemented in the CMake language (see -`TriBITS System Project Dependencies`_). CMake is a fairly simple programming -language with relatively simple rules (for the most part). However, compared -to other programming languages, there are a few peculiar aspects to the CMake -language that can make working with it difficult if you don't understand these -rules. For example there are unexpected variable scoping rules and how arguments -are passed to macros and functions can be tricky. Also, CMake has some interesting -gotchas. In order to effectively use TriBITS (or just raw CMake) to construct -and maintain a project's CMake files, one must know the basic rules of CMake +core TriBITS functionality itself is implemented in the CMake language (see +`TriBITS System Project Dependencies`_). CMake is a fairly simple programming +language with relatively simple rules (for the most part). However, compared +to other programming languages, there are a few peculiar aspects to the CMake +language that can make working with it difficult if you don't understand these +rules. For example there are unexpected variable scoping rules and how arguments +are passed to macros and functions can be tricky. Also, CMake has some interesting +gotchas. In order to effectively use TriBITS (or just raw CMake) to construct +and maintain a project's CMake files, one must know the basic rules of CMake and be aware of these gotchas. The first thing to understand about the CMake language is that nearly every @@ -217,9 +217,9 @@ control structures (i.e. see ``cmake --help-command if`` and ``cmake CMake offers a rich assortment of built-in commands for doing all sorts of things. Two of these are the built-in ``macro()`` and the ``function()`` commands which allow you to create user-defined macros and functions. TriBITS -is actually built on CMake functions and macros. All of the built-in and -user-defined macros, and some functions take an array of string arguments. -Some functions take in positional arguments. In fact, most functions take a +is actually built on CMake functions and macros. All of the built-in and +user-defined macros, and some functions take an array of string arguments. +Some functions take in positional arguments. In fact, most functions take a combination of positional and keyword arguments. Variable names are translated into their stored values using @@ -598,7 +598,7 @@ ${PROJECT_SOURCE_DIR}``) are:: project-checkin-test-config.py # [Optional] checkin-test.py config cmake/ NativeRepositoriesList.cmake # [Optional] Rarely used - ExtraRepositoriesList.cmake # [Optional] Lists repos and VC URLs + ExtraRepositoriesList.cmake # [Optional] Lists repos and VC URLs ProjectCiFileChangeLogic.py # [Optional] CI global change/test logic ProjectCompilerPostConfig.cmake # [Optional] Override/tweak build flags ProjectDependenciesSetup.cmake # [Optional] Project deps overrides @@ -903,16 +903,16 @@ are set. This file in Trilinos looked like:: ... include(${Kokkos_GEN_DIR}/kokkos_generated_settings.cmake) - + if (NOT KOKKOS_ARCH STREQUAL "None") - + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KOKKOS_CXX_FLAGS}") - + message("-- " "Skip adding flags for OpenMP because Kokkos flags does that ...") set(OpenMP_CXX_FLAGS_OVERRIDE " ") - + endif() - + endif() The exact context where this file is processed (if it exists) is described in @@ -1942,7 +1942,7 @@ A TriBITS Subpackage: ``${PARENT_PACKAGE_NAME}_ENABLE_TESTS=ON``. The contents of a TriBITS Subpackage are almost identical to those of a -TriBITS Package. The differences are described below and in `How is a TriBITS +TriBITS Package. The differences are described below and in `How is a TriBITS Subpackage different from a TriBITS Package?`_. For more details on the definition of a TriBITS Package (or subpackage), see: @@ -2149,8 +2149,10 @@ are some of the issues to consider when breaking up software into packages and subpackages that will be mentioned in other sections as well. -TriBITS TPL -+++++++++++ +.. _TriBITS TPL: + +TriBITS External Package/TPL +++++++++++++++++++++++++++++ A *TriBITS TPL*: @@ -2183,26 +2185,32 @@ disabled, all of the downstream packages that depend on that TPL will be automatically disabled as well (see `TPL disable triggers auto-disables of downstream dependencies`_). -For each TPL referenced in a `/TPLsList.cmake`_ file using the macro -`tribits_repository_define_tpls()`_, there must exist a file, typically called -``FindTPL${TPL_NAME}.cmake``, that once processed, produces the target -```${TPL_NAME}::all_libs``. Most ``FindTPL${TPL_NAME}.cmake`` files just use -the function `tribits_tpl_find_include_dirs_and_libraries()`_ to define the -TriBITS TPL. A simple example of such a file is the common TriBITS -``FindTPLPETSC.cmake`` module which is currently: + +TriBITS External Package/TPL Core Files +....................................... + +For each external package/TPL referenced in a `/TPLsList.cmake`_ file +using the macro `tribits_repository_define_tpls()`_, there must exist a file, +typically called ``FindTPL.cmake``, that once processed, produces the +target ```::all_libs`` and generates a wrapper package config file +``Config.cmake``. A simple example of such a file is the common +TriBITS ``FindTPLPETSC.cmake`` module which is currently: .. include:: ../../common_tpls/FindTPLPETSC.cmake :literal: -Some concrete ``FindTPL${TPL_NAME}.cmake`` files actually do use -``find_package()`` and a standard CMake package find module to fill in the -guts of finding at TPL which is perfectly fine. In this case, the purpose for -the wrapping ``FindTPL${TPL_NAME}.cmake`` file is to ensure the definition of -the complete target ``${TPL_NAME}::all_libs`` which contains all usage -requirements for the external package/TPL (i.e. all of the libraries, include -directories, etc.). For more details on properly using ``find_package()`` to -define a ``FindTPL${TPL_NAME}.cmake`` file, see `How to use find_package() for -a TriBITS TPL`_. +Many concrete ``FindTPL.cmake`` files use ``find_package()`` +internally and a standard CMake package find module or an installed +``Config.cmake`` file to fill in the guts of finding at TPL. In this +case, the purpose for the wrapping ``FindTPL.cmake`` file is to +ensure the definition of the complete target ``::all_libs`` which +contains all usage requirements for the external package/TPL (i.e. all of the +libraries, include directories, etc.). For more details creating or upgrading +a ``FindTPL.cmake`` file, see `How to add a new TriBITS TPL`_. + + +TriBITS External Package/TPL Core Variables +........................................... Once the `/TPLsList.cmake`_ files are all processed, then each defined TPL ``TPL_NAME`` is assigned the following global non-cache variables: @@ -2213,15 +2221,16 @@ defined TPL ``TPL_NAME`` is assigned the following global non-cache variables: ``${TPL_NAME}_FINDMOD`` - Gives the location for the TPL's find module. This is set using the - ``FINDMOD`` field in the call to `tribits_repository_define_tpls()`_. The - final value of the variable is defined by the *last* - `/TPLsList.cmake`_ file that is processed that declares the TPL - ``TPL_NAME``. For example, if ``Repo1/TPLsList.cmake`` and - ``Repo2/TPLsList.cmake`` both list the TPL ``SomeTpl``, then if ``Repo2`` - is processed after ``Repo1``, then ``SomeTpl_FINDMOD`` is determined by - ``Repo2/TPLsList.cmake`` and the find module listed in - ``Repo1/TPLsList.cmake`` is ignored. + Gives the location for the TPL's find module (typically called + ``FindTPL.cmake``, see `How to add a new TriBITS TPL`_). This is + set using the ``FINDMOD`` field in the call to + `tribits_repository_define_tpls()`_. The final value of the variable is + defined by the *last* `/TPLsList.cmake`_ file that is processed + that declares the TPL ``TPL_NAME``. For example, if + ``Repo1/TPLsList.cmake`` and ``Repo2/TPLsList.cmake`` both list the TPL + ``SomeTpl``, then if ``Repo2`` is processed after ``Repo1``, then + ``SomeTpl_FINDMOD`` is determined by ``Repo2/TPLsList.cmake`` and the find + module listed in ``Repo1/TPLsList.cmake`` is ignored. .. _${TPL_NAME}_TESTGROUP: @@ -2246,21 +2255,14 @@ As noted above, it is allowed for the same TPL to be listed in multiple the find module and the test group as as described above. The specification given in `Enabling support for an optional Third-Party -Library (TPL)`_ and `tribits_tpl_find_include_dirs_and_libraries()`_ describes -how the a ``FindTPL${TPL_NAME}.cmake`` module should behave and allow users to -override and specialize how a TPL's include directories and libraries are -determined. However, note that the TriBITS system does not require the usage -of the function ``tribits_tpl_find_include_dirs_and_libraries()`` and does not -even care about the TPL module name ``FindTPL${TPL_NAME}.cmake``. All that is -required is that some CMake file fragment exist such that, once included, will -define the target ``${TPL_NAME}::all_libs``. However, to be user friendly, -such a CMake file should respond to the same variables as accepted by the -standard ``tribits_tpl_find_include_dirs_and_libraries()`` function. - -The core variables related to an enabled TPL are ``${TPL_NAME}_LIBRARIES``, -``${TPL_NAME}_INCLUDE_DIRS``, and ``${TPL_NAME}_TESTGROUP`` as defined in -`tribits_tpl_find_include_dirs_and_libraries()`_ need to be defined. For more -details, see `tribits_repository_define_tpls()`_. +Library (TPL)`_ and `How to add a new TriBITS TPL`_ describes to create a +``FindTPL.cmake`` module. However, all that is required is that +some CMake file fragment exist such that, once included, will define the +target ``::all_libs`` and create the ``Config.cmake`` file +in the correct location. + + + Processing of TriBITS Files: Ordering and Details @@ -2337,7 +2339,7 @@ proceeds through the call to `tribits_project()`_. | 5) ``include(`` `/Version.cmake`_ ``)`` | 6) Define primary TriBITS options and read in the list of extra repositories | (calls ``tribits_define_global_options_and_define_extra_repos()``) -| * ``include(`` `/cmake/ExtraRepositoriesList.cmake`_ ``)`` +| * ``include(`` `/cmake/ExtraRepositoriesList.cmake`_ ``)`` | 7) For each ```` in all defined TriBITS repositories: | * ``include(`` `/cmake/CallbackSetupExtraOptions.cmake`_ ``)`` | * Call macro ``tribits_repository_setup_extra_options()`` @@ -2381,7 +2383,7 @@ project, repository, package, and subpackage files should be clear. All of this information should also be clear when enabling `File Processing Tracing`_ and watching the output from the ``cmake`` configure STDOUT. -Reduced Package Dependency Processing +Reduced Package Dependency Processing ++++++++++++++++++++++++++++++++++++++ In addition to the full processing that occurs as part of the `Full TriBITS @@ -2667,7 +2669,7 @@ without having to define its own ``QT`` TPL in its repository's TriBITS, it can be difficult to know where the right place is to set a given set of variables. The primary considerations for where to set a variable depend on: - + .. ToDo: Describe considerations on where to set variables ... @@ -3176,7 +3178,7 @@ enable/disable cache variables (with the initial default values):: Trilinos_ENABLE_Teuchos="" Trilinos_ENABLE_RTOp"" - Trilinos_ENABLE_Epetra="" + Trilinos_ENABLE_Epetra="" Trilinos_ENABLE_Triutils="" Trilinos_ENABLE_EpetraExt="" Trilinos_ENABLE_ThyraCore="" @@ -3443,7 +3445,7 @@ In more detail, these rules/behaviors are: variable `${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES`_: .. _${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES=ON: - + * If ``${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES=ON``, then TriBITS will disable the explicit enable and continue on. In the above example, TriBITS will override ``Trilinos_ENABLE_RTOp=ON`` and set @@ -3475,7 +3477,7 @@ In more detail, these rules/behaviors are: Trilinos_ENABLE_ThyraGoodStuff=ON # Only if enabling ST code! Trilinos_ENABLE_ThyraEpetra=ON Trilinos_ENABLE_ThyraEpetraExt=ON # Only if enabling ST code! - + (Note that ``Trilinos_ENABLE_ThyraCrazyStuff`` is **not** set to ``ON`` because it is already set to ``OFF`` by default, see `EX SE packages disabled by default`_.) Likewise, explicitly setting @@ -3843,12 +3845,12 @@ tests/examples and TPLs can be clearly seen when processing the TPLs and top-level packages in the lines:: Getting information for all enabled TPLs ... - + -- Processing enabled TPL: BLAS -- Processing enabled TPL: LAPACK - + Configuring individual enabled Trilinos packages ... - + Processing enabled package: Teuchos (Libs) Processing enabled package: RTOp (Libs) Processing enabled package: Epetra (Libs) @@ -4681,7 +4683,7 @@ the `checkin-test.py`_ tool in extended pre-push testing. .. _Performance Testing: -**Performance Testing** +**Performance Testing** *Performance Testing* builds are a special class of builds that have tests that are specifically designed to test the run-time performance of a particular @@ -5158,26 +5160,26 @@ the commands:: $ git clone git@someurl.com:MetaProject $ cd MetaProject/ - $ ./cmake/tribits/ci_support/clone_extra_repos.py + $ ./cmake/tribits/ci_support/clone_extra_repos.py which produces the output like:: - ... - + ... + *** *** Clone the selected extra repos: *** - + Cloning repo ExtraRepo1 ... - + Running: git clone git@someurl.com:ExtraRepo1 ExtraRepo1 - + Cloning repo ExtraRepo2 ... - + Running: git clone git@someurl.com:ExtraRepo2 ExtraRepo1/ExtraRepo2 - + Cloning repo ExtraRepo3 ... - + Running: git clone git@someurl.com:ExtraRepo3 ExtraRepo3 See `clone_extra_repos.py --help`_ for more details. @@ -5224,7 +5226,7 @@ Some of the aggregate commands that one would typically run under the base The tool ``gitdist`` is provided under TriBITS directory:: - cmake/tribits/python_utils/gitidst + cmake/tribits/python_utils/gitidst and can be installed by the `install_devtools.py`_ tool (see `TriBITS Development Toolset`_). See `gitdist documentation`_ for more details. @@ -5452,43 +5454,54 @@ subpackages, do the following: and tests run as new pieces are added. -How to add a new TriBITS TPL ----------------------------- +.. _How to add a new TriBITS TPL: + +How to add a new TriBITS external package/TPL +--------------------------------------------- -In order for an SE package to define a dependency on a new TPL (i.e. one that -has not already been declared in the current repo's or an upstream repo's -`/TPLsList.cmake`_ file), one must add and modify a few -repository-level files. +In order for a TriBITS package to define a dependency on a new external +package/TPL (i.e. a TPL that has not already been declared in the current +repo's or an upstream repo's `/TPLsList.cmake`_ file), one must add +and modify a few repository-level files in addition to modifying files within +the TriBITS packages that use the new external package/TPL. To add a new TriBITS TPL, do the following: 1) Chose a name ```` for the new TPL (must be globally unique across all TriBITS repos, see `Globally unique TriBITS TPL names`_) and which - TriBITS repository (````) to define the new TPL in. The right - repo is usually the one where the package exists that needs the new TPL - dependency. - -2) Create the TPL find module, e.g. ``/tpls/FindTPL.cmake`` - (see `TriBITS TPL`_ and `tribits_tpl_find_include_dirs_and_libraries()`_ - for details). List the default required header files and/or libraries that - must be provided by the TPL. NOTE: This find module can also (optionally) - use ``find_package( ...)`` for the default find operation. For - details, see `How to use find_package() for a TriBITS TPL`_. + TriBITS repository (````) to define the new TPL inside of. (The + right repo is usually the one where the package exists that needs the new + TPL dependency.) + +2) Create the TPL find module file ``FindTPL.cmake`` (or some other + name, see `TriBITS TPL`_) under some location under ```` + (e.g. ``/cmake/tpls/``) or under the package that uses it + (e.g. ``/cmake/tpls/``). How this file is defined depends on + if it uses ``find_package()`` or not and if that + ``find_package()`` command creates modern CMake IMPORTED + targets or not (see `Creating FindTPL*.cmake using find_package() with + IMPORTED targets`_ and `Creating FindTPL*.cmake using find_package() + without IMPORTED targets`_). If not using ``find_package()``, + follow the instructions in `Creating a FindTPL*.cmake module without + find_package()`_. 3) Add a row for the new TPL to the `/TPLsList.cmake`_ file after any - TPLs that this new TPL may depend on. + TPLs that this new TPL may depend on. (One must also set the cache + variable ``_LIB_ENABLED_DEPENDENCIES`` to point the direct + dependencies of this new TPL. See the example in + ``TribitsExampleProject2/TPLsList.cmake``.) 4) Configure the TriBITS project enabling the new TPL with ``TPL_ENABLE_=ON`` and see that the new find module finds the TPL correctly at configure time. -5) List the new TPL in the package(s) that need this dependency in the - package's `/cmake/Dependencies.cmake`_ file (or - `//cmake/Dependencies.cmake`_ for a subpackage). +5) List the new external packages/TPL in the package(s) that need this + dependency in the package's `/cmake/Dependencies.cmake`_ file + (or `//cmake/Dependencies.cmake`_ for a subpackage). -6) If the TPL is an optional TPL for the package, then:: +6) If the TPL is optional for the package, then:: - #cmakedefine HAVE__ + #cmakedefine HAVE__ should be added to the package's ``_config.h.in`` file (see `tribits_configure_file()`_) so that the code knows if the TPL is defined @@ -5497,85 +5510,270 @@ To add a new TriBITS TPL, do the following: 7) Use the TPL in the packages that define the dependency on the new TPL, configure, test, etc. -.. ToDo: Provide more details on various things. +The following subsections describe the various use cases for creating (or +upgrading) ``FindTPL*.cmake`` modules. The main axes of variation for +``FindTPL*.cmake`` modules are: + +a) Use an inner ``find_package()`` call or just use a simple list + of header file names and library names? + +b) The call ``find_package()`` defines modern IMPORTED targets or + only provides variables for the list of include directories and libraries? + +c) Maintain backward compatibility with the legacy TriBITS TPL system that + allows the user to set cache variables for the include directories and link + libraries or force users to always call ``find_package()``? + + +Creating FindTPL*.cmake using find_package() +++++++++++++++++++++++++++++++++++++++++++++ + +When defining a ``FindTPL.cmake`` file, it encouraged to utilize +``find_package( ...)`` to provide the default find operation (and +also the definition of the IMPORTED targets needed to use the external package +when supported). (Here, typically ```` and ```` are the +same names, but there are cases where the names may be different or use +different capitalization.) However, the state of the current ecosystem of +``Find.cmake`` modules and ``Config.cmake`` package +config files is a bit uneven. While all find modules and package config files +should be defining modern CMake IMPORTED targets which contains all the needed +usage requirements (such as the target properties +``INTERFACE_INCLUDE_DIRECTORIES`` and ``INTERFACE_LINK_LIBRARIES``) and use +``find_dependency()`` to get all of their required external upstream package +dependencies, many do not. Also, many of these don't provide a complete +``::all_libs`` target which is required for a TriBITS-compatible +external package/TPL. + +In this case, the ``FindTPL.cmake`` file provides a thin "glue" layer +to adapt the information and objects provided by the +``find_package( ...)`` call into a complete +``::all_libs`` target and a wrapper ``Config.cmake`` file +for consumption by downstream TriBITS-compatible packages. + +The following subsections will describe how to create these TriBITS-compatible +``FindTPL.cmake`` modules for all of the various cases using +``find_package( ...)``. + + +Creating FindTPL*.cmake using find_package() with IMPORTED targets +.................................................................. + +For cases where ``find_package()`` provides complete and proper +modern (namespaced) IMPORTED targets (but is missing the +``::all_libs`` target or the name ```` and ```` +name are different), these ``FindTPL.cmake`` modules can call the +function +`tribits_external_package_create_imported_all_libs_target_and_config_file()`_ +after calling ``find_package()`` to create a very thin wrapper +``FindTPL.cmake`` module. In these cases, such a +``FindTPL.cmake`` module file is nothing more than:: + + find_package( REQUIRED) + tribits_external_package_create_imported_all_libs_target_and_config_file( + + INNER_FIND_PACKAGE_NAME + IMPORTED_TARGETS_FOR_ALL_LIBS ... ) + +The function +`tribits_external_package_create_imported_all_libs_target_and_config_file()`_ +creates the target ``::all_libs`` and the wrapper file +``Config.cmake`` which is installed by TriBITS. The only unique +information required to create this glue module is the name of the external +package ```` and the exact full names of the IMPORTED targets +`` ...`` provided by the +``find_package( ...)`` call. + +Such simple ``FindTPL.cmake`` modules do not follow the legacy +TriBITS TPL convention of allowing users to specify a TPL by setting the cache +variables ``_INCLUDE_DIRS``, ``_LIBRARY_DIRS``, and +``_LIBRARY_NAMES`` or by setting ``TPL__INCLUDE_DIRS`` and +``_LIBRARIES``. But as the ecosystem of CMake software transitions +to modern CMake and uniform usage of complete ``Config.cmake`` files, +that is the reasonable thing to do. + +However, to maintain backwards compatibility with the legacy TriBITS TPL +system (such as when upgrading a existing ``FindTPL.cmake`` file), a +``FindTPL.cmake`` file can be extended to use the +`tribits_tpl_allow_pre_find_package()`_ in combination with the function +`tribits_tpl_find_include_dirs_and_libraries()`_ function as follows:: + + set(REQUIRED_HEADERS ...) + set(REQUIRED_LIBS_NAMES ...) + set(IMPORTED_TARGETS_FOR_ALL_LIBS ...) -.. ToDo: Add an example of an optional TPL to some TribitsExampleProject -.. package and refer to it here. + tribits_tpl_allow_pre_find_package( _ALLOW_PREFIND) + if (_ALLOW_PREFIND) + message("-- Using find_package( ...) ...") + find_package() + if (_FOUND) + message("-- Found _DIR='${_DIR}'") + message("-- Generating ::all_libs and Config.cmake") + tribits_external_package_create_imported_all_libs_target_and_config_file( + INNER_FIND_PACKAGE_NAME + IMPORTED_TARGETS_FOR_ALL_LIBS ${IMPORTED_TARGETS_FOR_ALL_LIBS} ) + endif() + endif() -How to use find_package() for a TriBITS TPL -------------------------------------------- + if (NOT TARGET ::all_libs) + tribits_tpl_find_include_dirs_and_libraries( + REQUIRED_HEADERS ${REQUIRED_HEADERS} + REQUIRED_LIBS_NAMES ${REQUIRED_LIBS_NAMES} ) + endif() + +Above, if ``find_package()`` is called and returns +``_FOUND=FALSE``, then as fallback it will call +``tribits_tpl_find_include_dirs_and_libraries()`` to find the components of +the TPL. See the documentation for `tribits_tpl_allow_pre_find_package()`_ +for conditions where ``_ALLOW_PREFIND`` is set to ``FALSE`` (and +therefore ``find_package()`` is not called). + +Note that in the above ``FindTPL.cmake`` file that +``find_package()`` will be called even on reconfigures. That is +critical since ``find_package()`` defines IMPORTED targets that +must be available each time configure is called. Also, if +``find_package()`` is called and ``_FOUND=TRUE``, +then the function +`tribits_external_package_create_imported_all_libs_target_and_config_file()`_ +is called which defines the targets ``::all_libs`` which means that +the function ``tribits_tpl_find_include_dirs_and_libraries()`` will **not** be +called. + +A concrete (and tested) example of the latter case can be found in the file +``TribitsExampleProject2/cmake/tpls/FindTPLTpl2.cmake``: + +.. include:: ../../examples/TribitsExampleProject2/cmake/tpls/FindTPLTpl2.cmake + :literal: + + +Creating FindTPL*.cmake using find_package() without IMPORTED targets +..................................................................... + +There are cases where calling ``find_package()`` to find the +parts of an external package does not create proper IMPORTED targets that can +be directly used. For example, legacy ``Find.cmake`` modules +(even many standard ``Find*.cmake`` modules shipped with CMake as of CMake +3.23) do not provide IMPORTED targets and instead only provide variables for +the list of include directories ``_INCLUDE_DIRS``, a list of +library files ``_LIBRARIES``, and other information. In cases +such as this, one can implement the ``FindTPL.cmake`` module by +calling ``find_package()``, setting +``TPL__INCLUDE_DIRS`` and ``TPL__LIBRARIES``, and then +calling `tribits_tpl_find_include_dirs_and_libraries()`_ to create the +``::all_libs`` target and the ``Config.cmake`` wrapper +config file. + +The simplest way to implement ``FindTPL.cmake`` is to always call +``find_package()`` as:: + + message("-- Using find_package( ...) ...") + find_package( REQUIRED) + + # Tell TriBITS that we found and there no need to look any further + set(TPL__INCLUDE_DIRS ${_INCLUDE_DIRS} CACHE PATH "...") + set(TPL__LIBRARIES ${_LIBRARIES} CACHE FILEPATH "...") + set(TPL__LIBRARY_DIRS ${_LIBRARY_DIRS} CACHE PATH "...") + + tribits_tpl_find_include_dirs_and_libraries( + REQUIRED_HEADERS neverFindThisHeader + REQUIRED_LIBS_NAMES neverFindThisLib + ) + +The above will always call ``find_package( REQUIRED)``, and if it +can't find the package, it will error out and stop the configure process. + +While the above ``FindTPL.cmake`` file is pretty simple, it does not +allow for a fall-back using the legacy TriBITS TPL find system using +`tribits_tpl_find_include_dirs_and_libraries()`_. One can allow for a +fall-back find by passing a set of header files and library names for +``tribits_tpl_find_include_dirs_and_libraries()`` to find. This can be done +using the ``FindTPL.cmake`` module:: -When defining a ``FindTPL.cmake`` file, it is possible and encouraged -to utilize ``find_package( ...)`` to provide the default find -operation. However, most ``Find.cmake`` modules and even some -``Config.cmake`` config files don't provide all of the required -features needed by downstream TriBITS packages. Specifically, these modules -and config files usually don't provide a complete ``::all_libs`` -target that contains all usage requirements (such as the -``INTERFACE_INCLUDE_DIRECTORIES`` and ``INTERFACE_LINK_LIBRARIES`` target -properties) for the external package/TPL libraries. Also, in order for the -resulting ``FindTPL.cmake`` module to behave consistently between all -the various TriBITS TPLs (and allow the standard TriBITS TPL find overrides) -and maintain backwards compatibility, one must use the TriBITS function -`tribits_tpl_allow_pre_find_package()`_ in combination with the function -`tribits_tpl_find_include_dirs_and_libraries()`_. One basic form of the -resulting TriBITS TPL module file ``FindTPL.cmake`` that uses a list -of include directories and library files locations looks like:: - - # First, set up the variables for the (backward-compatible) TriBITS way of - # finding . These are used in case find_package( ...) is - # not called or does not find . Also, these variables need to be - # non-null in order to trigger the right behavior in the function - # tribits_tpl_find_include_dirs_and_libraries(). set(REQUIRED_HEADERS ...) set(REQUIRED_LIBS_NAMES ...) - - # Second, search for components (if allowed) using the standard - # find_package( ...). + + message("-- Using find_package( ...) ...") + find_package() + if (_FOUND) + # Tell TriBITS that we found and there no need to look any further + set(TPL__INCLUDE_DIRS ${_INCLUDE_DIRS} CACHE PATH "...") + set(TPL__LIBRARIES ${_LIBRARIES} CACHE FILEPATH "...") + set(TPL__LIBRARY_DIRS ${_LIBRARY_DIRS} CACHE PATH "...") + endif() + + tribits_tpl_find_include_dirs_and_libraries( + REQUIRED_HEADERS ${REQUIRED_HEADERS} + REQUIRED_LIBS_NAMES ${REQUIRED_LIBS_NAMES} ) + +Above, if ``find_package()`` can't find ````, then +the function ``tribits_tpl_find_include_dirs_and_libraries()`` will try to +find the listed required header files and libraries, using the legacy TriBITS +TPL find system. And if ``find_package()`` can find +````, then all the call to +`tribits_tpl_find_include_dirs_and_libraries()`_ will not look for anything +and will just take the information in the variables +``TPL__INCLUDE_DIRS`` and ``TPL__LIBRARIES`` and build +IMPORTED targets and the ``::all_libs`` target. + +Finally, if one is upgrading an existing ``FindTPL.cmake`` file to +use ``find_package()`` but needs to maintain backward +compatibility for existing configure scripts for the project that might be +using the legacy TriBITS TPL system, one can use the function +`tribits_tpl_allow_pre_find_package()`_ to determine if +``find_package()`` can be called or if the legacy TriBITS TPL +find must be used (to maintain backward compatibility). This +``FindTPL.cmake`` looks like:: + + set(REQUIRED_HEADERS ...) + set(REQUIRED_LIBS_NAMES ...) + tribits_tpl_allow_pre_find_package( _ALLOW_PREFIND) + if (_ALLOW_PREFIND) - message("-- Using find_package( ...) ...") - find_package() - if (_FOUND) - # Tell TriBITS that we found and there no need to look any further! - set(TPL__INCLUDE_DIRS ${_INCLUDE_DIRS} CACHE PATH "...") - set(TPL__LIBRARIES ${_LIBRARIES} CACHE FILEPATH "...") - set(TPL__LIBRARY_DIRS ${_LIBRARY_DIRS} CACHE PATH "...") + message("-- Using find_package ...) ...") + find_package() + if (_FOUND) + # Tell TriBITS that we found and there no need to look any further + set(TPL__INCLUDE_DIRS ${_INCLUDE_DIRS} CACHE PATH "...") + set(TPL__LIBRARIES ${_LIBRARIES} CACHE FILEPATH "...") + set(TPL__LIBRARY_DIRS ${_LIBRARY_DIRS} CACHE PATH "...") endif() endif() - - # Third, call tribits_tpl_find_include_dirs_and_libraries() + tribits_tpl_find_include_dirs_and_libraries( REQUIRED_HEADERS ${REQUIRED_HEADERS} - REQUIRED_LIBS_NAMES ${REQUIRED_LIBS_NAMES} - ) - # NOTE: If find_package( ...) was called and successfully found - # , then tribits_tpl_find_include_dirs_and_libraries() will use the - # already-set variables and just print them out. This is the final "hook" - # into the TriBITS TPL system. - -With this approach, the ``FindTPL.cmake`` module preserves all of the -user behavior described in `Enabling support for an optional Third-Party -Library (TPL)`_ for overriding what TPL components to look for, where to look -and finally to override what is actually used. That is, if the user sets the -cache variables ``TPL__INCLUDE_DIRS``, ``TPL__LIBRARIES``, -or ``TPL__LIBRARY_DIRS``, then they should be used without question -(which is why the ``set( ... CACHE ...)`` calls in the above example do not -use ``FORCE``). + REQUIRED_LIBS_NAMES ${REQUIRED_LIBS_NAMES} ) + +The above will result in skipping the call of ``find_package()`` +if any of the legacy TPL find variables are set. But if the legacy TPL find +variables are not set, then the default find will use +``find_package()`` and will only fall back on the legacy TriBITS +TPL find operation if ``find_package()`` sets +``_FOUND=FALSE``. + +With this last approach, the ``FindTPL.cmake`` module preserves all +of the user behavior described in `Enabling support for an optional +Third-Party Library (TPL)`_ for overriding what TPL components to look for, +where to look, and finally to override what is actually used. That is, if the +user sets the cache variables ``TPL__INCLUDE_DIRS``, +``TPL__LIBRARIES``, or ``TPL__LIBRARY_DIRS``, then they +should be used without question (which is why the ``set( ... CACHE ...)`` +calls in the above example do not use ``FORCE``). If one wants to skip and ignore the standard TriBITS TPL override variables ``_INCLUDE_DIRS``, ``_LIBRARY_NAMES``, or ``_LIBRARY_DIRS``, then one can set:: - set(_FORCE_PRE_FIND_PACKAGE TRUE CACHE BOOL + set(_FORCE_PRE_FIND_PACKAGE TRUE CACHE BOOL "Always first call find_package( ...) unless explicit override") at the top of the file ``FindTPL.cmake`` and ``tribits_tpl_allow_pre_find_package()`` will ignore these variables and return ``TRUE``. This avoids name classes with the variables -``_INCLUDE_DIRS`` and ``_LIBRARY_DIRS`` which are often used -in the concrete CMake ``Find.cmake`` module files themselves. +``_INCLUDE_DIRS`` and ``_LIBRARY_DIRS`` with +``_INCLUDE_DIRS`` and ``_LIBRARY_DIRS`` (when `` == +``) which are often used in the concrete legacy CMake +``Find.cmake`` module files themselves. For a slightly more complex (but real-life) example, see ``FindTPLHDF5.cmake`` which is: @@ -5583,75 +5781,50 @@ which is: .. include:: ../../common_tpls/FindTPLHDF5.cmake :literal: -Note that some specialized ``Find.cmake`` modules do more than just -return a list of include directories and libraries. Some, like +Note that some specialized ``Find.cmake`` modules do more than +just return a list of include directories and libraries. Some, like ``FindQt4.cmake`` also return other variables that are used in downstream packages. therefore, in these cases, ``find_package(Qt4 ...)`` must be called -on every configure. In specialized cases such as this, one must write a more -specialized ``FindTPL.cmake`` file and can't use the -`tribits_tpl_allow_pre_find_package()`_ function like shown above. Such -find modules cannot completely adhere to the standard behavior described in -`Enabling support for an optional Third-Party Library (TPL)`_. +on every configure. Such find modules cannot completely adhere to the +standard legacy TriBITS behavior described in `Enabling support for an +optional Third-Party Library (TPL)`_. -One issue to be made aware of is that code in ``FindTPL.cmake`` must -generate the file:: - /external_packages//Config.cmake +Creating a FindTPL*.cmake module without find_package() ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -where ``Config.cmake`` defines the ``::all_libs`` target. -The function `tribits_tpl_find_include_dirs_and_libraries()`_ creates these -files automatically when working with the lists ``TPL__INCLUDE_DIRS`` -and ``TPL__LIBRARIES`` as shown in the examples above. But in cases -where the inner ``find_package( ...)`` call actually generates a set -of modern CMake IMPORTED targets, the code in ``Find.cmake`` will -need to skip calling ``tribits_tpl_find_include_dirs_and_libraries()`` and -will instead need to build the target ``::all_libs`` itself and will -need to build the and write the wrapper file ``Config.cmake`` -manually into ``/external_packages//`` that does the right -thing when they are included by downstream ``Config.cmake`` files. - -An example of a custom ``FindTPL.cmake`` file that calls -``find_package( ...)`` which produces modern CMake targets that -manually creates the ``::all_libs`` target is given in -``TribitsExampleProject2/cmake/tpls/FindTPLTpl1.cmake`` which is: - -.. include:: ../../examples/TribitsExampleProject2/cmake/tpls/FindTPLTpl1.cmake - :literal: +For external packages that don't have a ``Find.cmake`` module or +``Config.cmake`` package config file, it may make sense to create +a simple ``FindTpl.cmake`` module that just calls +`tribits_tpl_find_include_dirs_and_libraries()`_ with the set of required +header files and libraries that must be found. A simple +``FindTPL.cmake`` module of this form is:: -Another issue that comes up with external packages/TPLs like HDF5 that needs -to be discussed here is the fact that TriBITS generates and installs files of -the name ``HDF5Config.cmake`` that can be found by calls to -``find_package(HDF5)``. These TriBITS-generated ``HDF5Config.cmake`` files -are primarily meant to be included by and provide targets for downstream -TriBITS package ``Config.cmake`` files. These TriBITS-generated -``HDF5Config.cmake`` files may not behave the same way that a more general -``FindHDF5.config`` modules or ``HDF5Config.camke`` configure files would -behave as expected when found by ``find_package(HDF5)`` commands called in -some arbitrary downstream raw CMake project. - -Therefore, to avoid having an installed TriBITS-generated ``HDF5Config.cmake`` -file, for example, being found by the inner call to ``find_package(HDF5 ...)`` -in the file ``FindTPLHDF5.cmake`` (which would be disastrous), TriBITS employs -two safeguards. First, TriBITS-generated ``Config.cmake`` files are -placed into the build directory ``/external_packages/`` and -installed into the directory ``/lib/external_packages/`` so they -will not be found by default when ``/cmake_packages`` and/or -````, respectively, are added to ``CMake_PREFIX_PATH``. Also, -even if ``/lib/external_packages`` or -``/external_packages`` do get added to the search path somehow -(e.g. through ``CMAKE_INSTALL_PREFIX``), the TriBITS framework will set the -variable ``TRIBITS_FINDING_RAW__PACKAGE_FIRST=TRUE`` before including -``FindTPL.cmake`` and there is special logic in the TriBITS-generated -``ConfigVersion.cmake`` file that will set -``PACKAGE_VERSION_COMPATIBLE=OFF`` and result in ``find_package()`` -not selecting ``Config.cmake``. (It turns out that CMake's -``find_package()`` command always includes the file -``ConfigVersion.cmake``, even if no version information is passed to -the command ``find_package()``. This allows special logic to be -placed in the file ``ConfigVersion.cmake`` to determine if -``find_package()`` will select a given ``Config.cmake`` file -that is in the search path based on a number of different criteria such as in -this case.) + tribits_tpl_find_include_dirs_and_libraries( + REQUIRED_HEADERS ... + REQUIRED_LIBS_NAMES ... + ) + + +Requirements for FindTPL*.cmake modules ++++++++++++++++++++++++++++++++++++++++ + +It is possible to create a ``FindTPL.cmake`` module without using any +TriBITS functions. The only firm requirements for a +``FindTPL.cmake`` file after it is included are: + +* The target ``::all_libs`` must be created and it must contain all + of the needed libraries, include directories, and other usage requirements + (including for all upstream external packages/TPLs). + +* The file ``/external_packages//Config.cmake`` + must be created in the build directory and when including the file + ``Config.cmake`` it must define the equivalent target + ``::all_libs`` (and must call ``find_dependency()`` correctly on + all upstream external packages/TPLs). + +Some of issues to consider in this case are described in the section `Tricky +considerations for TriBITS-generated Config.cmake files`_. How to add a new TriBITS Repository @@ -5744,7 +5917,7 @@ as follows: #if HAVE__ # include "_" - #endif + #endif 4) **For an optional dependency, use CMake if() statements based on ${PACKAGE_NAME}_ENABLE_${OPTIONAL_DEP_PACKAGE_NAME}:** When a package @@ -5761,7 +5934,7 @@ as follows: endif() .. ToDo: Find an example to point to in TribitsExampleProject. - + NOTE: TriBITS will automatically add the include directories for the upstream package to the compile lines for the downstream package source builds and will add the libraries for the upstream package to the link lines to the downstream @@ -5824,7 +5997,7 @@ follows: #if HAVE__ # include "_" - #endif + #endif 4) **For an optional dependency, use CMake if() statements based on ${PACKAGE_NAME}_ENABLE_${OPTIONAL_DEP_TPL_NAME}:** When a package @@ -5841,7 +6014,7 @@ follows: endif() .. ToDo: Find an example to point to in TribitsExampleProject. - + NOTE: TriBITS will automatically add the include directories for the upstream TPL to the compile lines for the downstream package source builds and will add the libraries for the upstream TPL to the link lines to the downstream package @@ -6296,7 +6469,7 @@ The following steps describe how to submit results to a CDash site using the /TribitsExamplProject and then run ``make dashboard``. - + 4) Add custom CTest -S driver scripts. For driving different builds and tests, one needs to set up one or more @@ -6355,7 +6528,7 @@ The following steps describe how to submit results to a CDash site using the submit to CDash in a variety of ways: * Cron jobs can be set up to run them at the same time every day. - + * Jenkins jobs can be set up to run them based on various criteria. * Travis CI can run them to respond to GitHub pushes. @@ -6404,22 +6577,21 @@ given below. )`` in the CTest -S ``*.cmake`` driver script itself or can set it in the environment when running the ctest -S driver script. For example:: - + $ env _TRACK= ... \ ctest -V -S .cmake - + If the "build type" for the CDash group ```` was set to "Daily", then set `CTEST_TEST_TYPE`_ to ``Nightly``. Otherwise, ``CTEST_TEST_TYPE`` can be set to ``Continuous`` or ``Experimental``. -Additional Topics -================= +Miscellaneous Topics +==================== In this section, a number of miscellaneous topics and TriBITS features are discussed. These features and topics are either not considered primary -features of TriBITS (but can be very useful in many situations) or don't neatly -fit into one of the other sections. +features of TriBITS or don't neatly fit into one of the other sections. TriBITS Repository Contents @@ -6624,6 +6796,53 @@ ready to compile code. All of the major variables set as part of this process are printed to the ``cmake`` stdout when the project is configured. +Tricky considerations for TriBITS-generated Config.cmake files +----------------------------------------------------------------------- + +An issue that comes up with external packages/TPLs like HDF5 that needs to be +discussed here is the fact that ``FindTPL.cmake`` files create (See +`How to add a new TriBITS TPL`_) and TriBITS installs files of the name +``Config.cmake`` and that could potentially be found by calls to +``find_package()`` (when `` == `` like with +HDF5). These TriBITS-generated ``Config.cmake`` files are primarily +meant to be included by and provide the ``::all_libs`` targets for +downstream TriBITS-compatible ``Config.cmake`` files. These +TriBITS-generated ``Config.cmake`` files will usually not behave the +same way that a more general ``Find.config`` modules or native +``Config.cmake`` configure files would behave as expected when found +by ``find_package()`` commands called in some arbitrary downstream +raw CMake project. Therefore, to avoid having an installed TriBITS-generated +``HDF5Config.cmake`` file, for example, being found by the inner call to +``find_package(HDF5 ...)`` in the file ``FindTPLHDF5.cmake`` (which would be +disastrous), TriBITS employs two safeguards. First, TriBITS-generated +``Config.cmake`` files are placed into the build directory under:: + + /external_packages//Config.cmake + +and installed into the directory under:: + + /lib/external_packages//Config.cmake + +so they will not be found by ``find_package()`` by default when +``/cmake_packages`` and/or ````, respectively, are added +to ``CMake_PREFIX_PATH``. Also, even if +``/lib/external_packages`` or ``/external_packages`` do +get added to the search path somehow (e.g. by appending those to +``CMAKE_INSTALL_PREFIX``), the TriBITS framework will set the variable +``TRIBITS_FINDING_RAW__PACKAGE_FIRST=TRUE`` before including +``FindTPL.cmake`` and there is special logic in the TriBITS-generated +``ConfigVersion.cmake`` file that will set +``PACKAGE_VERSION_COMPATIBLE=OFF`` and result in ``find_package()`` +not selecting the TriBITS-generated ``Config.cmake`` file. (It turns +out that CMake's ``find_package()`` command always includes the file +``ConfigVersion.cmake``, even if no version information is passed to +the command ``find_package()``. This allows special logic to be +placed in the file ``ConfigVersion.cmake`` to determine if +``find_package()`` will select a given ``Config.cmake`` file +that is in the search path based on a number of different criteria such as in +this case.) + + Installation considerations --------------------------- @@ -6891,12 +7110,12 @@ rebase by default) as shown in the following Trilinos commit:: commit 71ce56bd2d268922fda7b8eca74fad0ffbd7d807 Author: Roscoe A. Bartlett Date: Thu Feb 19 12:04:11 2015 -0500 - + Define HAVE_TEUCHOSCORE_CXX11 in TeuchosCore_config.h - + This makes TeuchosCore a good example for how Trilinos (or any TriBITS) subpackages should put in an optional dependency on C++11. - + Build/Test Cases Summary Enabled Packages: TeuchosCore Disabled Packages: [...] @@ -7045,16 +7264,16 @@ the commands:: $ cat ../git_bisect_log.log | grep "possible first bad commit" | \ sed "s/possible first bad commit://g" | sed "s/[a-z0-9]\{30\}\]/]/g" $ git bisect reset - + This set of commands yield the output:: Bisecting: 1128 revisions left to test after this (roughly 10 steps) [9634d462dba77704b598e89ba69ba3ffa5a71471] Revert "Trilinos: remove _def.hpp [...]" - + real 1m22.961s user 0m57.157s sys 3m40.376s - + # [165067ce53] MueLu: SemiCoarsenPFactory. Use strided maps to properly transfer [...] # [ada21a95a9] MueLu: refurbish LineDetectionFactory # [83f05e8970] MueLu: stop semi-coarsening if no z-layers are left. @@ -7068,7 +7287,7 @@ bounded in the set of commits ``8b79832..165067c``:: 165067c "MueLu: SemiCoarsenPFactory. Use strided maps to properly [...]." Author: Tobias Wiesner Date: Thu Jul 2 12:11:24 2015 -0600 - + 8b79832 "Ifpack2: RBILUK: adding additional ETI types" Author: Jonathan Hu Date: Thu Jul 2 14:17:40 2015 -0700 @@ -7095,7 +7314,7 @@ intermediate commits are in Trilinos. All that matters is the usage of the ``checkin-test.py`` tool (another motivation for the usage of the ``checkin-test.py`` tool, see `Pre-push Testing using checkin-test.py`_ for others as well). - + Note that above, we grep the output from ``git bisect log`` for the set of possible "bad" commits instead of just looking at the output from the ``git bisect run