Skip to content

Commit

Permalink
SQUASH AGAINST: WIP: Add HowTos for TriBITS-compliant raw CMake packa…
Browse files Browse the repository at this point in the history
  • Loading branch information
bartlettroscoe committed Sep 12, 2023
1 parent ed04232 commit 7f7a11a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 49 deletions.
2 changes: 2 additions & 0 deletions tribits/doc/guides/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
145 changes: 98 additions & 47 deletions tribits/doc/guides/TribitsGuidesBody.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 ``<Package>Config.cmake`` file
that provides the required targets and behaviors. For most existing raw CMake
projects that already produce a ``<Package>Config.cmake`` file, that usually
just means adding a IMPORTED target to the installed ``<Package>Config.cmake``
file called ``<Package>::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
---------------------------------------------------------------------

Expand All @@ -6272,42 +6357,24 @@ TriBITS project. The raw CMake code for such a package must provide the
in the generated ``<Package>Config.cmake`` file for the build directory and in
the installed ``<Package>Config.cmake`` file. Every such TriBITS-compliant
internal package is capable of installing TriBITS-compliant external package's
``<Package>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.
``<Package>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
Expand All @@ -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 ``<Package>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
``<Package>Config.cmake`` file called ``<Package>::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
---------------------------------------------------------

Expand Down
11 changes: 11 additions & 0 deletions tribits/doc/guides/generate-guide.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")

0 comments on commit 7f7a11a

Please sign in to comment.