I'm updating a (very old) find-module of a library. So the situation is an existing shared library which uses CMake itself. Users might already have this installed somewhere, in package repos or whatever.
Now they want to use this. The good way would be
find_package(Foo REQUIRED)
target_link_libraries(MyProject Foo::Foo)
So thats the goal.
The question is: How would a good find_package-Config or -Module look like which allows this 2-liner to work? It should meet these 2 requirements:
- Allow a CMake version to use the library older than the one used to build it
- Enforce e.g C++11 mode. In a Find-Module one can set the C++11 requirement based on the version (
cxx_std_11
(CMake 3.8+),cxx_alias_templates
(CMake 3.1+),check_cxx_source_compiles
with C++11 code and a warning for older CMakes)
There are 2 ways of doing that:
- Update the find-module to define an imported library
Foo::Foo
and set it up correctly (using properties) and be nice to also setFOO_INCLUDE_DIR
andFOO_LIBRARIES
for old CMake w/o targets.
This is pretty easy: Just usefind_path
andfind_library
, set up the imported target and be done. Works forwards and backwards compatible so even the old versions would be found.
Usage:
The user copies (the most recent) FindFoo.cmake
to its project into e.g. cmake/Modules
and points CMAKE_MODULE_PATH
to it, or copy FindFoo.cmake
to some CMake default path.
Listening to Daniel Pfeiffer and Modern CMake which says
If you are the library author, don't make a Find<mypackage>.cmake script!
So we export and install targets.
This is a bit messy. Following changes are required:- Add
EXPORTS FooTargets
andINCLUDES DESTINATION include
toinstall(TARGETS
(see Pfeiffer #24) which basically just defines an export. (I don't really see, why I would want to create an extra name for something that already has a name. Why can't the below command not simply refer to a target?) - Add
install(EXPORT FooTargets NAMESPACE Foo:: DESTINATION lib/cmake/Foo)
which would create aFooTargets.cmake
in<CMAKE_INSTALL_PREFIX>/lib/cmake/Foo
that defines a targetFoo::Foo
with (hopefully) all its dependencies - Add "something" creating
FooConfigVersion.cmake
possibly by usingwrite_basic_package_version_file
that, to my understanding, hard-codes the version to that file - Create a
FooConfig.cmake
that may usefind_dependency
to search for libraries that Foo depends on and includesFooTargets.cmake
- Install
FooConfig.cmake
andFooConfigVersion.cmake
tolib/cmake/Foo
- modify
target_include_directories
to use separateBUILD_INTERFACE
andINSTALL_INTERFACE
paths
- Add
Usage:
find_package
automatically finds the FooConfig.cmake
and FooConfigVersion.cmake
when Foo
is searched for.
So the Config-Module should be preferred but problems I see are:
- The process looks more complicated
- It cannot be used to enable users to find older versions of the library (that did not use this approach)
- It excludes all (library-)users with older CMake (2.8.11 is probably the minimum required here)
- It requires a newer CMake version to build the library itself
- The C++11 requirement seems to be very hard to encode
So can we solve the requirements with a CMake-Config? An answer should provide a solution or at least a well grounded "impossible". It should also address the problems outlined at the end.
Final Note: I guess this makes a nice wiki-entry if it doesn't exist.