[CMake] find_package: request/proposal for better version matching support
Nicholas Braden
nicholas11braden at gmail.com
Wed Apr 13 01:04:13 EDT 2016
I've run into a bit of an issue with the find_package interface. Let's
say I want to use a library libsemver:
find_package(semver REQUIRED)
Now, I want my code to work even when libsemver releases new versions
with breaking API changes, and I happen to know they follow the
semantic versioning system. So, I lock my project to any version where
the major version is 1:
find_package(semver 1 EXACT REQUIRED)
This works for a while, but then I discover that version 1.0 is not
sufficient and I need at least version 1.1 - but there's a problem.
There are other versions after 1.1, such as 1.2, which contain new
features and bug fixes that many users will want, but I still want to
let my users use 1.1 if that's all they have installed on their system
and/or they cannot upgrade to the newer versions.
If I write `find_package(semver 1.1 REQUIRED)`, this allows it to find
version 2 which has breaking API changes and will not allow my project
to compile.
If I write `find_package(semver 1.1 EXACT REQUIRED)` this does not
allow it to find version 1.2 which my users may want to use for the
new features and bug fixes.
I don't currently see any direct way to say that the major version
must be 'exact' and the minor version must be 'at least'. The only
options I see are messy - for example, writing my own find module
instead of using the existing one provided by libsemver, or trying to
optionally find each known minor version in order of preference.
Neither of these is a good option because it now forces my project to
stay in sync with libsemver. As a result, the latter option will not
allow me to go back to previous commits and try to compile them
because their version lists will be out of date, and the former option
will require me to manually keep my find module in sync with
libsemver's find module by constantly patching it with the version
hack instead of just simply copying it without changes.
So it seems I am stuck between a rock and a hard place. If there is a
better alternative or a way around this I don't know of, please
enlighten me. I have done some thinking on this and I believe I have
thought of a good way to fix this problem while retaining
compatibility in CMake - that is, I know the general idea of what I
would need to change in CMake itself and would be willing to create
such a patch if it were simple enough. However, I want feedback before
I go any further - this is my idea:
Instead of only allowing EXACT in find_package, which requires all the
specified version numbers to match (or whatever custom logic the find
module uses), I would make it so you could instead specify one of
EXACT_MAJOR, EXACT_MINOR, EXACT_PATCH, or EXACT_TWEAK. For example:
find_package(semver 1.1 EXACT_MAJOR REQUIRED)
The above would require the major version to be exactly 1, but the
minor version need only be at least 1. Thus, 2.0 would not match, but
1.1 and 1.2 would.
find_package(semver 1.2.3 EXACT_MINOR REQUIRED)
The above would require the major version to be exactly 1, the minor
version to be exactly 2, and the patch version to be at least 3.
EXACT_MAJOR is implicitly set.
Of course, implementing this in CMake itself would not be the end of
the story - this would also require that the find module be aware of
the new options. For existing find modules, they would behave as if
EXACT were specified, and would need to be manually updated to account
for the new EXACT_* options. But, EXACT would still be a valid option
to use, so existing projects need not update all their find_package
calls, and find modules don't need to be updated if nobody wants to
support the new functionality.
If you are wondering about edge cases, I have already thought of some
and know how to deal with them - for example, `find_package(semver 1.1
EXACT_TWEAK REQUIRED)` would issue either an error or warning (not
sure which is better). I think edge case discussion would be better
suited to when/if this is actually being implemented - for now I just
want general feedback. The basic functionality within CMake would
probably be simple to implement (I assume), but CMake has a lot of
find modules included with it that would need to be individually
updated to support the new functionality, and I'm not sure if that
should be in the same patch or not.
Any feedback on this subject would be great - I'd love to resolve this
problem or, even better, find out it isn't a problem in the first
place. Again, if implementing the changes aren't too complicated I
would even be willing to do the work and create the patch myself. I
have implemented find modules with good versioning support myself and
am familiar with how they work from that perspective, but I don't know
how the internals of CMake look.
About package config files - I'm really not sure what to do here,
because the documentation for them explicitly states "When multiple
package configuration files are available whose version files claim
compatibility with the version requested it is unspecified which one
is chosen. No attempt is made to choose a highest or closest version
number." - it is for this reason that I personally prefer to use find
modules instead so I can control the version selection behavior. I
think it would still be possible to implement my changes with that
no-guarantee clause in mind for package config files, but as I have
never actually used a library with package config files nor
implemented any myself, I'm not very sure. I feel much more confident
about find modules. I think only package config version files would
need to be updated in order to understand the new EXACT_* options,
correct? And of course they could fall back on the original EXACT
behavior.
Thank you all for reading carefully, and I look forward to your
thoughts and ideas.
Nicholas "LB" Braden
More information about the CMake
mailing list