diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index b4ccb1e59..16506d4fc 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -121,7 +121,7 @@ tribits_add_advanced_test( TribitsAdjustPackageEnables_UnitTests ) -tribits_add_advanced_test( TribitsWriteClientExportFiles_UnitTests +tribits_add_advanced_test( TribitsInternalPackageWriteConfigFile_UnitTests OVERALL_WORKING_DIRECTORY TEST_NAME TEST_0 CMND ${CMAKE_COMMAND} ARGS @@ -129,7 +129,7 @@ tribits_add_advanced_test( TribitsWriteClientExportFiles_UnitTests -D${PROJECT_NAME}_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} -DCURRENT_TEST_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR} -DCMAKE_CURRENT_LIST_DIR=${CMAKE_CURRENT_SOURCE_DIR} - -P "${CMAKE_CURRENT_SOURCE_DIR}/TribitsWriteClientExportFiles_UnitTests.cmake" + -P "${CMAKE_CURRENT_SOURCE_DIR}/TribitsInternalPackageWriteConfigFile_UnitTests.cmake" PASS_REGULAR_EXPRESSION_ALL "Final UnitTests Result: num_run = 12" "Final UnitTests Result: PASSED" diff --git a/test/core/DependencyUnitTests/CMakeLists.txt b/test/core/DependencyUnitTests/CMakeLists.txt index df4e5ce95..74384b65c 100644 --- a/test/core/DependencyUnitTests/CMakeLists.txt +++ b/test/core/DependencyUnitTests/CMakeLists.txt @@ -631,6 +631,169 @@ create_reduced_dependency_handling_test_case( # HDF5 (and that is a valid configuration when Netcdf is built without HDF5). +# +# Test treating internal packages as TPLs with ReducedMockTrilinos +# + + +create_reduced_dependency_handling_test_case( + ST_TplEnableRTOpOn_EnableAllPackages_EnableTests + ARGS + -DTPL_ENABLE_RTOp=ON + -DTrilinos_ENABLE_ALL_PACKAGES=ON + -DTrilinos_ENABLE_SECONDARY_TESTED_CODE=ON + -DTrilinos_ENABLE_TESTS=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + + "Initial package build status:" + "-- Initial: MPI_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: Boost_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: UMFPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: AMD_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: PETSC_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Initial: Teuchos_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: RTOp_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: Epetra_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: Triutils_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: EpetraExt_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: ThyraCoreLibs_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: ThyraGoodStuff_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: ThyraCrazyStuff_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: ThyraEpetra_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: ThyraEpetraExt_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Initial: Thyra_PACKAGE_BUILD_STATUS=INTERNAL" + + "Adjust the set of internal and external packages:" + "-- Treating internal package RTOp as EXTERNAL because TPL_ENABLE_RTOp=ON" + "-- Treating internal package Teuchos as EXTERNAL because downstream package RTOp being treated as EXTERNAL" + "-- NOTE: LAPACK is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: BLAS is indirectly downstream from a TriBITS-compliant external package" + + "Final package build status [(]enabled only[)]:" + "-- Final: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Teuchos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RTOp_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Epetra_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Triutils_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: EpetraExt_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraCoreLibs_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraGoodStuff_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraEpetra_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraEpetraExt_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Thyra_PACKAGE_BUILD_STATUS=INTERNAL" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs" + "Processing enabled external package/TPL: BLAS [(]enabled by Epetra, disable with -DTPL_ENABLE_BLAS=OFF[)]" + "Processing enabled external package/TPL: LAPACK [(]enabled by Epetra, disable with -DTPL_ENABLE_LAPACK=OFF[)]" + "Processing enabled external package/TPL: Teuchos [(]enabled explicitly, disable with -DTPL_ENABLE_Teuchos=OFF[)]" + "Processing enabled external package/TPL: RTOp [(]enabled explicitly, disable with -DTPL_ENABLE_RTOp=OFF[)]" + + "Getting information for all remaining enabled external packages/TPLs" + + "Configuring individual enabled Trilinos packages ..." + "Processing enabled top-level package: Epetra [(]Libs, Tests, Examples[)]" + "Processing enabled top-level package: Triutils [(]Libs, Tests, Examples[)]" + "Processing enabled top-level package: EpetraExt [(]Libs, Tests, Examples[)]" + "Processing enabled top-level package: Thyra [(]CoreLibs, GoodStuff, Epetra, EpetraExt, Tests, Examples[)]" + + ) + + +create_reduced_dependency_handling_test_case( + ST_TplEnableThyraCoreLibsOn_EnableAllPackages_EnableTests + ARGS + -DTPL_ENABLE_ThyraCoreLibs=ON + -DTrilinos_ENABLE_ALL_PACKAGES=ON + -DTrilinos_ENABLE_SECONDARY_TESTED_CODE=ON + -DTrilinos_ENABLE_TESTS=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package Thyra as EXTERNAL because subpackage ThyraCoreLibs being treated as EXTERNAL [(]TPL_ENABLE_ThyraCoreLibs=ON[)]" + "-- Treating internal package ThyraCoreLibs as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraGoodStuff as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetraExt as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package EpetraExt as EXTERNAL because downstream package ThyraEpetraExt being treated as EXTERNAL" + "-- Treating internal package Epetra as EXTERNAL because downstream package ThyraEpetra being treated as EXTERNAL" + "-- Treating internal package Teuchos as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package RTOp as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package Triutils as EXTERNAL because downstream package EpetraExt being treated as EXTERNAL" + "-- NOTE: LAPACK is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: BLAS is indirectly downstream from a TriBITS-compliant external package" + + "Final package build status [(]enabled only[)]:" + "-- Final: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Teuchos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RTOp_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Epetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Triutils_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: EpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraCoreLibs_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraGoodStuff_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Thyra_PACKAGE_BUILD_STATUS=EXTERNAL" + + "Final set of enabled top-level packages: 0" + "Final set of enabled packages: 0" + "Final set of non-enabled top-level packages: 0" + "Final set of non-enabled packages: 0" + "Final set of enabled top-level external packages/TPLs: BLAS LAPACK Teuchos RTOp Epetra Triutils EpetraExt Thyra 8" + "Final set of enabled external packages/TPLs: BLAS LAPACK Teuchos RTOp Epetra Triutils EpetraExt ThyraCoreLibs ThyraGoodStuff ThyraEpetra ThyraEpetraExt Thyra 12" + "Final set of non-enabled top-level external packages/TPLs: MPI Boost UMFPACK AMD PETSC 5" + "Final set of non-enabled external packages/TPLs: MPI Boost UMFPACK AMD PETSC ThyraCrazyStuff 6" + + ) + + +create_reduced_dependency_handling_test_case( + TplEnableThyraCoreLibsOn + ARGS + -DTPL_ENABLE_ThyraCoreLibs=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + "Enabling all required [(]and optional since Trilinos_ENABLE_ALL_OPTIONAL_PACKAGES=ON[)] upstream packages for current set of enabled packages [(]Trilinos_ENABLE_SECONDARY_TESTED_CODE=OFF[)] ..." + "-- Setting Trilinos_ENABLE_Teuchos=ON because ThyraCoreLibs has a required dependence on Teuchos" + "-- Setting Trilinos_ENABLE_RTOp=ON because ThyraCoreLibs has a required dependence on RTOp" + "-- Setting TPL_ENABLE_BLAS=ON because Teuchos has a required dependence on BLAS" + "-- Setting TPL_ENABLE_LAPACK=ON because Teuchos has a required dependence on LAPACK" + + "Enabling the shell of non-enabled parent packages [(]mostly for show[)] that have at least one subpackage enabled ..." + "-- Setting Trilinos_ENABLE_Thyra=ON because TPL_ENABLE_ThyraCoreLibs=ON" + + "Adjust the set of internal and external packages:" + "-- Treating internal package Thyra as EXTERNAL because subpackage ThyraCoreLibs being treated as EXTERNAL [(]TPL_ENABLE_ThyraCoreLibs=ON[)]" + "-- Treating internal package ThyraCoreLibs as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package Teuchos as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package RTOp as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + + "Final package build status [(]enabled only[)]:" + "-- Final: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Teuchos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RTOp_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraCoreLibs_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Thyra_PACKAGE_BUILD_STATUS=EXTERNAL" + + "Final set of enabled top-level packages: 0" + "Final set of enabled packages: 0" + "Final set of non-enabled top-level packages: Epetra Triutils EpetraExt 3" + "Final set of non-enabled packages: Epetra Triutils EpetraExt 3" + "Final set of enabled external packages/TPLs: BLAS LAPACK Teuchos RTOp ThyraCoreLibs Thyra 6" + "Final set of non-enabled external packages/TPLs: MPI Boost UMFPACK AMD PETSC ThyraGoodStuff ThyraCrazyStuff ThyraEpetra ThyraEpetraExt 9" + + ) + + +# ??? + + ##################################################################### # # Unit tests for dependency handling for full set of packages @@ -658,7 +821,6 @@ function(create_dependency_handling_test_case TEST_NAME) TEST_0 CMND "${CMAKE_COMMAND}" ARGS -D${MOCK_PROJECT_NAME}_TRIBITS_DIR:FILEPATH=${${PROJECT_NAME}_TRIBITS_DIR} - -D${MOCK_PROJECT_NAME}_SHORTCIRCUIT_AFTER_DEPENDENCY_HANDLING:BOOL=ON -D${MOCK_PROJECT_NAME}_DEPS_XML_OUTPUT_FILE:STRING= -D${MOCK_PROJECT_NAME}_DEPS_HTML_OUTPUT_FILE:STRING= -D${MOCK_PROJECT_NAME}_ENABLE_C:BOOL=OFF @@ -1626,3 +1788,240 @@ create_dependency_handling_test_case( "Final set of enabled top-level packages: Teuchos RTOp Epetra Zoltan Triutils Tpetra EpetraExt Thyra Isorropia AztecOO Galeri Amesos Ifpack ML Stratimikos Teko ExtraPack 17" "Final set of non-enabled top-level packages: TrilinosFramework Shards Stokhos Sacado Intrepid Belos RBGen Phalanx Panzer Stalix 10" ) + + +# +# Test treating internal packages as TPLs with MockTrilinos +# + + +create_dependency_handling_test_case( + ST_TplEnableThyraCoreLibsOn_EnableAllPackages_EnableTests + ARGS + -DTPL_ENABLE_ThyraCoreLibs=ON + -DTrilinos_ENABLE_ALL_PACKAGES=ON + -DTrilinos_ENABLE_SECONDARY_TESTED_CODE=ON + -DTrilinos_ENABLE_TESTS=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package Thyra as EXTERNAL because subpackage ThyraCoreLibs being treated as EXTERNAL [(]TPL_ENABLE_ThyraCoreLibs=ON[)]" + "-- Treating internal package ThyraCoreLibs as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraGoodStuff as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetraExt as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraTpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package Tpetra as EXTERNAL because downstream package ThyraTpetra being treated as EXTERNAL" + "-- Treating internal package EpetraExt as EXTERNAL because downstream package ThyraEpetraExt being treated as EXTERNAL" + "-- Treating internal package Epetra as EXTERNAL because downstream package ThyraEpetra being treated as EXTERNAL" + "-- Treating internal package Teuchos as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package RTOp as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package Triutils as EXTERNAL because downstream package EpetraExt being treated as EXTERNAL" + "-- Treating internal package Zoltan as EXTERNAL because downstream package EpetraExt being treated as EXTERNAL" + "-- NOTE: Boost is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: LAPACK is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: BLAS is indirectly downstream from a TriBITS-compliant external package" + + "Final package build status [(]enabled only[)]:" + "-- Final: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Boost_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: DUMMY_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: TrilinosFramework_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Teuchos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RTOp_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Epetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Zoltan_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Shards_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Triutils_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Tpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: EpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Sacado_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraCoreLibs_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraGoodStuff_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraTpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Thyra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Isorropia_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: AztecOO_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Galeri_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Amesos_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Intrepid_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Ifpack_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ML_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Belos_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Stratimikos_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: RBGen_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Phalanx_PACKAGE_BUILD_STATUS=INTERNAL" + + "Final set of enabled top-level packages: TrilinosFramework Shards Sacado Isorropia AztecOO Galeri Amesos Intrepid Ifpack ML Belos Stratimikos RBGen Phalanx 14" + "Final set of enabled packages: TrilinosFramework Shards Sacado Isorropia AztecOO Galeri Amesos Intrepid Ifpack ML Belos Stratimikos RBGen Phalanx 14" + "Final set of non-enabled top-level packages: Stokhos Panzer 2" + "Final set of non-enabled packages: Stokhos Panzer 2" + "Final set of enabled external packages/TPLs: BLAS LAPACK Boost DUMMY Teuchos RTOp Epetra Zoltan Triutils Tpetra EpetraExt ThyraCoreLibs ThyraGoodStuff ThyraEpetra ThyraEpetraExt ThyraTpetra Thyra 17" + "Final set of non-enabled external packages/TPLs: MPI Scotch METIS ParMETIS CppUnit ADOLC ADIC TVMET y12m SuperLUDist SuperLU UMFPACK AMD PETSC MUMPS ThyraCrazyStuff 16" + + ) + + +create_dependency_handling_test_case( + ST_EnableMPI_TplEnableStratimikosOn_EnablePanzerOn_EnableMLOff_EnableTests + ARGS + -DTrilinos_ENABLE_SECONDARY_TESTED_CODE=ON + -DTPL_ENABLE_MPI=ON + -DTPL_ENABLE_Stratimikos=ON + -DTrilinos_ENABLE_Panzer=ON + -DTrilinos_ENABLE_ML=OFF + -DTrilinos_ENABLE_TESTS=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + "Explicitly enabled top-level packages on input [(]by user[)]: Stratimikos Panzer 2" + "Explicitly disabled top-level packages on input [(]by user or by default[)]: Stokhos ML 2" + + "Adjust the set of internal and external packages:" + "-- Treating internal package Stratimikos as EXTERNAL because TPL_ENABLE_Stratimikos=ON" + "-- Treating internal package ThyraEpetraExt as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package ThyraCoreLibs as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Amesos as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package AztecOO as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Belos as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Ifpack as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Teuchos as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package Epetra as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package Tpetra as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package EpetraExt as EXTERNAL because downstream package Amesos being treated as EXTERNAL" + "-- Treating internal package Triutils as EXTERNAL because downstream package AztecOO being treated as EXTERNAL" + "-- Treating internal package Thyra as EXTERNAL because subpackage ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package ThyraGoodStuff as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraTpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package RTOp as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package Zoltan as EXTERNAL because downstream package EpetraExt being treated as EXTERNAL" + "-- NOTE: Boost is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: LAPACK is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: BLAS is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: MPI is indirectly downstream from a TriBITS-compliant external package" + + "Final set of enabled packages: Shards Sacado Galeri Intrepid Phalanx Panzer 6" + "Final set of non-enabled top-level packages: TrilinosFramework Stokhos Isorropia RBGen 4" + "Final set of non-enabled packages: TrilinosFramework Stokhos Isorropia RBGen 4" + "Final set of enabled top-level external packages/TPLs: MPI BLAS LAPACK Boost Teuchos RTOp Epetra Zoltan Triutils Tpetra EpetraExt Thyra AztecOO Amesos Ifpack Belos Stratimikos 17" + "Final set of enabled external packages/TPLs: MPI BLAS LAPACK Boost Teuchos RTOp Epetra Zoltan Triutils Tpetra EpetraExt ThyraCoreLibs ThyraGoodStuff ThyraEpetra ThyraEpetraExt ThyraTpetra Thyra AztecOO Amesos Ifpack Belos Stratimikos 22" + "Final set of non-enabled top-level external packages/TPLs: Scotch METIS ParMETIS CppUnit ADOLC ADIC TVMET y12m SuperLUDist SuperLU UMFPACK AMD PETSC MUMPS DUMMY ML 16" + "Final set of non-enabled external packages/TPLs: Scotch METIS ParMETIS CppUnit ADOLC ADIC TVMET y12m SuperLUDist SuperLU UMFPACK AMD PETSC MUMPS DUMMY ThyraCrazyStuff ML 17" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs" + "Processing enabled external package/TPL: MPI [(]enabled explicitly, disable with -DTPL_ENABLE_MPI=OFF[)]" + "Processing enabled external package/TPL: BLAS [(]enabled by Epetra, disable with -DTPL_ENABLE_BLAS=OFF[)]" + "Processing enabled external package/TPL: LAPACK [(]enabled by Epetra, disable with -DTPL_ENABLE_LAPACK=OFF[)]" + "Processing enabled external package/TPL: Boost [(]enabled by Panzer, disable with -DTPL_ENABLE_Boost=OFF[)]" + "Processing enabled external package/TPL: Teuchos [(]enabled by Panzer, disable with -DTPL_ENABLE_Teuchos=OFF[)]" + "Processing enabled external package/TPL: RTOp [(]enabled by ThyraCoreLibs, disable with -DTPL_ENABLE_RTOp=OFF[)]" + "Processing enabled external package/TPL: Epetra [(]enabled by Panzer, disable with -DTPL_ENABLE_Epetra=OFF[)]" + "Processing enabled external package/TPL: Zoltan [(]enabled by EpetraExt, disable with -DTPL_ENABLE_Zoltan=OFF[)]" + "Processing enabled external package/TPL: Triutils [(]enabled by Stratimikos, disable with -DTPL_ENABLE_Triutils=OFF[)]" + "Processing enabled external package/TPL: Tpetra [(]enabled by Panzer, disable with -DTPL_ENABLE_Tpetra=OFF[)]" + "Processing enabled external package/TPL: EpetraExt [(]enabled by Panzer, disable with -DTPL_ENABLE_EpetraExt=OFF[)]" + "Processing enabled external package/TPL: Thyra [(]enabled by Panzer, disable with -DTPL_ENABLE_Thyra=OFF[)]" + "Processing enabled external package/TPL: AztecOO [(]enabled by Stratimikos, disable with -DTPL_ENABLE_AztecOO=OFF[)]" + "Processing enabled external package/TPL: Amesos [(]enabled by Stratimikos, disable with -DTPL_ENABLE_Amesos=OFF[)]" + "Processing enabled external package/TPL: Ifpack [(]enabled by Phalanx, disable with -DTPL_ENABLE_Ifpack=OFF[)]" + "Processing enabled external package/TPL: Belos [(]enabled by Phalanx, disable with -DTPL_ENABLE_Belos=OFF[)]" + "Processing enabled external package/TPL: Stratimikos [(]enabled explicitly, disable with -DTPL_ENABLE_Stratimikos=OFF[)]" + + "Getting information for all remaining enabled external packages/TPLs" + + "Configuring individual enabled Trilinos packages ..." + "Processing enabled top-level package: Shards [(]Libs[)]" + "Processing enabled top-level package: Sacado [(]Libs[)]" + "Processing enabled top-level package: Galeri [(]Libs[)]" + "Processing enabled top-level package: Intrepid [(]Libs[)]" + "Processing enabled top-level package: Phalanx [(]Libs[)]" + "Processing enabled top-level package: Panzer [(]Libs, Tests, Examples[)]" + + ) +# NOTE: The above test checks that internal packages that are treated as +# external packages correctly express what enabled them. + + +create_dependency_handling_test_case( + ST_TplEnableStratimikosOn_EnableMLOff_EnableAllPackages_EnableTests + ARGS + -DTPL_ENABLE_Stratimikos=ON + -DTrilinos_ENABLE_ML=OFF + -DTrilinos_ENABLE_ALL_PACKAGES=ON + -DTrilinos_ENABLE_SECONDARY_TESTED_CODE=ON + -DTrilinos_ENABLE_TESTS=ON + -DTrilinos_DUMP_PACKAGE_BUILD_STATUS=ON + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package Stratimikos as EXTERNAL because TPL_ENABLE_Stratimikos=ON" + "-- Treating internal package ThyraEpetraExt as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package ThyraCoreLibs as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Amesos as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package AztecOO as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Belos as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Ifpack as EXTERNAL because downstream package Stratimikos being treated as EXTERNAL" + "-- Treating internal package Teuchos as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package Epetra as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package Tpetra as EXTERNAL because downstream package Belos being treated as EXTERNAL" + "-- Treating internal package EpetraExt as EXTERNAL because downstream package Amesos being treated as EXTERNAL" + "-- Treating internal package Triutils as EXTERNAL because downstream package AztecOO being treated as EXTERNAL" + "-- Treating internal package Thyra as EXTERNAL because subpackage ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package ThyraGoodStuff as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraEpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package ThyraTpetra as EXTERNAL because downstream package Thyra being treated as EXTERNAL" + "-- Treating internal package RTOp as EXTERNAL because downstream package ThyraCoreLibs being treated as EXTERNAL" + "-- Treating internal package Zoltan as EXTERNAL because downstream package EpetraExt being treated as EXTERNAL" + "-- NOTE: Boost is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: LAPACK is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: BLAS is indirectly downstream from a TriBITS-compliant external package" + + "Final package build status [(]enabled only[)]:" + "-- Final: BLAS_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: LAPACK_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Boost_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: DUMMY_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: TrilinosFramework_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Teuchos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RTOp_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Epetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Zoltan_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Shards_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Triutils_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Tpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: EpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Sacado_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: ThyraCoreLibs_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraGoodStuff_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraEpetraExt_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: ThyraTpetra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Thyra_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Isorropia_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: AztecOO_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Galeri_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Amesos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Intrepid_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Ifpack_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Belos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: Stratimikos_PACKAGE_BUILD_STATUS=EXTERNAL" + "-- Final: RBGen_PACKAGE_BUILD_STATUS=INTERNAL" + "-- Final: Phalanx_PACKAGE_BUILD_STATUS=INTERNAL" + + "Final set of enabled top-level packages: TrilinosFramework Shards Sacado Isorropia Galeri Intrepid RBGen Phalanx 8" + "Final set of enabled packages: TrilinosFramework Shards Sacado Isorropia Galeri Intrepid RBGen Phalanx 8" + "Final set of non-enabled top-level packages: Stokhos Panzer 2" + "Final set of non-enabled packages: Stokhos Panzer 2" + "Final set of enabled external packages/TPLs: BLAS LAPACK Boost DUMMY Teuchos RTOp Epetra Zoltan Triutils Tpetra EpetraExt ThyraCoreLibs ThyraGoodStuff ThyraEpetra ThyraEpetraExt ThyraTpetra Thyra AztecOO Amesos Ifpack Belos Stratimikos 22" + "Final set of non-enabled external packages/TPLs: MPI Scotch METIS ParMETIS CppUnit ADOLC ADIC TVMET y12m SuperLUDist SuperLU UMFPACK AMD PETSC MUMPS ThyraCrazyStuff ML 17" + + ) +# NOTE: The above test implicitly makes ThyraCoreLibs and ThyraEpetraExt +# EXTERNAL due to Stratimikos being EXTERNAL and makes sure that all of the +# Thyra subpackages get changed to EXTERNAL. This above test also disables ML +# to turn off the dependency between Stratimikos and Isorropia so that the +# Isorropia package stays INTERNAL. That is, we don't want to make more +# packages EXTERNAL that we need to based on the final set of enables and +# disables and the enabled optional dependencies between packages. diff --git a/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake b/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake index 4fdc0e159..d3e950fef 100644 --- a/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake +++ b/test/core/ExamplesUnitTests/TribitsExampleProject2_Tests.cmake @@ -771,3 +771,300 @@ if (${testNameBase}_NAME) set_tests_properties(${${testNameBase}_NAME} PROPERTIES DEPENDS ${TribitsExampleProject2_Tpls_install_STATIC_NAME} ) endif() + + +################################################################################ + + +function(TribitsExampleProject2_External_Package_by_Package + sharedOrStatic findingTplsMethod + ) + + TribitsExampleProject2_test_setup_header() + + set(tplInstallBaseDir + "${TribitsExampleProject2_Tpls_install_${sharedOrStatic}_DIR}") + + set(allTplsNoPrefindArgs + "-DTpl1_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl2_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl3_ALLOW_PACKAGE_PREFIND=OFF" + "-DTpl4_ALLOW_PACKAGE_PREFIND=OFF" + ) + + if (sharedOrStatic STREQUAL "STATIC") + set(libExt "a") + elseif (sharedOrStatic STREQUAL "SHARED") + set(libExt "so") + else() + message(FATAL_ERROR "Error: Invalid value of" + " sharedOrStatic='${sharedOrStatic}'!") + endif() + + if (findingTplsMethod STREQUAL "TPL_LIBRARY_AND_INCLUDE_DIRS") + set(tpl1LibAndIncDirsArgs + "-DTpl1_INCLUDE_DIRS=${tplInstallBaseDir}/install_tpl1/include" + "-DTpl1_LIBRARY_DIRS=${tplInstallBaseDir}/install_tpl1/lib" + "-DTpl1_ALLOW_PACKAGE_PREFIND=OFF") + set(tpl2LibAndIncDirsArgs + "-DTpl2_INCLUDE_DIRS=${tplInstallBaseDir}/install_tpl2/include" + "-DTpl2_LIBRARY_DIRS=${tplInstallBaseDir}/install_tpl2/lib" + "-DTpl2_ALLOW_PACKAGE_PREFIND=OFF") + set(tpl3LibAndIncDirsArgs + "-DTpl3_INCLUDE_DIRS=${tplInstallBaseDir}/install_tpl3/include" + "-DTpl3_LIBRARY_DIRS=${tplInstallBaseDir}/install_tpl3/lib" + "-DTpl3_ALLOW_PACKAGE_PREFIND=OFF") + set(tpl4LibAndIncDirsArgs + "-DTpl4_INCLUDE_DIRS=${tplInstallBaseDir}/install_tpl4/include" + "-DTpl4_ALLOW_PACKAGE_PREFIND=OFF") + set(tpl1CMakePrefixPath "") + set(tpl2CMakePrefixPath "") + set(tpl3CMakePrefixPath "") + set(tpl4CMakePrefixPath "") + set(tpl1FoundRegexes + "TPL_Tpl1_LIBRARIES='.*/install_tpl1/lib/libtpl1[.]${libExt}'" + "TPL_Tpl1_INCLUDE_DIRS='.*/install_tpl1/include'") + set(tpl2FoundRegexes + "TPL_Tpl2_LIBRARIES='.*/install_tpl2/lib/libtpl2b[.]${libExt}[;].*/install_tpl2/lib/libtpl2a[.]${libExt}'" + "TPL_Tpl2_INCLUDE_DIRS='.*/install_tpl2/include'") + set(tpl3FoundRegexes + "TPL_Tpl3_LIBRARIES='.*/install_tpl3/lib/libtpl3[.]${libExt}'" + "TPL_Tpl3_INCLUDE_DIRS='.*/install_tpl3/include'") + set(tpl4FoundRegexes + "-- TPL_Tpl4_INCLUDE_DIRS='.*/install_tpl4/include'") + elseif (findingTplsMethod STREQUAL "CMAKE_PREFIX_PATH_CACHE") + set(testNameSuffix "_CMAKE_PREFIX_PATH_CACHE") + set(tpl1LibAndIncDirsArgs "-DTpl1_ALLOW_PACKAGE_PREFIND=ON") + set(tpl2LibAndIncDirsArgs "-DTpl2_ALLOW_PACKAGE_PREFIND=ON") + set(tpl3LibAndIncDirsArgs "-DTpl3_ALLOW_PACKAGE_PREFIND=ON") + set(tpl4LibAndIncDirsArgs "-DTpl4_ALLOW_PACKAGE_PREFIND=ON") + set(tpl1CMakePrefixPath "${tplInstallBaseDir}/install_tpl1") + set(tpl2CMakePrefixPath "${tplInstallBaseDir}/install_tpl2") + set(tpl3CMakePrefixPath "${tplInstallBaseDir}/install_tpl3") + set(tpl4CMakePrefixPath "${tplInstallBaseDir}/install_tpl4") + set(tpl1FoundRegexes + "-- Using find_package[(]Tpl1 ...[)] ..." + "-- Found Tpl1_DIR='.*/install_tpl1/lib/cmake/Tpl1'" + "-- Generating Tpl1::all_libs and Tpl1Config.cmake") + set(tpl2FoundRegexes + "-- Using find_package[(]Tpl2 ...[)] ..." + "-- Found Tpl2_DIR='.*/install_tpl2/lib/cmake/Tpl2'" + "-- Generating Tpl2::all_libs and Tpl2Config.cmake") + set(tpl3FoundRegexes + "-- Using find_package[(]Tpl3 ...[)] ..." + "-- Found Tpl3_DIR='.*/install_tpl3/lib/cmake/Tpl3'" + "-- Generating Tpl3::all_libs and Tpl3Config.cmake") + set(tpl4FoundRegexes + "-- Using find_package[(]Tpl4 ...[)] ..." + "-- Found Tpl4_DIR='.*/install_tpl4/lib/cmake/Tpl4'" + "-- Generating Tpl4::all_libs and Tpl4Config.cmake") + else() + message(FATAL_ERROR + "Error, findingTplsMethod='${findingTplsMethod}' is invalid!") + endif() + + set(testNameBase ${CMAKE_CURRENT_FUNCTION}_${sharedOrStatic}${testNameSuffix}) + set(testName ${PACKAGE_NAME}_${testNameBase}) + set(testDir "${CMAKE_CURRENT_BINARY_DIR}/${testName}") + + tribits_add_advanced_test( ${testNameBase} + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + EXCLUDE_IF_NOT_TRUE ${PROJECT_NAME}_ENABLE_Fortran IS_REAL_LINUX_SYSTEM + LIST_SEPARATOR + + TEST_0 + MESSAGE "Link TribitsExampleProject2 so it is easy to access" + CMND ln + ARGS -s ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject2 . + + TEST_1 + MESSAGE "Configure to build and install just Package1" + WORKING_DIRECTORY Build_Package1 + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject2_COMMON_CONFIG_ARGS} + -DTribitsExProj2_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj2_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj2_ENABLE_Package1=ON + -DCMAKE_INSTALL_PREFIX=../install_package1 + -DTribitsExProj2_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_Tpl1=ON + ${tpl1LibAndIncDirsArgs} + -DCMAKE_PREFIX_PATH=${tpl1CMakePrefixPath} + ../TribitsExampleProject2 + PASS_REGULAR_EXPRESSION_ALL + "Final set of enabled top-level packages: Package1 1" + "Final set of non-enabled top-level packages: Package2 Package3 2" + "Final set of enabled top-level external packages/TPLs: Tpl1 1" + "Final set of non-enabled top-level external packages/TPLs: Tpl2 Tpl3 Tpl4 3" + + "Getting information for all enabled external packages/TPLs ..." + "Processing enabled external package/TPL: Tpl1 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl1=OFF[)]" + ${tpl1FoundRegexes} + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + # NOTE: Above Tpl1 is found and the wrapper file Tpl1Config.cmake is + # created and installed. This Tpl1Config.cmake file gets used in + # downstream CMake project configures. + + TEST_2 + MESSAGE "Build and install just Package1" + WORKING_DIRECTORY Build_Package1 + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_COMMAND} ARGS --build . --target install + + TEST_3 + MESSAGE "Configure to build and install just Package2" + WORKING_DIRECTORY Build_Package2 + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject2_COMMON_CONFIG_ARGS} + -DTribitsExProj2_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj2_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj2_ENABLE_Package2=ON + -DCMAKE_INSTALL_PREFIX=../install_package2 + -DTribitsExProj2_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_Package1=ON # Pull in already installed Package! + -DTPL_ENABLE_Tpl2=ON + ${tpl2LibAndIncDirsArgs} + -DTPL_ENABLE_Tpl3=ON + ${tpl3LibAndIncDirsArgs} + -DCMAKE_PREFIX_PATH=../install_package1${tpl2CMakePrefixPath}${tpl3CMakePrefixPath} + ../TribitsExampleProject2 + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package Package1 as EXTERNAL because TPL_ENABLE_Package1=ON" + "-- NOTE: Tpl1 is directly downstream from a TriBITS-compliant external package Package1" + + "Final set of enabled top-level packages: Package2 1" + "Final set of non-enabled top-level packages: Package3 1" + "Final set of enabled top-level external packages/TPLs: Tpl1 Tpl2 Tpl3 Package1 4" + "Final set of non-enabled top-level external packages/TPLs: Tpl4 1" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs ..." + "Processing enabled external package/TPL: Tpl1 [(]enabled by Package1, disable with -DTPL_ENABLE_Tpl1=OFF[)]" + "-- The external package/TPL Tpl1 will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: Package1 [(]enabled explicitly, disable with -DTPL_ENABLE_Package1=OFF[)]" + "-- Calling find_package[(]Package1[)] for TriBITS-compliant external package" + + "Getting information for all remaining enabled external packages/TPLs ..." + "Processing enabled external package/TPL: Tpl2 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl2=OFF[)]" + ${tpl2FoundRegexes} + "Processing enabled external package/TPL: Tpl3 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl3=OFF[)]" + ${tpl3FoundRegexes} + + "Configuring individual enabled TribitsExProj2 packages ..." + "Processing enabled top-level package: Package2 [(]Libs[)]" + + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + # NOTE: Above shows how a TriBITS TPL can depend on an upstream TriBITS + # TPL found by earlier TriBITS package build and install. In this case, + # Tpl1 is found and the Tpl1Config.cmake wrapper file is created as part + # of the upstream configure and build of Package1 and the definition of + # Tpl1 is pulled in when find_package(Package1) is called on the + # TriBITS-compliant external package Package1. Then Tpl2 and Tpl2 are + # found and Tpl2Config.cmake and Tpl3Config.cmake are created that point + # to pre-installed Tpl1Config.cmake. + + TEST_4 + MESSAGE "Build and install just Package2" + WORKING_DIRECTORY Build_Package2 + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_COMMAND} ARGS --build . --target install + + TEST_5 + MESSAGE "Configure to build, test, and install the rest of TribitsExampleProject2 (Package2)" + WORKING_DIRECTORY Build + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject2_COMMON_CONFIG_ARGS} + -DTribitsExProj2_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj2_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj2_ENABLE_ALL_PACKAGES=ON + -DTribitsExProj2_ENABLE_TESTS=ON + -DCMAKE_INSTALL_PREFIX=../install + -DTribitsExProj2_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_Package2=ON # Pull in already installed Package! + -DTPL_ENABLE_Tpl1=ON + -DTPL_ENABLE_Tpl2=ON + -DTPL_ENABLE_Tpl3=ON + -DTPL_ENABLE_Tpl4=ON + ${tpl4LibAndIncDirsArgs} + -DCMAKE_PREFIX_PATH=../install_package2${tpl4CMakePrefixPath} + ../TribitsExampleProject2 + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package Package2 as EXTERNAL because TPL_ENABLE_Package2=ON" + "-- Treating internal package Package1 as EXTERNAL because downstream package Package2 being treated as EXTERNAL" + "-- NOTE: Tpl3 is directly downstream from a TriBITS-compliant external package Package2" + "-- NOTE: Tpl2 is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: Tpl1 is indirectly downstream from a TriBITS-compliant external package" + + "Final set of enabled top-level packages: Package3 1" + "Final set of non-enabled top-level packages: 0" + "Final set of enabled top-level external packages/TPLs: Tpl1 Tpl2 Tpl3 Tpl4 Package1 Package2 6" + "Final set of non-enabled top-level external packages/TPLs: 0" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs ..." + "Processing enabled external package/TPL: Tpl1 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl1=OFF[)]" + "-- The external package/TPL Tpl1 will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: Tpl2 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl2=OFF[)]" + "-- The external package/TPL Tpl2 will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: Tpl3 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl3=OFF[)]" + "-- The external package/TPL Tpl3 will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: Package1 [(]enabled explicitly, disable with -DTPL_ENABLE_Package1=OFF[)]" + "-- The external package/TPL Package1 will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: Package2 [(]enabled explicitly, disable with -DTPL_ENABLE_Package2=OFF[)]" + "-- Calling find_package[(]Package2[)] for TriBITS-compliant external package" + + "Getting information for all remaining enabled external packages/TPLs ..." + + "Processing enabled external package/TPL: Tpl4 [(]enabled explicitly, disable with -DTPL_ENABLE_Tpl4=OFF[)]" + ${tpl4FoundRegexes} + + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + # NOTE: Above, only the newly enabled TPL Tpl4 is found and its + # Tpl4Config.cmake file is linked to the pre-installed + # Tpl1Config.comake, Tpl2Config.cmake and Tpl3Config.cmake files. And + # the needed info from Tpl1, Tpl2, and Tpl3 is pulled in from + # find_package(Package2). + + TEST_6 + MESSAGE "Build and install the rest of TribitsExampleProject2 (Package3)" + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_COMMAND} ARGS --build . --target install + + TEST_7 + MESSAGE "Run remaining tests for TribitsExampleProject2 (Package3)" + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_CTEST_COMMAND} + PASS_REGULAR_EXPRESSION_ALL + "Package3_Prg [.]+ *Passed" + "100% tests passed, 0 tests failed out of 1" + ALWAYS_FAIL_ON_NONZERO_RETURN + + ADDED_TEST_NAME_OUT ${testNameBase}_NAME + ) + + if (${testNameBase}_NAME) + set(${testNameBase}_NAME ${${testNameBase}_NAME} PARENT_SCOPE) + set(${testNameBase}_INSTALL_DIR "${testDir}/install" PARENT_SCOPE) + set_tests_properties(${${testNameBase}_NAME} + PROPERTIES DEPENDS ${TribitsExampleProject2_Tpls_install_${sharedOrStatic}_NAME} ) + endif() + +endfunction() + + +TribitsExampleProject2_External_Package_by_Package(STATIC TPL_LIBRARY_AND_INCLUDE_DIRS) +TribitsExampleProject2_External_Package_by_Package(SHARED TPL_LIBRARY_AND_INCLUDE_DIRS) +TribitsExampleProject2_External_Package_by_Package(STATIC CMAKE_PREFIX_PATH_CACHE) +TribitsExampleProject2_External_Package_by_Package(SHARED CMAKE_PREFIX_PATH_CACHE) + +# NOTE: The above tests check a few different use cases for building and +# installing TriBITS packages from a single TriBITS project incrementally. diff --git a/test/core/ExamplesUnitTests/TribitsExampleProject_Tests.cmake b/test/core/ExamplesUnitTests/TribitsExampleProject_Tests.cmake index 864bce7ca..7f0290286 100644 --- a/test/core/ExamplesUnitTests/TribitsExampleProject_Tests.cmake +++ b/test/core/ExamplesUnitTests/TribitsExampleProject_Tests.cmake @@ -2448,7 +2448,7 @@ tribits_add_advanced_test( TribitsExampleProject_ALL_NoFortran_WrapExternal_Verb "WithSubpackages_LIBRARIES='WithSubpackagesC::pws_c[;]WithSubpackagesB::pws_b[;]WithSubpackagesA::pws_a'" - "WrapExternal_LIBRARIES='external_func[;]pws_a'" + "WrapExternal_LIBRARIES='external_func[;]WithSubpackagesA::pws_a'" "pws_b_TARGET_NAME='pws_b'" "b_test_TARGET_NAME='WithSubpackagesB_b_test'" @@ -2569,7 +2569,7 @@ tribits_add_advanced_test( TribitsExampleProject_HeaderOnlyTpl_FailThenPass "When you reconfigure, just grep the cmake stdout for 'HeaderOnlyTpl'" "and then follow the disables that occur as a result to see what impact" "this TPL disable has on the configuration of TribitsExProj." - "CMake Error at .+/TribitsProcessEnabledTpl[.]cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" " ERROR: TPL_HeaderOnlyTpl_NOT_FOUND=TRUE, aborting!" "Call Stack .most recent call first.:" "-- Configuring incomplete, errors occurred!" @@ -2624,7 +2624,7 @@ tribits_add_advanced_test( TribitsExampleProject_HeaderOnlyTpl_HardEnable_Fail "and then follow the disables that occur as a result to see what impact" "this TPL disable has on the configuration of TribitsExProj." "-- ERROR: Failed finding all of the parts of TPL 'HeaderOnlyTpl' .see above., Aborting!" - "CMake Error at .+/TribitsProcessEnabledTpl[.]cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" " ERROR: TPL_HeaderOnlyTpl_NOT_FOUND=TRUE, aborting!" "Call Stack .most recent call first.:" "-- Configuring incomplete, errors occurred!" @@ -3209,3 +3209,355 @@ if (TribitsExampleProject_extra_link_flags_NAME) set_tests_properties(${TribitsExampleProject_extra_link_flags_NAME} PROPERTIES DEPENDS ${SimpleTpl_install_STATIC_NAME} ) endif() + + +################################################################################### + + +tribits_add_advanced_test( TribitsExampleProject_External_SimpleCxx + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + EXCLUDE_IF_NOT_TRUE ${PROJECT_NAME}_ENABLE_Fortran IS_REAL_LINUX_SYSTEM + + TEST_0 + MESSAGE "Copy TribitsExampleProject so we can change it" + CMND cp + ARGS -r ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject . +# CMND ln +# ARGS -s ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject . + + TEST_1 + MESSAGE "Configure to just build and install just SimpleCxx" + CMND ${CMAKE_COMMAND} + WORKING_DIRECTORY Build_SimpleCxx + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_SimpleCxx=ON + -DCMAKE_INSTALL_PREFIX=../install/simple_cxx + -DTribitsExProj_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_MPI=OFF + -DTPL_ENABLE_SimpleTpl=ON + -DSimpleTpl_INCLUDE_DIRS=${SimpleTpl_install_STATIC_DIR}/install/include + -DSimpleTpl_LIBRARY_DIRS=${SimpleTpl_install_STATIC_DIR}/install/lib + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_2 + MESSAGE "Build just SimpleCxx" + CMND make ARGS ${CTEST_BUILD_FLAGS} + WORKING_DIRECTORY Build_SimpleCxx + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_3 + MESSAGE "Install just SimpleCxx" + CMND make ARGS ${CTEST_BUILD_FLAGS} install + WORKING_DIRECTORY Build_SimpleCxx + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_4 + MESSAGE "Make sure only SimpleCxxConfig.cmake was installed" + CMND ls ARGS install/simple_cxx/lib/cmake + PASS_REGULAR_EXPRESSION_ALL + "SimpleCxx" + FAIL_REGULAR_EXPRESSION + "TribitsExProj" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_5 + MESSAGE "Remove the build directory for SimpleCxx" + CMND ${CMAKE_COMMAND} ARGS -E rm -R Build_SimpleCxx + + TEST_6 + MESSAGE "Remove the source directory for SimpleCxx" + CMND ${CMAKE_COMMAND} ARGS -E rm -R + TribitsExampleProject/packages/simple_cxx/CMakeLists.txt + TribitsExampleProject/packages/simple_cxx/src + TribitsExampleProject/packages/simple_cxx/test + + TEST_7 + MESSAGE "Configure rest of TribitsExampleProject against pre-installed SimpleCxx" + CMND ${CMAKE_COMMAND} + WORKING_DIRECTORY Build + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_ALL_PACKAGES=ON + -DTribitsExProj_ENABLE_TESTS=ON + -DTribitsExProj_ENABLE_INSTALL_CMAKE_CONFIG_FILES=OFF # Allow WrapExternal enable + -DTPL_ENABLE_SimpleCxx=ON + -DCMAKE_PREFIX_PATH=../install/simple_cxx + -DTPL_ENABLE_MPI=OFF + -DTPL_ENABLE_SimpleTpl=ON + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package SimpleCxx as EXTERNAL because TPL_ENABLE_SimpleCxx=ON" + "-- NOTE: SimpleTpl is directly downstream from a TriBITS-compliant external package SimpleCxx" + "-- NOTE: HeaderOnlyTpl is directly downstream from a TriBITS-compliant external package SimpleCxx" + + "Final set of enabled top-level packages: MixedLang WithSubpackages WrapExternal 3" + "Final set of enabled packages: MixedLang WithSubpackagesA WithSubpackagesB WithSubpackagesC WithSubpackages WrapExternal 6" + "Final set of non-enabled top-level packages: 0" + "Final set of non-enabled packages: 0" + "Final set of enabled top-level external packages/TPLs: HeaderOnlyTpl SimpleTpl SimpleCxx 3" + "Final set of enabled external packages/TPLs: HeaderOnlyTpl SimpleTpl SimpleCxx 3" + "Final set of non-enabled top-level external packages/TPLs: MPI 1" + "Final set of non-enabled external packages/TPLs: MPI 1" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs ..." + "Processing enabled external package/TPL: HeaderOnlyTpl [(]enabled by SimpleCxx, disable with -DTPL_ENABLE_HeaderOnlyTpl=OFF[)]" + "-- The external package/TPL HeaderOnlyTpl will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: SimpleTpl [(]enabled explicitly, disable with -DTPL_ENABLE_SimpleTpl=OFF[)]" + "-- The external package/TPL SimpleTpl will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: SimpleCxx [(]enabled explicitly, disable with -DTPL_ENABLE_SimpleCxx=OFF[)]" + "-- Calling find_package[(]SimpleCxx[)] for TriBITS-compliant external package" + + "Getting information for all remaining enabled external packages/TPLs ..." + + "Configuring individual enabled TribitsExProj packages ..." + "Processing enabled top-level package: MixedLang [(]Libs, Tests, Examples[)]" + "Processing enabled top-level package: WithSubpackages [(]A, B, C, Tests, Examples[)]" + "Processing enabled top-level package: WrapExternal [(]Libs, Tests, Examples[)]" + + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_8 + MESSAGE "Build TribitsExampleProject" + CMND make ARGS ${CTEST_BUILD_FLAGS} + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_9 + MESSAGE "Run all the tests with ctest" + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_CTEST_COMMAND} + PASS_REGULAR_EXPRESSION_ALL + "100% tests passed, 0 tests failed out of 8" + ALWAYS_FAIL_ON_NONZERO_RETURN + + ADDED_TEST_NAME_OUT TribitsExampleProject_External_SimpleCxx_NAME + ) +# NOTE: The above test is a strong check that SimpleCxx is built and installed +# first and then is used in the later build of the rest of +# TribitsExampleProject. If you comment out -DTPL_ENABLE_SimpleCxx=ON, then +# it will not build! This test also uniquely tests a few other TriBITS features: +# +# * _SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES (ensures the directory +# * install/simple_cxx/lib/cmake/TribitsExProj does not get created and +# * therefore the file TribitsExProjConfig.cmake does not get installed). + + +if (TribitsExampleProject_External_SimpleCxx_NAME) + set_tests_properties(${TribitsExampleProject_External_SimpleCxx_NAME} + PROPERTIES DEPENDS ${SimpleTpl_install_STATIC_NAME} ) +endif() + + +################################################################################ + + +tribits_add_advanced_test( TribitsExampleProject_External_Package_by_Package + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + EXCLUDE_IF_NOT_TRUE ${PROJECT_NAME}_ENABLE_Fortran IS_REAL_LINUX_SYSTEM + LIST_SEPARATOR + + TEST_0 + MESSAGE "Link TribitsExampleProject so it is easy to access" + CMND ln + ARGS -s ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject . + + TEST_1 + MESSAGE "Configure to build and install just SimpleCxx" + WORKING_DIRECTORY Build_SimpleCxx + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_SimpleCxx=ON + -DCMAKE_INSTALL_PREFIX=../install_simplecxx + -DTribitsExProj_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_MPI=OFF + -DTPL_ENABLE_SimpleTpl=ON + -DSimpleTpl_INCLUDE_DIRS=${SimpleTpl_install_STATIC_DIR}/install/include + -DSimpleTpl_LIBRARY_DIRS=${SimpleTpl_install_STATIC_DIR}/install/lib + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_2 + MESSAGE "Build and install just SimpleCxx" + CMND make ARGS ${CTEST_BUILD_FLAGS} install + WORKING_DIRECTORY Build_SimpleCxx + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_3 + MESSAGE "Configure to build and install just MixedLang" + WORKING_DIRECTORY Build_MixedLang + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_MixedLang=ON + -DCMAKE_INSTALL_PREFIX=../install_mixedlang + -DTribitsExProj_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_MPI=OFF + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_4 + MESSAGE "Build and install just MixedLang" + CMND make ARGS ${CTEST_BUILD_FLAGS} install + WORKING_DIRECTORY Build_MixedLang + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_5 + MESSAGE "Configure to build and install just WithSubpackages against pre-installed SimpleCxx and MixedLang" + CMND ${CMAKE_COMMAND} + WORKING_DIRECTORY Build_WithSubpackages + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_WithSubpackages=ON + -DTribitsExProj_ENABLE_TESTS=ON + -DCMAKE_INSTALL_PREFIX=../install_withsubpackages + -DTribitsExProj_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=TRUE + -DTPL_ENABLE_MPI=OFF + -DTPL_ENABLE_SimpleTpl=ON + -DTPL_ENABLE_SimpleCxx=ON + -DTPL_ENABLE_MixedLang=ON + -DCMAKE_PREFIX_PATH=../install_simplecxx../install_mixedlang + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package MixedLang as EXTERNAL because TPL_ENABLE_MixedLang=ON" + "-- Treating internal package SimpleCxx as EXTERNAL because TPL_ENABLE_SimpleCxx=ON" + "-- NOTE: SimpleTpl is directly downstream from a TriBITS-compliant external package SimpleCxx" + "-- NOTE: HeaderOnlyTpl is directly downstream from a TriBITS-compliant external package SimpleCxx" + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_6 + MESSAGE "Build and install just WithSubpackages" + CMND make ARGS ${CTEST_BUILD_FLAGS} install + WORKING_DIRECTORY Build_WithSubpackages + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_7 + MESSAGE "Test WithSubpackages" + WORKING_DIRECTORY Build_WithSubpackages + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_CTEST_COMMAND} + PASS_REGULAR_EXPRESSION_ALL + "WithSubpackagesA_test_of_a [.]* +Passed" + "WithSubpackagesB_test_of_b [.]* +Passed" + "WithSubpackagesB_test_of_b_mixed_lang [.]* +Passed" + "WithSubpackagesC_test_of_c_util [.]* +Passed" + "WithSubpackagesC_test_of_c [.]* Passed" + "WithSubpackagesC_test_of_c_b_mixed_lang ... Passed" + "100% tests passed, 0 tests failed out of 6" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_8 + MESSAGE "Configure rest of TribitsExampleProject against pre-installed SimpleCxx, MixedLang, and WithSubpackages" + CMND ${CMAKE_COMMAND} + WORKING_DIRECTORY Build + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_ALL_PACKAGES=ON + -DTribitsExProj_ENABLE_TESTS=ON + -DTribitsExProj_ENABLE_INSTALL_CMAKE_CONFIG_FILES=OFF # Allow WrapExternal enable + -DTPL_ENABLE_MixedLang=ON + -DTPL_ENABLE_WithSubpackages=ON + -DCMAKE_PREFIX_PATH=../install_withsubpackages../install_mixedlang + -DTPL_ENABLE_MPI=OFF + -DTPL_ENABLE_SimpleTpl=ON + ../TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Adjust the set of internal and external packages:" + "-- Treating internal package WithSubpackages as EXTERNAL because TPL_ENABLE_WithSubpackages=ON" + "-- Treating internal package WithSubpackagesA as EXTERNAL because downstream package WithSubpackages being treated as EXTERNAL" + "-- Treating internal package WithSubpackagesB as EXTERNAL because downstream package WithSubpackages being treated as EXTERNAL" + "-- Treating internal package WithSubpackagesC as EXTERNAL because downstream package WithSubpackages being treated as EXTERNAL" + "-- Treating internal package SimpleCxx as EXTERNAL because downstream package WithSubpackagesB being treated as EXTERNAL" + "-- Treating internal package MixedLang as EXTERNAL because TPL_ENABLE_MixedLang=ON" + "-- NOTE: SimpleTpl is indirectly downstream from a TriBITS-compliant external package" + "-- NOTE: HeaderOnlyTpl is indirectly downstream from a TriBITS-compliant external package" + + "Final set of enabled top-level packages: WrapExternal 1" + "Final set of enabled packages: WrapExternal 1" + "Final set of non-enabled top-level packages: 0" + "Final set of non-enabled packages: 0" + "Final set of enabled top-level external packages/TPLs: HeaderOnlyTpl SimpleTpl SimpleCxx MixedLang WithSubpackages 5" + "Final set of enabled external packages/TPLs: HeaderOnlyTpl SimpleTpl SimpleCxx MixedLang WithSubpackagesA WithSubpackagesB WithSubpackagesC WithSubpackages 8" + "Final set of non-enabled top-level external packages/TPLs: MPI 1" + "Final set of non-enabled external packages/TPLs: MPI 1" + + "Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs ..." + "Processing enabled external package/TPL: HeaderOnlyTpl [(]enabled by SimpleCxx, disable with -DTPL_ENABLE_HeaderOnlyTpl=OFF[)]" + "-- The external package/TPL HeaderOnlyTpl will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: SimpleTpl [(]enabled explicitly, disable with -DTPL_ENABLE_SimpleTpl=OFF[)]" + "-- The external package/TPL SimpleTpl will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: SimpleCxx [(]enabled explicitly, disable with -DTPL_ENABLE_SimpleCxx=OFF[)]" + "-- The external package/TPL SimpleCxx will be read in by a downstream TriBITS-compliant external package" + "Processing enabled external package/TPL: MixedLang [(]enabled explicitly, disable with -DTPL_ENABLE_MixedLang=OFF[)]" + "-- Calling find_package[(]MixedLang[)] for TriBITS-compliant external package" + "Processing enabled external package/TPL: WithSubpackages [(]enabled explicitly, disable with -DTPL_ENABLE_WithSubpackages=OFF[)]" + "-- Calling find_package[(]WithSubpackages[)] for TriBITS-compliant external package" + + "Getting information for all remaining enabled external packages/TPLs ..." + + "Configuring individual enabled TribitsExProj packages ..." + "Processing enabled top-level package: WrapExternal [(]Libs, Tests, Examples[)]" + + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + # NOTE: Above, we don't need to look in install_simplecxx for SimpleCxx + # because that will get found through WithSubpackages. But we do need to + # look for MixedLang because the libraries for WithSubpackages does not + # actually depend on MixedLang so we need to add where to find it. + + TEST_9 + MESSAGE "Build rest of TribitsExampleProject" + CMND make ARGS ${CTEST_BUILD_FLAGS} + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + + TEST_10 + MESSAGE "Run all the remaining tests with ctest" + WORKING_DIRECTORY Build + SKIP_CLEAN_WORKING_DIRECTORY + CMND ${CMAKE_CTEST_COMMAND} + PASS_REGULAR_EXPRESSION_ALL + "WrapExternal_run_external_func [.]* +Passed" + "100% tests passed, 0 tests failed out of 1" + ALWAYS_FAIL_ON_NONZERO_RETURN + + ADDED_TEST_NAME_OUT TribitsExampleProject_External_Package_by_Package_NAME + ) +# NOTE: The above test is a strong check that packages can be installed +# individually in stages on top of each other and that we are correctly +# writing wrapper Config.cmake files for TriBITS-compliant +# external packages (in this case for WithSubpackagesAConfig.cmake to +# include). + + +if (TribitsExampleProject_External_Package_by_Package_NAME) + set_tests_properties(${TribitsExampleProject_External_Package_by_Package_NAME} + PROPERTIES DEPENDS ${SimpleTpl_install_STATIC_NAME} ) +endif() diff --git a/test/core/ProcessEnabledTpls/CMakeLists.txt b/test/core/ProcessEnabledTpls/CMakeLists.txt index a2f1d4285..da1dcee88 100644 --- a/test/core/ProcessEnabledTpls/CMakeLists.txt +++ b/test/core/ProcessEnabledTpls/CMakeLists.txt @@ -223,7 +223,7 @@ create_process_enabled_tpls_test_case( "When you reconfigure, just grep the cmake stdout for 'HeaderOnlyTpl'" "and then follow the disables that occur as a result to see what impact" "this TPL disable has on the configuration of DummyProj." - "CMake Error at .+/TribitsProcessEnabledTpl[.]cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeaderOnlyTpl_NOT_FOUND=TRUE, aborting!" ) @@ -244,7 +244,7 @@ create_process_enabled_tpls_test_case( "and then follow the disables that occur as a result to see what impact" "this TPL disable has on the configuration of ${MOCK_PROJECT_NAME}." "-- ERROR: Failed finding all of the parts of TPL 'HeaderOnlyTpl' .see above., Aborting!" - "CMake Error at .+/TribitsProcessEnabledTpl[.]cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeaderOnlyTpl_NOT_FOUND=TRUE, aborting!" ) @@ -481,7 +481,7 @@ create_process_enabled_tpls_test_case( "When you reconfigure, just grep the cmake stdout for 'HeadersAndLibsTpl'" "and then follow the disables that occur as a result to see what impact" "this TPL disable has on the configuration of DummyProj." - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -503,7 +503,7 @@ create_process_enabled_tpls_test_case( "-- TIP: If the TPL 'HeadersAndLibsTpl' is on your system then you can set:" "-- ERROR: Failed finding all of the parts of TPL 'HeadersAndLibsTpl' .see above., Aborting!" "TIP: One way to get past the configure failure for the" - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -526,7 +526,7 @@ create_process_enabled_tpls_test_case( "-- TIP: If the TPL 'HeadersAndLibsTpl' is on your system then you can set:" "-- ERROR: Failed finding all of the parts of TPL 'HeadersAndLibsTpl' .see above., Aborting!" "TIP: One way to get past the configure failure for the" - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -545,7 +545,7 @@ create_process_enabled_tpls_test_case( "-- Searching for libs in HeadersAndLibsTpl_LIBRARY_DIRS='.+/HeadersAndLibsTpl/lib'" "-- Searching for a lib in the set .badlibname.:" "-- NOTE: Did not find a lib in the lib set .badlibname. for the TPL 'HeadersAndLibsTpl'!" - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -563,7 +563,7 @@ create_process_enabled_tpls_test_case( "-- Searching for libs in HeadersAndLibsTpl_LIBRARY_DIRS='.+/HeadersAndLibsTpl/lib'" "-- Searching for a lib in the set .badlibname.:" "-- ERROR: Did not find a lib in the lib set .badlibname. for the TPL 'HeadersAndLibsTpl'!" - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -603,7 +603,7 @@ create_process_enabled_tpls_test_case( "-- Searching for libs in HeadersAndLibsTpl_LIBRARY_DIRS='.+/HeadersAndLibsTpl/lib'" "-- Searching for a lib in the set .badlibname.:" "-- ERROR: Did not find a lib in the lib set .badlibname. for the TPL 'HeadersAndLibsTpl'!" - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) @@ -626,7 +626,7 @@ create_process_enabled_tpls_test_case( "-- TIP: If the TPL 'HeadersAndLibsTpl' is on your system then you can set:" "-- ERROR: Failed finding all of the parts of TPL 'HeadersAndLibsTpl' .see above., Aborting!" "TIP: Even though the TPL 'HeadersAndLibsTpl' was explicitly enabled in input," - "CMake Error at .+/TribitsProcessEnabledTpl.cmake:[0-9]+ [(]message[)]:" + "CMake Error at .+/TribitsProcessEnabledTpls[.]cmake:[0-9]+ [(]message[)]:" "ERROR: TPL_HeadersAndLibsTpl_NOT_FOUND=TRUE, aborting!" ) diff --git a/test/core/ProcessEnabledTpls/TribitsProcessEnabledTplTesterCMakeLists.txt b/test/core/ProcessEnabledTpls/TribitsProcessEnabledTplTesterCMakeLists.txt index f3c1ef646..c7c7459cd 100644 --- a/test/core/ProcessEnabledTpls/TribitsProcessEnabledTplTesterCMakeLists.txt +++ b/test/core/ProcessEnabledTpls/TribitsProcessEnabledTplTesterCMakeLists.txt @@ -56,7 +56,7 @@ set( CMAKE_MODULE_PATH "${${PROJECT_NAME}_TRIBITS_DIR}/core/package_arch" ) -include(TribitsProcessEnabledTpl) +include(TribitsProcessEnabledTpls) # Passed in on command-line print_var("TPL_NAME") @@ -72,7 +72,7 @@ endif() # Do the processing of the TPL message("") -tribits_process_enabled_tpl(${TPL_NAME}) +tribits_process_enabled_standard_tpl(${TPL_NAME}) message("") message("Exported TPL_ENABLE_${TPL_NAME}='${TPL_ENABLE_${TPL_NAME}}'") message("Exported TPL_${TPL_NAME}_NOT_FOUND='${TPL_${TPL_NAME}_NOT_FOUND}'") diff --git a/test/core/TribitsExternalPackageWriteConfigFile_UnitTests.cmake b/test/core/TribitsExternalPackageWriteConfigFile_UnitTests.cmake index a2d07c9d5..8c6572aa6 100644 --- a/test/core/TribitsExternalPackageWriteConfigFile_UnitTests.cmake +++ b/test/core/TribitsExternalPackageWriteConfigFile_UnitTests.cmake @@ -840,6 +840,11 @@ target_link_libraries(SomeTpl::all_libs INTERFACE tribits::SomeTpl::somelib ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -876,6 +881,11 @@ target_include_directories(SomeTpl::all_libs SYSTEM INTERFACE "/some/other/path/to/include/e" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -918,6 +928,11 @@ target_include_directories(SomeTpl::all_libs SYSTEM INTERFACE "/some/path/to/include/C" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -961,6 +976,11 @@ target_include_directories(SomeTpl::all_libs SYSTEM INTERFACE "/some/other/path/to/include/b" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -1020,6 +1040,11 @@ target_link_options(SomeTpl::all_libs INTERFACE "-L/some/explicit/path1" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -1095,6 +1120,11 @@ target_link_options(SomeTpl::all_libs INTERFACE "-L/some/explicit/path1" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) @@ -1135,42 +1165,18 @@ if (TARGET SomeTpl::all_libs) return() endif() -include(CMakeFindDependencyMacro) - -# Don't allow find_dependency() to search anything other than _DIR -set(SomeTpl_SearchNoOtherPathsArgs - NO_DEFAULT_PATH - NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_PACKAGE_REGISTRY - NO_CMAKE_SYSTEM_PATH - NO_CMAKE_SYSTEM_PACKAGE_REGISTRY - CMAKE_FIND_ROOT_PATH_BOTH - ONLY_CMAKE_FIND_ROOT_PATH - NO_CMAKE_FIND_ROOT_PATH - ) - if (NOT TARGET PublicTpl::all_libs) - set(PublicTpl_DIR "${CMAKE_CURRENT_LIST_DIR}/../PublicTpl") - find_dependency(PublicTpl REQUIRED CONFIG ${SomeTpl_SearchNoOtherPathsArgs}) - unset(PublicTpl_DIR) + include("${CMAKE_CURRENT_LIST_DIR}/../PublicTpl/PublicTplConfig.cmake") endif() if (NOT TARGET PrivateTpl::all_libs) - set(PrivateTpl_DIR "${CMAKE_CURRENT_LIST_DIR}/../PrivateTpl") - find_dependency(PrivateTpl REQUIRED CONFIG ${SomeTpl_SearchNoOtherPathsArgs}) - unset(PrivateTpl_DIR) + include("${CMAKE_CURRENT_LIST_DIR}/../PrivateTpl/PrivateTplConfig.cmake") endif() if (NOT TARGET DefaultVisTpl::all_libs) - set(DefaultVisTpl_DIR "${CMAKE_CURRENT_LIST_DIR}/../DefaultVisTpl") - find_dependency(DefaultVisTpl REQUIRED CONFIG ${SomeTpl_SearchNoOtherPathsArgs}) - unset(DefaultVisTpl_DIR) + include("${CMAKE_CURRENT_LIST_DIR}/../DefaultVisTpl/DefaultVisTplConfig.cmake") endif() -unset(SomeTpl_SearchNoOtherPathsArgs) - add_library(tribits::SomeTpl::lib1 IMPORTED INTERFACE) set_target_properties(tribits::SomeTpl::lib1 PROPERTIES IMPORTED_LIBNAME "lib1") @@ -1200,6 +1206,11 @@ target_link_options(SomeTpl::all_libs INTERFACE "-L/some/explicit/path1" ) + +# Standard TriBITS-compliant external package variables +set(SomeTpl_IS_TRIBITS_COMPLIANT TRUE) +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE "${CMAKE_CURRENT_LIST_FILE}") +set(SomeTpl_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}") ]=] ) diff --git a/test/core/TribitsWriteClientExportFiles_UnitTests.cmake b/test/core/TribitsInternalPackageWriteConfigFile_UnitTests.cmake similarity index 98% rename from test/core/TribitsWriteClientExportFiles_UnitTests.cmake rename to test/core/TribitsInternalPackageWriteConfigFile_UnitTests.cmake index b8cdc31cf..2fc6d7ae8 100644 --- a/test/core/TribitsWriteClientExportFiles_UnitTests.cmake +++ b/test/core/TribitsInternalPackageWriteConfigFile_UnitTests.cmake @@ -43,12 +43,12 @@ message("CURRENT_TEST_DIRECTORY = ${CURRENT_TEST_DIRECTORY}") include(${CMAKE_CURRENT_LIST_DIR}/TribitsAdjustPackageEnablesHelpers.cmake) include(TribitsPackageMacros) -include(TribitsWriteClientExportFiles) +include(TribitsInternalPackageWriteConfigFile) ##################################################################### # -# Unit tests for code in TribitsWriteClientExportFiles.cmake +# Unit tests for code in TribitsInternalPackageWriteConfigFile.cmake # ##################################################################### diff --git a/tribits/CHANGELOG.md b/tribits/CHANGELOG.md index 51e332f4a..ad09ea89d 100644 --- a/tribits/CHANGELOG.md +++ b/tribits/CHANGELOG.md @@ -4,10 +4,59 @@ ChangeLog for TriBITS ## 2023-02-24: -* **Changed:** Upgrade minimum required CMake version from 3.17 to 3.23. +* **Changed:** Upgraded minimum required CMake version from 3.17 to 3.23. Existing TriBITS projects that have already upgraded to require CMake 3.23+ should not notice any major changes due to this change. +## 2023-02-21: + +* **Added:** Added support for pre-installed internal packages treated as + external packages. Now, any set of internally defined TriBITS packages for + a TriBITS project can be pre-built and pre-installed and the remaining + packages in the TriBITS project can be configured to point to those by + setting `-D TPL_ENABLE_=ON`. This allows great flexibility in how + a TriBITS project's packages can be and built, installed, and deployed. + This technically implements "Use Case 3: Configure/build pointing to a + subset of already installed TriBITS packages in same repo" in [TriBITS + #63](https://github.com/TriBITSPub/TriBITS/issues/63). See the section + "Building against pre-installed packages" in the updated build reference + documentation for details. + +* **Fixed:** Setting `-D_ENABLE_=ON` for an external + package/TPL `` will not correctly enable and process the TPL. + +## 2022-12-07: + +* **Changed:** Setting `-D_ENABLE_=ON` now triggers the + enable an external package/TPL `` similar to the way that + `-DTPL_ENABLE_` has always done. This is technically a change in + backward compatibility because setting `_ENABLE_=ON` for + an external package/TPL used to be ignored. This change was done as part of + a general refactoring to unify the handling of internal and external + packages and is a side effect of that refactoring (see [TriBITS + #63](https://github.com/TriBITSPub/TriBITS/issues/63)). (Initially, setting + `-D_ENABLE_=ON` resulted in a failed configure because the + refactoring was not complete for the handling of external packages/TPL. But + this was fixed in a latter update.) + +## 2023-10-25: + +* **Added:** New option `_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES` + skips the install of the project-level `Config.cmake` file. The + default value is ``FALSE`` so as to maintain backward compatibility. (The + project can change the default.) + +* **Changed:** External packages/TPLs are now processed at the base project + scope level. This allows simple `set()` statements in package module files + or config files included by `find_package()` to have project-level scope for + the entire TriBITS project. This is more similar to how a raw CMake project + would usually behave that calls `find_package()` in the base + `CMakeLists.txt` file. Before, calls to `find_package()` were wrapped in a + CMake `function()` called from the base project directory scope. So while + IMPORTED targets created from a `find_package()` command where visible at + the base directory project-level scope, local variables were not. With this + change, now they are. + ## 2023-01-10: * **Added:** Added back support for deprecated variable diff --git a/tribits/ci_support/TribitsWriteXmlDependenciesFiles.cmake b/tribits/ci_support/TribitsWriteXmlDependenciesFiles.cmake index 1091008e3..2360acf16 100644 --- a/tribits/ci_support/TribitsWriteXmlDependenciesFiles.cmake +++ b/tribits/ci_support/TribitsWriteXmlDependenciesFiles.cmake @@ -178,7 +178,6 @@ function(tribits_write_deps_to_xml_string packageName libOrTest requiredOrOpti set(listType ${libOrTest}_${requiredOrOptional}_DEP_${packagesOrTpls}) message("") - print_var(listType) tribits_get_legacy_package_deps_sublist(${packageName} ${libOrTest} ${requiredOrOptional} ${packagesOrTpls} legacyPackageDepsList) diff --git a/tribits/core/installation/add_project_install_commands/CMakeLists.txt b/tribits/core/installation/add_project_install_commands/CMakeLists.txt index 14054ad19..67c74c964 100644 --- a/tribits/core/installation/add_project_install_commands/CMakeLists.txt +++ b/tribits/core/installation/add_project_install_commands/CMakeLists.txt @@ -2,10 +2,11 @@ set(tribits_install_src "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") if ( ${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES - AND NOT ${PROJECT_NAME}_ENABLE_INSTALLATION_TESTING + AND (NOT ${PROJECT_NAME}_ENABLE_INSTALLATION_TESTING) + AND (NOT ${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES) ) - include(TribitsWriteClientExportFiles) + include(TribitsProjectWriteConfigFile) tribits_write_project_client_export_files() diff --git a/tribits/core/package_arch/TribitsAdjustPackageEnables.cmake b/tribits/core/package_arch/TribitsAdjustPackageEnables.cmake index 53bbb1f2b..cc6da7aba 100644 --- a/tribits/core/package_arch/TribitsAdjustPackageEnables.cmake +++ b/tribits/core/package_arch/TribitsAdjustPackageEnables.cmake @@ -87,6 +87,7 @@ macro(tribits_adjust_package_enables) tribits_sweep_backward_enable_upstream_packages() tribits_set_cache_vars_for_current_enabled_packages() tribits_do_final_parent_packages_enables_for_subpackage_enables() + tribits_adjust_internal_external_packages() tribits_setup_enabled_lists_and_pkg_idxs() tribits_setup_direct_packages_dependencies_lists_and_lib_required_enable_vars() tribits_print_direct_packages_dependencies_lists() @@ -224,7 +225,7 @@ endmacro() # NOTE: Above, we are sweeping over *all* of the not-disabled packages listed # in ${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES, including those package that # might have _PACKAGE_BUILD_STATUS=EXTERNAL. That makes sense -# because these are TriBITS (or TriBITS compatible) packages so we should +# because these are TriBITS (or TriBITS-compliant) packages so we should # assume that all of their downstream packages, whether internal or external, # should be enabled as well. If we find this is not the desirable behavior, # then we can change this later. @@ -276,8 +277,7 @@ endmacro() # @MACRO: tribits_sweep_backward_enable_upstream_packages() # -# Sweep backwards and enable required and (optionally) optional upstream -# packages. +# Sweep backwards and enable required (and optional) upstream packages. # # This sets the final value for: # @@ -351,6 +351,30 @@ macro(tribits_do_final_parent_packages_enables_for_subpackage_enables) endmacro() +# @MACRO: tribits_adjust_internal_external_packages() +# +# Macro to adjust the set of internal and external packages by changing +# `_PACKAGE_BUILD_STATUS`. +# +# This macro sweeps backwards over the dependency graph setting. +# +# NOTE: This is called **after** all of the logic that determines what +# packages are enabled or disabled. This is because we don't want to change +# the enable/disable logic when one or more initially internal packages are +# made external. We are going to just assume that if an initially internal +# package that is declared external should be disabled, then the user will +# need to make that decision explicitly. +# +macro(tribits_adjust_internal_external_packages) + tribits_create_reverse_list(${PROJECT_NAME}_DEFINED_PACKAGES + ${PROJECT_NAME}_REVERSE_DEFINED_PACKAGES) + message("\nAdjust the set of internal and external packages:\n") + foreach(packageName IN LISTS ${PROJECT_NAME}_REVERSE_DEFINED_PACKAGES) + tribits_set_package_and_related_upstream_packages_to_external(${packageName}) + endforeach() +endmacro() + + # Macro that sets up the basic lists of enabled packages and packages. # macro(tribits_setup_enabled_lists_and_pkg_idxs) @@ -663,7 +687,9 @@ endmacro() # macro(tribits_enable_upstream_packages packageName) - if (${PROJECT_NAME}_ENABLE_${packageName}) + tribits_get_package_enable_status(${packageName} packageEnable packageEnableVar) + + if (packageEnable) foreach(depPkg IN LISTS ${packageName}_LIB_DEFINED_DEPENDENCIES) tribits_private_enable_dep_package(${packageName} ${depPkg} LIB) @@ -769,13 +795,15 @@ endmacro() macro(tribits_enable_parent_package_for_subpackage_enables toplevelPackageName) foreach(tap2_subPkgName IN LISTS ${toplevelPackageName}_SUBPACKAGES) set(subpkgFullName ${toplevelPackageName}${tap2_subPkgName}) - if (${PROJECT_NAME}_ENABLE_${subpkgFullName} - AND (NOT ${PROJECT_NAME}_ENABLE_${toplevelPackageName}) - ) + tribits_get_package_enable_status(${toplevelPackageName} + toplevelPackageEnable toplevelPackageEnableVarName) + tribits_get_package_enable_status(${subpkgFullName} + subpkgEnable subpkgEnableVarName) + if (subpkgEnable AND (NOT toplevelPackageEnable)) message("-- " - "Setting ${PROJECT_NAME}_ENABLE_${toplevelPackageName}=ON" - " because ${PROJECT_NAME}_ENABLE_${subpkgFullName}=ON") - set(${PROJECT_NAME}_ENABLE_${toplevelPackageName} ON) + "Setting ${toplevelPackageEnableVarName}=ON because" + " ${subpkgEnableVarName}=${subpkgEnable}") + set(${toplevelPackageEnableVarName} ON) tribits_set_parent_package_subpackage_enable_for_enabled_subpackages( ${toplevelPackageName}) tribits_set_parent_package_test_example_enable_for_enabled_subpackages( @@ -794,6 +822,51 @@ macro(tribits_enable_parent_package_for_subpackage_enables toplevelPackageName) endmacro() +# Macro that sets $``{packageName}_PACKAGE_BUILD_STATUS=EXTERNAL and direct +# upstream dependent packages ``${depPkg}_PACKAGE_BUILD_STATUS=EXTERNAL`` if +# required. +# +# * Set an INTERNAL package as EXTERNAL if ``TPL_ENABLE_${packageName}`` is +# ``TRUE`` +# +# * Set a top-level package to EXTERNAL if any of its subpackages are EXTERNAL +# (or ``TPL_ENABLE_${subpkgFullName}`` is TRUE). +# +# This macro must be called in a backward/reverse sweep over the dependency +# graph to work correctly. It sets upstream packages as EXTERNAL if the given +# downstream package ```` is EXTERNAL. There is also special +# logic for handling a package that has subpackages. That is, if any +# subpackage of ```` is determined is EXTERNAL, then the parent +# package is set to EXTERNAL and all of the other subpackages in parent +# package ```` are set as EXTERNAL as well. (We don't allow a +# subset of subpackages in a parent package to be EXTERNAL and the other +# subpackages to be INTERNAL. That would be way too complicated to implement +# and be way too confusing for implementors and users.) +# +macro(tribits_set_package_and_related_upstream_packages_to_external packageName) + + tribits_set_parent_package_external_if_subpackage_external(${packageName} + subpackageTriggeredParentPackageExternal) + + tribits_set_package_to_external_if_requested_by_user(${packageName}) + + tribits_set_upstream_dep_packages_as_external(${packageName} + ${subpackageTriggeredParentPackageExternal}) + + tribits_set_package_as_processed_by_downstream_tribits_external_package(${packageName}) + +endmacro() +# NOTE: In the above macro, if ${packageName} is made EXTERNAL because it one +# of its subpackages is considered EXTERNAL, then the loop over all of the +# package's upstream dependencies listed in +# ${packageName}_LIB_DEFINED_DEPENDENCIES results in all of the other +# subpackages in that package to also be treated as external. (I.e., there is +# no need for a special loop over subpackages for the parent package. And the +# only direct dependencies for a parent package should be its subpackages. If +# that is not the case, then, technically, this would be setting more packages +# as EXTERNAL than need to be.) + + # Macro that sets up the flat list of direct package dependencies and enabled # package dependencies and sets ${packageName}_ENABLE_${depPkg} for LIB # dependencies @@ -1049,9 +1122,11 @@ macro(tribits_private_enable_dep_package packageName depPkgName libOrTest) tribits_get_package_enable_status(${depPkgName} depPkgEnable depPkgEnableVar) if (depPkgEnable) #message("The package is already enabled so there is nothing to enable!") - elseif (${depPkgEnableVar} STREQUAL "") + elseif ("${depPkgEnable}" STREQUAL "") set(tpedp_enableDepPkg "") - if (${packageName}_${libOrTest}_DEP_REQUIRED_${depPkgName}) + if (${packageName}_${libOrTest}_DEP_REQUIRED_${depPkgName} + AND (NOT "${${packageName}_SOURCE_DIR}" STREQUAL "") + ) message("-- " "Setting ${depPkgEnableVar}=ON" " because ${packageName} has a required dependence on ${depPkgName}") set(tpedp_enableDepPkg ON) @@ -1164,6 +1239,125 @@ macro(tribits_private_add_optional_package_enable packageName optionalDepPkgNa endmacro() +# Set the parent package as EXTERNAL if any of its subpackages are being +# treated as EXTERNAL and return bool if that is the case. +# +# On output, ``_PACKAGE_BUILD_STATUS`` will have been set +# to ``EXTERNAL`` if the returned var +# ``subpackageTriggeredParentPackageExternalOut`` is ``TRUE``. +# +macro(tribits_set_parent_package_external_if_subpackage_external parentPackageName + subpackageTriggeredParentPackageExternalOut + ) + + set(subpackageTriggeredParentPackageExternal FALSE) + + if (NOT ${parentPackageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + foreach (tap2_subPkgName IN LISTS ${parentPackageName}_SUBPACKAGES) + set(subpkgFullName ${parentPackageName}${tap2_subPkgName}) + tribits_package_is_external(${subpkgFullName} subpkgIsExternal) + if (subpkgIsExternal) + set(becauseMsgStr "subpackage ${subpkgFullName} being treated as EXTERNAL") + if (TPL_ENABLE_${subpkgFullName}) + string(APPEND becauseMsgStr + " (TPL_ENABLE_${subpkgFullName}=${TPL_ENABLE_${subpkgFullName}})") + endif() + tribits_set_internal_package_to_external(${parentPackageName} "${becauseMsgStr}") + set(subpackageTriggeredParentPackageExternal TRUE) + break() + endif() + endforeach() + endif() + + set(${subpackageTriggeredParentPackageExternalOut} + ${subpackageTriggeredParentPackageExternal}) + +endmacro() + + +# Macro that sets ``_PACKAGE_BUILD_STATUS`` to ``EXTERNAL`` if +# requested by the user (e.g. by setting ``TPL_ENABLE_``). +# +macro(tribits_set_package_to_external_if_requested_by_user packageName) + if (NOT ${packageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + if (TPL_ENABLE_${packageName}) + tribits_set_internal_package_to_external(${packageName} + "TPL_ENABLE_${packageName}=${TPL_ENABLE_${packageName}}") + endif() + endif() +endmacro() + + +# Macro that sets all of the direct upstream dependent packages as EXTERNAL if +# they should be. +# +# NOTE: We only bother setting upstream dependencies as EXTERNAL if the +# package ```` is enabled or if it is a parent package (enabled +# or not) where at least one of its subpackages is enabled and is being +# treated as EXTERNAL. (In the latter case, any subpackages that are not +# enabled will still be set as EXTERNAL.) +# +macro(tribits_set_upstream_dep_packages_as_external packageName + subpackageTriggeredParentPackageExternal + ) + + tribits_get_package_enable_status(${packageName} packageEnable "") + + if (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + foreach(depPkg IN LISTS ${packageName}_LIB_DEFINED_DEPENDENCIES) + if ((NOT ${depPkg}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") AND + (subpackageTriggeredParentPackageExternal OR packageEnable) + ) + tribits_set_internal_package_to_external(${depPkg} + "downstream package ${packageName} being treated as EXTERNAL") + endif() + endforeach() + endif() + +endmacro() + + +# Mark a package as being processed by a downstream TriBITS-compliant external +# package +# +macro(tribits_set_package_as_processed_by_downstream_tribits_external_package packageName) + + set_default(${packageName}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE FALSE) + + tribits_get_package_enable_status(${packageName} packageEnable "") + + if (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + + foreach(fwdDepPkg IN LISTS ${packageName}_FORWARD_LIB_DEFINED_DEPENDENCIES) + + if((${fwdDepPkg}_IS_TRIBITS_COMPLIANT + OR ${fwdDepPkg}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE) + AND (${fwdDepPkg}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + ) + tribits_get_package_enable_status(${fwdDepPkg} fwdDepPkgEnable "") + if (${fwdDepPkg}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE) + set(directOrIndirectStr "indirectly") + set(downstreamPkgStr "") + else() + set(directOrIndirectStr "directly") + set(downstreamPkgStr " ${fwdDepPkg}") + endif() + if (packageEnable AND (NOT ${packageName}_IS_TRIBITS_COMPLIANT)) + message("-- " + "NOTE: ${packageName} is ${directOrIndirectStr} downstream from a" + " TriBITS-compliant external package${downstreamPkgStr}") + endif() + set(${packageName}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE TRUE) + break() + endif() + + endforeach() + + endif() + +endmacro() + + # Macro that sets ``_ENABLE_=ON`` if not already # enabled for all enabled subpackages of a parent package. # @@ -1204,4 +1398,52 @@ macro(tribits_set_parent_package_test_example_enable_for_enabled_subpackages endmacro() +# Macro that sets an internal package to EXTERNAL and print so and why (if the +# package is actually enabled) +# +# Usage:: +# +# tribits_set_internal_package_to_external( "" +# "" ...) +# +# This always sets ``_PACKAGE_BUILD_STATUS=EXTERNAL`` but only +# prints the message if ```` is enabled. +# +macro(tribits_set_internal_package_to_external depPkgName) + if (NOT ${depPkgName}_INTERNAL_PACKAGE_ALREADY_SET_EXTERNAL) + tribits_get_package_enable_status(${depPkgName} depPkgEnable "") + if (depPkgEnable) + message("-- " + "Treating internal package ${depPkgName} as EXTERNAL because" + " " ${ARGN}) + endif() + set(${depPkgName}_PACKAGE_BUILD_STATUS EXTERNAL) + set(${depPkgName}_FINDMOD TRIBITS_PKG) + set(${depPkgName}_INTERNAL_PACKAGE_ALREADY_SET_EXTERNAL TRUE) + endif() +endmacro() + + +macro(tribits_set_as_processed_by_downstream_tribits_external_package packageName + depPkgName + ) + +endmacro() + + +# Function to return if is to be treated as an EXTERNAL package +# in processing of the package +# +function(tribits_package_is_external packageName packageIsExternalOut) + if (TPL_ENABLE_${packageName}) + set(packageIsExternal TRUE) + elseif (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") + set(packageIsExternal TRUE) + else() + set(packageIsExternal FALSE) + endif() + set(${packageIsExternalOut} ${packageIsExternal} PARENT_SCOPE) +endfunction() + + # LocalWords: tribits TriBITS foreach endmacro endfunction diff --git a/tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake b/tribits/core/package_arch/TribitsExternalPackageWithImportedTargetsFindTplModuleHelpers.cmake similarity index 57% rename from tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake rename to tribits/core/package_arch/TribitsExternalPackageWithImportedTargetsFindTplModuleHelpers.cmake index 1873267bd..d6f3fd7ae 100644 --- a/tribits/core/package_arch/TribitsExternalPackageFindTplHelpers.cmake +++ b/tribits/core/package_arch/TribitsExternalPackageWithImportedTargetsFindTplModuleHelpers.cmake @@ -38,12 +38,32 @@ # @HEADER -# @FUNCTION: tribits_extpkg_create_imported_all_libs_target_and_config_file() +################################################################################ +# +# Module TribitsExternalPackageWithImportedTargetsFindTplModuleHelpers.cmake # -# Call from a ``FindTPL.cmake`` module that calls inner -# ``find_package()`` for external package that uses modern CMake +# Contains functions for implementing FindTPL.cmake files for +# external packages using find_package() that producing modern # IMPORTED targets. # +# NOTE: The acronym 'extpkgwit' stands for "External Package With Imported +# Targets". +# +################################################################################ + + +include(TribitsExternalPackageWriteConfigFile) + + + +# @FUNCTION: tribits_extpkg_create_imported_all_libs_target_and_config_file() +# +# Called from a `FindTPL.cmake`_ module which first calls +# ``find_package()``and the calls this function to get and +# external package that uses modern CMake IMPORTED targets. This function +# creates the ``::all_libs`` target and creates a TriBITS-compliant +# external package wrapper file `Config.cmake`. +# # Usage:: # # tribits_extpkg_create_imported_all_libs_target_and_config_file( @@ -51,18 +71,21 @@ # 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:: +# This function is called from a TriBITS ``FindTPL.cmake`` wrapper +# module after it calls ``find_package()`` and then this function +# 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. +# The generated ``Config.cmake`` file pulls in the upstream +# TriBITS-compliant ``Config.cmake` files, calls +# ``find_dependency()`` (with no other arguments), defines the +# `::all_libs`` target, and then sets up the correct dependencies +# between these targets. # # For more details, see `Creating FindTPL.cmake using find_package() # with IMPORTED targets`_. @@ -87,56 +110,10 @@ function(tribits_extpkg_create_imported_all_libs_target_and_config_file target_link_libraries(${tplName}::all_libs INTERFACE ${importedTarget}) endforeach() - # Create Config.cmake file - tribits_extpkg_create_package_config_file_with_imported_targets( + # Create the TriBITS-compliant Config.cmake wrapper file + tribits_extpkgwit_create_package_config_file( ${tplName} INNER_FIND_PACKAGE_NAME ${PARSE_INNER_FIND_PACKAGE_NAME} IMPORTED_TARGETS_FOR_ALL_LIBS ${PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS} ) endfunction() - - -function(tribits_extpkg_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" ) - if (${externalPkg}_DIR) - string(APPEND configFileStr - "set(${externalPkg}_DIR \"${${externalPkg}_DIR}\")\n" ) - endif() - string(APPEND configFileStr - "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() -# -# NOTE: Above, ${externalPkg}_DIR is only set when -# find_package(${externalPkg}) finds a package configure file -# ${externalPkg}Config.cmake and **not** when it uses a -# Find${externalPkg}.cmake module. Therefore, there is no reason to set -# ${externalPkg}_DIR in this file if it will not be used. diff --git a/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake b/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake index fd4adb86a..85f37f3df 100644 --- a/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake +++ b/tribits/core/package_arch/TribitsExternalPackageWriteConfigFile.cmake @@ -42,14 +42,22 @@ include_guard() include(TribitsGeneralMacros) include(TribitsPackageDependencies) +include(TribitsWritePackageConfigFileHelpers) include(MessageWrapper) +################################################################################ +# +# User-level functions +# +################################################################################ + + # @FUNCTION: tribits_extpkg_write_config_file() # -# Write out a ``Config.cmake`` file given the list of include -# directories and libraries for an external package/TPL. +# Write out a ``Config.cmake`` file for a TriBITS TPL given the list +# of include directories and libraries for an external package/TPL. # # Usage:: # @@ -67,6 +75,9 @@ include(MessageWrapper) # and writes that text to the file ```` so see that function # for more details. # +# NOTE: This is used for a classic TriBITS TPL that does **not** use +# ``find_package()`` with modern IMPORTED targets. +# function(tribits_extpkg_write_config_file tplName tplConfigFile) tribits_extpkg_write_config_file_str(${tplName} tplConfigFileStr) file(WRITE "${tplConfigFile}" "${tplConfigFileStr}") @@ -164,6 +175,108 @@ function(tribits_extpkg_install_config_version_file tplName endfunction() +################################################################################ +# +# TriBITS Implementation functions +# +################################################################################ + + +# @FUNCTION: tribits_extpkgwit_create_package_config_file() +# +# Create the ``Config.cmake`` file for a TriBITS external package/TPL +# that is defined by a set of IMPORTED targets by call to +# ``find_package()`` +# +# Usage:: +# +# tribits_extpkgwit_create_package_config_file( +# INNER_FIND_PACKAGE_NAME +# IMPORTED_TARGETS_FOR_ALL_LIBS ... ) +# +function(tribits_extpkgwit_create_package_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) + set(externalPkg ${PARSE_INNER_FIND_PACKAGE_NAME}) + + # Create header for Config.cmake file + set(configFileStr "") + tribits_extpkgwit_append_package_config_file_header_str( + ${tplName} ${externalPkg} configFileStr) + + # Get ${externalPkg} from where you found it before (see note below) + tribits_extpkgwit_append_find_dependency_external_package_str( + ${tplName} ${externalPkg} configFileStr) + + # Pull in upstream Config.cmake files + tribits_extpkg_append_find_upstream_dependencies_str(${tplName} configFileStr) + + # Add the ${tplName}::all_libs target and link to this ${externalPkg} + # package's native IMPORTED targets + tribits_extpkg_append_create_all_libs_target_str( ${tplName} + LIB_TARGETS_LIST ${PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS} + CONFIG_FILE_STR_INOUT configFileStr ) + + # Also link against upstream package's `::all_libs` targets + tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str(${tplName} + ${tplName}::all_libs configFileStr) + + tribits_extpkg_append_tribits_compliant_package_config_vars_str(${tplName} + configFileStr) + + tribits_extpkg_write_package_config_file_from_str(${tplName} "${configFileStr}") +endfunction() + + +function(tribits_extpkgwit_append_find_dependency_external_package_str + tplName externalPkg configFileStrVarInOut + ) + set(configFileStr "${${configFileStrVarInOut}}") + if (${externalPkg}_DIR) + string(APPEND configFileStr + "set(${externalPkg}_DIR \"${${externalPkg}_DIR}\")\n" ) + endif() + string(APPEND configFileStr + "find_dependency(${externalPkg})\n\n") + set(${configFileStrVarInOut} "${configFileStr}" PARENT_SCOPE) +endfunction() +# +# NOTE: Above, ${externalPkg}_DIR is only set when +# find_package(${externalPkg}) finds a package configure file +# ${externalPkg}Config.cmake and **not** when it uses a +# Find${externalPkg}.cmake module. Therefore, there is no reason to set +# ${externalPkg}_DIR in this file if it will not be used. + + +function(tribits_extpkgwit_append_package_config_file_header_str + tplName externalPkg configFileStrVarInOut + ) + set(configFileStr "${${configFileStrVarInOut}}") + string(APPEND configFileStr + "# TriBITS-compliant Package config file for external package/TPL '${tplName}'\n" + "# based on non TriBITS-compliant external package '${externalPkg}' that uses\n" + "# modern IMPORTED targets\n" + "#\n" + "# Generated by CMake, do not edit!\n" + "\n" + "# Guard against multiple inclusion\n" + "if (TARGET ${tplName}::all_libs)\n" + " return()\n" + "endif()\n" + "\n" + "include(CMakeFindDependencyMacro)\n\n" + ) + set(${configFileStrVarInOut} "${configFileStr}" PARENT_SCOPE) +endfunction() + + # @FUNCTION: tribits_extpkg_write_config_file_str() # # Create the text string for a ``Config.cmake`` file given the list @@ -242,7 +355,7 @@ endfunction() # regarded as an error. # # For more details on the handling of individual ``TPL__LIBRARIES`` -# arguments, see `tribits_tpl_libraries_entry_type()`_. +# arguments, see `tribits_extpkg_tpl_libraries_entry_type()`_. # # The list of directories given in ``TPL__INCLUDE_DIRS`` is added to # the ``::all_libs`` target using ``target_include_directories()``. @@ -281,8 +394,8 @@ function(tribits_extpkg_write_config_file_str tplName tplConfigFileStrOut) "\n" ) - # B) Call find_dependency() for all direct dependent upstream TPLs - tribits_extpkg_add_find_upstream_dependencies_str(${tplName} + # B) Pull in upstream packages + tribits_extpkg_append_find_upstream_dependencies_str(${tplName} configFileStr) # C) Create IMPORTED library targets from TPL_${tplName}_LIBRARIES @@ -294,94 +407,70 @@ function(tribits_extpkg_write_config_file_str tplName tplConfigFileStrOut) ) # D) Create the ::all_libs target - tribits_extpkg_create_all_libs_target( + tribits_extpkg_append_create_all_libs_target_str( ${tplName} LIB_TARGETS_LIST ${libTargets} LIB_LINK_FLAGS_LIST ${libLinkFlags} CONFIG_FILE_STR_INOUT configFileStr ) - # E) Set the output + # E) Add standard TriBITS-compliant external package vars + tribits_extpkg_append_tribits_compliant_package_config_vars_str(${tplName} configFileStr) + + # F) Set the output set(${tplConfigFileStrOut} "${configFileStr}" PARENT_SCOPE) endfunction() -# @FUNCTION: tribits_extpkg_add_find_upstream_dependencies_str() +# @FUNCTION: tribits_extpkg_append_find_upstream_dependencies_str() # -# Add code to call find_dependency() for all upstream external packages/TPLs -# listed in ``_LIB_ENABLED_DEPENDENCIES``. +# Add includes for all upstream external packages/TPLs listed in +# ``_LIB_ENABLED_DEPENDENCIES``. # # Usage:: # -# tribits_extpkg_add_find_upstream_dependencies_str(tplName +# tribits_extpkg_append_find_upstream_dependencies_str(tplName # configFileFragStrInOut) # -# NOTE: This also requires that ``_DIR`` be set for each +# NOTE: This also requires that +# ``_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE`` be set for each # external package/TPL listed in ``_LIB_ENABLED_DEPENDENCIES``. # -function(tribits_extpkg_add_find_upstream_dependencies_str +function(tribits_extpkg_append_find_upstream_dependencies_str tplName configFileFragStrInOut ) if (NOT "${${tplName}_LIB_ENABLED_DEPENDENCIES}" STREQUAL "") set(configFileFragStr "${${configFileFragStrInOut}}") - string(APPEND configFileFragStr - "include(CMakeFindDependencyMacro)\n" - "\n" - "# Don't allow find_dependency() to search anything other than _DIR\n" - "set(${tplName}_SearchNoOtherPathsArgs\n" - " NO_DEFAULT_PATH\n" - " NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH\n" - " NO_CMAKE_ENVIRONMENT_PATH\n" - " NO_SYSTEM_ENVIRONMENT_PATH\n" - " NO_CMAKE_PACKAGE_REGISTRY\n" - " NO_CMAKE_SYSTEM_PATH\n" - " NO_CMAKE_SYSTEM_PACKAGE_REGISTRY\n" - " CMAKE_FIND_ROOT_PATH_BOTH\n" - " ONLY_CMAKE_FIND_ROOT_PATH\n" - " NO_CMAKE_FIND_ROOT_PATH\n" - " )\n" - "\n" - ) foreach (upstreamTplDepEntry IN LISTS ${tplName}_LIB_ENABLED_DEPENDENCIES) tribits_extpkg_get_dep_name_and_vis( "${upstreamTplDepEntry}" upstreamTplDepName upstreamTplDepVis) - if ("${${upstreamTplDepName}_DIR}" STREQUAL "") - message(FATAL_ERROR "ERROR: ${upstreamTplDepName}_DIR is empty!") + if (NOT "${${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}" + STREQUAL "" + ) + set(upstreamTplPackageConfigFileDir + "${${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}") + else() + set(upstreamTplPackageConfigFileDir + "\${CMAKE_CURRENT_LIST_DIR}/../${upstreamTplDepName}") endif() string(APPEND configFileFragStr "if (NOT TARGET ${upstreamTplDepName}::all_libs)\n" - " set(${upstreamTplDepName}_DIR \"\${CMAKE_CURRENT_LIST_DIR}/../${upstreamTplDepName}\")\n" - " find_dependency(${upstreamTplDepName} REQUIRED CONFIG \${${tplName}_SearchNoOtherPathsArgs})\n" - " unset(${upstreamTplDepName}_DIR)\n" + " include(\"${upstreamTplPackageConfigFileDir}/${upstreamTplDepName}Config.cmake\")\n" "endif()\n" "\n" ) endforeach() - string(APPEND configFileFragStr - "unset(${tplName}_SearchNoOtherPathsArgs)\n" - "\n" - ) set(${configFileFragStrInOut} "${configFileFragStr}" PARENT_SCOPE) endif() endfunction() # -# NOTE: Above, to be the most flexible, we have to set -# `_DIR` and then call `find_dependency()` instead of just -# including the file: -# -# include("${_DIR}/Config.cmake") -# -# This is to allow finding and depending on external packages/TPLs that may -# have different names than Config.cmake. The CMake -# command find_package() only returns _DIR, not the full -# path to the config file or even the config file name. It is a little bit -# dangerous to use find_dependency() in case the config fire is not found in -# the directory `_DIR` but I am not sure how else to do -# this. -# -# ToDo: It would be great to make the above find_dependency() call **only ** -# search the directory _DIR and no others. That would make +# NOTE: Above, we include the upstream ${upstreamTplDepName}Config.cmake file +# from either beside the current location (in the build tree or the install +# tree) or we use the location set in +# ${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR which would +# have been set by the ${upstreamTplDepName}Config.cmake file itself from an +# upstream install as pulled in from a TriBITS-compliant external package. # @FUNCTION: tribits_extpkg_process_libraries_list() @@ -435,7 +524,7 @@ function(tribits_extpkg_process_libraries_list tplName) set(configFileStr "") set(libTargets "") - set(lastLibProcessed "") + set(previousLibProcessed "") # Iterate through libs in reverse order setting dependencies on the libs # that came before them so CMake will put in right order on the link line. @@ -446,8 +535,7 @@ function(tribits_extpkg_process_libraries_list tplName) list(REVERSE reverseLibraries) foreach (libentry IN LISTS reverseLibraries) - #print_var(libentry) - tribits_tpl_libraries_entry_type(${libentry} libEntryType) + tribits_extpkg_tpl_libraries_entry_type(${libentry} libEntryType) if (libEntryType STREQUAL "UNSUPPORTED_LIB_ENTRY") message_wrapper(SEND_ERROR "ERROR: Can't handle argument '${libentry}' in list TPL_${tplName}_LIBRARIES") @@ -458,7 +546,7 @@ function(tribits_extpkg_process_libraries_list tplName) list(APPEND libLinkFlagsList "${libentry}") else() tribits_extpkg_process_libraries_list_library_entry( - ${tplName} "${libentry}" ${libEntryType} libTargets lastLibProcessed + ${tplName} "${libentry}" ${libEntryType} libTargets previousLibProcessed configFileStr ) endif() endforeach() @@ -474,13 +562,13 @@ function(tribits_extpkg_process_libraries_list tplName) endfunction() -# @FUNCTION: tribits_tpl_libraries_entry_type() +# @FUNCTION: tribits_extpkg_tpl_libraries_entry_type() # # Returns the type of the library entry in the list TPL__LIBRARIES # # Usage:: # -# tribits_tpl_libraries_entry_type( ) +# tribits_extpkg_tpl_libraries_entry_type( ) # # Arguments: # @@ -505,7 +593,7 @@ endfunction() # # * ``UNSUPPORTED_LIB_ENTRY``: An unsupported lib option # -function(tribits_tpl_libraries_entry_type libentry libEntryTypeOut) +function(tribits_extpkg_tpl_libraries_entry_type libentry libEntryTypeOut) string(SUBSTRING "${libentry}" 0 1 firstCharLibEntry) string(SUBSTRING "${libentry}" 0 2 firstTwoCharsLibEntry) if (firstTwoCharsLibEntry STREQUAL "-l") @@ -536,11 +624,11 @@ endfunction() # function(tribits_extpkg_process_libraries_list_library_entry tplName libentry libEntryType - libTargetsInOut lastLibProcessedInOut configFileStrInOut + libTargetsInOut previousLibProcessedInOut configFileStrInOut ) # Set local vars for inout vars set(libTargets ${${libTargetsInOut}}) - set(lastLibProcessed ${${lastLibProcessedInOut}}) + set(previousLibProcessed ${${previousLibProcessedInOut}}) set(configFileStr ${${configFileStrInOut}}) # Get libname tribits_extpkg_get_libname_and_path_from_libentry( @@ -550,24 +638,27 @@ function(tribits_extpkg_process_libraries_list_library_entry if (NOT (prefixed_libname IN_LIST libTargets)) tribits_extpkg_append_add_library_str (${libname} ${prefixed_libname} ${libEntryType} "${libpath}" configFileStr) - if (lastLibProcessed) + if (previousLibProcessed) + # This is not the first lib so we only need to link to the previous lib string(APPEND configFileStr "target_link_libraries(${prefixed_libname}\n" - " INTERFACE tribits::${tplName}::${lastLibProcessed})\n" + " INTERFACE tribits::${tplName}::${previousLibProcessed})\n" ) else() - tribits_extpkg_append_upstream_target_link_libraries_str( ${tplName} + # Only on the first lib do we add dependencies on all of the + # `::all_libs` targets + tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str( ${tplName} ${prefixed_libname} configFileStr ) endif() string(APPEND configFileStr "\n") # Update for next loop - set(lastLibProcessed ${libname}) + set(previousLibProcessed ${libname}) list(APPEND libTargets ${prefixed_libname}) endif() # Set output vars set(${libTargetsInOut} ${libTargets} PARENT_SCOPE) - set(${lastLibProcessedInOut} ${lastLibProcessed} PARENT_SCOPE) + set(${previousLibProcessedInOut} ${previousLibProcessed} PARENT_SCOPE) set(${configFileStrInOut} ${configFileStr} PARENT_SCOPE) endfunction() # NOTE: Above, we only need to link the first library @@ -641,7 +732,7 @@ function(tribits_extpkg_get_libname_from_full_lib_path full_lib_path set(libname "") string(LENGTH "${full_libname}" full_libname_len) if (full_libname_len LESS 0) - tribits_print_invalid_lib_name(${tplName} "${full_lib_path}") + tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}") endif() if (WIN32) # Native windows compilers does not prepend library names with 'lib' @@ -657,14 +748,14 @@ function(tribits_extpkg_get_libname_from_full_lib_path full_lib_path if (last_ext STREQUAL ".framework") set(libname "${full_libname}") else() - tribits_print_invalid_lib_name(${tplName} "${full_lib_path}") + tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}") endif() endif() else() # I.e. Linux # Every other system (i.e. Linux) prepends the library name with 'lib' so # assert for that if (NOT beginsWithLib) - tribits_print_invalid_lib_name(${tplName} "${full_lib_path}") + tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}") else() string(SUBSTRING "${full_libname}" 3 -1 libname) endif() @@ -693,7 +784,7 @@ function(tribits_extpkg_get_libname_from_lib_name_link_option # Assert begging part '-l' string(SUBSTRING "${lib_name_link_option}" 0 2 firstTwoCharsLibEntry) if ( ) - tribits_print_invalid_lib_link_option(${tplName} "${lib_name_link_option}") + tribits_extpkg_print_invalid_lib_link_option(${tplName} "${lib_name_link_option}") endif() # Get from -l string(SUBSTRING "${lib_name_link_option}" 2 -1 libname) @@ -702,19 +793,26 @@ function(tribits_extpkg_get_libname_from_lib_name_link_option endfunction() -function(tribits_print_invalid_lib_name tplName full_libname) +function(tribits_extpkg_print_invalid_lib_name tplName full_libname) message_wrapper(SEND_ERROR "ERROR: TPL_${tplName}_LIBRARIES entry '${full_libname}' not a valid lib file name!") endfunction() -function(tribits_print_invalid_lib_link_option tplName liblinkoption) +function(tribits_extpkg_print_invalid_lib_link_option tplName liblinkoption) message(SEND_ERROR "ERROR: TPL_${tplName}_LIBRARIES entry '${liblinkoption}' not a valid lib name link option!") endfunction() -function(tribits_extpkg_append_upstream_target_link_libraries_str +# @FUNCTION: tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str() +# +# Append text calling `target_link_libraries( ... )` against +# the `::all_libs` targets for all of the direct enabled upstream +# dependencies listed in '_LIB_ENABLED_DEPENDENCIES` (taking into +# account `PUBLIC` and `PRIVATE` dependencies). +# +function(tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str tplName prefix_libname configFileStrInOut ) set(configFileStr "${${configFileStrInOut}}") @@ -750,14 +848,14 @@ endfunction() # libraries being listed on link lines for downstsream library and exec links. -# @FUNCTION: tribits_extpkg_create_all_libs_target() +# @FUNCTION: tribits_extpkg_append_create_all_libs_target_str() # # Creates the ``::all_libs`` target command text using input info and # from ``TPL__INCLUDE_DIRS``. # # Usage:: # -# tribits_extpkg_create_all_libs_target( +# tribits_extpkg_append_create_all_libs_target_str( # # LIB_TARGETS_LIST # LIB_LINK_FLAGS_LIST @@ -777,7 +875,7 @@ endfunction() # ````: [out] A string variable that will be # appended with the ``::all_libs`` target statements. # -function(tribits_extpkg_create_all_libs_target tplName) +function(tribits_extpkg_append_create_all_libs_target_str tplName) # Parse commandline arguments @@ -791,7 +889,7 @@ function(tribits_extpkg_create_all_libs_target tplName) tribits_check_for_unparsed_arguments() # Set short-hand local vars - set(libTarget "${PARSE_LIB_TARGETS_LIST}") + set(libTargets "${PARSE_LIB_TARGETS_LIST}") set(libLinkFlags "${PARSE_LIB_LINK_FLAGS_LIST}") # Capture the initial input string in case the name of the var @@ -845,4 +943,3 @@ function(tribits_extpkg_create_all_libs_target tplName) PARENT_SCOPE) endfunction() - diff --git a/tribits/core/package_arch/TribitsGetPackageEnableStatus.cmake b/tribits/core/package_arch/TribitsGetPackageEnableStatus.cmake index 3fac736a7..3d7c425d7 100644 --- a/tribits/core/package_arch/TribitsGetPackageEnableStatus.cmake +++ b/tribits/core/package_arch/TribitsGetPackageEnableStatus.cmake @@ -69,24 +69,19 @@ function(tribits_get_package_enable_status packageName packageEnableOut tribits_assert_package_enable_status(${packageName}) # Determine which variable, if any, to extract enable status from set(packageEnableVarName "") - if (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "INTERNAL") + if (NOT "${${PROJECT_NAME}_ENABLE_${packageName}}" STREQUAL "") + set(packageEnableVarName ${PROJECT_NAME}_ENABLE_${packageName}) + elseif (NOT "${TPL_ENABLE_${packageName}}" STREQUAL "") + set(packageEnableVarName TPL_ENABLE_${packageName}) + elseif (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "INTERNAL") set(packageEnableVarName ${PROJECT_NAME}_ENABLE_${packageName}) elseif (${packageName}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") - if (NOT "${TPL_ENABLE_${packageName}}" STREQUAL "") - set(packageEnableVarName TPL_ENABLE_${packageName}) - elseif (NOT "${${PROJECT_NAME}_ENABLE_${packageName}}" STREQUAL "") - set(packageEnableVarName ${PROJECT_NAME}_ENABLE_${packageName}) - else() - # If neither is set, select the default var TPL name - set(packageEnableVarName TPL_ENABLE_${packageName}) - endif() - endif() - if (packageEnableVarName) - set(packageEnable ${${packageEnableVarName}}) + set(packageEnableVarName TPL_ENABLE_${packageName}) else() - set(packageEnable "") + message(FATAL_ERROR "Could not determine status of package ${packageName}") endif() - # Set output args + # Extract the enable status, set output args + set(packageEnable ${${packageEnableVarName}}) if (packageEnableOut) set(${packageEnableOut} ${packageEnable} PARENT_SCOPE) endif() diff --git a/tribits/core/package_arch/TribitsGetEnabledSublists.cmake b/tribits/core/package_arch/TribitsGetPackageSublists.cmake similarity index 56% rename from tribits/core/package_arch/TribitsGetEnabledSublists.cmake rename to tribits/core/package_arch/TribitsGetPackageSublists.cmake index 0444ba3dd..ddc392e53 100644 --- a/tribits/core/package_arch/TribitsGetEnabledSublists.cmake +++ b/tribits/core/package_arch/TribitsGetPackageSublists.cmake @@ -40,6 +40,55 @@ include(TribitsGetPackageEnableStatus) +# @FUNCTION: tribits_filter_package_list_from_var() +# +# Filter a list of packages based on several criteria including +# internal/external, enable status (with empty or non-empty) +# +# Usage:: +# +# tribits_filter_package_list_from_var( +# +# ) +# +# Where: +# +# * ````: Name of input list var of packages +# * ````: ``INTERNAL``, ``EXTERNAL`` or "" (i.e. both +# INTERNAL and EXTERNAL packages) (matches +# ``_PACKAGE_BUILD_STATUS``) +# * ````: ``ON`` for elements that match ``TRUE`` , ``OFF`` +# for elements that match ``FALSE`` +# * ````: Enable status is ``NONEMPTY`` (i.e. must have a +# value) or ``INCLUDE_EMPTY`` (matches those with a value and with empty +# ""). +# * ````: The name of the var that will store the filtered +# sublist of packages. +# +function(tribits_filter_package_list_from_var packageListVarName + internalOrExternal enabledFlag enableEmptyStatus packageSublistOut + ) + tribits_assert_include_empty_param(${enableEmptyStatus}) + tribits_get_sublist_internal_external(${packageListVarName} "${internalOrExternal}" + packageListTmp "") + if (enabledFlag AND (enableEmptyStatus STREQUAL "NONEMPTY")) + tribits_get_sublist_enabled(packageListTmp + packageSublist "") + elseif (enabledFlag AND (enableEmptyStatus STREQUAL "INCLUDE_EMPTY")) + tribits_get_sublist_nondisabled(${packageListTmp} packageSublist "") + elseif (NOT enabledFlag AND (enableEmptyStatus STREQUAL "NONEMPTY")) + tribits_get_sublist_disabled(packageListTmp + packageSublist "") + elseif (NOT enabledFlag AND (enableEmptyStatus STREQUAL "INCLUDE_EMPTY")) + tribits_get_sublist_nonenabled(packageListTmp + packageSublist "") + else() + message(FATAL_ERROR "Should never get here!") + endif() + set(${packageSublistOut} ${packageSublist} PARENT_SCOPE) +endfunction() + + # @FUNCTION: tribits_get_sublist_enabled() # # Get sub-list of enabled packages @@ -47,13 +96,13 @@ include(TribitsGetPackageEnableStatus) # Usage:: # # tribits_get_sublist_enabled( -# ) +# [] ) # # On output, ```` contains the sublist of entries in # ```` which evaluate to ``TRUE`` in an ``if ()`` statement. # function(tribits_get_sublist_enabled enableListName - enabledSublistNameOut numEnabledVarOut + enabledSublistNameOut numEnabledVarOut ) set(enabledSublist) foreach(pkgName IN LISTS ${enableListName}) @@ -77,7 +126,7 @@ endfunction() # Usage:: # # tribits_get_sublist_nondisabled( -# ) +# [] ) # # On output, ```` contains the sublist of entries from # ```` for which evaluate to ``TRUE`` or empty ``""`` in an @@ -108,7 +157,7 @@ endfunction() # Usage:: # # tribits_get_sublist_disabled( -# ) +# [] ) # # On output, ```` contains the sublist of entries # ```` which evaluate to ``FALSE`` and is not empty ``""`` in @@ -139,7 +188,7 @@ endfunction() # Usage:: # # tribits_get_sublist_nonenabled( -# ) +# [] ) # # On output, ```` contains the subset of entries in # ```` that evaluate to ``FALSE`` (which can also be empty @@ -161,3 +210,63 @@ function(tribits_get_sublist_nonenabled enableListName set(${numNonenabledVarOut} ${numNonenabled} PARENT_SCOPE) endif() endfunction() + + +# @FUNCTION: tribits_get_sublist_internal_external() +# +# Get sub-list of packages that are INTERNAL, EXTERNAL, or either. +# +# Usage:: +# +# tribits_get_sublist_internal_external( +# [] ) +# +# where: +# +# * `` is either `INTERNAL`, `EXTERNAL` or empty "". +# +# On output, ```` contains the sublist of entries in +# ```` which are either `INTERNAL` or `EXTERNAL` or both +# (if `` is "") based on `_PACKAGE_BUILD_STATUS` +# for each element package name. +# +function(tribits_get_sublist_internal_external inputPackageListName internalOrExternal + sublistNameOut sizeSublistOut + ) + tribits_assert_internal_or_external_arg("${internalOrExternal}") + if (NOT internalOrExternal STREQUAL "") + set(sublist "") + foreach(pkgName IN LISTS ${inputPackageListName}) + if (${pkgName}_PACKAGE_BUILD_STATUS STREQUAL internalOrExternal) + list(APPEND sublist ${pkgName}) + endif() + endforeach() + else() + set(sublist ${${inputPackageListName}}) + endif() + set(${sublistNameOut} ${sublist} PARENT_SCOPE) + if (numEnabledVarOut) + list(LENGTH sublist sizeSublist) + set(${sizeSublistOut} ${sizeSublist} PARENT_SCOPE) + endif() +endfunction() + + +function(tribits_assert_internal_or_external_arg internalOrExternal) + set(allowedValuesList "INTERNAL" "EXTERNAL" "") + if (NOT internalOrExternal IN_LIST allowedValuesList) + message(FATAL_ERROR "ERROR, the argument internalOrExternal=" + "'${internalOrExternal}' is not in the list of allowed values" + ${allowedValuesList} ) + endif() +endfunction() + + +function(tribits_assert_include_empty_param enableEmptyStatus) + if ((NOT enableEmptyStatus STREQUAL "NONEMPTY") AND + (NOT enableEmptyStatus STREQUAL "INCLUDE_EMPTY") + ) + message(FATAL_ERROR "Error, argument enableEmptyStatus='${enableEmptyStatus}'" + " is invalid! Use 'NONEMPTY' or 'INCLUDE_EMPTY'.") + endif() +endfunction() diff --git a/tribits/core/package_arch/TribitsGlobalMacros.cmake b/tribits/core/package_arch/TribitsGlobalMacros.cmake index 63e0930da..3ebfa7d9b 100644 --- a/tribits/core/package_arch/TribitsGlobalMacros.cmake +++ b/tribits/core/package_arch/TribitsGlobalMacros.cmake @@ -44,7 +44,7 @@ include(TribitsTestCategories) include(TribitsGeneralMacros) include(TribitsAddTestHelpers) include(TribitsVerbosePrintVar) -include(TribitsProcessEnabledTpl) +include(TribitsProcessEnabledTpls) include(TribitsInstallHeaders) include(TribitsGetVersionDate) include(TribitsReportInvalidTribitsUsage) @@ -597,13 +597,21 @@ macro(tribits_define_global_options_and_define_extra_repos) if ("${${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES_DEFAULT}" STREQUAL "") set(${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES_DEFAULT OFF) endif() - advanced_set(${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES ${${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES_DEFAULT} CACHE BOOL "Determines if ${PROJECT_NAME}Config.cmake and Config.cmake files are created or not." ) + if ("${${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES_DEFAULT}" STREQUAL "") + set(${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES_DEFAULT OFF) + endif() + advanced_set(${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES + ${${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES_DEFAULT} + CACHE BOOL + "Skip installing the file ${PROJECT_NAME}Config.cmake." + ) + if (NOT ${PROJECT_NAME}_GENERATE_EXPORT_FILE_DEPENDENCIES_DEFAULT) # We need to generate the dependency logic for export dependency files if # asked. @@ -1453,52 +1461,27 @@ macro(tribits_handle_project_extra_link_flags_as_a_tpl) set(${lastLibTplName}_FINDMOD "${${PROJECT_NAME}_TRIBITS_DIR}/common_tpls/FindTPLProjectLastLib.cmake") - # Tack on ${PROJECT_NAME}TribitsLastLib as a dependency to all enabled - # external packages/TPLs - foreach(TPL_NAME ${${PROJECT_NAME}_DEFINED_TPLS}) - list(APPEND ${TPL_NAME}_LIB_DEFINED_DEPENDENCIES ${lastLibTplName}) - if (TPL_ENABLE_${TPL_NAME}) - list(APPEND ${TPL_NAME}_LIB_ENABLED_DEPENDENCIES ${lastLibTplName}) + # Tack on ${PROJECT_NAME}TribitsLastLib as a dependency to all packages + foreach(packageName ${${PROJECT_NAME}_DEFINED_PACKAGES}) + tribits_get_package_enable_status(${packageName} packageEnable "") + list(APPEND ${packageName}_LIB_DEFINED_DEPENDENCIES ${lastLibTplName}) + if (packageEnable) + list(APPEND ${packageName}_LIB_ENABLED_DEPENDENCIES ${lastLibTplName}) endif() endforeach() - # Prepend ${PROJECT_NAME}TribitsLastLib to the list of external packages/TPLs + # Prepend ${PROJECT_NAME}TribitsLastLib to the list of packages list(PREPEND ${PROJECT_NAME}_DEFINED_TPLS ${lastLibTplName}) + list(PREPEND ${PROJECT_NAME}_DEFINED_TOPLEVEL_PACKAGES ${lastLibTplName}) + list(PREPEND ${PROJECT_NAME}_DEFINED_PACKAGES ${lastLibTplName}) set(TPL_ENABLE_${lastLibTplName} ON) set(${lastLibTplName}_PACKAGE_BUILD_STATUS EXTERNAL) - # Tack on ${PROJECT_NAME}TribitsLastLib as a dependency to all enabled - # internal packages - foreach(PACKAGE_NAME ${${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES}) - list(APPEND ${PACKAGE_NAME}_LIB_DEFINED_DEPENDENCIES ${lastLibTplName}) - if (${PROJECT_NAME}_ENABLE_${PACKAGE_NAME}) - list(APPEND ${PACKAGE_NAME}_LIB_ENABLED_DEPENDENCIES ${lastLibTplName}) - endif() - endforeach() - endif() endmacro() -# Gather information from enabled TPLs -# -macro(tribits_process_enabled_tpls) - - tribits_config_code_start_timer(CONFIGURE_TPLS_TIME_START_SECONDS) - - foreach(TPL_NAME ${${PROJECT_NAME}_DEFINED_TPLS}) - if (TPL_ENABLE_${TPL_NAME}) - tribits_process_enabled_tpl(${TPL_NAME}) - endif() - endforeach() - - tribits_config_code_stop_timer(CONFIGURE_TPLS_TIME_START_SECONDS - "\nTotal time to configure enabled external packages/TPLs") - -endmacro() - - # # Macros for setting up the standard environment # @@ -2102,7 +2085,10 @@ macro(tribits_configure_enabled_packages) # other even downstream packages (which is pretty messed up really). # - foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES}) + tribits_filter_package_list_from_var(${PROJECT_NAME}_DEFINED_TOPLEVEL_PACKAGES + INTERNAL ON NONEMPTY ${PROJECT_NAME}_enabledInternalTopLevelPackages) + + foreach(TRIBITS_PACKAGE IN LISTS ${PROJECT_NAME}_enabledInternalTopLevelPackages) # Get all the package sources independent of whether they are enabled or not. # There are some messed up packages that grab parts out of unrelated @@ -2153,7 +2139,7 @@ macro(tribits_configure_enabled_packages) # Tell packages that are also repos they are being processed as a package. set(TRIBITS_PROCESSING_PACKAGE TRUE) - foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES}) + foreach(TRIBITS_PACKAGE IN LISTS ${PROJECT_NAME}_enabledInternalTopLevelPackages) tribits_determine_if_process_package(${TRIBITS_PACKAGE} PROCESS_PACKAGE PACKAGE_ENABLE_STR) diff --git a/tribits/core/package_arch/TribitsWriteClientExportFiles.cmake b/tribits/core/package_arch/TribitsInternalPackageWriteConfigFile.cmake similarity index 67% rename from tribits/core/package_arch/TribitsWriteClientExportFiles.cmake rename to tribits/core/package_arch/TribitsInternalPackageWriteConfigFile.cmake index 7ef8f2666..914825ffa 100644 --- a/tribits/core/package_arch/TribitsWriteClientExportFiles.cmake +++ b/tribits/core/package_arch/TribitsInternalPackageWriteConfigFile.cmake @@ -37,177 +37,115 @@ # ************************************************************************ # @HEADER + +################################################################################ +# +# Module TribitsInternalPackageWriteConfigFile.cmake +# +# This module contains code for generating Config.cmake files for +# internal TriBITS packages. +# +################################################################################ + + include(TribitsGeneralMacros) include(TribitsPkgExportCacheVars) +include(TribitsWritePackageConfigFileHelpers) -### -### WARNING: See "NOTES TO DEVELOPERS" at the bottom of the file -### TribitsPackageMacros.cmake! -### -# This function will take a list and turn it into a space separated string -# adding the prefix to the front of every entry. +# Generate the ${PACKAGE_NAME}Config.cmake file for package PACKAGE_NAME. # -function(tribits_list_to_string LIST PREFIX OUTPUT_STRING) - set(LIST_STRING "") +# ToDo: Finish documentation! +# +function(tribits_write_package_client_export_files PACKAGE_NAME) - foreach(ITEM ${LIST}) - set(LIST_STRING "${LIST_STRING} ${PREFIX}${ITEM}") - endforeach() + if(${PROJECT_NAME}_VERBOSE_CONFIGURE) + message("\nTRIBITS_WRITE_PACKAGE_CLIENT_EXPORT_FILES: ${PACKAGE_NAME}") + endif() - set(${OUTPUT_STRING} ${LIST_STRING} PARENT_SCOPE) -endfunction() + set(buildDirCMakePkgsDir + "${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_CMAKE_PKGS_DIR}") -# This function will take a list of libraries and turn it into a space -# separated string. In this case though the prefix is not always added -# to the front of each entry as libraries can be specified either as a -# name of a library to find or the absolute path to the library file -# with any decorations the system uses. When an absolute path is given -# the entry is used verbatim. -# -function(tribits_library_list_to_string LIST PREFIX OUTPUT_STRING) - set(LIST_STRING "") + set(EXPORT_FILES_ARGS PACKAGE_NAME ${PACKAGE_NAME}) - foreach(ITEM ${LIST}) - string(SUBSTRING ${ITEM} 0 1 OPTION_FLAG) - if(EXISTS ${ITEM} OR OPTION_FLAG STREQUAL "-") - set(LIST_STRING "${LIST_STRING} ${ITEM}") - else() - set(LIST_STRING "${LIST_STRING} ${PREFIX}${ITEM}") + if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) + if(${PROJECT_NAME}_VERBOSE_CONFIGURE) + message("For package ${PACKAGE_NAME} creating ${PACKAGE_NAME}Config.cmake") endif() - endforeach() + set(PACKAGE_CONFIG_FOR_BUILD_BASE_DIR + "${buildDirCMakePkgsDir}/${PACKAGE_NAME}" ) + set(PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles" ) + append_set(EXPORT_FILES_ARGS + PACKAGE_CONFIG_FOR_BUILD_BASE_DIR "${PACKAGE_CONFIG_FOR_BUILD_BASE_DIR}" + PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR "${PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR}" + ) + endif() + + tribits_write_flexible_package_client_export_files(${EXPORT_FILES_ARGS}) + + tribits_write_package_client_export_files_install_targets(${EXPORT_FILES_ARGS}) - set(${OUTPUT_STRING} ${LIST_STRING} PARENT_SCOPE) endfunction() -# @FUNCTION: tribits_write_flexible_package_client_export_files() +# @FUNCTION: tribits_write_package_client_export_files_install_targets() # -# Utility function for writing ``${PACKAGE_NAME}Config.cmake`` files for -# package ``${PACKAGE_NAME}`` with some greater flexibility than what is -# provided by the function ``tribits_write_package_client_export_files()`` and -# to allow unit testing the generation of these files.. +# Create the ``ConfigTargets.cmake`` file and install rules and the +# install() target for the previously generated +# ``Config_install.cmake`` files generated by the +# `tribits_write_flexible_package_client_export_files()`_ function. # # Usage:: # -# tribits_write_flexible_package_client_export_files( +# tribits_write_package_client_export_files_install_targets( # PACKAGE_NAME -# [EXPORT_FILE_VAR_PREFIX ] -# [PACKAGE_CONFIG_FOR_BUILD_BASE_DIR ] -# [PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR ] +# PACKAGE_CONFIG_FOR_BUILD_BASE_DIR +# PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR # ) # -# The arguments are: -# -# ``PACKAGE_NAME `` -# -# Gives the name of the TriBITS package for which the export files should -# be created. -# -# ``EXPORT_FILE_VAR_PREFIX `` -# -# If specified, then all of the variables in the generated export files -# will be prefixed with ``_`` instead of -# ``_``. -# -# ``PACKAGE_CONFIG_FOR_BUILD_BASE_DIR `` -# -# If specified, then the package's ``Config.cmake`` file and -# supporting files will be written under the directory -# ``/`` (and any subdirs that does exist -# will be created). The generated file ``Config.cmake`` is -# for usage of the package in the build tree (not the install tree) and -# points to include directories and libraries in the build tree. -# -# ``PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR `` -# -# If specified, then the package's ``Config_install.cmake`` -# file and supporting files will be written under the directory -# ``/`` (and any subdirs that does exist -# will be created). The file ``${PACKAGE_NAME}Config_install.cmake`` is -# meant to be installed renamed as ``Config.cmake`` in the -# install tree and it points to installed include directories and -# libraries. -# -# NOTE: This function does *not* contain any ``install()`` command itself -# because CMake will not allow those to even be present in scripting mode that -# is used for unit testing this function. Instead, the commands to install -# the files are added by the function -# ``tribits_write_package_client_export_files_install_targets()``. +# The install() commands must be in a different subroutine or CMake will not +# allow you to call the routine, even if you if() it out! # -function(tribits_write_flexible_package_client_export_files) - - if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) - message("\ntribits_write_flexible_package_client_export_files(${ARGN})") - endif() - - # - # A) Process the command-line arguments - # +function(tribits_write_package_client_export_files_install_targets) cmake_parse_arguments( #prefix PARSE #options - "WRITE_INSTALL_CMAKE_CONFIG_FILE" + "" #one_value_keywords - "PACKAGE_NAME;EXPORT_FILE_VAR_PREFIX;PACKAGE_CONFIG_FOR_BUILD_BASE_DIR;PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR" + "PACKAGE_NAME;PACKAGE_CONFIG_FOR_BUILD_BASE_DIR;PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR" #multi_value_keywords "" ${ARGN} ) - tribits_check_for_unparsed_arguments() - - if (NOT ${PROJECT_NAME}_GENERATE_EXPORT_FILE_DEPENDENCIES) - message(SEND_ERROR "Error: Can't generate export dependency files because" - " ${PROJECT_NAME}_GENERATE_EXPORT_FILE_DEPENDENCIES is not ON!") - return() - endif() - set(PACKAGE_NAME ${PARSE_PACKAGE_NAME}) - if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) - print_var(PACKAGE_NAME) - endif() - set(EXPORT_FILE_VAR_PREFIX ${PACKAGE_NAME}) - if (PARSE_EXPORT_FILE_VAR_PREFIX) - set(EXPORT_FILE_VAR_PREFIX ${PARSE_EXPORT_FILE_VAR_PREFIX}) - endif() - if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) - print_var(EXPORT_FILE_VAR_PREFIX) + if (PARSE_PACKAGE_CONFIG_FOR_BUILD_BASE_DIR) + tribits_get_package_config_build_dir_targets_file(${PACKAGE_NAME} + "${PARSE_PACKAGE_CONFIG_FOR_BUILD_BASE_DIR}" packageConfigBuildDirTargetsFile ) + export( + EXPORT ${PACKAGE_NAME} + NAMESPACE ${PACKAGE_NAME}:: + FILE "${packageConfigBuildDirTargetsFile}" ) endif() - # Generate a note discouraging editing of the Config.cmake file - set(DISCOURAGE_EDITING "Do not edit: This file was generated automatically by CMake.") - - # - # B) Deal with the library rpath issues with shared libs - # - - # Write the specification of the rpath if necessary. This is only needed if - # we're building shared libraries. - - if(BUILD_SHARED_LIBS) - string(REPLACE ";" ":" SHARED_LIB_RPATH_COMMAND "${FULL_LIBRARY_DIRS_SET}") - set(SHARED_LIB_RPATH_COMMAND - ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${SHARED_LIB_RPATH_COMMAND}) + if (PARSE_PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR) + install( + FILES + "${PARSE_PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR}/${PACKAGE_NAME}Config_install.cmake" + DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PACKAGE_NAME}" + RENAME ${PACKAGE_NAME}Config.cmake + ) + install( + EXPORT ${PACKAGE_NAME} + NAMESPACE ${PACKAGE_NAME}:: + DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PACKAGE_NAME}" + FILE "${PACKAGE_NAME}Targets.cmake" ) endif() - # - # C) Create the contents of the Config.cmake file for the build tree - # - - tribits_generate_package_config_file_for_build_tree(${PACKAGE_NAME} - EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX}) - - # - # D) Create Config_install.cmake file for the install tree - # - - tribits_generate_package_config_file_for_install_tree(${PACKAGE_NAME} - EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX}) - endfunction() @@ -260,7 +198,7 @@ function(tribits_generate_package_config_file_for_build_tree packageName) # below) set(PACKAGE_CONFIG_CODE "") - tribits_append_dependent_package_config_file_includes_and_enables(${packageName} + tribits_append_dependent_package_config_file_includes_and_enables_str(${packageName} EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX} EXT_PKG_CONFIG_FILE_BASE_DIR "${buildDirExtPkgsDir}" PKG_CONFIG_FILE_BASE_DIR "${buildDirCMakePkgsDir}" @@ -280,9 +218,12 @@ function(tribits_generate_package_config_file_for_build_tree packageName) "${PACKAGE_CONFIG_FOR_BUILD_BASE_DIR}" packageConfigBuildDirTargetsFile ) string(APPEND PACKAGE_CONFIG_CODE "\n# Import ${packageName} targets\n" - "include(\"${packageConfigBuildDirTargetsFile}\")") + "include(\"${packageConfigBuildDirTargetsFile}\")\n") endif() + tribits_extpkg_append_tribits_compliant_package_config_vars_str(${packageName} + PACKAGE_CONFIG_CODE) + tribits_set_compiler_vars_for_config_file(BUILD_DIR) if ("${CMAKE_CXX_FLAGS}" STREQUAL "") @@ -348,30 +289,10 @@ function(tribits_generate_package_config_file_for_install_tree packageName) set(EXPORT_FILE_VAR_PREFIX ${packageName}) endif() - # Set the include and library directories relative to the location - # at which the ${PROJECT_NAME}Config.cmake file is going to be - # installed. Note the variable reference below is escaped so it - # won't be replaced until a client project attempts to locate - # directories using the installed config file. This is to deal with - # installers that allow relocation of the install tree at *install* - # time. - # The export files are typically installed in - # //cmake//. - # The relative path to the installation dir is hence k*(../) + ../../, where - # k is the number of components in . Extract those here. - # This doesn't work if ${${PROJECT_NAME}_INSTALL_LIB_DIR} contains "./" or - # "../" components, but really, it never did. All of this should actually be - # handled by CMake's configure_package_config_file(). - string(REPLACE "/" ";" PATH_LIST ${${PROJECT_NAME}_INSTALL_LIB_DIR}) - set(RELATIVE_PATH "../..") - foreach(PATH ${PATH_LIST}) - set(RELATIVE_PATH "${RELATIVE_PATH}/..") - endforeach() - # Custom code in configuration file. set(PACKAGE_CONFIG_CODE "") - tribits_append_dependent_package_config_file_includes_and_enables(${packageName} + tribits_append_dependent_package_config_file_includes_and_enables_str(${packageName} EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX} EXT_PKG_CONFIG_FILE_BASE_DIR "\${CMAKE_CURRENT_LIST_DIR}/../../${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR}" @@ -381,7 +302,10 @@ function(tribits_generate_package_config_file_for_install_tree packageName) # Import install targets string(APPEND PACKAGE_CONFIG_CODE "\n# Import ${packageName} targets\n" - "include(\"\${CMAKE_CURRENT_LIST_DIR}/${packageName}Targets.cmake\")") + "include(\"\${CMAKE_CURRENT_LIST_DIR}/${packageName}Targets.cmake\")\n") + + tribits_extpkg_append_tribits_compliant_package_config_vars_str(${packageName} + PACKAGE_CONFIG_CODE) # Write the specification of the rpath if necessary. This is only needed if # we're building shared libraries. @@ -407,7 +331,137 @@ function(tribits_generate_package_config_file_for_install_tree packageName) endfunction() -# @FUNCTION: tribits_append_dependent_package_config_file_includes_and_enables() +# @FUNCTION: tribits_write_flexible_package_client_export_files() +# +# Utility function for writing ``${PACKAGE_NAME}Config.cmake`` files for +# package ``${PACKAGE_NAME}`` with some greater flexibility than what is +# provided by the function ``tribits_write_package_client_export_files()`` and +# to allow unit testing the generation of these files.. +# +# Usage:: +# +# tribits_write_flexible_package_client_export_files( +# PACKAGE_NAME +# [EXPORT_FILE_VAR_PREFIX ] +# [PACKAGE_CONFIG_FOR_BUILD_BASE_DIR ] +# [PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR ] +# ) +# +# The arguments are: +# +# ``PACKAGE_NAME `` +# +# Gives the name of the TriBITS package for which the export files should +# be created. +# +# ``EXPORT_FILE_VAR_PREFIX `` +# +# If specified, then all of the variables in the generated export files +# will be prefixed with ``_`` instead of +# ``_``. +# +# ``PACKAGE_CONFIG_FOR_BUILD_BASE_DIR `` +# +# If specified, then the package's ``Config.cmake`` file and +# supporting files will be written under the directory +# ``/`` (and any subdirs that does exist +# will be created). The generated file ``Config.cmake`` is +# for usage of the package in the build tree (not the install tree) and +# points to include directories and libraries in the build tree. +# +# ``PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR `` +# +# If specified, then the package's ``Config_install.cmake`` +# file and supporting files will be written under the directory +# ``/`` (and any subdirs that does exist +# will be created). The file ``${PACKAGE_NAME}Config_install.cmake`` is +# meant to be installed renamed as ``Config.cmake`` in the +# install tree and it points to installed include directories and +# libraries. +# +# NOTE: This function does *not* contain any ``install()`` command itself +# because CMake will not allow those to even be present in scripting mode that +# is used for unit testing this function. Instead, the commands to install +# the files are added by the function +# ``tribits_write_package_client_export_files_install_targets()``. +# +function(tribits_write_flexible_package_client_export_files) + + if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) + message("\ntribits_write_flexible_package_client_export_files(${ARGN})") + endif() + + # + # A) Process the command-line arguments + # + + cmake_parse_arguments( + #prefix + PARSE + #options + "WRITE_INSTALL_CMAKE_CONFIG_FILE" + #one_value_keywords + "PACKAGE_NAME;EXPORT_FILE_VAR_PREFIX;PACKAGE_CONFIG_FOR_BUILD_BASE_DIR;PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR" + #multi_value_keywords + "" + ${ARGN} + ) + + tribits_check_for_unparsed_arguments() + + if (NOT ${PROJECT_NAME}_GENERATE_EXPORT_FILE_DEPENDENCIES) + message(SEND_ERROR "Error: Can't generate export dependency files because" + " ${PROJECT_NAME}_GENERATE_EXPORT_FILE_DEPENDENCIES is not ON!") + return() + endif() + + set(PACKAGE_NAME ${PARSE_PACKAGE_NAME}) + if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) + print_var(PACKAGE_NAME) + endif() + + set(EXPORT_FILE_VAR_PREFIX ${PACKAGE_NAME}) + if (PARSE_EXPORT_FILE_VAR_PREFIX) + set(EXPORT_FILE_VAR_PREFIX ${PARSE_EXPORT_FILE_VAR_PREFIX}) + endif() + if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) + print_var(EXPORT_FILE_VAR_PREFIX) + endif() + + # Generate a note discouraging editing of the Config.cmake file + set(DISCOURAGE_EDITING "Do not edit: This file was generated automatically by CMake.") + + # + # B) Deal with the library rpath issues with shared libs + # + + # Write the specification of the rpath if necessary. This is only needed if + # we're building shared libraries. + + if(BUILD_SHARED_LIBS) + string(REPLACE ";" ":" SHARED_LIB_RPATH_COMMAND "${FULL_LIBRARY_DIRS_SET}") + set(SHARED_LIB_RPATH_COMMAND + ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${SHARED_LIB_RPATH_COMMAND}) + endif() + + # + # C) Create the contents of the Config.cmake file for the build tree + # + + tribits_generate_package_config_file_for_build_tree(${PACKAGE_NAME} + EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX}) + + # + # D) Create Config_install.cmake file for the install tree + # + + tribits_generate_package_config_file_for_install_tree(${PACKAGE_NAME} + EXPORT_FILE_VAR_PREFIX ${EXPORT_FILE_VAR_PREFIX}) + +endfunction() + + +# @FUNCTION: tribits_append_dependent_package_config_file_includes_and_enables_str() # # Append the includes for upstream external packages (TPLs) and internal # packages as well as the enables/disables for upstream dependencies to an @@ -415,7 +469,7 @@ endfunction() # # Usage:: # -# tribits_append_dependent_package_config_file_includes_and_enables( +# tribits_append_dependent_package_config_file_includes_and_enables_str( # # EXPORT_FILE_VAR_PREFIX # EXT_PKG_CONFIG_FILE_BASE_DIR @@ -423,10 +477,10 @@ endfunction() # CONFIG_FILE_STR_INOUT # ) # -function(tribits_append_dependent_package_config_file_includes_and_enables packageName) +function(tribits_append_dependent_package_config_file_includes_and_enables_str packageName) if (TRIBITS_WRITE_FLEXIBLE_PACKAGE_CLIENT_EXPORT_FILES_DEBUG_DUMP) - message("tribits_append_dependent_package_config_file_includes_and_enables(${ARGV})") + message("tribits_append_dependent_package_config_file_includes_and_enables_str(${ARGV})") endif() # Parse input @@ -474,11 +528,17 @@ function(tribits_append_dependent_package_config_file_includes_and_enables packa foreach(depPkg IN LISTS ${packageName}_LIB_ENABLED_DEPENDENCIES) set(packageConfigBaseDir "") # Initially, no add include() if (${depPkg}_PACKAGE_BUILD_STATUS STREQUAL "INTERNAL") - set(packageConfigBaseDir "${pkgConfigFileBaseDir}/${depPkg}") + set(packageConfigBaseDir "\${CMAKE_CURRENT_LIST_DIR}/../${depPkg}") elseif (${depPkg}_PACKAGE_BUILD_STATUS STREQUAL "EXTERNAL") - set(packageConfigBaseDir "${extPkgConfigFileBaseDir}/${depPkg}") + if (NOT "${${depPkg}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}" STREQUAL "") + set(packageConfigBaseDir "${${depPkg}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}") + else() + set(packageConfigBaseDir + "\${CMAKE_CURRENT_LIST_DIR}/../../${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR}/${depPkg}") + endif() else() - message(FATAL_ERROR "ERROR: ${depPkg}_PACKAGE_BUILD_STATUS='${${depPkg}_PACKAGE_BUILD_STATUS}' invalid!") + message(FATAL_ERROR "ERROR:" + " ${depPkg}_PACKAGE_BUILD_STATUS='${${depPkg}_PACKAGE_BUILD_STATUS}' invalid!") endif() if (packageConfigBaseDir) string(APPEND configFileStr @@ -495,66 +555,6 @@ function(tribits_append_dependent_package_config_file_includes_and_enables packa endfunction() -# @FUNCTION: tribits_write_package_client_export_files_install_targets() -# -# Create the ``ConfigTargets.cmake`` file and install rules and the -# install() target for the previously generated -# ``Config_install.cmake`` files generated by the -# `tribits_write_flexible_package_client_export_files()`_ function. -# -# Usage:: -# -# tribits_write_package_client_export_files_install_targets( -# PACKAGE_NAME -# PACKAGE_CONFIG_FOR_BUILD_BASE_DIR -# PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR -# ) -# -# The install() commands must be in a different subroutine or CMake will not -# allow you to call the routine, even if you if() it out! -# -function(tribits_write_package_client_export_files_install_targets) - - cmake_parse_arguments( - #prefix - PARSE - #options - "" - #one_value_keywords - "PACKAGE_NAME;PACKAGE_CONFIG_FOR_BUILD_BASE_DIR;PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR" - #multi_value_keywords - "" - ${ARGN} - ) - - set(PACKAGE_NAME ${PARSE_PACKAGE_NAME}) - - if (PARSE_PACKAGE_CONFIG_FOR_BUILD_BASE_DIR) - tribits_get_package_config_build_dir_targets_file(${PACKAGE_NAME} - "${PARSE_PACKAGE_CONFIG_FOR_BUILD_BASE_DIR}" packageConfigBuildDirTargetsFile ) - export( - EXPORT ${PACKAGE_NAME} - NAMESPACE ${PACKAGE_NAME}:: - FILE "${packageConfigBuildDirTargetsFile}" ) - endif() - - if (PARSE_PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR) - install( - FILES - "${PARSE_PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR}/${PACKAGE_NAME}Config_install.cmake" - DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PACKAGE_NAME}" - RENAME ${PACKAGE_NAME}Config.cmake - ) - install( - EXPORT ${PACKAGE_NAME} - NAMESPACE ${PACKAGE_NAME}:: - DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PACKAGE_NAME}" - FILE "${PACKAGE_NAME}Targets.cmake" ) - endif() - -endfunction() - - # Function to return the full path the targets file for the # Config.cmake file in the build tree. # @@ -567,219 +567,6 @@ function(tribits_get_package_config_build_dir_targets_file PACKAGE_NAME endfunction() -# Generate the ${PACKAGE_NAME}Config.cmake file for package PACKAGE_NAME. -# -# ToDo: Finish documentation! -# -function(tribits_write_package_client_export_files PACKAGE_NAME) - - if(${PROJECT_NAME}_VERBOSE_CONFIGURE) - message("\nTRIBITS_WRITE_PACKAGE_CLIENT_EXPORT_FILES: ${PACKAGE_NAME}") - endif() - - set(buildDirCMakePkgsDir - "${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_CMAKE_PKGS_DIR}") - - set(EXPORT_FILES_ARGS PACKAGE_NAME ${PACKAGE_NAME}) - - if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) - if(${PROJECT_NAME}_VERBOSE_CONFIGURE) - message("For package ${PACKAGE_NAME} creating ${PACKAGE_NAME}Config.cmake") - endif() - set(PACKAGE_CONFIG_FOR_BUILD_BASE_DIR - "${buildDirCMakePkgsDir}/${PACKAGE_NAME}" ) - set(PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR - "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles" ) - append_set(EXPORT_FILES_ARGS - PACKAGE_CONFIG_FOR_BUILD_BASE_DIR "${PACKAGE_CONFIG_FOR_BUILD_BASE_DIR}" - PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR "${PACKAGE_CONFIG_FOR_INSTALL_BASE_DIR}" - ) - endif() - - tribits_write_flexible_package_client_export_files(${EXPORT_FILES_ARGS}) - - tribits_write_package_client_export_files_install_targets(${EXPORT_FILES_ARGS}) - -endfunction() - - -# Write the outer TriBITS Config.cmake file -# -# If ${PROJECT_NAME}_VERSION is not set or is '' on input, then it will be set -# to 0.0.0 in order to create the ${PROJECT_NAME}ConfigVersion.cmake file. -# -# ToDo: Finish documentation! -# -function(tribits_write_project_client_export_files) - - set(EXPORT_FILE_VAR_PREFIX ${PROJECT_NAME}) - - # Reversing the package list so that libraries will be produced in order of - # most dependent to least dependent. - set(PACKAGE_LIST ${${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES}) - if (PACKAGE_LIST) - list(REVERSE PACKAGE_LIST) - endif() - - # Loop over all packages to determine which were enabled. Then build a list - # of all their libraries/includes in the proper order for linking - set(FULL_PACKAGE_SET "") - set(FULL_LIBRARY_SET "") - foreach(TRIBITS_PACKAGE ${PACKAGE_LIST}) - if(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}) - list(APPEND FULL_PACKAGE_SET ${TRIBITS_PACKAGE}) - list(APPEND FULL_LIBRARY_SET ${${TRIBITS_PACKAGE}_LIBRARIES}) - endif() - endforeach() - - set(${PROJECT_NAME}_CONFIG_LIBRARIES ${FULL_LIBRARY_SET}) - - # Reversing the tpl list so that the list of tpls will be produced in - # order of most dependent to least dependent. - if (${PROJECT_NAME}_DEFINED_TPLS) - set(TPL_LIST ${${PROJECT_NAME}_DEFINED_TPLS}) - list(REVERSE TPL_LIST) - endif() - - # Loop over all TPLs to determine which were enabled. Then build a list - # of all their libraries/includes in the proper order for linking - set(FULL_TPL_SET "") - set(FULL_TPL_LIBRARY_SET "") - foreach(TPL ${TPL_LIST}) - if(TPL_ENABLE_${TPL}) - list(APPEND FULL_TPL_SET ${TPL}) - list(APPEND FULL_TPL_LIBRARY_SET ${TPL_${TPL}_LIBRARIES}) - endif() - endforeach() - - set(${PROJECT_NAME}_CONFIG_TPL_LIBRARIES ${FULL_TPL_LIBRARY_SET}) - - # - # Configure two files for finding ${PROJECT_NAME}. One for the build tree - # and one for installing - # - - # Generate a note discouraging editing of the Config.cmake file - set(DISCOURAGE_EDITING "Do not edit: This file was generated automatically by CMake.") - - # Write the specification of the rpath if necessary. This is only needed if - # we're building shared libraries. - if(BUILD_SHARED_LIBS) - string(REPLACE ";" ":" SHARED_LIB_RPATH_COMMAND - "${${PROJECT_NAME}_CONFIG_LIBRARY_DIRS}") - set(SHARED_LIB_RPATH_COMMAND ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${SHARED_LIB_RPATH_COMMAND}) - endif() - - # Custom code in configuration file. - set(PROJECT_CONFIG_CODE "") - - # Appending the logic to include each package's config file. - set(LOAD_CODE "# Load configurations from enabled packages") - foreach(TRIBITS_PACKAGE ${FULL_PACKAGE_SET}) - set(LOAD_CODE "${LOAD_CODE} -include(\"${${TRIBITS_PACKAGE}_BINARY_DIR}/${TRIBITS_PACKAGE}Config.cmake\")") - endforeach() - set(PROJECT_CONFIG_CODE "${PROJECT_CONFIG_CODE}\n${LOAD_CODE}") - - tribits_set_compiler_vars_for_config_file(INSTALL_DIR) - - if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) - # In TribitsProjectConfigTemplate.cmake.in, we would like to preserve - # ${}-variables after the conversion to TribitsProjectConfigTemplate.cmake. - # To this end, one typically uses the @-syntax for variables. That doesn't - # support nested variables, however. Use ${PDOLLAR} as a workaround, cf. - # . - set(PDOLLAR "$") - set(tribitsInstallationDir - "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") - set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR "") - configure_file( - "${tribitsInstallationDir}/TribitsProjectConfigTemplate.cmake.in" - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" ) - endif() - - ###### - # Create a configure file for the install tree and set the install target for it. This - # file isn't generally useful inside the build tree. It will be placed in the base - # install directory for ${PROJECT_NAME} when installed. - ###### - - # Set the include and library directories relative to the location - # at which the ${PROJECT_NAME}Config.cmake file is going to be - # installed. Note the variable reference below is escaped so it - # won't be replaced until a client project attempts to locate - # directories using the installed config file. This is to deal with - # installers that allow relocation of the install tree at *install* - # time. - # The export files are typically installed in - # //cmake//. - # The relative path to the installation dir is hence k*(../) + ../../, where - # k is the number of components in . Extract those here. - # This doesn't work if ${${PROJECT_NAME}_INSTALL_LIB_DIR} contains "./" or - # "../" components, but really, it never did. All of this should actually be - # handled by CMake's configure_package_config_file(). - string(REPLACE "/" ";" PATH_LIST ${${PROJECT_NAME}_INSTALL_LIB_DIR}) - set(RELATIVE_PATH "../..") - foreach(PATH ${PATH_LIST}) - set(RELATIVE_PATH "${RELATIVE_PATH}/..") - endforeach() - - # Write the specification of the rpath if necessary. This is only needed if - # we're building shared libraries. - if(BUILD_SHARED_LIBS) - set(SHARED_LIB_RPATH_COMMAND - "${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_LIB_DIR}" - ) - endif() - - if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) - - tribits_set_compiler_vars_for_config_file(INSTALL_DIR) - - # Custom code in configuration file. - set(PROJECT_CONFIG_CODE "") - - set(PDOLLAR "$") # Hack used in configure file below - - if (IS_ABSOLUTE "${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") - set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR "${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") - else() - set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR - "${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") - endif() - - configure_file( - "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}/TribitsProjectConfigTemplate.cmake.in" - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config_install.cmake" - ) - - install( - FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config_install.cmake" - DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PROJECT_NAME}" - RENAME ${PROJECT_NAME}Config.cmake - ) - endif() - - # - # Configure the version file for ${PROJECT_NAME} - # - include(CMakePackageConfigHelpers) - if ("${${PROJECT_NAME}_VERSION}" STREQUAL "") - set(${PROJECT_NAME}_VERSION 0.0.0) - endif() - write_basic_package_version_file( - ${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - VERSION ${${PROJECT_NAME}_VERSION} - COMPATIBILITY SameMajorVersion - ) - install( - FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PROJECT_NAME}" - ) - -endfunction() - - macro(tribits_set_compiler_var_for_config_file LANG FOR_DIR) if (NOT "${CMAKE_${LANG}_COMPILER_FOR_CONFIG_FILE_${FOR_DIR}}" STREQUAL "") set(CMAKE_${LANG}_COMPILER_FOR_CONFIG_FILE diff --git a/tribits/core/package_arch/TribitsPackageMacros.cmake b/tribits/core/package_arch/TribitsPackageMacros.cmake index 2886b2b95..0a091c4d2 100644 --- a/tribits/core/package_arch/TribitsPackageMacros.cmake +++ b/tribits/core/package_arch/TribitsPackageMacros.cmake @@ -38,7 +38,7 @@ # @HEADER include(TribitsPackageSetupCompilerFlags) -include(TribitsWriteClientExportFiles) +include(TribitsInternalPackageWriteConfigFile) include(TribitsGeneralMacros) include(TribitsLibIsTestOnly) diff --git a/tribits/core/package_arch/TribitsPrintEnabledPackagesLists.cmake b/tribits/core/package_arch/TribitsPrintEnabledPackagesLists.cmake index b49d96372..eb42f8be3 100644 --- a/tribits/core/package_arch/TribitsPrintEnabledPackagesLists.cmake +++ b/tribits/core/package_arch/TribitsPrintEnabledPackagesLists.cmake @@ -37,7 +37,7 @@ # ************************************************************************ # @HEADER -include(TribitsGetEnabledSublists) +include(TribitsGetPackageSublists) # @FUNCTION: tribits_print_enables_before_adjust_package_enables() @@ -50,18 +50,24 @@ include(TribitsGetEnabledSublists) # tribits_print_enables_before_adjust_package_enables() # function(tribits_print_enables_before_adjust_package_enables) - tribits_print_internal_toplevel_package_list_enable_status( - "\nExplicitly enabled top-level packages on input (by user)" ON FALSE) - tribits_print_internal_package_list_enable_status( - "\nExplicitly enabled packages on input (by user)" ON FALSE) - tribits_print_internal_toplevel_package_list_enable_status( - "\nExplicitly disabled top-level packages on input (by user or by default)" OFF FALSE) - tribits_print_internal_package_list_enable_status( - "\nExplicitly disabled packages on input (by user or by default)" OFF FALSE) - tribits_print_tpl_list_enable_status( - "\nExplicitly enabled external packages/TPLs on input (by user)" ON FALSE) - tribits_print_tpl_list_enable_status( - "\nExplicitly disabled external packages/TPLs on input (by user or by default)" OFF FALSE) + tribits_print_toplevel_package_list_enable_status( + "\nExplicitly enabled top-level packages on input (by user)" + INTERNAL ON NONEMPTY) + tribits_print_package_list_enable_status( + "\nExplicitly enabled packages on input (by user)" INTERNAL ON NONEMPTY) + tribits_print_toplevel_package_list_enable_status( + "\nExplicitly disabled top-level packages on input (by user or by default)" + INTERNAL OFF NONEMPTY) + tribits_print_package_list_enable_status( + "\nExplicitly disabled packages on input (by user or by default)" + INTERNAL OFF NONEMPTY) + tribits_print_package_list_enable_status( + "\nExplicitly enabled external packages/TPLs on input (by user)" EXTERNAL ON NONEMPTY) + tribits_print_package_list_enable_status( + "\nExplicitly disabled external packages/TPLs on input (by user or by default)" + EXTERNAL OFF NONEMPTY) + tribits_print_package_build_status("\nInitial package build status:\n" + "-- Initial: " PRINT_ALL) endfunction() @@ -75,111 +81,97 @@ endfunction() # tribits_print_enables_after_adjust_package_enables() # function(tribits_print_enables_after_adjust_package_enables) - tribits_print_prefix_string_and_list( - "\nFinal set of enabled top-level packages" - "${${PROJECT_NAME}_ENABLED_INTERNAL_TOPLEVEL_PACKAGES}") - tribits_print_prefix_string_and_list( - "\nFinal set of enabled packages" - "${${PROJECT_NAME}_ENABLED_INTERNAL_PACKAGES}") - tribits_print_internal_toplevel_package_list_enable_status( - "\nFinal set of non-enabled top-level packages" OFF TRUE) - tribits_print_internal_package_list_enable_status( - "\nFinal set of non-enabled packages" OFF TRUE) - tribits_print_tpl_list_enable_status( - "\nFinal set of enabled external packages/TPLs" ON FALSE) - tribits_print_tpl_list_enable_status( - "\nFinal set of non-enabled external packages/TPLs" OFF TRUE) + tribits_print_toplevel_package_list_enable_status( + "\nFinal set of enabled top-level packages" INTERNAL ON NONEMPTY) + tribits_print_package_list_enable_status( + "\nFinal set of enabled packages" INTERNAL ON NONEMPTY) + tribits_print_toplevel_package_list_enable_status( + "\nFinal set of non-enabled top-level packages" INTERNAL OFF INCLUDE_EMPTY) + tribits_print_package_list_enable_status( + "\nFinal set of non-enabled packages" INTERNAL OFF INCLUDE_EMPTY) + tribits_print_toplevel_package_list_enable_status( + "\nFinal set of enabled top-level external packages/TPLs" EXTERNAL ON NONEMPTY) + tribits_print_package_list_enable_status( + "\nFinal set of enabled external packages/TPLs" EXTERNAL ON NONEMPTY) + tribits_print_toplevel_package_list_enable_status( + "\nFinal set of non-enabled top-level external packages/TPLs" EXTERNAL OFF INCLUDE_EMPTY) + tribits_print_package_list_enable_status( + "\nFinal set of non-enabled external packages/TPLs" EXTERNAL OFF INCLUDE_EMPTY) + tribits_print_package_build_status("\nFinal package build status (enabled only):\n" + "-- Final: " PRINT_ONLY_ENABLED) endfunction() -# Function that prints the current set of enabled internal top-level packages +# Function that prints the current set of enabled internal or external +# top-level packages # -function(tribits_print_internal_toplevel_package_list_enable_status - DOCSTRING ENABLED_FLAG INCLUDE_EMPTY +function(tribits_print_toplevel_package_list_enable_status + docString internalOrExternal enabledFlag enableEmptyStatus ) tribits_print_packages_list_enable_status_from_var( - ${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES - "${DOCSTRING}" ${ENABLED_FLAG} ${INCLUDE_EMPTY} ) + ${PROJECT_NAME}_DEFINED_TOPLEVEL_PACKAGES + "${docString}" "${internalOrExternal}" ${enabledFlag} ${enableEmptyStatus} ) endfunction() # Prints the current set of enabled/disabled internal packages # -function(tribits_print_internal_package_list_enable_status - DOCSTRING ENABLED_FLAG INCLUDE_EMPTY +function(tribits_print_package_list_enable_status + docString internalOrExternal enabledFlag enableEmptyStatus ) - if (ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_enabled( - ${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES - internalPackagesEnableStatusList "") - elseif (ENABLED_FLAG AND INCLUDE_EMPTY) - tribits_get_sublist_nondisabled( - ${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES ${PROJECT_NAME} - internalPackagesEnableStatusList "") - elseif (NOT ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_disabled( - ${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES - internalPackagesEnableStatusList "") - else() # NOT ENABLED_FLAG AND INCLUDE_EMPTY - tribits_get_sublist_nonenabled( - ${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES - internalPackagesEnableStatusList "") - endif() - tribits_print_prefix_string_and_list("${DOCSTRING}" - "${internalPackagesEnableStatusList}") -endfunction() - - -# Print the current set of enabled/disabled TPLs -# -function(tribits_print_tpl_list_enable_status DOCSTRING ENABLED_FLAG INCLUDE_EMPTY) - if (ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_enabled( ${PROJECT_NAME}_DEFINED_TPLS - tplsEnableStatusList "") - elseif (ENABLED_FLAG AND INCLUDE_EMPTY) - tribits_get_sublist_nondisabled( ${PROJECT_NAME}_DEFINED_TPLS - tplsEnableStatusList "") - elseif (NOT ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_disabled( ${PROJECT_NAME}_DEFINED_TPLS - tplsEnableStatusList "") - else() # NOT ENABLED_FLAG AND INCLUDE_EMPTY - tribits_get_sublist_nonenabled( ${PROJECT_NAME}_DEFINED_TPLS - tplsEnableStatusList "") - endif() - tribits_print_prefix_string_and_list("${DOCSTRING}" "${tplsEnableStatusList}") + tribits_print_packages_list_enable_status_from_var( + ${PROJECT_NAME}_DEFINED_PACKAGES + "${docString}" "${internalOrExternal}" ${enabledFlag} ${enableEmptyStatus} ) endfunction() # Print the current set of enabled/disabled packages given input list of # packages # -function(tribits_print_packages_list_enable_status_from_var PACKAGES_LIST_VAR - DOCSTRING ENABLED_FLAG INCLUDE_EMPTY +function(tribits_print_packages_list_enable_status_from_var packageListVarName + docString internalOrExternal enabledFlag enableEmptyStatus ) - if (ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_enabled(${PACKAGES_LIST_VAR} - enableStatusList "") - elseif (ENABLED_FLAG AND INCLUDE_EMPTY) - tribits_get_sublist_nondisabled(${PACKAGES_LIST_VAR} enableStatusList "") - elseif (NOT ENABLED_FLAG AND NOT INCLUDE_EMPTY) - tribits_get_sublist_disabled(${PACKAGES_LIST_VAR} - enableStatusList "") - else() # NOT ENABLED_FLAG AND INCLUDE_EMPTY - tribits_get_sublist_nonenabled(${PACKAGES_LIST_VAR} - enableStatusList "") - endif() - tribits_print_prefix_string_and_list("${DOCSTRING}" "${enableStatusList}") + tribits_filter_package_list_from_var(${packageListVarName} + "${internalOrExternal}" "${enabledFlag}" ${enableEmptyStatus} packageSublist) + tribits_print_prefix_string_and_list("${docString}" packageSublist) endfunction() # Print out a list with white-space separators with an initial doc string # -function(tribits_print_prefix_string_and_list DOCSTRING LIST_TO_PRINT) - string(REPLACE ";" " " LIST_TO_PRINT_STR "${LIST_TO_PRINT}") - list(LENGTH LIST_TO_PRINT NUM_ELEMENTS) - if (NUM_ELEMENTS GREATER "0") - message("${DOCSTRING}: ${LIST_TO_PRINT_STR} ${NUM_ELEMENTS}") +function(tribits_print_prefix_string_and_list docString listNameToPrint) + string(REPLACE ";" " " listToPrintStr "${${listNameToPrint}}") + list(LENGTH ${listNameToPrint} numElements) + if (numElements GREATER "0") + message("${docString}: ${listToPrintStr} ${numElements}") + else() + message("${docString}: ${numElements}") + endif() +endfunction() + + +# Print out the `_PACKAGE_BUILD_STATUS` vars +# +function(tribits_print_package_build_status summaryHeaderStr prefixStr + printEnabledOpt + ) + if (printEnabledOpt STREQUAL "PRINT_ALL") + set(printAll ON) + elseif (printEnabledOpt STREQUAL "PRINT_ONLY_ENABLED") + set(printAll OFF) else() - message("${DOCSTRING}: ${NUM_ELEMENTS}") + message(FATAL_ERROR + "Error, invalid value for printEnabledOpt='${printEnabledOpt}'") + endif() + + if (${PROJECT_NAME}_DUMP_PACKAGE_BUILD_STATUS) + message("${summaryHeaderStr}") + foreach(packageName IN LISTS ${PROJECT_NAME}_DEFINED_PACKAGES) + tribits_get_package_enable_status(${packageName} packageEnable "") + if (printAll OR packageEnable) + message("${prefixStr}${packageName}_PACKAGE_BUILD_STATUS=" + "${${packageName}_PACKAGE_BUILD_STATUS}") + endif() + endforeach() endif() endfunction() diff --git a/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake b/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake deleted file mode 100644 index f6925f208..000000000 --- a/tribits/core/package_arch/TribitsProcessEnabledTpl.cmake +++ /dev/null @@ -1,168 +0,0 @@ -# @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 - - -# Standard TriBITS Includes -include(TribitsExternalPackageFindTplHelpers) -include(TribitsExternalPackageWriteConfigFile) -include(TribitsTplFindIncludeDirsAndLibraries) -include(TribitsGeneralMacros) - -# Standard TriBITS utilities includes -include(AppendStringVar) -include(TribitsStandardizePaths) - - -# @FUNCTION: tribits_process_enabled_tpl() -# -# Process an enabled TPL's FindTPL${TPL_NAME}.cmake module. -# -function(tribits_process_enabled_tpl TPL_NAME) - - # Setup the processing string - set(PROCESSING_MSG_STRING "Processing enabled external package/TPL: ${TPL_NAME} (") - if (${TPL_NAME}_ENABLING_PKG) - string(APPEND PROCESSING_MSG_STRING - "enabled by ${${TPL_NAME}_ENABLING_PKG}," ) - else() - string(APPEND PROCESSING_MSG_STRING - "enabled explicitly," ) - endif() - string(APPEND PROCESSING_MSG_STRING - " disable with -DTPL_ENABLE_${TPL_NAME}=OFF)" ) - - # Print the processing header - message("${PROCESSING_MSG_STRING}") - - if (NOT ${PROJECT_NAME}_TRACE_DEPENDENCY_HANDLING_ONLY) - - # Locate the FindTPL${TPL_NAME}.cmake module - if (${PROJECT_NAME}_VERBOSE_CONFIGURE) - print_var(${TPL_NAME}_FINDMOD) - endif() - if (${TPL_NAME}_FINDMOD STREQUAL "TRIBITS_PKG") - set(TPL_${TPL_NAME}_PARTS_ALREADY_SET FALSE) # ToDo: Take out? - if (NOT TPL_${TPL_NAME}_PARTS_ALREADY_SET) - find_package(${TPL_NAME} CONFIG REQUIRED) - global_set(TPL_${TPL_NAME}_LIBRARIES - "${${TPL_NAME}_LIBRARIES}" "${${TPL_NAME}_TPL_LIBRARIES}") - global_set(TPL_${TPL_NAME}_PARTS_ALREADY_SET TRUE) - endif() - return() - elseif (IS_ABSOLUTE ${${TPL_NAME}_FINDMOD}) - #message("${${TPL_NAME}_FINDMOD} is absolute!") - set(CURRENT_TPL_PATH "${${TPL_NAME}_FINDMOD}") - else() - #message("${${TPL_NAME}_FINDMOD} is *NOT* absolute!") - set(CURRENT_TPL_PATH "${PROJECT_SOURCE_DIR}/${${TPL_NAME}_FINDMOD}") - endif() - #print_var(CURRENT_TPL_PATH) - - # Process the FindTPL${TPL_NAME}.cmake module - tribits_trace_file_processing(TPL INCLUDE "${CURRENT_TPL_PATH}") - set(TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST TRUE) - include("${CURRENT_TPL_PATH}") - unset(TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST) - # NOTE: Above, setting TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST=TRUE - # triggers special logic in the TriBITS-created - # ${TPL_NAME}ConfigVersion.cmake file to set - # PACKAGE_VERSION_COMPATIBLE=FALSE and result in find_package(${TPL_NAME}) - # that may be called inside of ${TPL_NAME}_FINDMOD to not find a - # TriBITS-generated ${TPL_NAME}Config.cmake file. This allows - # find_package(${TPL_NAME}) to usae a proper non-TriBITS - # Find${TPL_NAME}.cmake module or find a non-TriBITS - # ${TPL_NAME}Config.cmake module. - - if (${PROJECT_NAME}_VERBOSE_CONFIGURE) - print_var(TPL_${TPL_NAME}_NOT_FOUND) - endif() - - # Address failed find of the TPL - if (TPL_${TPL_NAME}_NOT_FOUND AND NOT TPL_TENTATIVE_ENABLE_${TPL_NAME}) - message( - "-- NOTE: The find module file for this failed TPL '${TPL_NAME}' is:\n" - " ${CURRENT_TPL_PATH}\n" - " which is pointed to in the file:\n" - " ${${TPL_NAME}_TPLS_LIST_FILE}\n" - ) - if (${TPL_NAME}_ENABLING_PKG) - message( - "TIP: One way to get past the configure failure for the\n" - "TPL '${TPL_NAME}' is to simply disable it with:\n" - " -DTPL_ENABLE_${TPL_NAME}=OFF\n" - "which will disable it and will recursively disable all of the\n" - "downstream packages that have required dependencies on it, including\n" - "the package '${${TPL_NAME}_ENABLING_PKG}' which triggered its enable.\n" - "When you reconfigure, just grep the cmake stdout for '${TPL_NAME}'\n" - "and then follow the disables that occur as a result to see what impact\n" - "this TPL disable has on the configuration of ${PROJECT_NAME}.\n" - ) - else() - message( - "TIP: Even though the TPL '${TPL_NAME}' was explicitly enabled in input,\n" - "it can be disabled with:\n" - " -DTPL_ENABLE_${TPL_NAME}=OFF\n" - "which will disable it and will recursively disable all of the\n" - "downstream packages that have required dependencies on it.\n" - "When you reconfigure, just grep the cmake stdout for '${TPL_NAME}'\n" - "and then follow the disables that occur as a result to see what impact\n" - "this TPL disable has on the configuration of ${PROJECT_NAME}.\n" - ) - endif() - message(FATAL_ERROR - "ERROR: TPL_${TPL_NAME}_NOT_FOUND=${TPL_${TPL_NAME}_NOT_FOUND}, aborting!") - endif() - - # Generate the ConfigVersion.cmake file if it has not been - # created yet and add install targets for Config[Version].cmake - set(buildDirExternalPkgsDir - "${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR}") - set(tplConfigFile - "${buildDirExternalPkgsDir}/${TPL_NAME}/${TPL_NAME}Config.cmake") - set(tplConfigVersionFile - "${buildDirExternalPkgsDir}/${TPL_NAME}/${TPL_NAME}ConfigVersion.cmake") - tribits_extpkg_write_config_version_file(${TPL_NAME} - "${tplConfigVersionFile}") - tribits_extpkg_install_config_file(${TPL_NAME} "${tplConfigFile}") - tribits_extpkg_install_config_version_file(${TPL_NAME} - "${tplConfigVersionFile}") - - endif() - -endfunction() diff --git a/tribits/core/package_arch/TribitsProcessEnabledTpls.cmake b/tribits/core/package_arch/TribitsProcessEnabledTpls.cmake new file mode 100644 index 000000000..b161a9ede --- /dev/null +++ b/tribits/core/package_arch/TribitsProcessEnabledTpls.cmake @@ -0,0 +1,286 @@ +# @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 + + +# Standard TriBITS Includes +include(TribitsExternalPackageWithImportedTargetsFindTplModuleHelpers) +include(TribitsExternalPackageWriteConfigFile) +include(TribitsTplFindIncludeDirsAndLibraries) +include(TribitsGeneralMacros) + +# Standard TriBITS utilities includes +include(AppendStringVar) +include(TribitsStandardizePaths) + + +# Gather information from enabled TPLs +# +macro(tribits_process_enabled_tpls) + + tribits_config_code_start_timer(CONFIGURE_TPLS_TIME_START_SECONDS) + + tribits_filter_package_list_from_var(${PROJECT_NAME}_DEFINED_TOPLEVEL_PACKAGES + EXTERNAL ON NONEMPTY ${PROJECT_NAME}_enabledExternalTopLevelPackages) + + tribits_project_has_tribits_compliant_external_packages( + ${PROJECT_NAME}_enabledExternalTopLevelPackages + projectHasTribitsCompliantExternalPackages ) + + if (projectHasTribitsCompliantExternalPackages) + message("") + message("Getting information for all enabled TriBITS-compliant" + " or upstream external packages/TPLs ...") + message("") + + foreach(TPL_NAME IN LISTS ${PROJECT_NAME}_enabledExternalTopLevelPackages) + if (${TPL_NAME}_IS_TRIBITS_COMPLIANT + OR ${TPL_NAME}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE + ) + tribits_process_enabled_tribits_compliant_or_upstream_tpl(${TPL_NAME}) + endif() + endforeach() + + set(remainingTplsTextStr " remaining") + + else() + + set(remainingTplsTextStr "") + + endif() + + message("") + message("Getting information for all${remainingTplsTextStr} enabled external packages/TPLs ...") + message("") + + foreach(TPL_NAME IN LISTS ${PROJECT_NAME}_enabledExternalTopLevelPackages) + if ((NOT ${TPL_NAME}_IS_TRIBITS_COMPLIANT) + AND (NOT ${TPL_NAME}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE) + ) + tribits_process_enabled_standard_tpl(${TPL_NAME}) + endif() + endforeach() + + tribits_config_code_stop_timer(CONFIGURE_TPLS_TIME_START_SECONDS + "\nTotal time to configure enabled external packages/TPLs") + +endmacro() + + +macro(tribits_process_enabled_tribits_compliant_or_upstream_tpl TPL_NAME) + + tribits_get_enabled_tpl_processing_string(${TPL_NAME} tplProcessingString) + message("${tplProcessingString}") + + if (NOT ${PROJECT_NAME}_TRACE_DEPENDENCY_HANDLING_ONLY) + if (NOT ${TPL_NAME}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE) + tribits_process_enabled_tribits_compliant_tpl(${TPL_NAME}) + else() + message("-- " + "The external package/TPL ${TPL_NAME} will be read in by a downstream" + " TriBITS-compliant external package") + endif() + endif() + +endmacro() + + +# @MACRO: tribits_process_enabled_standard_tpl() +# +# Process an enabled TPL's FindTPL${TPL_NAME}.cmake module. +# +macro(tribits_process_enabled_standard_tpl TPL_NAME) + + tribits_get_enabled_tpl_processing_string(${TPL_NAME} tplProcessingString) + message("${tplProcessingString}") + + if (NOT ${PROJECT_NAME}_TRACE_DEPENDENCY_HANDLING_ONLY) + + # Locate the FindTPL${TPL_NAME}.cmake module + if (${PROJECT_NAME}_VERBOSE_CONFIGURE) + print_var(${TPL_NAME}_FINDMOD) + endif() + + tribits_process_enabled_tribits_find_tpl_mod_file(${TPL_NAME}) + tribits_address_failed_tpl_find(${TPL_NAME}) + tribits_generate_tpl_version_file_and_add_package_config_install_targets( + ${TPL_NAME}) + + endif() + +endmacro() + + +# Get external package/TPL processing string +# +function(tribits_get_enabled_tpl_processing_string TPL_NAME tplProcessingStringOut) + set(tplProcessingString "Processing enabled external package/TPL: ${TPL_NAME} (") + if (${TPL_NAME}_ENABLING_PKG) + string(APPEND tplProcessingString "enabled by ${${TPL_NAME}_ENABLING_PKG}," ) + else() + string(APPEND tplProcessingString "enabled explicitly," ) + endif() + string(APPEND tplProcessingString " disable with -DTPL_ENABLE_${TPL_NAME}=OFF)" ) + set(${tplProcessingStringOut} "${tplProcessingString}" PARENT_SCOPE) +endfunction() + + +# Process an enabled TPL defined using a TriBITS-compliant external +# packages Config.cmake file +# +macro(tribits_process_enabled_tribits_compliant_tpl TPL_NAME) + message("-- " + "Calling find_package(${TPL_NAME}) for TriBITS-compliant external package") + find_package(${TPL_NAME} CONFIG REQUIRED) +endmacro() + + +# Process an enabled TPL defined using a FindTPL.cmake module +# +macro(tribits_process_enabled_tribits_find_tpl_mod_file TPL_NAME) + + if (IS_ABSOLUTE ${${TPL_NAME}_FINDMOD}) + #message("${${TPL_NAME}_FINDMOD} is absolute!") + set(CURRENT_TPL_PATH "${${TPL_NAME}_FINDMOD}") + else() + #message("${${TPL_NAME}_FINDMOD} is *NOT* absolute!") + set(CURRENT_TPL_PATH "${PROJECT_SOURCE_DIR}/${${TPL_NAME}_FINDMOD}") + endif() + #print_var(CURRENT_TPL_PATH) + + # Process the FindTPL${TPL_NAME}.cmake module + tribits_trace_file_processing(TPL INCLUDE "${CURRENT_TPL_PATH}") + set(TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST TRUE) + include("${CURRENT_TPL_PATH}") + unset(TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST) + # NOTE: Above, setting TRIBITS_FINDING_RAW_${TPL_NAME}_PACKAGE_FIRST=TRUE + # triggers special logic in the TriBITS-created + # ${TPL_NAME}ConfigVersion.cmake file to set + # PACKAGE_VERSION_COMPATIBLE=FALSE and result in find_package(${TPL_NAME}) + # that may be called inside of ${TPL_NAME}_FINDMOD to not find a + # TriBITS-generated ${TPL_NAME}Config.cmake file. This allows + # find_package(${TPL_NAME}) to usae a proper non-TriBITS + # Find${TPL_NAME}.cmake module or find a non-TriBITS + # ${TPL_NAME}Config.cmake module. + + if (${PROJECT_NAME}_VERBOSE_CONFIGURE) + print_var(TPL_${TPL_NAME}_NOT_FOUND) + endif() + +endmacro() + + +function(tribits_address_failed_tpl_find TPL_NAME) + # Address failed find of the TPL + if (TPL_${TPL_NAME}_NOT_FOUND AND NOT TPL_TENTATIVE_ENABLE_${TPL_NAME}) + message( + "-- NOTE: The find module file for this failed TPL '${TPL_NAME}' is:\n" + " ${CURRENT_TPL_PATH}\n" + " which is pointed to in the file:\n" + " ${${TPL_NAME}_TPLS_LIST_FILE}\n" + ) + if (${TPL_NAME}_ENABLING_PKG) + message( + "TIP: One way to get past the configure failure for the\n" + "TPL '${TPL_NAME}' is to simply disable it with:\n" + " -DTPL_ENABLE_${TPL_NAME}=OFF\n" + "which will disable it and will recursively disable all of the\n" + "downstream packages that have required dependencies on it, including\n" + "the package '${${TPL_NAME}_ENABLING_PKG}' which triggered its enable.\n" + "When you reconfigure, just grep the cmake stdout for '${TPL_NAME}'\n" + "and then follow the disables that occur as a result to see what impact\n" + "this TPL disable has on the configuration of ${PROJECT_NAME}.\n" + ) + else() + message( + "TIP: Even though the TPL '${TPL_NAME}' was explicitly enabled in input,\n" + "it can be disabled with:\n" + " -DTPL_ENABLE_${TPL_NAME}=OFF\n" + "which will disable it and will recursively disable all of the\n" + "downstream packages that have required dependencies on it.\n" + "When you reconfigure, just grep the cmake stdout for '${TPL_NAME}'\n" + "and then follow the disables that occur as a result to see what impact\n" + "this TPL disable has on the configuration of ${PROJECT_NAME}.\n" + ) + endif() + message(FATAL_ERROR + "ERROR: TPL_${TPL_NAME}_NOT_FOUND=${TPL_${TPL_NAME}_NOT_FOUND}, aborting!") + endif() +endfunction() + + +# Generate the ConfigVersion.cmake file for a TriBITS TPL and install +# the already generated Config.cmake file +# +function(tribits_generate_tpl_version_file_and_add_package_config_install_targets + TPL_NAME + ) + set(buildDirExternalPkgsDir + "${${PROJECT_NAME}_BINARY_DIR}/${${PROJECT_NAME}_BUILD_DIR_EXTERNAL_PKGS_DIR}") + set(tplConfigFile + "${buildDirExternalPkgsDir}/${TPL_NAME}/${TPL_NAME}Config.cmake") + set(tplConfigVersionFile + "${buildDirExternalPkgsDir}/${TPL_NAME}/${TPL_NAME}ConfigVersion.cmake") + tribits_extpkg_write_config_version_file(${TPL_NAME} + "${tplConfigVersionFile}") + tribits_extpkg_install_config_file(${TPL_NAME} "${tplConfigFile}") + tribits_extpkg_install_config_version_file(${TPL_NAME} + "${tplConfigVersionFile}") +endfunction() + + +function(tribits_project_has_tribits_compliant_external_packages + enabledExternalTopLevelPackagesListName + projectHasTribitsCompliantExternalPackagesOut + ) + + set(projectHasTribitsCompliantExternalPackages FALSE) + + foreach(TPL_NAME IN LISTS ${enabledExternalTopLevelPackagesListName}) + if (${TPL_NAME}_IS_TRIBITS_COMPLIANT + OR ${TPL_NAME}_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE + ) + set(projectHasTribitsCompliantExternalPackages TRUE) + break() + endif() + endforeach() + + set(${projectHasTribitsCompliantExternalPackagesOut} + ${projectHasTribitsCompliantExternalPackages} PARENT_SCOPE) + +endfunction() diff --git a/tribits/core/package_arch/TribitsProcessPackagesAndDirsLists.cmake b/tribits/core/package_arch/TribitsProcessPackagesAndDirsLists.cmake index d045fdedf..447f98265 100644 --- a/tribits/core/package_arch/TribitsProcessPackagesAndDirsLists.cmake +++ b/tribits/core/package_arch/TribitsProcessPackagesAndDirsLists.cmake @@ -572,6 +572,7 @@ macro(tribits_process_packages_and_dirs_lists REPOSITORY_NAME REPOSITORY_DIR) set(${TRIBITS_PACKAGE}_PARENT_REPOSITORY ${REPOSITORY_NAME}) tribits_insert_standard_package_options(${TRIBITS_PACKAGE} ${PACKAGE_TESTGROUP}) set(${TRIBITS_PACKAGE}_PACKAGE_BUILD_STATUS INTERNAL) + set(${TRIBITS_PACKAGE}_IS_TRIBITS_COMPLIANT TRUE) else() if (${PROJECT_NAME}_VERBOSE_CONFIGURE) message( @@ -593,6 +594,7 @@ macro(tribits_process_packages_and_dirs_lists REPOSITORY_NAME REPOSITORY_DIR) print_var(${TRIBITS_PACKAGE}_PARENT_PACKAGE) print_var(${TRIBITS_PACKAGE}_PARENT_REPOSITORY) print_var(${TRIBITS_PACKAGE}_PACKAGE_BUILD_STATUS) + print_var(${TRIBITS_PACKAGE}_IS_TRIBITS_COMPLIANT) endif() if (TRIBITS_PROCESS_PACKAGES_AND_DIRS_LISTS_VERBOSE) diff --git a/tribits/core/package_arch/TribitsProcessTplsLists.cmake b/tribits/core/package_arch/TribitsProcessTplsLists.cmake index 611dcf3f7..f5e5a6e55 100644 --- a/tribits/core/package_arch/TribitsProcessTplsLists.cmake +++ b/tribits/core/package_arch/TribitsProcessTplsLists.cmake @@ -47,10 +47,10 @@ include(Split) # @MACRO: tribits_repository_define_tpls() # -# Define the list of `TriBITS TPLs`_ (external packages) for a given `TriBITS -# Repository`_ which includes the TPL name, find module, and classification . -# This macro is typically called from inside of the repository's -# `/TPLsList.cmake`_ file. +# Define the list of `TriBITS External Packages/TPLs`_ for a given `TriBITS +# Repository`_ which includes the external package/TPL name, TriBITS TPL find +# module, and classification . This macro is typically called from inside of +# a TriBITS Repository's `/TPLsList.cmake`_ file. # # Usage:: # @@ -62,58 +62,53 @@ include(Split) # # This macro sets up a 2D array of ``NumTPLS`` by ``NumColumns`` listing out # the `TriBITS TPLs`_ for a `TriBITS Repository`_. Each row (with 3 entries) -# specifies a TPL which contains the columns (ordered 0-2): +# specifies a different TriBITS exernal package/TPL which contains the columns +# (ordered 0-2): # -# 0. **TPL** (````): The name of the TriBITS TPL ````. -# This name must be unique across all other TriBITS TPLs in this or any -# other TriBITS repo that might be combined into a single TriBITS project -# meta-build (see `Globally unique TriBITS TPL names`_). However, a TPL -# can be redefined from an upstream repo (see below). The name should be a -# valid identifier (e.g. matches the regex ``[a-zA-Z_][a-zA-Z0-9_]*``). -# TPL names typically use mixed case (e.g. ``SomeTpl`` and not -# ``SOMETPL``). +# 0. **TPL** (````): The name of the TriBITS external package/TPL +# ````. This name must be unique across all other TriBITS TPLs in +# this or any other TriBITS repo that might be combined into a single +# TriBITS project meta-build (see `Globally unique TriBITS TPL names`_). +# However, a TPL can be redefined from an upstream repo (see below). The +# name should be a valid identifier (e.g. matches the regex +# ``[a-zA-Z_][a-zA-Z0-9_]*``). TPL names typically use mixed case +# (e.g. ``SomeTpl``, not ``SOMETPL``). # -# 1. **FINDMOD** (````): The relative or absolute path for the -# find module, usually with the name `FindTPL.cmake`_. If it is a -# relative path, it is considered relative to the repository base directory -# ````. If just the base path for the find module is given, -# ending with ``"/"`` (e.g. ``"cmake/tpls/"``), then the find module will -# be assumed to be under that this directory with the standard name +# 1. **FINDMOD** (````): For a TriBITS external package/TPL that +# **is not** a `TriBITS-compliant external package`_, this is set to the +# relative or absolute path for the TriBITS TPL find module, usually with +# the name `FindTPL.cmake`_. If it is a relative path, it is +# considered relative to the repository base directory ````. If +# just the base path for the find module is given, ending with ``"/"`` +# (e.g. ``"cmake/tpls/"``), then the find module will be assumed to be +# under that this directory with the standard name # ``FindTPL.cmake``. (See `Creating the FindTPL.cmake -# file`_.) +# file`_.) However, if the external package **is** a `TriBITS-compliant +# external package`_, provide the value ``TRIBITS_PKG`` instead and no +# ``FindTPL.cmake`` file is needed. If a +# ``FindTPLDependencies.cmake`` file is needed in this case, then +# provide the path to that file (relative or absolute, directory or file +# path) using ``TRIBITS_PKG:``. This field is used to +# set the variables `_FINDMOD`_ and +# `_DEPENDENCIES_FILE`_. # -# 2. **CLASSIFICATION** (````): Gives the `Package Test -# Group`_ `PT`_, `ST`_, or `EX`_ and the maturity level ``EP``, ``RS``, -# ``PG``, ``PM``, ``GRS``, ``GPG``, ``GPM``, ``UM``. These are separated -# by a coma with no space in between such as ``"RS,PT"`` for a "Research -# Stable", "Primary Tested" package. No spaces are allowed so that CMake -# treats this a one field in the array. The maturity level can be left off -# in which case it is assumed to be ``UM`` for "Unspecified Maturity". +# 2. **CLASSIFICATION** (````): Gives the `Package Test Group`_ +# `PT`_, `ST`_, or `EX`_ and the maturity level ``EP``, ``RS``, ``PG``, +# ``PM``, ``GRS``, ``GPG``, ``GPM``, ``UM``. These are separated by a coma +# with no space in between such as ``"RS,PT"`` for a "Research Stable", +# "Primary Tested" package. No spaces are allowed so that CMake treats +# this a one field in the array. The maturity level can be left off in +# which case it is assumed to be ``UM`` for "Unspecified Maturity". This +# field is used to set the variable `_TESTGROUP`_ and +# ``_MATURITY_LEVEL``. # -# A TPL defined in a upstream repo can listed again in a downstream repo, -# which allows redefining the find module that is used to specify the TPL. -# This allows downstream repos to add additional requirements for a given TPL -# (i.e. add more libraries, headers, etc.). However, the downstream repo's -# find module file must find the TPL components that are fully compatible with -# the upstream's find module. -# -# This macro just sets the variable:: -# -# ${REPOSITORY_NAME}_TPLS_FINDMODS_CLASSIFICATIONS -# -# in the current scope. The advantages of using this macro instead of -# directly setting this variable are that the macro: -# -# * Asserts that the variable ``REPOSITORY_NAME`` is defined and set -# -# * Avoids having to hard-code the assumed repository name -# ``${REPOSITORY_NAME}``. This provides more flexibility for how other -# TriBITS projects choose to name a given TriBITS repo (i.e. the name of -# repo subdirs). -# -# * Avoids misspelling the name of the variable -# ``${REPOSITORY_NAME}_TPLS_FINDMODS_CLASSIFICATIONS``. If one misspells -# the name of a macro, it is an immediate error in CMake. +# A TPL defined in a upstream repo can be listed again in a downstream repo, +# which allows redefining the find module that is used to specify the external +# package/TPL. This allows downstream repos to add additional requirements +# for a given TPL (i.e. add more libraries, headers, etc.). However, the +# downstream repo's find module file must find the TPL components that are +# fully compatible with the upstream defined find module in terms of what it +# provides for packages in the upstream repos. # macro(tribits_repository_define_tpls) assert_defined(REPOSITORY_NAME) @@ -275,6 +270,14 @@ macro(tribits_process_tpls_lists REPOSITORY_NAME REPOSITORY_DIR) set(${TPL_NAME}_PACKAGE_BUILD_STATUS EXTERNAL) + # Set ${TPL_NAME}_IS_TRIBITS_COMPLIANT + + if (${TPL_NAME}_FINDMOD STREQUAL "TRIBITS_PKG") + set(${TPL_NAME}_IS_TRIBITS_COMPLIANT TRUE) + else() + set(${TPL_NAME}_IS_TRIBITS_COMPLIANT FALSE) + endif() + # Print variables/properties for the TPL if (${PROJECT_NAME}_VERBOSE_CONFIGURE OR TRIBITS_PROCESS_TPLS_LISTS_VERBOSE) @@ -283,6 +286,7 @@ macro(tribits_process_tpls_lists REPOSITORY_NAME REPOSITORY_DIR) print_var(${TPL_NAME}_DEPENDENCIES_FILE) print_var(${TPL_NAME}_TPLS_LIST_FILE) print_var(${TPL_NAME}_PACKAGE_BUILD_STATUS) + print_var(${TPL_NAME}_IS_TRIBITS_COMPLIANT) endif() # Set cache var TPL_ENABLE_${TPL_NAME} with default "" diff --git a/tribits/core/package_arch/TribitsProjectImpl.cmake b/tribits/core/package_arch/TribitsProjectImpl.cmake index 892cecc6b..f27caa3e6 100644 --- a/tribits/core/package_arch/TribitsProjectImpl.cmake +++ b/tribits/core/package_arch/TribitsProjectImpl.cmake @@ -190,10 +190,6 @@ macro(tribits_project_impl) # G) Go get the information for all enabled TPLS # - message("") - message("Getting information for all enabled external packages/TPLs ...") - message("") - tribits_process_enabled_tpls() # diff --git a/tribits/core/package_arch/TribitsProjectWriteConfigFile.cmake b/tribits/core/package_arch/TribitsProjectWriteConfigFile.cmake new file mode 100644 index 000000000..5f4fa7089 --- /dev/null +++ b/tribits/core/package_arch/TribitsProjectWriteConfigFile.cmake @@ -0,0 +1,228 @@ +# @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 + + +################################################################################ +# +# Module TribitsInternalPackageWriteConfigFile.cmake +# +# This module contains code for generating Config.cmake files for +# TriBITS projects. +# +################################################################################ + + +include(TribitsInternalPackageWriteConfigFile) + + +# Write the outer TriBITS Config.cmake file +# +# If ${PROJECT_NAME}_VERSION is not set or is '' on input, then it will be set +# to 0.0.0 in order to create the ${PROJECT_NAME}ConfigVersion.cmake file. +# +# ToDo: Finish documentation! +# +function(tribits_write_project_client_export_files) + + set(EXPORT_FILE_VAR_PREFIX ${PROJECT_NAME}) + + # Reversing the package list so that libraries will be produced in order of + # most dependent to least dependent. + set(PACKAGE_LIST ${${PROJECT_NAME}_DEFINED_INTERNAL_PACKAGES}) + if (PACKAGE_LIST) + list(REVERSE PACKAGE_LIST) + endif() + + # Loop over all packages to determine which were enabled. Then build a list + # of all their libraries/includes in the proper order for linking + set(FULL_PACKAGE_SET "") + set(FULL_LIBRARY_SET "") + foreach(TRIBITS_PACKAGE ${PACKAGE_LIST}) + if(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}) + list(APPEND FULL_PACKAGE_SET ${TRIBITS_PACKAGE}) + list(APPEND FULL_LIBRARY_SET ${${TRIBITS_PACKAGE}_LIBRARIES}) + endif() + endforeach() + + set(${PROJECT_NAME}_CONFIG_LIBRARIES ${FULL_LIBRARY_SET}) + + # Reversing the tpl list so that the list of tpls will be produced in + # order of most dependent to least dependent. + if (${PROJECT_NAME}_DEFINED_TPLS) + set(TPL_LIST ${${PROJECT_NAME}_DEFINED_TPLS}) + list(REVERSE TPL_LIST) + endif() + + # Loop over all TPLs to determine which were enabled. Then build a list + # of all their libraries/includes in the proper order for linking + set(FULL_TPL_SET "") + set(FULL_TPL_LIBRARY_SET "") + foreach(TPL ${TPL_LIST}) + if(TPL_ENABLE_${TPL}) + list(APPEND FULL_TPL_SET ${TPL}) + list(APPEND FULL_TPL_LIBRARY_SET ${TPL_${TPL}_LIBRARIES}) + endif() + endforeach() + + set(${PROJECT_NAME}_CONFIG_TPL_LIBRARIES ${FULL_TPL_LIBRARY_SET}) + + # + # Configure two files for finding ${PROJECT_NAME}. One for the build tree + # and one for installing + # + + # Generate a note discouraging editing of the Config.cmake file + set(DISCOURAGE_EDITING "Do not edit: This file was generated automatically by CMake.") + + # Write the specification of the rpath if necessary. This is only needed if + # we're building shared libraries. + if(BUILD_SHARED_LIBS) + string(REPLACE ";" ":" SHARED_LIB_RPATH_COMMAND + "${${PROJECT_NAME}_CONFIG_LIBRARY_DIRS}") + set(SHARED_LIB_RPATH_COMMAND ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${SHARED_LIB_RPATH_COMMAND}) + endif() + + # Custom code in configuration file. + set(PROJECT_CONFIG_CODE "") + + # Appending the logic to include each package's config file. + set(LOAD_CODE "# Load configurations from enabled packages") + foreach(TRIBITS_PACKAGE ${FULL_PACKAGE_SET}) + set(LOAD_CODE "${LOAD_CODE} +include(\"${${TRIBITS_PACKAGE}_BINARY_DIR}/${TRIBITS_PACKAGE}Config.cmake\")") + endforeach() + set(PROJECT_CONFIG_CODE "${PROJECT_CONFIG_CODE}\n${LOAD_CODE}") + + tribits_set_compiler_vars_for_config_file(INSTALL_DIR) + + if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) + # In TribitsProjectConfigTemplate.cmake.in, we would like to preserve + # ${}-variables after the conversion to TribitsProjectConfigTemplate.cmake. + # To this end, one typically uses the @-syntax for variables. That doesn't + # support nested variables, however. Use ${PDOLLAR} as a workaround, cf. + # . + set(PDOLLAR "$") + set(tribitsInstallationDir + "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") + set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR "") + configure_file( + "${tribitsInstallationDir}/TribitsProjectConfigTemplate.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" ) + endif() + + ###### + # Create a configure file for the install tree and set the install target for it. This + # file isn't generally useful inside the build tree. It will be placed in the base + # install directory for ${PROJECT_NAME} when installed. + ###### + + # Set the include and library directories relative to the location + # at which the ${PROJECT_NAME}Config.cmake file is going to be + # installed. Note the variable reference below is escaped so it + # won't be replaced until a client project attempts to locate + # directories using the installed config file. This is to deal with + # installers that allow relocation of the install tree at *install* + # time. + # The export files are typically installed in + # //cmake//. + # The relative path to the installation dir is hence k*(../) + ../../, where + # k is the number of components in . Extract those here. + # This doesn't work if ${${PROJECT_NAME}_INSTALL_LIB_DIR} contains "./" or + # "../" components, but really, it never did. All of this should actually be + # handled by CMake's configure_package_config_file(). + string(REPLACE "/" ";" PATH_LIST ${${PROJECT_NAME}_INSTALL_LIB_DIR}) + set(RELATIVE_PATH "../..") + foreach(PATH ${PATH_LIST}) + set(RELATIVE_PATH "${RELATIVE_PATH}/..") + endforeach() + + # Write the specification of the rpath if necessary. This is only needed if + # we're building shared libraries. + if(BUILD_SHARED_LIBS) + set(SHARED_LIB_RPATH_COMMAND + "${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_LIB_DIR}" + ) + endif() + + if (${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES) + + tribits_set_compiler_vars_for_config_file(INSTALL_DIR) + + # Custom code in configuration file. + set(PROJECT_CONFIG_CODE "") + + set(PDOLLAR "$") # Hack used in configure file below + + if (IS_ABSOLUTE "${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") + set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR "${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") + else() + set(TRIBITS_PROJECT_INSTALL_INCLUDE_DIR + "${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}") + endif() + + configure_file( + "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}/TribitsProjectConfigTemplate.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config_install.cmake" + ) + + install( + FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config_install.cmake" + DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PROJECT_NAME}" + RENAME ${PROJECT_NAME}Config.cmake + ) + endif() + + # + # Configure the version file for ${PROJECT_NAME} + # + include(CMakePackageConfigHelpers) + if ("${${PROJECT_NAME}_VERSION}" STREQUAL "") + set(${PROJECT_NAME}_VERSION 0.0.0) + endif() + write_basic_package_version_file( + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY SameMajorVersion + ) + install( + FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/cmake/${PROJECT_NAME}" + ) + +endfunction() diff --git a/tribits/core/package_arch/TribitsReadDepsFilesCreateDepsGraph.cmake b/tribits/core/package_arch/TribitsReadDepsFilesCreateDepsGraph.cmake index bd5f09e61..c8c22505b 100644 --- a/tribits/core/package_arch/TribitsReadDepsFilesCreateDepsGraph.cmake +++ b/tribits/core/package_arch/TribitsReadDepsFilesCreateDepsGraph.cmake @@ -554,10 +554,10 @@ endfunction() # Implementation macro for tribits_set_dep_packages() to deal with a package # that is not defined by TriBITS. # -# ToDo #63: This may need to be modified when dealing with TriBITS-compatible +# ToDo #63: This may need to be modified when dealing with TriBITS-compliant # packages already installed out on the system. We may need a mode where we # don't assert packages that are not defined but instead just assume they are -# TriBITS-compatible packages already installed. +# TriBITS-compliant packages already installed. # macro(tribits_set_dep_packages__handle_undefined_pkg packageName depPkg requiredOrOptional pkgsOrTpls packageEnableVar @@ -960,6 +960,8 @@ macro(tribits_read_subpackage_deps_file_add_to_graph PACKAGE_NAME tribits_process_package_dependencies_lists(${SUBPACKAGE_FULLNAME}) + set(${SUBPACKAGE_FULLNAME}_IS_TRIBITS_COMPLIANT TRUE) + set(${SUBPACKAGE_FULLNAME}_REGRESSION_EMAIL_LIST ${${PACKAGE_NAME}_REGRESSION_EMAIL_LIST}) diff --git a/tribits/core/package_arch/TribitsSystemDataStructuresMacrosFunctions.rst b/tribits/core/package_arch/TribitsSystemDataStructuresMacrosFunctions.rst index f4661403f..861ccc835 100644 --- a/tribits/core/package_arch/TribitsSystemDataStructuresMacrosFunctions.rst +++ b/tribits/core/package_arch/TribitsSystemDataStructuresMacrosFunctions.rst @@ -428,7 +428,7 @@ Logic`_. Determining if a package is internal or external ++++++++++++++++++++++++++++++++++++++++++++++++ -As mentioned above, some subset of packages listed in +As mentioned above, some subset of initially internal packages listed in `${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES`_ (which all have ``${PACKAGE_NAME}_SOURCE_DIR != ""``) may be chosen to be external packages. Packages that could be built internally may be chosen to be treated as @@ -437,10 +437,6 @@ external packages (and therefore located on the system using -D TPL_ENABLE_=ON -or:: - - -D _ROOT= - .. _${PACKAGE_NAME}_PACKAGE_BUILD_STATUS: .. _${TPL_NAME}_PACKAGE_BUILD_STATUS: @@ -449,10 +445,91 @@ external package is provided by the variable:: ${PACKAGE_NAME}_PACKAGE_BUILD_STATUS=[INTERNAL|EXTERNAL] +(NOT: The value of ``${PACKAGE_NAME}_PACKAGE_BUILD_STATUS`` is only changed +after all of the enable/disable dependency logic is complete.) + As a result, every other package upstream from any of these ```` packages must therefore also be treated as external packages automatically and will have -``${PACKAGE_NAME}_PACKAGE_BUILD_STATUS=EXTERNAL`` set accordingly. +``${PACKAGE_NAME}_PACKAGE_BUILD_STATUS=EXTERNAL`` set accordingly. Also, if +any subpackage is determined to be EXTERNAL, then the parent package of that +subpackage and every other peer subpackage will also be set to EXTERNAL. + + +Processing of external packages/TPLs and TriBITS-compliant external packages ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The processing of external packages/TPLs is influenced by whether the external +package is a regular TriBITS TPL or is a TriBITS-compliant external +package. Here, a **TriBITS-Compliant External Package** has a +``Config.cmake`` file that satisfies the following properties: + +* Has the target ``::all_libs``. +* Calls ``find_dependency()`` for all upstream packages it depends on. +* Every upstream dependent package ```` has the target + ``::all_libs``. + +That means that when calling ``find_package()`` for a TriBITS-compliant +external package, there is no need to worry about finding any of its upstream +dependent external packages. That means that any external packages/TPLs +defined a TriBITS project which is upstream from a TriBITS-compliant +external package will be uniquely defined by calling ``find_package()`` on the +most downstream TriBITS-compliant external package that depends on it. +Therefore, defining the external packages and their targets in this set of +external packages just involves calling ``find_package()`` on the terminal +TriBITS-compliant external packages (i.e. TriBITS-compliant +external packages that don't have any downstream dependencies that are +external packages). Then the remaining subset of external packages/TPLs that +don't have a downstream TriBITS-compliant external package dependency +will be defined as usual. (ToDo: Put in a more detailed examples explaining +how this works.) + +The variables that are set internally to define these different subsets of +external packages/TPLs are: + +* ``_IS_TRIBITS_COMPLIANT``: Set the ``TRUE`` if the package + ```` provides the ``::all_libs`` target for itself and all + of its upstream dependent (internal or external) packages (whether this + package is treated as an internal or external package). + +* ``_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE``: Set to + ``TRUE`` if the external package/TPL will be processed by downstream TriBITS + complient package. In this case, we just print that we are skipping the + find operation and explain why. + +An external package with ``_IS_TRIBITS_COMPLIANT=TRUE`` **AND** +``_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE=FALSE`` is the +one for which ``find_package( CONFIG REQUIRED)`` will be called and +does not have any downstream packages that are being treated as external +packages. + +The variable ``_IS_TRIBITS_COMPLIANT`` is set right when the +packages are initially defined by reading in the various input files. That +is, all initially internal packages that are listed in a +`/PackagesList.cmake`_ file will have +``_IS_TRIBITS_COMPLIANT=TRUE`` set. While all external +packages/TPLs listed in a `/TPLsList.cmake`_ file will have +``_IS_TRIBITS_COMPLIANT=FALSE`` set (except for those tagged +with ``TRIBITS_PKG`` which will have +``_IS_TRIBITS_COMPLIANT=FALSE`` set). + +NOTE: When a TriBITS TPL (i.e. ``_IS_TRIBITS_COMPLIANT=FALSE``) +is being processed, we can't assume where its +``Config.cmake`` file exists so we must find upstream +dependencies using ``set(_DIR ...)`` and +``find_dependency( CONFIG REQUIRED)``. + +So the first loop over external packages/TPLs will be those external +packages/TPLs that have ``_IS_TRIBITS_COMPLIANT=TRUE`` **OR** +``_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE=TRUE``. And we +only call ``find_package()`` for those TriBITS-compliant external +packages that have ``_IS_TRIBITS_COMPLIANT=TRUE`` **AND** +``_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE=FALSE``. + +The second loop are those external packages/TPLs that don't have a downstream +TriBITS-compliant external package which are all of those external +packages for which ``_IS_TRIBITS_COMPLIANT=FALSE`` **AND** +``_PROCESSED_BY_DOWNSTREAM_TRIBITS_EXTERNAL_PACKAGE=FALSE``. Other package-related variables diff --git a/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake b/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake index ad2621289..490d204ec 100644 --- a/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake +++ b/tribits/core/package_arch/TribitsTplFindIncludeDirsAndLibraries.cmake @@ -724,8 +724,6 @@ function(tribits_tpl_find_include_dirs_and_libraries TPL_NAME) tribits_extpkg_write_config_file(${TPL_NAME} "${tplConfigFile}") if (NOT ${PROJECT_NAME}_ENABLE_INSTALLATION_TESTING) include("${tplConfigFile}") - set(${TPL_NAME}_DIR "${tplConfigFileBaseDir}" CACHE INTERNAL - "TriBITS-generated ${TPL_NAME}Config.cmake file used from this dir") endif() # NOTE: The file ConfigVersion.cmake will get created elsewhere as # will the install targets for the files Config and diff --git a/tribits/core/package_arch/TribitsWritePackageConfigFileHelpers.cmake b/tribits/core/package_arch/TribitsWritePackageConfigFileHelpers.cmake new file mode 100644 index 000000000..310e58876 --- /dev/null +++ b/tribits/core/package_arch/TribitsWritePackageConfigFileHelpers.cmake @@ -0,0 +1,65 @@ +# @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_extpkg_append_tribits_compliant_package_config_vars_str() +# +# Append the standard TriBITS-compliant external package variables +# +function(tribits_extpkg_append_tribits_compliant_package_config_vars_str packageName + packageConfigCodeStrVarInOut + ) + set(packageConfigCodeStr "${${packageConfigCodeStrVarInOut}}") + string(APPEND packageConfigCodeStr + "\n# Standard TriBITS-compliant external package variables\n" + "set(${packageName}_IS_TRIBITS_COMPLIANT TRUE)\n" + "set(${packageName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE \"\${CMAKE_CURRENT_LIST_FILE}\")\n" + "set(${packageName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR \"\${CMAKE_CURRENT_LIST_DIR}\")\n" + ) + set(${packageConfigCodeStrVarInOut} "${packageConfigCodeStr}" PARENT_SCOPE) +endfunction() + + +function(tribits_extpkg_write_package_config_file_from_str tplName configFileStr) + 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() \ No newline at end of file diff --git a/tribits/core/std_tpls/FindTPLMPI.cmake b/tribits/core/std_tpls/FindTPLMPI.cmake index f4917fd6a..dd555efd7 100644 --- a/tribits/core/std_tpls/FindTPLMPI.cmake +++ b/tribits/core/std_tpls/FindTPLMPI.cmake @@ -39,9 +39,9 @@ # Either the MPI compiler wrappers take care of these or the user has to set # the explicitly using basic compile flags and ${PROJECT_NAME}_EXTRA_LINK_FLAGS. -global_set(TPL_MPI_INCLUDE_DIRS) -global_set(TPL_MPI_LIBRARIES) -global_set(TPL_MPI_LIBRARY_DIRS) +global_set(TPL_MPI_INCLUDE_DIRS "") +global_set(TPL_MPI_LIBRARIES "") +global_set(TPL_MPI_LIBRARY_DIRS "") if(WIN32 AND TPL_ENABLE_MPI) find_package(MPI) diff --git a/tribits/ctest_driver/TribitsCTestDriverCore.cmake b/tribits/ctest_driver/TribitsCTestDriverCore.cmake index 467927afd..563f5de65 100644 --- a/tribits/ctest_driver/TribitsCTestDriverCore.cmake +++ b/tribits/ctest_driver/TribitsCTestDriverCore.cmake @@ -2274,8 +2274,9 @@ function(tribits_ctest_driver) select_final_set_of_packages_to_directly_test() # Above sets ${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST - tribits_print_packages_list_enable_status_from_var( ${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST - "\nFinal set of packages to be explicitly processed by CTest/CDash" ON FALSE) + tribits_print_packages_list_enable_status_from_var( + ${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST + "\nFinal set of packages to be explicitly processed by CTest/CDash" "" ON NONEMPTY) message( "\n***" diff --git a/tribits/ctest_driver/TribitsCTestDriverCoreHelpers.cmake b/tribits/ctest_driver/TribitsCTestDriverCoreHelpers.cmake index 837ddf05e..08c621ed4 100644 --- a/tribits/ctest_driver/TribitsCTestDriverCoreHelpers.cmake +++ b/tribits/ctest_driver/TribitsCTestDriverCoreHelpers.cmake @@ -513,9 +513,9 @@ macro(enable_only_modified_packages) message("\nDirectly modified or failing non-disabled packages that need" " to be tested: ALL_PACKAGES") else() - tribits_print_internal_package_list_enable_status( + tribits_print_package_list_enable_status( "\nDirectly modified or failing non-disabled packages that need to be tested" - ON FALSE ) + INTERNAL ON NONEMPTY ) endif() endmacro() diff --git a/tribits/doc/build_ref/TribitsBuildReferenceBody.rst b/tribits/doc/build_ref/TribitsBuildReferenceBody.rst index 6da3f7bd1..a9ab5f741 100644 --- a/tribits/doc/build_ref/TribitsBuildReferenceBody.rst +++ b/tribits/doc/build_ref/TribitsBuildReferenceBody.rst @@ -1958,6 +1958,81 @@ and module files. Therefore, don't enable this if Fortran code in your project is pulling in module files from TPLs. +Building against pre-installed packages +--------------------------------------- + +The project can build against any pre-installed packages defined in +the project and ignore the internally defined packages. To trigger the enable +of a pre-installed internal package treated as an external package, configure +with:: + + -D TPL_ENABLE_=ON + +That will cause the CMake project to pull in the pre-installed +package ```` as an external package using +``find_package()`` instead of configuring and building the +internally defined ```` package. + +Configuring and building against a pre-installed package treated as an +external packages has several consequences: + +* Any internal packages that are upstream from ```` from an + enabled set of dependencies will also be treated as external packages (and + therefore must be pre-installed as well). + +* The TriBITS package ``Dependencies.cmake`` files for the + ```` package and all of its upstream packages must still + exist and will still be read in by the CMake project and the same + enable/disable logic will be performed as if the packages were being treated + internal. (However, the base ``CMakeLists.txt`` and all of other files for + these internally defined packages being treated as external packages can be + missing and will be ignored.) + +* The same set of enabled and disabled upstream dependencies must be specified + to the CMake project that was used to pre-build and pre-install + these internally defined packages being treated as external packages. + (Otherwise, a configure error will result from the mismatch.) + +* The definition of any TriBITS external packages/TPLs that are enabled + upstream dependencies from any of these internally defined packages being + treated as external packages will be defined by the calls to + ``find_package()`` and will **not** be found again. + +The logic for treating internally defined packages as external packages will +be printed in the CMake configure output in the section ``Adjust the set of +internal and external packages`` with output like:: + + Adjust the set of internal and external packages ... + + -- Treating internal package as EXTERNAL because TPL_ENABLE_=ON + -- Treating internal package as EXTERNAL because downstream package being treated as EXTERNAL + -- NOTE: is indirectly downstream from a TriBITS-compliant external package + -- NOTE: is indirectly downstream from a TriBITS-compliant external package + +All of these internally defined being treated as external (and all of their +upstream dependencies) are processed in a loop over these just these +TriBITS-compliant external packages and ``find_package()`` is only called on +the terminal TriBITS-compliant external packages. This is shown in the CMake +output in the section ``Getting information for all enabled TriBITS-compliant +or upstream external packages/TPLs`` and looks like:: + + Getting information for all enabled TriBITS-compliant or upstream external packages/TPLs ... + + Processing enabled external package/TPL: (...) + -- The external package/TPL will be read in by a downstream TriBITS-compliant external package + Processing enabled external package/TPL: (...) + -- The external package/TPL will be read in by a downstream TriBITS-compliant external package + Processing enabled external package/TPL: (...) + -- The external package/TPL will be read in by a downstream TriBITS-compliant external package + Processing enabled external package/TPL: (...) + -- Calling find_package( for TriBITS-compliant external package + +In the above example ````, ```` and ```` are all direct or +indirect dependencies of ```` and therefore calling just +``find_package()`` fully defines those TriBITS-compliant external +packages as well. + + xSDK Configuration Options -------------------------- @@ -2804,6 +2879,12 @@ of packages the files are requested for with:: -D _GENERATE_EXPORT_FILES_FOR_ONLY_LISTED_PACKAGES=";" +To only install the package ``Config.cmake`` files and **not** the +project-level ``Config.cmake`` file, configure with:: + + -D _ENABLE_INSTALL_CMAKE_CONFIG_FILES=ON \ + -D _SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES=ON \ + NOTES: * Only enabled packages will have their export files generated. @@ -2811,6 +2892,13 @@ NOTES: * One would only want to limit the export files generated for very large projects where the cost my be high for doing so. +* One would want to skip the installation of the project-level + ``Config.cmake`` file in cases where the TriBITS project's packages + may be built in smaller subsets of packages in different individual CMake + project builds where there is no clear completion to the installation of the + packages for a given TriBITS project containing a larger collection of + packages. + Generating a project repo version file -------------------------------------- diff --git a/tribits/doc/guides/TribitsCMakeLanguageOverviewAndGotchas.rst b/tribits/doc/guides/TribitsCMakeLanguageOverviewAndGotchas.rst new file mode 100644 index 000000000..885229038 --- /dev/null +++ b/tribits/doc/guides/TribitsCMakeLanguageOverviewAndGotchas.rst @@ -0,0 +1,238 @@ +CMake Language Overview and Gotchas +----------------------------------- + +TriBITS removes a lot of the boiler plate code needed to write a CMake +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 external +packages/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 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 +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:: + + $ cmake --help-command + +Because tutorials and detailed documentation for the CMake language already +exists, this document does not attempt to provide a first reference to CMake +(which is a large topic in itself). However, what we try to provide below is +a short overview of the more quirky or surprising aspects of the CMake +language that a programmer experienced in another language might get tripped +up or surprised by. Some of the more unique features of the language are +described in order to help avoid some of these common mistakes and provide +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 +and be aware of these gotchas. + +The first thing to understand about the CMake language is that nearly every +line of CMake code is just a command taking a string (or an array of strings) +and functions that operate on strings. An array argument is just a single +string literal with elements separated by semi-colons ``";;..."``. +CMake is a bit odd in how it deals with these arrays, which are just +represented as a string with elements separated with semi-colons ``';'``. For +example, all of the following are equivalent and pass in a CMake array with 3 +elements [``A``], [``B``], and [``C``]:: + + some_func(A B C) + some_func("A" "B" "C") + some_func("A;B;C") + +However, the above is *not* the same as:: + + some_func("A B C") + +which just passes in a single element with value [``A B C``]. Raw quotes in +CMake basically escape the interpretation of space characters as array element +boundaries. Quotes around arguments with no spaces does nothing (as seen +above, except for the interpretation as variable names in an ``if()`` +statement). In order to get a quote char [``"``] into string, you must escape +it as:: + + some_func(\"A\") + +which passes an array with the single argument [``\"A\"``]. + +Variables are set using the built-in CMake ``set()`` command that just takes +string arguments like:: + + set(SOME_VARIABLE "some_value") + +In CMake, the above is identical, in every way, to:: + + set(SOME_VARIABLE some_value) + set("SOME_VARIABLE";"some_value") + set("SOME_VARIABLE;some_value") + +The function ``set()`` simply interprets the first argument to as the name of +a variable to set in the local scope. Many other built-in and user-defined +CMake functions work the same way. That is, some of the string arguments are +interpreted as the names of variables. There is no special language feature +that interprets them as variables (except in an ``if()`` statement). + +However, CMake appears to parse arguments differently for built-in CMake +control structure functions like ``foreach()`` and ``if()`` and does not just +interpret them as a string array. For example:: + + foreach (SOME_VAR "a;b;c") + message("SOME_VAR='${SOME_VAR}'") + endforeach() + +prints ```SOME_VAR='a;b;c'`` instead of printing ``SOME_VAR='a'`` followed by +``SOME_VAR='b'``, etc., as you would otherwise expect. Therefore, this simple +rule for the handling of function arguments as string arrays does not hold for +CMake logic control commands. Just follow the CMake documentation for these +control structures (i.e. see ``cmake --help-command if`` and ``cmake +--help-command foreach``). + +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 +combination of positional and keyword arguments. + +Variable names are translated into their stored values using +``${SOME_VARIABLE}``. The value that is extracted depends on if the variable +is set in the local or global (cache) scope. The local scopes for CMake start +in the base project directory in its base ``CMakeLists.txt`` file. Any +variables that are created by macros in that base local scope are seen across +an entire project but are *not* persistent across multiple successive +``cmake`` configure invocations where the cache file ``CMakeCache.txt`` is not +deleted in between. + +The handling of variables is one area where CMake is radically different from +most other languages. First, a variable that is not defined simply returns +nothing. What is surprising to most people about this is that it does not +even return an empty string that would register as an array element! For +example, the following set statement:: + + set(SOME_VAR a ${SOME_UNDEFINED_VAR} c) + +(where ``SOME_UNDEFINED_VAR`` is an undefined variable) produces +``SOME_VAR='a;c'`` and *not* ``'a;;c'``! The same thing occurs when an empty +variable is de-references such as with:: + + set(EMPTY_VAR "") + set(SOME_VAR a ${EMPTY_VAR} c) + +which produces ``SOME_VAR='a;c'`` and *not* ``'a;;c'``. In order to always +produce an element in the array even if the variable is empty, one must quote +the argument as with:: + + set(EMPTY_VAR "") + set(SOME_VAR a "${EMPTY_VAR}" c) + +which produces ``SOME_VAR='a;;c'``, or three elements as one might assume. + +This is a common error that people make when they call CMake functions +(built-in or TriBITS-defined) involving variables that might be undefined or +empty. For example, for the macro:: + + macro(some_macro A_ARG B_ARG C_ARG) + ... + endmacro() + +if someone tries to call it with (misspelled variable?):: + + some_macro(a ${SOME_OHTER_VAR} c) + +and if ``SOME_OHTER_VAR=""`` or if it is undefined, then CMake will error out +with the error message saying that the macro ``some_macro()`` takes 3 +arguments but only 2 were provided. If a variable might be empty but that is +still a valid argument to the command, then it must be quoted as:: + + some_macro(a "${SOME_OHTER_VAR}" c) + +Related to this problem is that if you misspell the name of a variable in a +CMake ``if()`` statement like:: + + if (SOME_VARBLE) + ... + endif() + +then it will always be false and the code inside the if statement will never +be executed! To avoid this problem, use the utility function +`assert_defined()`_ as:: + + assert_defined(SOME_VARBLE) + if (SOME_VARBLE) + ... + endif() + +In this case, the misspelled variable would be caught. + +While on the subject of ``if()`` statements, CMake has a strange convention. +When you say:: + + if (SOME_VAR) + do_something() + endif() + +then ``SOME_VAR`` is interpreted as a variable and will be considered true and +``do_something()`` will be called if ``${SOME_VAR}`` does *not* evaluate to +``0``, ``OFF``, ``NO``, ``FALSE``, ``N``, ``IGNORE``, ``""``, or ends in the +suffix ``-NOTFOUND``. How about that for a true/false rule! To be safe, use +``ON/OFF`` and ``TRUE/FALSE`` pairs for setting variables. Look up native +CMake documentation on ``if()`` for all the interesting details and all the +magical things it can do. + +**WARNING:** If you mistype ``"ON"`` as ``"NO"``, it evaluates to +``FALSE``/``OFF``! (That is a fun defect to track down!) + +CMake language behavior with respect to case sensitivity is also strange: + +* Calls of built-in and user-defined macros and functions is *case + insensitive*! That is ``set(...)``, ``set(...)``, ``set()``, and all other + combinations of upper and lower case characters for 'S', 'E', 'T' all call + the built-in ``set()`` function. The convention in TriBITS is to use + ``lower_case_with_underscores()`` for functions and macros. + +* However, the names of CMake (local or cache/global) variables are *case + sensitive*! That is, ``SOME_VAR`` and ``some_var`` are *different* + variables. Built-in CMake variables tend use all caps with underscores + (e.g. ``CMAKE_CURRENT_SOURCE_DIR``) but other built-in CMake variables tend + to use mixed case with underscores (e.g. ``CMAKE_Fortran_FLAGS``). TriBITS + tends to use a similar naming convention where project-level and cache + variables have mostly upper-case letters except for parts that are proper + nouns like the project, package or external package/TPL name + (e.g. ``TribitsExProj_TRIBITS_DIR``, ``TriBITS_SOURCE_DIR``, + ``Boost_INCLUDE_DIRS``). Local variables and function/macro parameters can + use camelCase or lower_case_with_underscores. + +I don't know of any other programming language that uses different case +sensitivity rules for variables and functions. However, because we must parse +macro and function arguments when writing user-defined macros and functions, +it is a good thing that CMake variables are case sensitive. Case insensitivity +would make it much harder and more expensive to parse argument lists that take +keyword-based arguments. + +Other mistakes that people make result from not understanding how CMake scopes +variables and other entities. CMake defines a global scope (i.e. "cache" +variables) and several nested local scopes that are created by +``add_subdirectory()`` and entering functions. See `dual_scope_set()`_ for a +short discussion of these scoping rules. And it is not just variables that +can have local and global scoping rules. Other entities, like defines set +with the built-in command ``add_definitions()`` only apply to the local scope +and child scopes. That means that if you call ``add_definitions()`` to set a +define that affects the meaning of a header-file in C or C++, for example, +that definition will *not* carry over to a peer subdirectory and those +definitions will not be set (see warning in `Miscellaneous Notes +(tribits_add_library())`_). diff --git a/tribits/doc/guides/TribitsCoreDetailedReference.rst b/tribits/doc/guides/TribitsCoreDetailedReference.rst index 2cc0fb95e..50a90c79a 100644 --- a/tribits/doc/guides/TribitsCoreDetailedReference.rst +++ b/tribits/doc/guides/TribitsCoreDetailedReference.rst @@ -89,6 +89,7 @@ a given TriBITS project are: * `${PROJECT_NAME}_REQUIRES_PYTHON`_ * `${PROJECT_NAME}_SET_INSTALL_RPATH`_ * `${PROJECT_NAME}_SHOW_TEST_START_END_DATE_TIME`_ +* `${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES`_ * `${PROJECT_NAME}_TEST_CATEGORIES`_ * `${PROJECT_NAME}_TPL_SYSTEM_INCLUDE_DIRS`_ * `${PROJECT_NAME}_TRACE_ADD_TEST`_ @@ -671,6 +672,19 @@ These options are described below. date/time for regular tests added with `tribits_add_test()`_ (which uses a raw command with ``add_test()``). +.. _${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES: + +**${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES** + + To change the default value of the + ``${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES`` to ``TRUE``, for + example, for a TriBITS project, set:: + + set(${PROJECT_NAME}_SKIP_INSTALL_PROJECT_CMAKE_CONFIG_FILES_DEFAULT TRUE) + + in the project's `/CMakeLists.txt`_ or + `/ProjectName.cmake`_ files. + .. _${PROJECT_NAME}_SKIP_EXTRAREPOS_FILE: **${PROJECT_NAME}_SKIP_EXTRAREPOS_FILE** diff --git a/tribits/doc/guides/TribitsGuidesBody.rst b/tribits/doc/guides/TribitsGuidesBody.rst index a196db14e..0cbcf2c5a 100644 --- a/tribits/doc/guides/TribitsGuidesBody.rst +++ b/tribits/doc/guides/TribitsGuidesBody.rst @@ -110,259 +110,21 @@ may not be necessary and the `TriBITS Overview`_ or the above roles and discussion help the reader select the right document to start with. +NOTE: Before getting started with TriBITS, if a reader is unfamiliar with +CMake, please review the `CMake Language Overview and Gotchas`_. Once those +CMake basics and common gotchas have been reviewed, we now get into the meat +of TriBITS starting with software engineering principles that lie at the +foundation of TriBITS. That is followed by with and overall of the structure +of a TriBITS project. -CMake Language Overview and Gotchas ------------------------------------ - -TriBITS removes a lot of the boiler plate code needed to write a CMake -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 external -packages/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 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 -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:: - - $ cmake --help-command - -Because tutorials and detailed documentation for the CMake language already -exists, this document does not attempt to provide a first reference to CMake -(which is a large topic in itself). However, what we try to provide below is -a short overview of the more quirky or surprising aspects of the CMake -language that a programmer experienced in another language might get tripped -up or surprised by. Some of the more unique features of the language are -described in order to help avoid some of these common mistakes and provide -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 -and be aware of these gotchas. - -The first thing to understand about the CMake language is that nearly every -line of CMake code is just a command taking a string (or an array of strings) -and functions that operate on strings. An array argument is just a single -string literal with elements separated by semi-colons ``";;..."``. -CMake is a bit odd in how it deals with these arrays, which are just -represented as a string with elements separated with semi-colons ``';'``. For -example, all of the following are equivalent and pass in a CMake array with 3 -elements [``A``], [``B``], and [``C``]:: - - some_func(A B C) - some_func("A" "B" "C") - some_func("A;B;C") - -However, the above is *not* the same as:: - - some_func("A B C") - -which just passes in a single element with value [``A B C``]. Raw quotes in -CMake basically escape the interpretation of space characters as array element -boundaries. Quotes around arguments with no spaces does nothing (as seen -above, except for the interpretation as variable names in an ``if()`` -statement). In order to get a quote char [``"``] into string, you must escape -it as:: - - some_func(\"A\") - -which passes an array with the single argument [``\"A\"``]. - -Variables are set using the built-in CMake ``set()`` command that just takes -string arguments like:: - - set(SOME_VARIABLE "some_value") - -In CMake, the above is identical, in every way, to:: - - set(SOME_VARIABLE some_value) - set("SOME_VARIABLE";"some_value") - set("SOME_VARIABLE;some_value") - -The function ``set()`` simply interprets the first argument to as the name of -a variable to set in the local scope. Many other built-in and user-defined -CMake functions work the same way. That is, some of the string arguments are -interpreted as the names of variables. There is no special language feature -that interprets them as variables (except in an ``if()`` statement). - -However, CMake appears to parse arguments differently for built-in CMake -control structure functions like ``foreach()`` and ``if()`` and does not just -interpret them as a string array. For example:: - - foreach (SOME_VAR "a;b;c") - message("SOME_VAR='${SOME_VAR}'") - endforeach() - -prints ```SOME_VAR='a;b;c'`` instead of printing ``SOME_VAR='a'`` followed by -``SOME_VAR='b'``, etc., as you would otherwise expect. Therefore, this simple -rule for the handling of function arguments as string arrays does not hold for -CMake logic control commands. Just follow the CMake documentation for these -control structures (i.e. see ``cmake --help-command if`` and ``cmake ---help-command foreach``). - -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 -combination of positional and keyword arguments. - -Variable names are translated into their stored values using -``${SOME_VARIABLE}``. The value that is extracted depends on if the variable -is set in the local or global (cache) scope. The local scopes for CMake start -in the base project directory in its base ``CMakeLists.txt`` file. Any -variables that are created by macros in that base local scope are seen across -an entire project but are *not* persistent across multiple successive -``cmake`` configure invocations where the cache file ``CMakeCache.txt`` is not -deleted in between. - -The handling of variables is one area where CMake is radically different from -most other languages. First, a variable that is not defined simply returns -nothing. What is surprising to most people about this is that it does not -even return an empty string that would register as an array element! For -example, the following set statement:: - - set(SOME_VAR a ${SOME_UNDEFINED_VAR} c) - -(where ``SOME_UNDEFINED_VAR`` is an undefined variable) produces -``SOME_VAR='a;c'`` and *not* ``'a;;c'``! The same thing occurs when an empty -variable is de-references such as with:: - - set(EMPTY_VAR "") - set(SOME_VAR a ${EMPTY_VAR} c) - -which produces ``SOME_VAR='a;c'`` and *not* ``'a;;c'``. In order to always -produce an element in the array even if the variable is empty, one must quote -the argument as with:: - - set(EMPTY_VAR "") - set(SOME_VAR a "${EMPTY_VAR}" c) - -which produces ``SOME_VAR='a;;c'``, or three elements as one might assume. - -This is a common error that people make when they call CMake functions -(built-in or TriBITS-defined) involving variables that might be undefined or -empty. For example, for the macro:: - - macro(some_macro A_ARG B_ARG C_ARG) - ... - endmacro() - -if someone tries to call it with (misspelled variable?):: - - some_macro(a ${SOME_OHTER_VAR} c) - -and if ``SOME_OHTER_VAR=""`` or if it is undefined, then CMake will error out -with the error message saying that the macro ``some_macro()`` takes 3 -arguments but only 2 were provided. If a variable might be empty but that is -still a valid argument to the command, then it must be quoted as:: - - some_macro(a "${SOME_OHTER_VAR}" c) - -Related to this problem is that if you misspell the name of a variable in a -CMake ``if()`` statement like:: - - if (SOME_VARBLE) - ... - endif() - -then it will always be false and the code inside the if statement will never -be executed! To avoid this problem, use the utility function -`assert_defined()`_ as:: - - assert_defined(SOME_VARBLE) - if (SOME_VARBLE) - ... - endif() - -In this case, the misspelled variable would be caught. - -While on the subject of ``if()`` statements, CMake has a strange convention. -When you say:: - - if (SOME_VAR) - do_something() - endif() - -then ``SOME_VAR`` is interpreted as a variable and will be considered true and -``do_something()`` will be called if ``${SOME_VAR}`` does *not* evaluate to -``0``, ``OFF``, ``NO``, ``FALSE``, ``N``, ``IGNORE``, ``""``, or ends in the -suffix ``-NOTFOUND``. How about that for a true/false rule! To be safe, use -``ON/OFF`` and ``TRUE/FALSE`` pairs for setting variables. Look up native -CMake documentation on ``if()`` for all the interesting details and all the -magical things it can do. - -**WARNING:** If you mistype ``"ON"`` as ``"NO"``, it evaluates to -``FALSE``/``OFF``! (That is a fun defect to track down!) - -CMake language behavior with respect to case sensitivity is also strange: - -* Calls of built-in and user-defined macros and functions is *case - insensitive*! That is ``set(...)``, ``set(...)``, ``set()``, and all other - combinations of upper and lower case characters for 'S', 'E', 'T' all call - the built-in ``set()`` function. The convention in TriBITS is to use - ``lower_case_with_underscores()`` for functions and macros. - -* However, the names of CMake (local or cache/global) variables are *case - sensitive*! That is, ``SOME_VAR`` and ``some_var`` are *different* - variables. Built-in CMake variables tend use all caps with underscores - (e.g. ``CMAKE_CURRENT_SOURCE_DIR``) but other built-in CMake variables tend - to use mixed case with underscores (e.g. ``CMAKE_Fortran_FLAGS``). TriBITS - tends to use a similar naming convention where project-level and cache - variables have mostly upper-case letters except for parts that are proper - nouns like the project, package or external package/TPL name - (e.g. ``TribitsExProj_TRIBITS_DIR``, ``TriBITS_SOURCE_DIR``, - ``Boost_INCLUDE_DIRS``). Local variables and function/macro parameters can - use camelCase or lower_case_with_underscores. - -I don't know of any other programming language that uses different case -sensitivity rules for variables and functions. However, because we must parse -macro and function arguments when writing user-defined macros and functions, -it is a good thing that CMake variables are case sensitive. Case insensitivity -would make it much harder and more expensive to parse argument lists that take -keyword-based arguments. - -Other mistakes that people make result from not understanding how CMake scopes -variables and other entities. CMake defines a global scope (i.e. "cache" -variables) and several nested local scopes that are created by -``add_subdirectory()`` and entering functions. See `dual_scope_set()`_ for a -short discussion of these scoping rules. And it is not just variables that -can have local and global scoping rules. Other entities, like defines set -with the built-in command ``add_definitions()`` only apply to the local scope -and child scopes. That means that if you call ``add_definitions()`` to set a -define that affects the meaning of a header-file in C or C++, for example, -that definition will *not* carry over to a peer subdirectory and those -definitions will not be set (see warning in `Miscellaneous Notes -(tribits_add_library())`_). - -Now that some CMake basics and common gotchas have been reviewed, we now get -into the meat of TriBITS starting with the overall structure of a TriBITS -project in the next section. Software Engineering Packaging Principles ----------------------------------------- -The term "software engineering" package is adopted in TriBITS nomenclature in -order to highlight and the role of defining and managing "Packages" according -to standard software engineering packaging principles. In his book [`Agile -Software Development, 2003`_], Robert Martin defines several object-oriented -(OO) software engineering principles related to packaging software which are -listed below: +The design of TriBITS takes into account standard software engineering +packaging principles. In his book [`Agile Software Development, 2003`_], +Robert Martin defines several software engineering principles related to +packaging software which are listed below: * *Package Cohesion OO Principles*: @@ -398,6 +160,7 @@ further. However, interested readers are strongly encouraged to read [`Agile Software Development, 2003`_] as one of the better software engineering books out there (see https://bartlettroscoe.github.io/reading-list/#most_recommended_se_books). + TriBITS Project Structure ========================= @@ -472,7 +235,7 @@ units are: Packages`_. A modern TriBITS external package/TPL (Third Party Library) is typically just a small file ``FindTPL.cmake`` that calls ``find_package()`` and defines the ``::all_libs`` - target. More generally, an external package/TPL can be specificed as a list + target. More generally, an external package/TPL can be specified as a list list of libraries and/or include directories for header files. Examples of basic external packages/TPLs include ``BLAS``, ``LAPACK``, and ``Boost``. @@ -1798,6 +1561,17 @@ defined: what contexts the package is enabled or not for testing-related purposes (see `Nested Layers of TriBITS Project Testing`_) + .. _${PACKAGE_NAME}_SUBPACKAGES: + + ``${PACKAGE_NAME}_SUBPACKAGES`` + + Defines the list of subpackage names for a top-level parent package. This + gives the unique subpackage name without the parent package prefix. For + example, the `ReducedMockTrilinos`_ package ``Thyra`` has the subpackages + ``CoreLibs``, ``GoodStuff``, etc. (which forms the full package names + ``ThyraCoreLibs``, ``ThyraGoodStuff``, etc.). If a top-level package is + not broken down into subpackages, then this list is empty. + .. _TriBITS Package Cache Variables: In addition, the following user-settable **TriBITS Package Cache Variables** @@ -2155,10 +1929,11 @@ A *TriBITS External Package/TPL*: interface to one or more downstream TriBITS Packages. * Has a globally unique name ```` (see `Globally unique TriBITS TPL names`_) that is declared in a `/TPLsList.cmake`_ file. -* Has as `FindTPL.cmake`_ module that finds the pieces of an external - package/TPL and provides them to downstream packages through a required - INTERFACE target ``::all_libs`` (which gives the libraries, include - directories, and other usage requirements). +* Has as `FindTPL.cmake`_ module (for non-`TriBITS-Compliant External + Packages`_) that finds the pieces of an external package/TPL and provides + them to downstream packages through a required INTERFACE target + ``::all_libs`` (which gives the libraries, include directories, and + other usage requirements, see `TriBITS-Compliant External Package`_). * Is listed as an explicit optional or required dependency in one or more downstream TriBITS packages' `/cmake/Dependencies.cmake`_ files. * Can be enabled automatically or can trigger the disable of dependent @@ -2177,6 +1952,14 @@ if an external package/TPL is explicitly disabled, all of the downstream packages that depend on it will be automatically disabled as well (see `Package disable triggers auto-disables of downstream dependencies`_). +NOTE: The TriBITS TPL system implements a mechanism to turn external +dependencies into both `TriBITS-compliant packages`_ for consumption by +downstream TriBITS internal packages and also writes ``Config.cmake`` +files that are `TriBITS-compliant external packages`_ for consumption by +downstream ``Config.cmake`` files (which are `TriBITS-compliant +external packages`_) generated by `TriBITS-compliant internal packages`_. + + .. _Globally unique TriBITS TPL names: **WARNING:** One must be very careful to pick **Globally unique TriBITS @@ -2213,12 +1996,13 @@ below: .. _FindTPL.cmake: .. _/FindTPL.cmake: -**/FindTPL.cmake**: [Required] Defines how an external -package/TPL is found and provided for usage by a downstream TriBITS package by -providing the ``::all_libs`` target and a package config file -``Config.cmake`` that also defines the target -``::all_libs``. (The requirements for a ``FindTPL.cmake`` -file are given in `Requirements for FindTPL.cmake modules`_). +**/FindTPL.cmake**: [Required] *TriBITS TPL find module* +that defines how a TriBITS external package/TPL is found and provided for +usage by a downstream TriBITS package. This module must provide the +``::all_libs`` target and must create a `TriBITS-compliant external +package`_ wrapper package config file ``Config.cmake``. (See the +requirements for a ``FindTPL.cmake`` file in `Requirements for +FindTPL.cmake modules`_). The form of a simple ``FindTPL.cmake`` file that uses an internal call to ``find_package()`` which provides modern IMPORTED CMake @@ -2234,7 +2018,8 @@ In this case, the purpose for the ``FindTPL.cmake`` file (as apposed to a direct call to ``find_package()``) 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.). +include directories, etc.) and this also generates the wrapper package config +file ``Config.cmake``. The form of a simple ``FindTPL.cmake`` file that just provides a list of required header files and libraries that does **not** use an internal call @@ -2298,16 +2083,20 @@ defined TPL ``TPL_NAME`` is assigned the following global non-cache variables: ``${TPL_NAME}_FINDMOD`` - Relative path (w.r.t. ````) or absolute path for the external - package/TPL's find module (typically named `FindTPL.cmake`_): - 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. + For a **non-** `TriBITS-compliant external package`_, this is the relative + path (w.r.t. ````) or absolute path for the *TriBITS TPL find + module* (typically named `FindTPL.cmake`_). 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. NOTE: for a `TriBITS-compliant + external package`_, the special value ``TRIBITS_PKG`` is also recognized. + (Any pre-installed TriBITS package is a `TriBITS-compliant external + package`_.) .. __DEPENDENCIES_FILE: .. _${TPL_NAME}_DEPENDENCIES_FILE: @@ -2317,10 +2106,15 @@ defined TPL ``TPL_NAME`` is assigned the following global non-cache variables: Relative path (w.r.t. ````) or absolute path for the external package/TPL's dependencies file (typically named `FindTPLDependencies.cmake`_). This is always beside the find - module `${TPL_NAME}_FINDMOD`_ (and in fact - ``${TPL_NAME}_DEPENDENCIES_FILE`` is constructed from - ``${TPL_NAME}_FINDMOD``). - + module `${TPL_NAME}_FINDMOD`_. (In fact, for a **non-** + `TriBITS-compliant external package`_, ``${TPL_NAME}_DEPENDENCIES_FILE`` + is constructed from ``${TPL_NAME}_FINDMOD``). NOTE: A `TriBITS-compliant + external package`_ with dependencies will also have this file set and the + path will be specified independent of the path to the non-existent + ``FindTPL.cmake`` file (see the ``FINDMOD`` field in the call to + `tribits_repository_define_tpls()`_). + + .. __TESTGROUP: .. _${TPL_NAME}_TESTGROUP: ``${TPL_NAME}_TESTGROUP`` @@ -2775,6 +2569,158 @@ without having to define its own ``QT`` TPL in its repository's .. ToDo: Describe considerations on where to set variables ... +.. _TriBITS-Compliant Package: + +TriBITS-Compliant Packages +========================== + +At the CMake build-system level, there are just a few key requirements that a +TriBITS package has for its upstream dependent packages when it is being +configured to be built. These requirements apply whether the upstream package +is defined internally in the current CMake project or provided externally and +pulled in through ``find_package()``. + +The common requirements for both internal and external **TriBITS-compliant +packages** as imposed by downstream TriBITS internal packages are: + +* Provides the (INTERFACE) target ``::all_libs`` which provides all + usage requirements for the libraries of ```` through the target + properties: + + * ``INTERFACE_LINK_LIBRARIES``: The library files needed link against (or + upstream library targets including ``::all_libs`` for all + its upstream packages) + + * ``INTERFACE_INCLUDE_DIRECTORIES``: Include directories to all public header files + + * ``INTERFACE_COMPILE_OPTIONS``: Required compiler options + + * ``INTERFACE_COMPILE_DEFINITIONS``: Required compiler/macro definitions + + * ``INTERFACE_LINK_OPTIONS``: Required compiler/macro definitions + + * Any other ``INTERFACE_XXX`` or ``IMPORTED_XXX`` target property needed to + correctly use the libraries for package ````. + +* Provides namespaced variables ``_ENABLE_`` set to + ``TRUE`` or ``FALSE`` for all of the upstream required and optional + dependencies for the package ````. + +* [Optional] Provides namespaced variables of the form + ``_`` for any other information about the configuration + of package ```` that may need to be known by a downstream TriBITS + package. + +* [Optional] Provides any (namespaced by ``_`` or ``_``) + CMake macros or functions that downstream CMake packages may need to use the + upstream package ````. + +* All of the upstream dependencies (listed in the ``INTERFACE_LINK_LIBRARIES`` + property recursively) are also `TriBITS-compliant packages`_ + +The TriBITS system will also set the variable: + +* ``_IS_TRIBITS_COMPLIANT``: Set to ``TRUE`` + +for all packages that are determined to be TriBITS-compliant packages. + +The above are all that is needed by downstream TriBITS packages to build and +link against their upstream dependencies. + +If a TriBITS package provides any CTest tests/examples, then it must also +satsify the following requirements: + +* Test names must be prefixed with the package name ``_``. + +* Tests should only be added if the variable ``_ENABLE_TESTS`` is + true. + +* Examples (that run as CTest tests) should only be added if the variable + ``_ENABLE_EXAMPLES`` is true. + +* The test ``PROCESSORS`` and other test properties must be set in a way + consistent with `tribits_add_test()`_ so as to run in parallel with other + tests and not overwhelm the computing resources on the machine. + +Additional requirements are placed on TriBITS-compliant packages depending on +if they are defined as internal CMake packages (i.e. `TriBITS-compliant +internal packages`_) or are pulled in as external pre-built/pre-installed +packages (i.e. `TriBITS-compliant external packages`_). + + +.. _TriBITS-Compliant Internal Packages: + +TriBITS-Compliant Internal Packages +----------------------------------- + +For TriBITS packages that are defined, built, and installed from a TriBITS +CMake project, there are an additional set of requirements for them to +behavior correctly with respect to other TriBITS packages. + +The requirements for **TriBITS-compliant internal packages** are: + +* All of the requirements for a `TriBITS-Compliant Package`_. + +* At the end of configuration and generation, writes out a `TriBITS-Compliant + External Package`_ file ``Config.cmake`` and supporting files under + the build directory ``/cmake_packages//`` allowing the + built (but not installed) package to be used by downstream CMake + packages/projects. + +* Provides an install target to create a `TriBITS-Compliant External Package`_ + file ``Config.cmake`` and supporting files under the install + directory ``/lib/cmake//`` allowing the installed + package to be used by downstream CMake packages/projects. + +* All of the upstream dependencies (recursively) are also `TriBITS-compliant + packages`_ + +TriBITS internal packages that are defined using the TriBITS framework using +the TriBITS-provided macros and functions such as `tribits_add_library()`_ are +automatically `TriBITS-compliant internal packages`_ and when they are +installed they automatically provide `TriBITS-compliant external packages`_. +But it is possible for a CMake package to write its own raw CMake code to +satisfy these basic requirements for both internal and external packages. + + +.. _TriBITS-Compliant External Package: + +TriBITS-Compliant External Packages +----------------------------------- + +For packages that are installed on the system and not built in the current +CMake project, a streamlined type of `TriBITS External Package/TPL`_ is a +*TriBITS-compliant external package*. These special types of external +package's don't need to provide a `FindTPL.cmake`_ find module. +Instead, they are fully defined by calling ``find_package()`` to +locate and load their ``Config.cmake`` package config file. + +The requirements for **TriBITS-compliant external packages** are: + +* All of the requirements for a `TriBITS-Compliant Package`_. + +* Defined by an installed ``Config.cmake`` file that provides + IMPORTED targets and ``set()`` statements for all of the needed variables. + +* Provides CMake variables: + + * ``_CONFIG`` or + ``_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE``: Points to the file + ``Config.cmake`` (i.e. ``${CMAKE_CURRENT_LIST_FILE}``) + + * ``_DIR`` or + ``_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR`` Points to the base + directory for ``Config.cmake`` + (i.e. ``${CMAKE_CURRENT_LIST_DIR}``) + +* All of the upstream dependencies (recursively) are also provided as + `TriBITS-compliant external packages`_ with + ``Config.cmake`` files (see above) and all of the targets + and variables for a TriBITS-compliant external package are defined when the + ``Config.cmake`` file is included (or pulled in with + ``find_package()`` or ``find_dependency()``). + + Example TriBITS Projects ========================= @@ -5595,15 +5541,20 @@ To add a new TriBITS TPL, do the following: 3) **Create the FindTPL.cmake file** (or some other name, see `_FINDMOD`_) under ``/``. (See `Creating the - FindTPL.cmake file`_.) + FindTPL.cmake file`_.) However, if the external package/TPL is a + `TriBITS-compliant external package`_ this file is not needed and is + ignored. 4) **[Optional] Create the FindTPLDependencies.cmake file** in the same directory as the ``FindTPL.cmake`` file, ``/``. - (See `FindTPLDependencies.cmake`_.) + (See `FindTPLDependencies.cmake`_.) NOTE: This file is need for a + `TriBITS-compliant external package`_ if it has upstream dependent external + packages/TPLs (where the file ``FindTPL.cmake`` is not needed). -5) **Add a row to the /TPLsList.cmake file** for the new TPL after - any TPLs that this new TPL may depend on. (See - `/TPLsList.cmake`_.) +5) **Add a row to the /TPLsList.cmake file** for the new external + package/TPL after any upstream TPLs that this new TPL may depend on. NOTE: + For a `TriBITS-compliant external package`_, the special value + ``TRIBITS_PKG`` is used for the TPL (See `/TPLsList.cmake`_.) 6) **Configure the TriBITS project enabling the new TPL with TPL_ENABLE_=ON** and see that the TPL is found correctly at @@ -5674,16 +5625,16 @@ 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 +``::all_libs`` target which is required for a TriBITS-compliant 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. +for consumption by downstream TriBITS-compliant packages. -The following subsections will describe how to create these TriBITS-compatible +The following subsections will describe how to create these TriBITS-compliant ``FindTPL.cmake`` modules for all of the various cases using an internal call to ``find_package( ...)``: @@ -5698,10 +5649,9 @@ 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_extpkg_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 +function `tribits_extpkg_create_imported_all_libs_target_and_config_file()`_ +after calling ``find_package()`` to create a very thin find +module file ``FindTPL.cmake``. In these cases, such a ``FindTPL.cmake`` module file is nothing more than:: find_package( REQUIRED) @@ -5711,27 +5661,30 @@ after calling ``find_package()`` to create a very thin wrapper IMPORTED_TARGETS_FOR_ALL_LIBS ... ) The function -`tribits_extpkg_create_imported_all_libs_target_and_config_file()`_ -creates the target ``::all_libs`` and the wrapper file +`tribits_extpkg_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. +``find_package( ...)`` call. The TriBITS function +``tribits_extpkg_create_imported_all_libs_target_and_config_file()`` takes +care of all of the rest of the details. 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. +to modern CMake along with the proper usage of complete +``Config.cmake`` files, this 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:: +`tribits_tpl_allow_pre_find_package()`_ in combination with the functions +``tribits_extpkg_create_imported_all_libs_target_and_config_file()`` and +`tribits_tpl_find_include_dirs_and_libraries()`_ as follows:: set(REQUIRED_HEADERS ...) set(REQUIRED_LIBS_NAMES ...) @@ -5948,21 +5901,31 @@ header files and libraries that must be found. A simple 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: +It is possible to create a ``FindTPL.cmake`` find module without +using any TriBITS functions. The only firm requirements for a +``FindTPL.cmake`` file 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). + (including for all upstream external packages/TPLs) to implement a + `TriBITS-compliant package`_ to be consumed by downstream TriBITS packages. * 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 + must be created in the build directory, and when included, it must define + the equivalent IMPORTED target ``::all_libs``, pull all of the + ``Config.cmake`` files for upstream external packages/TPLs, and + define the needed variables to provide a `TriBITS-compliant external + package`_. + +TriBITS will set the remaining variables to provide a complete +`TriBITS-Compliant Package`_ for the current CMake project and will add the +install target to install the file +``/external_packages//Config.cmake`` to create a +`TriBITS-compliant external package`_. TriBITS will also automatically create +an appropriate package version file ``ConfigVersion.cmake``. + +Some of issues to consider in this case (and the role of the +``ConfigVersion.cmake`` file) are described in the section `Tricky considerations for TriBITS-generated Config.cmake files`_. @@ -6980,38 +6943,41 @@ 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 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:: +discussed here is the fact that ``FindTPL.cmake`` module files create +(See `How to add a new TriBITS TPL`_) and TriBITS installs package config +files of the name ``Config.cmake``. These TriBITS-generated package +config files ``Config.cmake`` could potentially be found by calls to +``find_package()`` (i.e. when `` == `` like +with HDF5). These TriBITS-generated ``Config.cmake`` files are +primarily meant to provide a `TriBITS-compliant external package`_ for +downstream TriBITS-compliant ``Config.cmake`` files. These +TriBITS-generated ``Config.cmake`` files will usually not behave the +same way existing ``Find.config`` find modules or native +``Config.cmake`` package config files would behave as expected by +downstream projects 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 could be disastrous), TriBITS employs two +safeguards. + +First, TriBITS-generated ``Config.cmake`` package config files are +placed into the build directory under:: /external_packages//Config.cmake -and installed into the directory under:: +and installed into the installation 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 +to ``CMAKE_PREFIX_PATH``. + +Second, even if the directories ``/lib/external_packages`` or +``/external_packages`` do get added to the search path somehow +(e.g. by appending those to ``CMAKE_INSTALL_PREFIX``), the companion +TriBITS-generated ``ConfigVersion.cmake`` files 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 @@ -7043,7 +7009,7 @@ will be used). Also, there are cases were one cannot easily control the default file or directory creation permissions using ``umask``. And there are cases where one would like to recursively install a set of directories and files where some of these files may be scripts that need to have the execute -permission set on them for them to work. The only to flexiable accomplish +permission set on them for them to work. The only to flexible accomplish that with CMake (if one does not know the exist list of those files or extensions of those files) is to pass in the ``SOURCE_PERMISSIONS`` option to the ``install(DIRECTORY ...)`` command. An example of this is shown in: diff --git a/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst b/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst index 597e2cb2a..15e079ea7 100644 --- a/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst +++ b/tribits/doc/guides/TribitsMacroFunctionDocTemplate.rst @@ -25,6 +25,7 @@ @MACRO: tribits_extpkg_define_dependencies() + @FUNCTION: tribits_extpkg_get_dep_name_and_vis() + @FUNCTION: tribits_extpkg_create_imported_all_libs_target_and_config_file() + +@FUNCTION: tribits_extpkg_tpl_libraries_entry_type() + @FUNCTION: tribits_extpkg_write_config_file() + @FUNCTION: tribits_extpkg_write_config_file_str() + @FUNCTION: tribits_find_most_recent_binary_file_timestamp() + @@ -39,7 +40,7 @@ @MACRO: tribits_package_define_dependencies() + @MACRO: tribits_package_postprocess() + @MACRO: tribits_process_subpackages() + -@FUNCTION: tribits_process_enabled_tpl() + +@MACRO: tribits_process_enabled_standard_tpl() + @MACRO: tribits_project() + @MACRO: tribits_project_define_extra_repositories() + @MACRO: tribits_project_enable_all() + @@ -51,7 +52,6 @@ @MACRO: tribits_subpackage_postprocess() + @FUNCTION: tribits_tpl_allow_pre_find_package() + @FUNCTION: tribits_tpl_find_include_dirs_and_libraries() + -@FUNCTION: tribits_tpl_libraries_entry_type() + @FUNCTION: tribits_tpl_tentatively_enable() + @FUNCTION: tribits_write_flexible_package_client_export_files() + @FUNCTION: tribits_verbose_print_var() + diff --git a/tribits/doc/guides/TribitsSystemMacroFunctionDocTemplate.rst b/tribits/doc/guides/TribitsSystemMacroFunctionDocTemplate.rst index a8c9f53d2..6a71292c4 100644 --- a/tribits/doc/guides/TribitsSystemMacroFunctionDocTemplate.rst +++ b/tribits/doc/guides/TribitsSystemMacroFunctionDocTemplate.rst @@ -16,15 +16,17 @@ understand the internals of TriBITS. @MACRO: tribits_append_forward_dep_packages() + @MACRO: tribits_assert_read_dependency_vars() + @FUNCTION: tribits_dump_package_dependencies_info() + -@FUNCTION: tribits_extpkg_add_find_upstream_dependencies_str() + -@FUNCTION: tribits_extpkg_create_all_libs_target() + +@FUNCTION: tribits_extpkg_append_create_all_libs_target_str() + +@FUNCTION: tribits_extpkg_append_find_upstream_dependencies_str() + @FUNCTION: tribits_extpkg_install_config_file() + @FUNCTION: tribits_extpkg_install_config_version_file() + @FUNCTION: tribits_extpkg_process_libraries_list() + @MACRO: tribits_extpkg_setup_enabled_dependencies() + @FUNCTION: tribits_extpkg_write_config_version_file() + +@FUNCTION: tribits_filter_package_list_from_var() + @FUNCTION: tribits_get_sublist_disabled() + @FUNCTION: tribits_get_sublist_enabled() + +@FUNCTION: tribits_get_sublist_internal_external() + @FUNCTION: tribits_get_sublist_nondisabled() + @FUNCTION: tribits_get_sublist_nonenabled() + @FUNCTION: tribits_print_initial_dependency_info() + diff --git a/tribits/doc/guides/maintainers_guide/TribitsMaintainersGuide.rst b/tribits/doc/guides/maintainers_guide/TribitsMaintainersGuide.rst index c9c0b1b7c..f9d973495 100644 --- a/tribits/doc/guides/maintainers_guide/TribitsMaintainersGuide.rst +++ b/tribits/doc/guides/maintainers_guide/TribitsMaintainersGuide.rst @@ -71,6 +71,8 @@ Developers`_ and `TriBITS System Architects`_. Appendix ======== +.. include:: ../TribitsCMakeLanguageOverviewAndGotchas.rst + .. include:: ../TribitsHistory.rst .. include:: ../TribitsPackageNotCMakePackage.rst diff --git a/tribits/doc/guides/users_guide/TribitsUsersGuide.rst b/tribits/doc/guides/users_guide/TribitsUsersGuide.rst index be4cee320..720a71c75 100644 --- a/tribits/doc/guides/users_guide/TribitsUsersGuide.rst +++ b/tribits/doc/guides/users_guide/TribitsUsersGuide.rst @@ -90,6 +90,8 @@ in the `Appendix`_. Appendix ======== +.. include:: ../TribitsCMakeLanguageOverviewAndGotchas.rst + .. include:: ../TribitsHistory.rst .. include:: ../TribitsPackageNotCMakePackage.rst diff --git a/tribits/examples/MockTrilinos/CMakeLists.txt b/tribits/examples/MockTrilinos/CMakeLists.txt index 49c1bcc08..7fb43de86 100644 --- a/tribits/examples/MockTrilinos/CMakeLists.txt +++ b/tribits/examples/MockTrilinos/CMakeLists.txt @@ -41,5 +41,6 @@ cmake_minimum_required(VERSION 3.23.0 FATAL_ERROR) include(${CMAKE_SOURCE_DIR}/ProjectName.cmake) project(${PROJECT_NAME} NONE) set(${PROJECT_NAME}_TRIBITS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." CACHE PATH "") +set(${PROJECT_NAME}_TRACE_DEPENDENCY_HANDLING_ONLY ON CACHE BOOL "") include("${${PROJECT_NAME}_TRIBITS_DIR}/TriBITS.cmake") tribits_project() diff --git a/tribits/examples/TribitsExampleProject/packages/simple_cxx/CMakeLists.txt b/tribits/examples/TribitsExampleProject/packages/simple_cxx/CMakeLists.txt index 4eb715a09..295e359fa 100644 --- a/tribits/examples/TribitsExampleProject/packages/simple_cxx/CMakeLists.txt +++ b/tribits/examples/TribitsExampleProject/packages/simple_cxx/CMakeLists.txt @@ -32,6 +32,7 @@ endif() global_set(EXPECTED_SIMPLECXX_AND_DEPS "SimpleCxx ${simpletplText}headeronlytpl") +tribits_pkg_export_cache_var(EXPECTED_SIMPLECXX_AND_DEPS) # # E) Do standard post processing diff --git a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt index 200d869b1..717246f3c 100644 --- a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt +++ b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt @@ -22,6 +22,7 @@ endif() global_set(EXPECTED_B_DEPS "${EXPECTED_A_AND_DEPS_STR}${EXPECTED_INSERTEDPKG_AND_DEPS_STR}${EXPECTED_SIMPLECXX_AND_DEPS}") +tribits_pkg_export_cache_var(EXPECTED_B_DEPS) tribits_add_test_directories(tests) diff --git a/tribits/examples/TribitsExampleProject/packages/wrap_external/CMakeLists.txt b/tribits/examples/TribitsExampleProject/packages/wrap_external/CMakeLists.txt index 0efcd994f..a9f8b0a37 100644 --- a/tribits/examples/TribitsExampleProject/packages/wrap_external/CMakeLists.txt +++ b/tribits/examples/TribitsExampleProject/packages/wrap_external/CMakeLists.txt @@ -7,21 +7,6 @@ # provides libraries that need to be cast as TriBITS CMake libraries. To # make this even more interesting, the external software has dependencies on # upstream TriBITS packages. -# -# An overview of the basic tasks required are: -# -# a) Enumerate the upstream packages and TPLs needed (this is done in the -# cmake/Dependencies.cmake file). -# -# b) Generate an export makefile for the upstream packages and TPLs -# -# c) Call the configure script for the external package passing the compilers, -# compiler flags, and a pointer to the export makefile (which is just used to -# lift the include dirs and libs). -# -# d) Define library targets for the external project and define a build rule -# for generating those libraries given the list of header and source files in -# the external project. tribits_package(WrapExternal) @@ -66,41 +51,51 @@ endif() string(TOUPPER "${CMAKE_BUILD_TYPE}" upperBuildType) -set(includeDirsList - -I ${WithSubpackagesA_SOURCE_DIR} - -I ${SimpleCxx_SOURCE_DIR}/src - -I ${SimpleCxx_BINARY_DIR}/src - ) +get_target_property(simpleCxx_IncludeDirs + SimpleCxx::simplecxx INTERFACE_INCLUDE_DIRECTORIES) + +get_target_property(withSubpackagesA_IncludeDirs + WithSubpackagesA::pws_a INTERFACE_INCLUDE_DIRECTORIES) + +set(includeDirsList ${withSubpackagesA_IncludeDirs} ${simpleCxx_IncludeDirs}) + if (${PACKAGE_NAME}_ENABLE_MixedLang) - list(PREPEND includeDirsList - -I ${MixedLang_SOURCE_DIR}/src - -I ${MixedLang_BINARY_DIR}/src - ) + get_target_property(mixedLang_IncludeDirs + MixedLang::mixedlang INTERFACE_INCLUDE_DIRECTORIES) + list(PREPEND includeDirsList ${mixedLang_IncludeDirs}) endif() -list(JOIN includeDirsList " " includeDirs) -# NOTE: TriBITS export Makefile support used to handle the above stuff -# automatically but that is what you give up when moving to modern CMake. +list(JOIN includeDirsList " -I" includeDirsCompileOptions) +set(includeDirsCompileOptions "-I${includeDirsCompileOptions}") # -# C) Do configuration of the external project +# C) Do configuration of the external project as a build target # set(EXTERNAL_FUNC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_func) set(EXTERNAL_FUNC_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/external_func) set(EXTERNAL_FUNC_LIB_FILE ${EXTERNAL_FUNC_BINARY_DIR}/libexternal_func.a) +set(EXTERNAL_FUNC_MAKEFILE ${EXTERNAL_FUNC_BINARY_DIR}/Makefile) file(MAKE_DIRECTORY ${EXTERNAL_FUNC_BINARY_DIR}) -execute_process( +add_custom_command( + OUTPUT ${EXTERNAL_FUNC_MAKEFILE} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${EXTERNAL_FUNC_SOURCE_DIR}/configure.py COMMAND ${PYTHON_EXECUTABLE} ${EXTERNAL_FUNC_SOURCE_DIR}/configure.py "--cxx=${CMAKE_CXX_COMPILER}" "--cxx-flags=${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${upperBuildType}}" "--ar=${CMAKE_AR}" - "--include-dirs=${includeDirs}" + "--include-dirs=${includeDirsCompileOptions}" "--src-dir=${EXTERNAL_FUNC_SOURCE_DIR}" "--build-dir=${EXTERNAL_FUNC_BINARY_DIR}" ) +# NOTE: Above, we have to run the configure.py script at build time after +# generation because ${includeDirsCompileOptions} contains generation +# expressions that are evaluated at generation time by the +# add_custom_command() call. + # # D) Define a custom build rule and target to create external_func library # @@ -109,6 +104,7 @@ add_custom_command( OUTPUT ${EXTERNAL_FUNC_LIB_FILE} DEPENDS ${EXTERNAL_FUNC_SOURCE_DIR}/external_func.hpp ${EXTERNAL_FUNC_SOURCE_DIR}/external_func.cpp + ${EXTERNAL_FUNC_MAKEFILE} COMMAND make ${CTEST_BUILD_FLAGS} WORKING_DIRECTORY ${EXTERNAL_FUNC_BINARY_DIR} ) @@ -137,13 +133,13 @@ add_dependencies(external_func build_external_func) # E.2) Make sure before we build the external library, we first build the # libraries. -add_dependencies(build_external_func pws_a) +add_dependencies(build_external_func WithSubpackagesA::pws_a) # NOTE: You have to put the lib dependencies on build target, not the imported # library target! # E.3) Update the TriBITS variables append_set(${PACKAGE_NAME}_LIB_TARGETS external_func) -global_set(${PACKAGE_NAME}_LIBRARIES external_func pws_a) +global_set(${PACKAGE_NAME}_LIBRARIES external_func WithSubpackagesA::pws_a) global_set(${PACKAGE_NAME}_HAS_NATIVE_LIBRARIES ON) tribits_include_directories(${EXTERNAL_FUNC_SOURCE_DIR}) # NOTE: Above, you have to add the upstream dependent libraries to the current