Hi,
I try to keep this question and its context as generic as possible, to help others who may be facing a similar challenge. Also, @craig.scott s excellent Professional CMake barely touches this part and I hope this question could spark some ideas for additional content.
Goal
My goal is to provide direct CMake support for an existing library which is both forward and backward-compatible.
This means that I would like to contribute CMake support directly upstream into the library starting at some version X, and provide a FindModule to allow forward-compatibility for versions before X.
Both the CMake config and the FindModule should provide the same variables and the same target to link against.
Further context
The library is complex and has a custom build configuration, which generates a pkg-config file using a python script.
pkg-config support is available for all relevant versions of the library.
It also allows downloading, building and installing dependencies during the configuration step. This can make the pkg-config file rather complex. Flags are not straight forward.
Finally, the primary library maintainers are not daily users of CMake, which makes code simplicity even more significant.
Support for versions prior to X
To provide forward-compatibility, I could write a FindModule which can then be copied into other projects to detect older versions of the library. This poses the question on how to design it.
Rely on pkg-config
As the library provides a pkg-config file, I could rely fully on the pkg-config and use FindPkgConfig to locate the library.
In the FindModule, I would locate the library, set up variables as well as an imported target with an alias.
Pro: everything complex is handled by the FindPkgConfig CMake FindModule. The Module is clean, simple, and understandable for non CMake experts.
Contra: pkg-config is required on the system and the pc files have to be detectable.
Use pkg-config as a hint
I copy the behaviour of many CMake-provided FindModules and use pkg-config as a hint to finding the library using find_library etc.
In the Find module, I would locate the library using pkg-config if it is available on the system, locate the library using the pkg-config info as hints, attempt handle additional flags, set up variables as well as an imported target.
Pro: does not require a pkg-config installation
Contra: correctly handling all flags the find module is very complex and poses a severe maintenance burden
Support starting at version X
There are multiple options to upstream direct CMake support, including not adding any direct support at all, solely relying on the above FindModule.
Generate CMake config files
I could reuse the existing code used to generate the pkg-config files to additionally generate CMake config and version files.
Pro: direct CMake support without additional dependencies
Contra: Adds maintainability overhead, as multiple places need to be changed to keep these config files consistent.
CMake Config as a pkg-config wrapper
I could reuse the existing code to generate a CMake version file and a CMake Config file which internally used pkg-config to request the exact version.
Pro: less code to maintain as the complicated parts are handled when creating the pkg-config file
Contra: may detect incorrect versions via pkg-config (same version different build) and requires pkg-config to be installed on the system.
FindModule only
I don’t provide CMake config and version files, but solely rely on the provided FindModule.
Pro: Even less code to maintain. No need to keep functionality aligned between the CMake config and the FindModule.
Contra: Limits functionality to the information provided by the FindModule. If it requires pkg-config to work, then CMake support as a whole requires a pkg-config installation.
These are the options I have considered until now.
Questions to the CMake community and developers:
- Can you think of further options, pros, or cons?
- Has experience shown that some methods are to be avoided/preferred?
- Which method would you accept as a contribution to your code base?