Skip to content

Commit

Permalink
Add some documentation for external packages/TPLs with modern targets (
Browse files Browse the repository at this point in the history
…TriBITSPub#299, TriBITSPub#427)

This is the start for adding documentaiton for new <tplName>Config.cmake and
<tplName>ConfigVersion.cmake files.  It mentions a few issues that I felt were
important enough to mention to TriBITS Project Developers and TriBITS Project
Users.
  • Loading branch information
bartlettroscoe committed Nov 10, 2021
1 parent 1507920 commit 22a56e4
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 17 deletions.
7 changes: 7 additions & 0 deletions tribits/doc/build_ref/TribitsBuildReferenceBody.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3743,6 +3743,13 @@ options from the source tree and the build tree are automatically injected
into the build targets associated with the ``<downstream-target>`` object
compile lines and link lines.

Also note that package config files for all of the enabled external
packages/TPLs will also be written into the build tree under
``<upstreamBuildDir>/external_packages``. These contain modern CMake targets
that are pulled in by the downstream ``<Package>Config.cmake`` files under
``<upstreamBuildDir>/external_packages``. These external package/TPL config
files are placed in a seprate directory to avoid being found by accident.


Installation Testing
====================
Expand Down
104 changes: 87 additions & 17 deletions tribits/doc/guides/TribitsGuidesBody.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2150,11 +2150,12 @@ applied math and computational science community and are not likely to clash.
Using a TriBITS TPL is to be preferred over using raw CMake
``find_package(<someCMakePackage>)`` because the TriBITS system guarantees
that only a single unique version of TPL of the same version will be used by
multiple packages. Also, by defining a TriBITS TPL, automatic enable/disable
logic will be applied as described in `Package Dependencies and Enable/Disable
Logic`_. For example, if a TPL is explicitly disabled, all of the downstream
packages that depend on that TPL will be automatically disabled as well (see
`TPL disable triggers auto-disables of downstream dependencies`_).
multiple packages that uses the TPL. Also, by defining a TriBITS TPL,
automatic enable/disable logic will be applied as described in `Package
Dependencies and Enable/Disable Logic`_. For example, if a TPL is explicitly
disabled, all of the downstream packages that depend on that TPL will be
automatically disabled as well (see `TPL disable triggers auto-disables of
downstream dependencies`_).

For each TPL referenced in a `<repoDir>/TPLsList.cmake`_ file using the macro
`tribits_repository_define_tpls()`_, there must exist a file, typically called
Expand All @@ -2171,11 +2172,12 @@ module which is currently:
Some concrete ``FindTPL${TPL_NAME}.cmake`` files actually do use
``find_package()`` and a standard CMake package find module to fill in the
guts of finding at TPL which is perfectly fine. In this case, the purpose for
the wrapping ``FindTPL${TPL_NAME}.cmake`` file is to standardize the output
variables ``TPL_${TPL_NAME}_INCLUDE_DIRS`` and ``TPL_${TPL_NAME}_LIBRARIES``.
For more details on properly using ``find_package()`` to define a
``FindTPL${TPL_NAME}.cmake`` file, see `How to use find_package() for a
TriBITS TPL`_.
the wrapping ``FindTPL${TPL_NAME}.cmake`` file is to ensure the definition of
the complete target ``${TPL_NAME}::all_libs`` which contains all usage
requirements for the external package/TPL (i.e. all of the libraries, include
directories, etc.). For more details on properly using ``find_package()`` to
define a ``FindTPL${TPL_NAME}.cmake`` file, see `How to use find_package() for
a TriBITS TPL`_.

Once the `<repoDir>/TPLsList.cmake`_ files are all processed, then each
defined TPL ``TPL_NAME`` is assigned the following global non-cache variables:
Expand Down Expand Up @@ -5472,14 +5474,22 @@ To add a new TriBITS TPL, do the following:
How to use find_package() for a TriBITS TPL
-------------------------------------------

When defining a ``FindTPL<tplName>.cmake`` file, it is possible (and
encouraged) to utilize ``find_package(<tplName> ...)`` to provide the default
find operation. In order for the resulting ``FindTPL<tplName>.cmake`` to
behave consistently between all the various TriBITS TPLs (and allow the
standard TriBITS TPL find overrides) one must use the TriBITS function
When defining a ``FindTPL<tplName>.cmake`` file, it is possible and encouraged
to utilize ``find_package(<tplName> ...)`` to provide the default find
operation. However, most ``Find<tplName>.cmake`` modules and even some
``<tplName>Config.cmake`` config files don't provide all of the required
features needed by downstream TriBITS packages. Specifically, these modules
and config files usually don't provide a complete ``<tplName>::all_libs``
target that contains all usage requirements (such as the
``INTERFACE_INCLUDE_DIRECTORIES`` and ``INTERFACE_LINK_LIBRARIES`` target
properties) for the external package/TPL libraries. Also, in order for the
resulting ``FindTPL<tplName>.cmake`` module to behave consistently between all
the various TriBITS TPLs (and allow the standard TriBITS TPL find overrides)
and maintain backwards compatibility, one must use the TriBITS function
`tribits_tpl_allow_pre_find_package()`_ in combination with the function
`tribits_tpl_find_include_dirs_and_libraries()`_. The basic form of the
resulting TriBITS TPL module file ``FindTPL<tplName>.cmake`` looks like::
`tribits_tpl_find_include_dirs_and_libraries()`_. One basic form of the
resulting TriBITS TPL module file ``FindTPL<tplName>.cmake`` that uses a list
of include directories and library files locations looks like::

# First, set up the variables for the (backward-compatible) TriBITS way of
# finding <tplName>. These are used in case find_package(<tplName> ...) is
Expand Down Expand Up @@ -5550,6 +5560,66 @@ specialized ``FindTPL<tplName>.cmake`` file and can't use the
find modules cannot completely adhere to the standard behavior described in
`Enabling support for an optional Third-Party Library (TPL)`_.

One issue to be made aware of is that code in ``FindTPL<tplName>.cmake`` must
generate the files::

<buildDir>/external_packages/<tplName>/
<tplName>Config.cmake
<tplName>ConfigVersion.cmake

where ``<tplName>Config.cmake`` defines the ``<tplName>::all_libs`` target.
The function `tribits_tpl_find_include_dirs_and_libraries()`_ creates these
files automatically when working with the lists ``TPL_<tplName>_INCLUDE_DIRS``
and ``TPL_<tplName>_LIBRARIES`` as shown in the examples above. But in cases
where the inner ``find_package(<tplName> ...)`` call actually generates a set
of modern CMake IMPORTED targets, the code in ``Find<tplName>.cmake`` will
need to skip calling ``tribits_tpl_find_include_dirs_and_libraries()`` and
will instead need to build the target ``<tplName>::all_libs`` itself and will
need to build the and write wrapper ``<tplName>Config.cmake`` and
``<tplName>ConfigVersion.cmake`` files manually into
``<buildDir>/external_packages/<tplName>/`` that do the right thing when they
are included by downstream ``<Package>Config.cmake`` files.

An example of a custom ``FindTPL<tplName>.cmake`` file that calls
``find_package(<tplName> ...)`` which produces modern CMake targets that
manually creates the ``<tplName>::all_libs`` target is given in
``TribitsExampleProject2/cmake/tpls/FindTPLTpl1.cmake`` which is:

.. include:: ../../examples/TribitsExampleProject2/cmake/tpls/FindTPLTpl1.cmake
:literal:

Another issue that comes up with external packages/TPLs like HDF5 that needs
to be discussed here is the fact that TriBITS generates and installs files of
the name ``HDF5Config.cmake`` that can be found by calls to
``find_package(HDF5)``. These TriBITS-generated ``HDF5Config.cmake`` files
are primarily meant to be included by and provide targets for TriBITS package
``<Package>Config.cmake`` files. These ``HDF5Config.cmake`` files may not
behavior the way that some arbitary downstream raw CMake project that runs
``find_package(HDF5)`` would expect.

Note that 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 ``<tplName>Config.cmake`` files are
installed into the directory ``<installDir>/lib/external_packages/`` so they
will not be found by default when ``<installDir>`` or
``<buildDir>/cmake_packages`` are added to ``CMake_PREFIX_PATH``. Also, even
if ``<installDir>/lib/external_packages`` or ``<buildDir>/external_packages``
do get added to the search path somehow (e.g. through
``CMAKE_INSTALL_PREFIX``), the TriBITS framework will set the variable
``TRIBITS_FINDING_RAW_<tplName>_PACKAGE_FIRST=TRUE`` before including
``FindTPL<tplName>.cmake`` and there is special logic in the TriBITS-generated
``<tplName>ConfigVersion.cmake`` file that will set
``PACKAGE_VERSION_COMPATIBLE=OFF`` and result in ``find_package(<tplName>)``
not selecting ``<tplName>Config.cmake``. (It turns out that CMake's
``find_package(<Package>)`` command always includes the file
``<Package>ConfigVersion.cmake``, even if no version information is passed to
the command ``find_package(<Package>)``. This allows special logic to be
placed in the file ``<Package>ConfigVersion.cmake`` to determine if
``find_package(<Package>)`` will select a given ``<Package>Config.cmake`` file
that is in the search path based on a number of different criteria such as in
this case.)


How to add a new TriBITS Repository
-----------------------------------
Expand Down

0 comments on commit 22a56e4

Please sign in to comment.