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_compileswith 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::Fooand set it up correctly (using properties) and be nice to also setFOO_INCLUDE_DIRandFOO_LIBRARIESfor old CMake w/o targets.
This is pretty easy: Just usefind_pathandfind_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 FooTargetsandINCLUDES DESTINATION includetoinstall(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.cmakein<CMAKE_INSTALL_PREFIX>/lib/cmake/Foothat defines a targetFoo::Foowith (hopefully) all its dependencies - Add "something" creating
FooConfigVersion.cmakepossibly by usingwrite_basic_package_version_filethat, to my understanding, hard-codes the version to that file - Create a
FooConfig.cmakethat may usefind_dependencyto search for libraries that Foo depends on and includesFooTargets.cmake - Install
FooConfig.cmakeandFooConfigVersion.cmaketolib/cmake/Foo - modify
target_include_directoriesto use separateBUILD_INTERFACEandINSTALL_INTERFACEpaths
- 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.