Help: Add a CMake manual for Packages related docs.
This commit is contained in:
parent
20cafa2e1f
commit
3fe4ac828d
|
@ -28,6 +28,7 @@ Reference Manuals
|
|||
/manual/cmake-commands.7
|
||||
/manual/cmake-generators.7
|
||||
/manual/cmake-modules.7
|
||||
/manual/cmake-packages.7
|
||||
/manual/cmake-policies.7
|
||||
/manual/cmake-properties.7
|
||||
/manual/cmake-variables.7
|
||||
|
|
|
@ -0,0 +1,414 @@
|
|||
.. cmake-manual-description: CMake Packages Reference
|
||||
|
||||
cmake-packages(7)
|
||||
*****************
|
||||
|
||||
.. only:: html or latex
|
||||
|
||||
.. contents::
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Packages provide dependency information to CMake based buildsystems. Packages
|
||||
are found with the :command:`find_package` command. The result of
|
||||
using ``find_package`` is either a set of :prop_tgt:`IMPORTED` targets, or
|
||||
a set of variables corresponding to build-relevant information.
|
||||
|
||||
Using Packages
|
||||
==============
|
||||
|
||||
CMake provides direct support for two forms of packages,
|
||||
`Config-file Packages`_ and `Find-module Packages`_.
|
||||
Indirect support for ``pkg-config`` packages is also provided via
|
||||
the :module:`FindPkgConfig` module. In all cases, the basic form
|
||||
of :command:`find_package` calls is the same:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt4 4.7.0 REQUIRED) # CMake provides a Qt4 find-module
|
||||
find_package(Qt5Core 5.1.0 REQUIRED) # Qt provides a Qt5 package config file.
|
||||
find_package(LibXml2 REQUIRED) # Use pkg-config via the LibXml2 find-module
|
||||
|
||||
In cases where it is known that a package configuration file is provided by
|
||||
upstream, and only that should be used, the ``CONFIG`` keyword may be passed
|
||||
to :command:`find_package`:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt5Core 5.1.0 CONFIG REQUIRED)
|
||||
find_package(Qt5Gui 5.1.0 CONFIG)
|
||||
|
||||
Similarly, the ``MODULE`` keyword says to use only a find-module:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt4 4.7.0 MODULE REQUIRED)
|
||||
|
||||
Specifying the type of package explicitly improves the error message shown to
|
||||
the user if it is not found.
|
||||
|
||||
Both types of packages also support specifying components of a package,
|
||||
either after the ``REQUIRED`` keyword:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt5 5.1.0 CONFIG REQUIRED Widgets Xml Sql)
|
||||
|
||||
or as a separate ``COMPONENTS`` list:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt5 5.1.0 COMPONENTS Widgets Xml Sql)
|
||||
|
||||
or as a separate ``OPTIONAL_COMPONENTS`` list:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Qt5 5.1.0 COMPONENTS Widgets
|
||||
OPTIONAL_COMPONENTS Xml Sql
|
||||
)
|
||||
|
||||
Handling of ``COMPONENTS`` and ``OPTIONAL_COMPONENTS`` is defined by the
|
||||
package.
|
||||
|
||||
Config-file Packages
|
||||
--------------------
|
||||
|
||||
A config-file package is a set of files provided by upstreams for downstreams
|
||||
to use. CMake searches in a number of locations for package configuration files, as
|
||||
described in the :command:`find_package` documentation. The most simple way for
|
||||
a CMake user to tell :manual:`cmake(1)` to search in a non-standard prefix for
|
||||
a package is to set the ``CMAKE_PREFIX_PATH`` cache variable.
|
||||
|
||||
Config-file packages are provided by upstream vendors as part of development
|
||||
packages, that is, they belong with the header files and any other files
|
||||
provided to assist downsteams in using the package.
|
||||
|
||||
A set of variables which provide package status information are also set
|
||||
automatically when using a config-file package. The ``<Package>_FOUND``
|
||||
variable is set to true or false, depending on whether the package was
|
||||
found. The ``<Package>_DIR`` cache variable is set to the location of the
|
||||
package configuration file.
|
||||
|
||||
Find-module Packages
|
||||
--------------------
|
||||
|
||||
A find module is a file with a set of rules for finding the required pieces of
|
||||
a dependency, primarily header files and libraries. Typically, a find module
|
||||
is needed when the upstream is not built with CMake, or is not CMake-aware
|
||||
enough to otherwise provide a package configuration file. Unlike a package configuration
|
||||
file, it is not shipped with upstream, but is used by downstream to find the
|
||||
files by guessing locations of files with platform-specific hints.
|
||||
|
||||
Unlike the case of an upstream-provided package configuration file, no single point
|
||||
of reference identifies the package as being found, so the ``<Package>_FOUND``
|
||||
variable is not automatically set by the :command:`find_package` command. It
|
||||
can still be expected to be set by convention however and should be set by
|
||||
the author of the Find-module. Similarly there is no ``<Package>_DIR`` variable,
|
||||
but each of the artifacts such as library locations and header file locations
|
||||
provide a separate cache variable.
|
||||
|
||||
See the :manual:`cmake-developer(7)` manual for more information about creating
|
||||
Find-module files.
|
||||
|
||||
Package Layout
|
||||
==============
|
||||
|
||||
A config-file package consists of a `Package Configuration File`_ and
|
||||
optionally a `Package Version File`_ provided with the project distribution.
|
||||
|
||||
Package Configuration File
|
||||
--------------------------
|
||||
|
||||
Consider a project ``Foo`` that installs the following files::
|
||||
|
||||
<prefix>/include/foo-1.2/foo.h
|
||||
<prefix>/lib/foo-1.2/libfoo.a
|
||||
|
||||
It may also provide a CMake package configuration file::
|
||||
|
||||
<prefix>/lib/cmake/foo-1.2/FooConfig.cmake
|
||||
|
||||
with content defining :prop_tgt:`IMPORTED` targets, or defining variables, such
|
||||
as::
|
||||
|
||||
# ...
|
||||
# (compute PREFIX relative to file location)
|
||||
# ...
|
||||
set(Foo_INCLUDE_DIRS ${PREFIX}/include/foo-1.2)
|
||||
set(Foo_LIBRARIES ${PREFIX}/lib/foo-1.2/libfoo.a)
|
||||
|
||||
If another project wishes to use ``Foo`` it need only to locate the ``FooConfig.cmake``
|
||||
file and load it to get all the information it needs about package content
|
||||
locations. Since the package configuration file is provided by the package
|
||||
installation it already knows all the file locations.
|
||||
|
||||
The :command:`find_package` command may be used to search for the package
|
||||
configuration file. This command constructs a set of installation prefixes
|
||||
and searches under each prefix in several locations. Given the name ``Foo``,
|
||||
it looks for a file called ``FooConfig.cmake`` or ``foo-config.cmake``.
|
||||
The full set of locations is specified in the :command:`find_package` command
|
||||
documentation. One place it looks is::
|
||||
|
||||
<prefix>/lib/cmake/Foo*/
|
||||
|
||||
where ``Foo*`` is a case-insensitive globbing expression. In our example the
|
||||
globbing expression will match ``<prefix>/lib/cmake/foo-1.2`` and the package
|
||||
configuration file will be found.
|
||||
|
||||
Once found, a package configuration file is immediately loaded. It, together
|
||||
with a package version file, contains all the information the project needs to
|
||||
use the package.
|
||||
|
||||
Package Version File
|
||||
--------------------
|
||||
|
||||
When the :command:`find_package` command finds a candidate package configuration
|
||||
file it looks next to it for a version file. The version file is loaded to test
|
||||
whether the package version is an acceptable match for the version requested.
|
||||
If the version file claims compatibility the configuration file is accepted.
|
||||
Otherwise it is ignored.
|
||||
|
||||
The name of the package version file must match that of the package configuration
|
||||
file but has either ``-version`` or ``Version`` appended to the name before
|
||||
the ``.cmake`` extension. For example, the files::
|
||||
|
||||
<prefix>/lib/cmake/foo-1.3/foo-config.cmake
|
||||
<prefix>/lib/cmake/foo-1.3/foo-config-version.cmake
|
||||
|
||||
and::
|
||||
|
||||
<prefix>/lib/cmake/bar-4.2/BarConfig.cmake
|
||||
<prefix>/lib/cmake/bar-4.2/BarConfigVersion.cmake
|
||||
|
||||
are each pairs of package configuration files and corresponding package version
|
||||
files.
|
||||
|
||||
When the :command:`find_package` command loads a version file it first sets the
|
||||
following variables:
|
||||
|
||||
``PACKAGE_FIND_NAME``
|
||||
The <package> name
|
||||
|
||||
``PACKAGE_FIND_VERSION``
|
||||
Full requested version string
|
||||
|
||||
``PACKAGE_FIND_VERSION_MAJOR``
|
||||
Major version if requested, else 0
|
||||
|
||||
``PACKAGE_FIND_VERSION_MINOR``
|
||||
Minor version if requested, else 0
|
||||
|
||||
``PACKAGE_FIND_VERSION_PATCH``
|
||||
Patch version if requested, else 0
|
||||
|
||||
``PACKAGE_FIND_VERSION_TWEAK``
|
||||
Tweak version if requested, else 0
|
||||
|
||||
``PACKAGE_FIND_VERSION_COUNT``
|
||||
Number of version components, 0 to 4
|
||||
|
||||
The version file must use these variables to check whether it is compatible or
|
||||
an exact match for the requested version and set the following variables with
|
||||
results:
|
||||
|
||||
``PACKAGE_VERSION``
|
||||
Full provided version string
|
||||
|
||||
``PACKAGE_VERSION_EXACT``
|
||||
True if version is exact match
|
||||
|
||||
``PACKAGE_VERSION_COMPATIBLE``
|
||||
True if version is compatible
|
||||
|
||||
``PACKAGE_VERSION_UNSUITABLE``
|
||||
True if unsuitable as any version
|
||||
|
||||
Version files are loaded in a nested scope so they are free to set any variables
|
||||
they wish as part of their computation. The find_package command wipes out the
|
||||
scope when the version file has completed and it has checked the output
|
||||
variables. When the version file claims to be an acceptable match for the
|
||||
requested version the find_package command sets the following variables for
|
||||
use by the project:
|
||||
|
||||
``<package>_VERSION``
|
||||
Full provided version string
|
||||
|
||||
``<package>_VERSION_MAJOR``
|
||||
Major version if provided, else 0
|
||||
|
||||
``<package>_VERSION_MINOR``
|
||||
Minor version if provided, else 0
|
||||
|
||||
``<package>_VERSION_PATCH``
|
||||
Patch version if provided, else 0
|
||||
|
||||
``<package>_VERSION_TWEAK``
|
||||
Tweak version if provided, else 0
|
||||
|
||||
``<package>_VERSION_COUNT``
|
||||
Number of version components, 0 to 4
|
||||
|
||||
The variables report the version of the package that was actually found.
|
||||
The ``<package>`` part of their name matches the argument given to the
|
||||
:command:`find_package` command.
|
||||
|
||||
Creating Packages
|
||||
=================
|
||||
|
||||
Usually, the upstream depends on CMake itself and can use some CMake facilities
|
||||
for creating the package files. Consider an upstream which provides a single
|
||||
shared library:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
project(UpstreamLib)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(Upstream_VERSION 3.4.1)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
add_library(ClimbingStats SHARED climbingstats.cpp)
|
||||
generate_export_header(ClimbingStats)
|
||||
|
||||
install(TARGETS ClimbingStats EXPORT ClimbingStatsTargets
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
climbingstats.h
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/climbingstats_export.h"
|
||||
DESTINATION
|
||||
include
|
||||
COMPONENT
|
||||
Devel
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ClimbingStatsConfigVersion.cmake"
|
||||
VERSION ${Upstream_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/ClimbingStats)
|
||||
install(EXPORT ClimbingStatsTargets
|
||||
FILE
|
||||
ClimbingStatsTargets.cmake
|
||||
NAMESPACE
|
||||
Upstream::
|
||||
DESTINATION
|
||||
${ConfigPackageLocation}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
cmake/ClimbingStatsConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ClimbingStatsConfigVersion.cmake"
|
||||
DESTINATION
|
||||
${ConfigPackageLocation}
|
||||
COMPONENT
|
||||
Devel
|
||||
)
|
||||
|
||||
The :module:`CMakePackageConfigHelpers` module provides a macro for creating
|
||||
a simple ``ConfigVersion.cmake`` file. This file sets the version of the
|
||||
package. It is read by CMake when :command:`find_package` is called to
|
||||
determine the compatibility with the requested version, and to set some
|
||||
version-specific variables ``<Package>_VERSION``, ``<Package>_VERSION_MAJOR``,
|
||||
``<Package>_VERSION_MINOR`` etc. The :command:`install(EXPORT)` command is
|
||||
used to export the targets in the ``ClimbingStatsTargets`` export-set, defined
|
||||
previously by the :command:`install(TARGETS)` command. This command generates
|
||||
the ``ClimbingStatsTargets.cmake`` file to contain :prop_tgt:`IMPORTED`
|
||||
targets, suitable for use by downsteams and arranges to install it to
|
||||
``lib/cmake/ClimbingStats``. The generated ``ClimbingStatsConfigVersion.cmake``
|
||||
and a ``cmake/ClimbingStatsConfig.cmake`` are installed to the same location,
|
||||
completing the package.
|
||||
|
||||
A ``NAMESPACE`` with double-colons is specified when exporting the targets
|
||||
for installation. This convention of double-colons gives CMake a hint that
|
||||
the name is an :prop_tgt:`IMPORTED` target when it is used by downstreams
|
||||
with the :command:`target_link_libraries` command. This way, CMake can
|
||||
issue a diagnostic if the package providing it has not yet been found.
|
||||
|
||||
In this case, when using :command:`install(TARGETS)` the ``INCLUDES DESTINATION``
|
||||
was specified. This causes the ``IMPORTED`` targets to have their
|
||||
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` populated with the ``include``
|
||||
directory in the :variable:`CMAKE_INSTALL_PREFIX`. When the ``IMPORTED``
|
||||
target is used by downsteam, it automatically consumes the entries from
|
||||
that property.
|
||||
|
||||
In this case, the ``ClimbingStatsConfig.cmake`` file could be as simple as:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
|
||||
|
||||
As this allows downstreams to use the ``IMPORTED`` targets. If any macros
|
||||
should be provided by the ``ClimbingStats`` package, they should
|
||||
be in a separate file which is installed to the same location as the
|
||||
``ClimbingStatsConfig.cmake`` file, and included from there.
|
||||
|
||||
This can also be extended to cover dependencies:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
# ...
|
||||
add_library(ClimbingStats SHARED climbingstats.cpp)
|
||||
generate_export_header(ClimbingStats)
|
||||
|
||||
find_package(Stats 2.6.4 REQUIRED)
|
||||
target_link_libraries(ClimbingStats PUBLIC Stats::Types)
|
||||
|
||||
As the ``Stats::Types`` target is a ``PUBLIC`` dependency of ``ClimbingStats``,
|
||||
downsteams must also find the ``Stats`` package and link to the ``Stats::Types``
|
||||
library. The ``Stats`` package should be found in the ``ClimbingStatsConfig.cmake``
|
||||
file to ensure this. The ``find_dependency`` macro from the
|
||||
:module:`CMakeFindDependencyMacro` helps with this by propagating
|
||||
whether the package is ``REQUIRED``, or ``QUIET`` etc. All ``REQUIRED``
|
||||
dependencies of a package should be found in the ``Config.cmake`` file:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
find_dependency(Stats 2.6.4)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
|
||||
|
||||
The ``find_dependency`` macro also sets ``ClimbingStats_FOUND`` to ``False`` if
|
||||
the dependency is not found, along with a diagnostic that the ``ClimbingStats``
|
||||
package can not be used without the ``Stats`` package.
|
||||
|
||||
If ``COMPONENTS`` are specified when the downstream uses :command:`find_package`,
|
||||
they are listed in the ``<Package>_FIND_COMPONENTS`` variable. If a particular
|
||||
component is non-optional, then the ``<Package>_FIND_REQUIRED_<comp>`` will
|
||||
be true. This can be tested with logic in the package configuration file:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
find_dependency(Stats 2.6.4)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
|
||||
|
||||
set(_supported_components Plot Table)
|
||||
|
||||
foreach(_comp ${ClimbingStats_FIND_COMPONENTS})
|
||||
if (NOT ";${_supported_components};" MATCHES _comp)
|
||||
set(ClimbingStats_FOUND False)
|
||||
set(ClimbingStats_NOTFOUND_MESSAGE "Specified unsupported component: ${_comp}")
|
||||
endif()
|
||||
include("${CMAKE_CURRENT_LIST_DIR}ClimbingStats${_comp}Targets.cmake")
|
||||
endforeach()
|
||||
|
||||
Here, the ``ClimbingStats_NOTFOUND_MESSAGE`` is set to a diagnosis that the package
|
||||
could not be found because an invalid component was specified. This message
|
||||
variable can be set for any case where the ``_FOUND`` variable is set to ``False``,
|
||||
and will be displayed to the user.
|
Loading…
Reference in New Issue