From 7f7a11a6fd97323bb692fcc5a4c33c94467041de Mon Sep 17 00:00:00 2001 From: "Roscoe A. Bartlett" Date: Fri, 8 Sep 2023 11:17:03 -0600 Subject: [PATCH] SQUASH AGAINST: WIP: Add HowTos for TriBITS-compliant raw CMake package (#582) --- tribits/doc/guides/.gitignore | 2 + tribits/doc/guides/TribitsGuidesBody.rst | 145 ++++++++++++------ tribits/doc/guides/generate-guide.sh | 11 ++ .../packages/package1/CMakeLists.raw.cmake | 3 +- 4 files changed, 112 insertions(+), 49 deletions(-) diff --git a/tribits/doc/guides/.gitignore b/tribits/doc/guides/.gitignore index 7f018678f..b1980aad1 100644 --- a/tribits/doc/guides/.gitignore +++ b/tribits/doc/guides/.gitignore @@ -4,6 +4,8 @@ /TriBITS.README.DIRECTORY_CONTENTS.rst.tmp /TribitsCommonTPLsList.txt /TribitsCommonTPLsList.txt.tmp +/TribitsExampleProject2_Package1_CMakeLists.raw.external.cmake +/TribitsExampleProject2_Package1_CMakeLists.raw.internal.cmake /TribitsGitVersion.txt /TribitsGitVersion.txt.tmp /TribitsHelloWorldDirAndFiles.txt diff --git a/tribits/doc/guides/TribitsGuidesBody.rst b/tribits/doc/guides/TribitsGuidesBody.rst index 2f19469df..259e0be06 100644 --- a/tribits/doc/guides/TribitsGuidesBody.rst +++ b/tribits/doc/guides/TribitsGuidesBody.rst @@ -6262,6 +6262,91 @@ file as well. Then every ``CMakeLists.txt`` file in subdirectories just calls ``include_tribits_build()``. That is it. +How to implement a TriBITS-compliant external package using raw CMake +--------------------------------------------------------------------- + +As described in `TriBITS-Compliant External Packages`_, it is possible to +create a raw CMake build system for a CMake package such that once it is +installed, satisfies the requirements for a TriBITS-compliant external +package. These installed packages provide a ``Config.cmake`` file +that provides the required targets and behaviors. For most existing raw CMake +projects that already produce a ``Config.cmake`` file, that usually +just means adding a IMPORTED target to the installed ``Config.cmake`` +file called ``::all_libs``. + +This is demonstrated in the `TribitsExampleProject2`_ package ``Package1``. +The base ``CMakeLists.txt`` file for building ``Package1`` with a raw CMake +build system (called ``CMakeLists.raw.cmake`` in that directory) for +implementing a TriBITS-compliant internal package looks like: + +.. include:: TribitsExampleProject2_Package1_CMakeLists.raw.external.cmake + :literal: + +As shown above, this simple CMake package contains the basic features of any +CMake project/package including calling the ``cmake_minimum_required()`` and +``project()`` commands as well as including ``GNUInstallDirs``. In this +example, the project/package being built ``Package1`` has a dependency on a +external package ``Tpl1`` pulled in with ``find_package(Tpl1)``. Also in this +example, the package has native tests it defines with ``include(CTest)`` and +``add_subdirectory()`` (if the user sets ``Package1_ENABLE_TESTS`` to ``ON``). + +As shown in the file ``package1/src/CMakeLists.raw.cmake`` (which gets +included from ``package1/src/CMakeLists.txt``): + +.. include:: ../../examples/TribitsExampleProject2/packages/package1/src/CMakeLists.raw.cmake + :literal: + +this package creates a single installable library target ``Package1_package1`` +which is aliased as ``Package1::package1`` in the current CMake project and +sets up to create the IMPORTED target ``Package1::package1`` in the generated +``Package1ConfigTarget.cmake`` file which gets included in the installed +``Package1Config.cmake`` file (as recommenced in the book "Professional +CMake", see below). In addition, the above code creates the installable +executable ``package1-prg``. + +The required ``Package1::all_libs`` target is generated by the included file +``package1/cmake/raw/DefineAllLibsTarget.cmake`` which contains the code: + +.. include:: ../../examples/TribitsExampleProject2/packages/package1/cmake/raw/DefineAllLibsTarget.cmake + :literal: + +The above code results in the IMPORTED target ``Package1::all_libs`` getting +put in the generated ``Package1ConfigTargets.cmake`` file (see below) and also +creates the alias library target ``Package1::all_libs`` in the current CMake +project (which is optional for a external package built in isolation but is +required for such package built in a larger project, as per suggested in the +book "Professional CMake" ). + +Finally, the code for generating and installing the ``Package1Config.cmake`` +file is given in the included file +``cmake/raw/GeneratePackageConfigFileForInstallDir.cmake`` with the contents: + +.. include:: ../../examples/TribitsExampleProject2/packages/package1/cmake/raw/GeneratePackageConfigFileForInstallDir.cmake + :literal: + +The above uses the command ``install(EXPORT ...)`` to have CMake automatically +generate the file ``Package1ConfigTargets.cmake`` which provides the IMPORTED +targets ``Package1::package1`` and ``Package1::all_libs``. The command +``configure_file()`` is used to generate the file +``Package1Config.install.cmake`` in the build directory from the template file +``Package1Config.cmake.in``. Finally, the ``install()`` command is used in +the file ``GeneratePackageConfigFileForInstallDir.cmake`` to set up the +installation of the ``Package1Config.cmake`` file. + +Note, the template file ``package1/cmake/raw/Package1Config.cmake.in`` is: + +.. include:: ../../examples/TribitsExampleProject2/packages/package1/cmake/raw/Package1Config.cmake.in + :literal: + +As shown in the all of the above code, there is a lot of boilerplate CMake +code needed to correctly define the targets such that they get put into the +installed ``Package1Config.cmake`` file using the correct namespace +``Package1::`` and care must be taken to ensure that a consistent "export set" +is used for this purpose. (For more details, see the book "Professional +CMake".) + + + How to implement a TriBITS-compliant internal package using raw CMake --------------------------------------------------------------------- @@ -6272,42 +6357,24 @@ TriBITS project. The raw CMake code for such a package must provide the in the generated ``Config.cmake`` file for the build directory and in the installed ``Config.cmake`` file. Every such TriBITS-compliant internal package is capable of installing TriBITS-compliant external package's -``Config.cmake`` file. This is demonstrated in the -`TribitsExampleProject2`_ package ``Package1``. The base ``CMakeLists.txt`` -file for building ``Package1`` with a raw CMake build system (called -``CMakeLists.raw.cmake`` in that directory) for implementing a -TriBITS-compliant internal package looks like: - -.. include:: ../../examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake - :literal: - -**SIDENOTE:** The above example shows the optional inclusion of the TriBITS -test function modules ``TribitsAddTest.cmake`` and -``TribitsAddAdvancedTest.cmake`` which are not included by default. (See `How -to use TriBITS testing support in non-TriBITS project`_). - -After the build targets the tests are defined, the ``Package1::all_libs`` -target is generated in such a way that ``Package1::all_libs`` will become an -IMPORTED target in the generated ``Package1ConfigTargets.cmake`` file and also -the ``Package1::all_libs`` will exist so it can be lined to by downstream -TriBITS packages. +``Config.cmake`` file. -The code at the end of the above ``CMakeLists.txt`` file shows the generation -of the installed ``Package1Config.cmake`` file. This file is configured from -the input file ``Package1Config.cmake.in``: +This is demonstrated in the `TribitsExampleProject2`_ package ``Package1``. +The base ``CMakeLists.txt`` file for building ``Package1`` with a raw CMake +build system (called ``CMakeLists.raw.cmake`` in that directory) for +implementing a TriBITS-compliant internal package (which also, by definition, +creates a TriBITS-compliant external package) looks like: -.. include:: ../../examples/TribitsExampleProject2/packages/package1/cmake/raw/Package1Config.cmake.in +.. include:: TribitsExampleProject2_Package1_CMakeLists.raw.internal.cmake :literal: -and is installed into the proper location of the location under -``${CMAKE_INSTALL_LIBDIR}/`` and itself includes the CMake generated and -installed ``Package1ConfigTargets.cmake`` file. +(NOTE: This is the identical to the base ``CMakeLists.txt`` file for a CMake +project/package that generates an TriBITS-Compliant External package described +in the previous section, except for the inclusion of the file:: + + include("${CMAKE_CURRENT_LIST_DIR}/cmake/raw/GeneratePackageConfigFileForBuildDir.cmake") -Creating library and executable targets for a TriBITS-compliant package -requires more that just calling ``add_library()``, ``add_executable()``, -``target_include_directories()`` and ``target_link_libraries()`` like a simple -CMake project. It also requires setting some target properties and calling -``install()`` with the correct EXPORT set and include destination. +ToDo: Finish this! **NOTE:** One should compare the above raw CMakeLists files to the more compact TriBITS versions for the base ``CMakeLists.txt`` file (called @@ -6323,22 +6390,6 @@ in the directory ``package1/src/``): :literal: -How to implement a TriBITS-compliant external package using raw CMake ---------------------------------------------------------------------- - -As described in `TriBITS-Compliant External Packages`_, it is possible to -create a raw CMake build system for a CMake package such that once it is -installed, satisfies all of the requirements for a TriBITS-compliant external -package. These installed packages provide a ``Config.cmake`` file -that provides all of the needed targets and behavior. For most existing raw -CMake package projects, that means adding a IMPORTED target to the installed -``Config.cmake`` file called ``::all_libs``. - -The raw CMake code to create a TriBITS-compliant external package is identical -for the case for creating a TriBITS-compliant internal package as described -above. The only difference is that such a package does not need to generate - - How to use TriBITS testing support in non-TriBITS project --------------------------------------------------------- diff --git a/tribits/doc/guides/generate-guide.sh b/tribits/doc/guides/generate-guide.sh index e8e4ae07d..8fda29901 100755 --- a/tribits/doc/guides/generate-guide.sh +++ b/tribits/doc/guides/generate-guide.sh @@ -152,6 +152,17 @@ function tribits_extract_other_doc { &> TribitsHelloWorldDirAndFiles.txt.tmp update_if_different TribitsHelloWorldDirAndFiles.txt tmp + echo + echo "Generating TribitsExampleProject2/Package1 CMakeList file variants ..." + echo + cat ../../examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake | \ + grep -v EnableTribitsTestSupport | \ + grep -v GeneratePackageConfigFileForBuildDir \ + &> TribitsExampleProject2_Package1_CMakeLists.raw.external.cmake + cat ../../examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake | \ + grep -v EnableTribitsTestSupport | \ + &> TribitsExampleProject2_Package1_CMakeLists.raw.internal.cmake + echo echo "Generating output for 'checkin-test.py --help' ..." echo diff --git a/tribits/examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake b/tribits/examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake index 559d2eee5..ad2a18182 100644 --- a/tribits/examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake +++ b/tribits/examples/TribitsExampleProject2/packages/package1/CMakeLists.raw.cmake @@ -17,8 +17,7 @@ if (Package1_ENABLE_TESTS) add_subdirectory(test) endif() +# Stuff that TriBITS does automatically include("${CMAKE_CURRENT_LIST_DIR}/cmake/raw/DefineAllLibsTarget.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/cmake/raw/GeneratePackageConfigFileForBuildDir.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/cmake/raw/GeneratePackageConfigFileForInstallDir.cmake")