I want my repo to depend on a package with a certain allowed version range. So, looking at the documentation, I write:
find_package(mypkg 0.3.3...<0.5.0 REQUIRED)
but when I configure with CMake (v3.23.0-rc2), this line yields:
CMake Error at CMakeLists.txt:24 (find_package):
Could not find a configuration file for package "mypkg" that is
compatible with requested version range "0.3.3...<0.5.0".
The following configuration files were considered but not accepted:
/opt/mypkg/lib64/cmake/mypkg/mypkg-config.cmake, version: 0.4.6
Why is 0.4.6 not compatible with 0.3.3...<0.5.0 ? Or - is something else wrong?
Additional information:
The using repo's CMakeLists.txt
has:
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
... changing it to 3.19 doesn't help.
By popular request, here's the package's auto-generated version config file:
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major and minor versions are the same as the current
# one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "0.4.6")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("0.4.6" MATCHES "^([0-9]+)\\.([0-9]+)")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
if(NOT CVF_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MINOR "${CVF_VERSION_MINOR}")
endif()
else()
set(CVF_VERSION_MAJOR "0.4.6")
set(CVF_VERSION_MINOR "")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
# both endpoints of the range must have the expected major and minor versions
math (EXPR CVF_VERSION_MINOR_NEXT "${CVF_VERSION_MINOR} + 1")
if (NOT (PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR)
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
AND NOT (PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MAX_MINOR STREQUAL CVF_VERSION_MINOR))
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL ${CVF_VERSION_MAJOR}.${CVF_VERSION_MINOR_NEXT})))
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
else()
if(NOT PACKAGE_FIND_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" PACKAGE_FIND_VERSION_MAJOR "${PACKAGE_FIND_VERSION_MAJOR}")
endif()
if(NOT PACKAGE_FIND_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" PACKAGE_FIND_VERSION_MINOR "${PACKAGE_FIND_VERSION_MINOR}")
endif()
if((PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) AND
(PACKAGE_FIND_VERSION_MINOR STREQUAL CVF_VERSION_MINOR))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
endif()
# if the installed project requested no architecture check, don't perform the check
if("FALSE")
return()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
In short: The version range 0.3.3...<0.5.0
is incorrect from the view of the compatibility policy, specified for the package. Given package is treated as compatible only when both major and minor versions in the request are the same as the package's version.
Correct version requests could be:
0.3.3...<0.4.0
0.4.3...<0.5.0
(But the package with version 0.4.6
would satisfy only the second request).
The config file is generated by write_basic_package_version_file with the COMPATIBILITY option SameMinorVersion
. This can be deduced from the description:
# ... it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major and minor versions are the same as the current
# one.
If requested a version range with both ends included (without <
), then both ends should have same major and minor versions:
# both endpoints of the range must have the expected major and minor versions
When upper end is excluded (with <
), then it could have minor version greater by 1 than the lower end.
Allowed:
3.3.0...3.3.5
3.4.2...3.4.10
3.3.0...<3.3.5
3.3.2...<3.4
Disallowed:
3.3.0...3.4.0
3.3.0...4.3.0
3.3.0...<3.5
3.3.0...<3.4.1
Only when version range is allowed, the package's version is checked to be inside the range. In other cases the package is treated as incompatible with the request.
From my understanding, the version request semantic in find_package
call is:
<
, the package's version should be compatible with both ends. And the package version should belong to the range.<
, the upper end could denote the "next incompatible" version of the package. In other aspects this case is similar to one without <
.