There have been a number of proposals to expand versioning in CMake. I like the summary and rationale from #16716.
cmake_minimum_required
cmake_policy
find_package
PACKAGE_FIND_VERSION{,_MAJOR,_MINOR,_PATCH,_TWEAK}
write_basic_package_version_file
COMPATIBILITY
argument and associated BasicConfigVersion-<VERSION_SCHEME>.cmake.in
filesif
VERSION_{LESS,GREATER,EQUAL,LESS_EQUAL,GREATER_EQUAL}
VERSION_MATCHES
or <VERSION_SCHEME>_MATCHES
project
PROJECT_VERSION{,_MAJOR,_MINOR,_PATCH,_TWEAK}
and <PROJECT-NAME>_VERSION{,_MAJOR,_MINOR,_PATCH,_TWEAK}
PROJECT_VERSION_SCHEME
and <PROJECT-NAME>_VERSION_SCHEME
PROJECT_VERSION_PRERELEASE
and PROJECT_VERSION_BUILD_IDENTIFIER
for semantic version, or PROJECT_VERSION_LOCAL
for PEP440)?VERSION_{LESS,GREATER,EQUAL,LESS_EQUAL,GREATER_EQUAL}
VERSION_MATCHES
or <VERSION_SCHEME>_MATCHES
cmake_minimum_required
and cmake_policy
only require a change if CMake is going to use an expanded version scheme. The stated preference appears to be to ignore prerelease versions, which is the current behavior.
VERSION_SATISFIES
or VERSION_MATCHES
such that the operation evaluates to TRUE
if the first argument matches the version spec in the second argument. The version spec can be a single version that the first argument must be compatible with or a set of constraints as in PEP440 version specifiers.
There are a couple of ways that this may be done:
MATCHES
/SATISFIES
operator for each schemeif(<string|expression> <VERSION_SCHEME>_MATCHES <string|expression>)
# Ex
if(1.2.0 SEMVER_MATCHES 1.1.0)
if(1.2.0 PEP440_MATCHES "~=1.1.0 !=1.1.1")
This is the approach that I took in !7387.
MATCHES
/SATISFIES
If this is feasible, it would make the documentation look a little better. Right now, all of the version comparison operations have essentially identical descriptions (of how CMake's current version precedence system works).
If [VERSION_SCHEME]
is omitted, default to the current behavior (dotted decimal, compare components in order to find a diff, ignore any non-digit, non-. characters and quit immediately if one is found). Allow users to explicitly choose this scheme by specifying SIMPLE
as the scheme?
if(<string|expression> VERSION_MATCHES [VERSION_SCHEME] <string|expression>)
# Ex
if(1.2.0 VERSION_MATCHES SEMVER 1.1.0)
if(1.2.0 VERSION_MATCHES PEP440 "~=1.1.0 !=1.1.1")
if(<string|expression> VERSION_MATCHES <string|expression> [VERSION_SCHEME])
# Ex
if(1.2.0 VERSION_MATCHES 1.1.0 SEMVER)
if(1.2.0 VERSION_MATCHES "~=1.1.0 !=1.1.1" PEP440)
Again, there a couple ways this might be approached:
$<<SCHEME>_MATCHES:v1,v2>
# Ex
$<VERSION_MATCHES:1.2.0,1.1.0>
$<SEMVER_MATCHES:1.2.0,1.1.0>
$<PEP440_MATCHES:1.2.0,"~=1.1.0 !=1.1.1">
$<VERSION_MATCHES:v1,v2[,SCHEME]>
# Ex
$<VERSION_MATCHES:1.2.0,1.1.0>
$<VERSION_MATCHES:1.2.0,1.1.0,SIMPLE>
$<VERSION_MATCHES:1.2.0,1.1.0,SEMVER>
$<VERSION_MATCHES:1.2.0,"~=1.1.0 !=1.1.1",PEP440)
Previous work (closed, but with an encouraging comment by @brad.king to re-open when the author has time): !985
Would require something like #22584 / !7386 as a prerequisite.
One partial implementation for semantic version is !7387, but as pointed out there, it might not be the ideal solution to the problem.
!7386 (closed) does precisely this.
Relates to #16716
Fair point.
So, it's entirely possible to have CMake's version operators use semantic versioning's precedence, but the current CMake position in the documentation is that CMake doesn't know/care/dictate any specific interpretation on your version numbers. There's some stuff in the weeds of the implementation where leading zeros in dotted decimal version numbers have meaning, but beyond that it's just comparing version components values in order until you find a difference. My thought was that it was less of an impact on people/projects to opt-in to new semantics for their version numbers rather than change how the system sees them. I don't know if it's possible to add an optional flag to the existing operators to tell them how you want to treat the versions. Somthing like:
if(<variable|string> VERSION_<LESS|GREATER|EQUAL|LESS_EQUAL|GREATER_EQUAL> <variable|string> [SIMPLE|SEMANTIC])
An example that neither system will treat properly is OpenSSL: 1.1.1o
. That's not legal semantic versioning and my code probably chokes on it (needs testing, I know), and CMake's comparison operators will ignore the alphabet char at the end, so 1.1.1g VERSION_EQUALS 1.1.1o
would evaluate to TRUE
.
Wasn't aware of support for version ranges. SemVer basically defines a compatible version as anything greater/equal to the requirement and still having the same major version (neglecting the unstable pre-1.0 API bits of the spec). I don't see a comparison operator for ranges, so that's why I defined SEMVER_SATISFIES
to check if an argument version is in that implicit range. Also wasn't aware of any generator expressions that dealt with versions.
Ah, is this why you wanted to know the relationship between this and !7386 (closed) ?
This change just opens up the allowed versions that you can pass to project
and find_package
leaving such things as determining precedence as something that people would need to do in their CMake scripting.
!7387 (closed) builds upon this to introduce full, integrated support for semantic versioning.
I'm hedging my bets. If I can get this MR in, but !7387 (closed) is too much, then I can be happy with opening the door and having my custom Config.cmake do the semantic versioning logic to determine if an installed package meets the requirements of a find_package
call.
Timothy Brackett (c7b9cf41) at 19 Jun 14:14
Attempt to fix rst indenting
Timothy Brackett (73a2066d) at 19 Jun 13:55
Really normalize to _VERSION_BUILD_IDENTIFIER
Do: reformat
Timothy Brackett (f3c5af66) at 19 Jun 13:43
Normalize BUILD_IDENTIFER and add help for new vars
... and 1 more commit
Timothy Brackett (448bfeff) at 19 Jun 13:20
Include <iterator> for std::back_inserter
Timothy Brackett (949b475e) at 19 Jun 13:18
Fix spelling mistake
Timothy Brackett (543cda4d) at 19 Jun 13:12
Introduce support for semantic versioning
... and 2 more commits
Timothy Brackett (3eb3c317) at 19 Jun 13:11
Fix misidentification of find_package in help
Timothy Brackett (14669d24) at 19 Jun 13:10
Reference CMP0140 where appropriate
Timothy Brackett (bb5313f7) at 19 Jun 13:00
Introduce support for semantic versioning
... and 1 more commit
Timothy Brackett (231b8d85) at 19 Jun 12:59
Add help for CMP0140
Do: reformat
Do: reformat
This change includes semantic versioning comparison operations (SEMVER_{LESS,LESS_EQUAL,GREATER,GREATER_EQUAL, EQUAL}) as well as a semantic versioning-specific conditional SEMVER_SATISFIES which evaluates if a version is compatible with a requirement version (greater than or equal with a matching major version number for major versions >= 1).
Related to #22584