I'm trying to enhance my CMake convention-over-configuration
framework at the moment. Each of my C++ components (i.e. CMake project) is built via that framework and the framework is already capable to create a CMake Package Configuration File using the configure_package_config_file()
command.
The following (minimal) template file PackageConfig.cmake.in
(v1) is used by the framework.
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
check_required_components("@PROJECT_NAME@")
Everything works fine if a component Foo built and installed with that approach
is used by another component Bar with the find_package(<package> CONFIG)
command (as long as the correct directory paths pointing to the
installed CMake Package Configuration File of Foo is set via the CLI).
But (of course) problems occur if A itself has one or more dependencies. Using the current approach, B has to find_package()
each of the dependencies of
A itself. That means that transitive dependencies are currently not reported to the component requiring a dependency. Obviously this is not what I want to
achieve.
After some googleing I've learned about the find_dependency()
command, which has been created to solve the problem mentioned:
It is designed to be used in a Package Configuration File (
<package>Config.cmake
). find_dependency forwards the correct parameters forQUIET
andREQUIRED
which were passed to the originalfind_package()
call. Any additional arguments specified are forwarded tofind_package()
.
So far so good, but wait... I have to explicitly set each dependency name and its version again? I've already done that when declaring the dependencies in the CMakeLists.txt
! How can I create a reusable and generic Package
Configuration File using that approach? I can't identify any solution to that problem at the moment, other than explicitly listing all dependencies (together with their version) in the CMakeLists.txt
and passing that list to the PackageConfig.cmake.in
.
Example: Untested PackageConfig.cmake.in
(v2):
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
# TODO(wolters): How-to implement this with a generic approach? Would the
# following work? Does a better solution do the problem exist?
#
# 1. Add the following to `CMakeLists.txt`:
# list(APPEND target_dependencies "Baz 1.2.3")
# list(APPEND target_dependencies "Example 0.9.0")
# 2. "Pass" the variable `target_dependencies` to the
# `configure_package_config_file` command.
# 3. Add the following code to the CMake package config file.
foreach(dependency "@target_dependencies@")
find_dependency(${dependency})
endforeach()
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
check_required_components("@PROJECT_NAME@")
Though this feels odd and I do not (yet) know if it works at all (but it should, theoretically).
So my question is: How can I generically implement transitive behavior for a CMake package configuration file.
Last but not least: I'm using the latest stable CMake version 3.9.4.
ExternalProject_Add()
to get a special version with debugging/tracing/profiling enabled, whereas the consumer will want to link with the standard version. – Ostapclock_gettime
may requirelibrt
for older glibc), or just a project's build option). @Ostap 100% right -- this is a big and damn complex problem. And also things get worse when some dependency (an imported target) do not belongs to any result offind_package
but was added e.g., bypkg_check_modules()
or "manually" imported. <TBC> – Swiss