Browse Source

CMakePackageConfigHelpers: Relax restrictions on version range

Marc Chevrier 5 years ago
parent
commit
55c3b6a77e

+ 21 - 12
Modules/BasicConfigVersion-SameMajorVersion.cmake.in

@@ -9,13 +9,6 @@
 # The variable CVF_VERSION must be set before calling configure_file().
 
 
-if (PACKAGE_FIND_VERSION_RANGE)
-  message(AUTHOR_WARNING
-    "`find_package()` specify a version range but the version strategy "
-    "(SameMajorVersion) of the module `${PACKAGE_FIND_NAME}` is incompatible "
-    "with this request. Only the lower endpoint of the range will be used.")
-endif()
-
 set(PACKAGE_VERSION "@CVF_VERSION@")
 
 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
@@ -28,14 +21,30 @@ else()
     set(CVF_VERSION_MAJOR "@CVF_VERSION@")
   endif()
 
-  if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
-    set(PACKAGE_VERSION_COMPATIBLE TRUE)
+  if(PACKAGE_FIND_VERSION_RANGE)
+    # both endpoints of the range must have the expected major version
+    math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
+    if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+        OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
+          OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
+      set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+        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()
-    set(PACKAGE_VERSION_COMPATIBLE FALSE)
-  endif()
+    if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
+      set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    else()
+      set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    endif()
 
-  if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+    if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
       set(PACKAGE_VERSION_EXACT TRUE)
+    endif()
   endif()
 endif()
 

+ 27 - 13
Modules/BasicConfigVersion-SameMinorVersion.cmake.in

@@ -10,13 +10,6 @@
 # The variable CVF_VERSION must be set before calling configure_file().
 
 
-if (PACKAGE_FIND_VERSION_RANGE)
-  message(AUTHOR_WARNING
-    "`find_package()` specify a version range but the version strategy "
-    "(SameMinorVersion) of the module `${PACKAGE_FIND_NAME}` is incompatible "
-    "with this request. Only the lower endpoint of the range will be used.")
-endif()
-
 set(PACKAGE_VERSION "@CVF_VERSION@")
 
 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
@@ -31,15 +24,36 @@ else()
     set(CVF_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)
+  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()
-    set(PACKAGE_VERSION_COMPATIBLE FALSE)
-  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)
+    if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
       set(PACKAGE_VERSION_EXACT TRUE)
+    endif()
   endif()
 endif()
 

+ 4 - 3
Modules/CMakePackageConfigHelpers.cmake

@@ -177,9 +177,10 @@ macro.
   packages with no binaries.
 
 .. versionadded:: 3.19
-  ``COMPATIBILITY_MODE`` ``AnyNewerVersion`` handles the version range
-  if any is specified (see :command:`find_package` command for the details).
-  All other modes are incompatible with version ranges and will display an
+  ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and
+  ``SameMinorVersion`` handle the version range if any is specified
+  (see :command:`find_package` command for the details).
+  ``ExactVersion`` mode is incompatible with version ranges and will display an
   author warning if one is specified.
 
 Internally, this macro executes :command:`configure_file()` to create the

+ 107 - 18
Tests/RunCMake/WriteBasicConfigVersionFile/All.cmake

@@ -3,16 +3,16 @@ set(CMAKE_SIZEOF_VOID_P 4)
 
 include(WriteBasicConfigVersionFile)
 
-set(_compatibilities AnyNewerVersion
-                     SameMajorVersion
-                     SameMinorVersion
-                     ExactVersion)
+set(COMPATIBILITIES AnyNewerVersion
+                    SameMajorVersion
+                    SameMinorVersion
+                    ExactVersion)
 
 function(TEST_WRITE_BASIC_CONFIG_VERSION_FILE_PREPARE _version_installed)
   set(_same_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
   set(_no_CMAKE_SIZEOF_VOID_P "")
   math(EXPR _diff_CMAKE_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P} + 1")
-  foreach(_compat ${_compatibilities})
+  foreach(_compat ${COMPATIBILITIES})
     set(_pkg ${_compat}${_version_installed})
     string(REPLACE "." "" _pkg ${_pkg})
     set(_filename "${CMAKE_CURRENT_BINARY_DIR}/${_pkg}ConfigVersion.cmake")
@@ -71,20 +71,58 @@ function(TEST_WRITE_BASIC_CONFIG_VERSION_FILE _version_installed
                                               _expected_compatible_SameMajorVersion
                                               _expected_compatible_SameMinorVersion
                                               _expected_compatible_ExactVersion)
-  set(PACKAGE_FIND_VERSION ${_version_requested})
-  if("${PACKAGE_FIND_VERSION}" MATCHES [[(^([0-9]+)(\.([0-9]+)(\.([0-9]+)(\.([0-9]+))?)?)?)?$]])
-    set(PACKAGE_FIND_VERSION_MAJOR "${CMAKE_MATCH_2}")
-    set(PACKAGE_FIND_VERSION_MINOR "${CMAKE_MATCH_4}")
-    set(PACKAGE_FIND_VERSION_PATCH "${CMAKE_MATCH_6}")
-    set(PACKAGE_FIND_VERSION_TWEAK "${CMAKE_MATCH_8}")
-  else()
-    message(FATAL_ERROR "_version_requested (${_version_requested}) should be a version number")
-  endif()
-
-  if ("${_version_installed}" STREQUAL "${_version_requested}")
-    set(_expected_exact 1)
-  else()
+  if("${_version_requested}" MATCHES [[^([0-9]+(\.[0-9]+)*)\.\.\.(<)?([0-9]+(\.[0-9]+)*)$]])
+    set (_compatibilities ${COMPATIBILITIES})
+    # ExactVersion must not be tested
+    list(POP_BACK _compatibilities)
+    set(PACKAGE_FIND_VERSION_RANGE TRUE)
+    set(PACKAGE_FIND_VERSION_RANGE_MIN INCLUDE)
+    if ("${CMAKE_MATCH_3}" STREQUAL "<")
+      set(PACKAGE_FIND_VERSION_RANGE_MAX EXCLUDE)
+    else()
+      set(PACKAGE_FIND_VERSION_RANGE_MAX INCLUDE)
+    endif()
+    set(PACKAGE_FIND_VERSION_MIN "${CMAKE_MATCH_1}")
+    set(PACKAGE_FIND_VERSION_MAX "${CMAKE_MATCH_4}")
+    if("${PACKAGE_FIND_VERSION_MIN}" MATCHES [[(^([0-9]+)(\.([0-9]+)(\.([0-9]+)(\.([0-9]+))?)?)?)?$]])
+      set(PACKAGE_FIND_VERSION_MIN_MAJOR "${CMAKE_MATCH_2}")
+      set(PACKAGE_FIND_VERSION_MIN_MINOR "${CMAKE_MATCH_4}")
+      set(PACKAGE_FIND_VERSION_MIN_PATCH "${CMAKE_MATCH_6}")
+      set(PACKAGE_FIND_VERSION_MIN_TWEAK "${CMAKE_MATCH_8}")
+    else()
+      message(FATAL_ERROR "_version_requested (${_version_requested}) should be a version range")
+    endif()
+    set(PACKAGE_FIND_VERSION "${PACKAGE_FIND_VERSION_MIN}")
+    set(PACKAGE_FIND_VERSION_MAJOR "${PACKAGE_FIND_VERSION_MIN_MAJOR}")
+    set(PACKAGE_FIND_VERSION_MINOR "${PACKAGE_FIND_VERSION_MIN_MINOR}")
+    set(PACKAGE_FIND_VERSION_PATCH "${PACKAGE_FIND_VERSION_MIN_PATCH}")
+    set(PACKAGE_FIND_VERSION_TWEAK "${PACKAGE_FIND_VERSION_MIN_TWEAK}")
+    if("${PACKAGE_FIND_VERSION_MAX}" MATCHES [[(^([0-9]+)(\.([0-9]+)(\.([0-9]+)(\.([0-9]+))?)?)?)?$]])
+      set(PACKAGE_FIND_VERSION_MAX_MAJOR "${CMAKE_MATCH_2}")
+      set(PACKAGE_FIND_VERSION_MAX_MINOR "${CMAKE_MATCH_4}")
+      set(PACKAGE_FIND_VERSION_MAX_PATCH "${CMAKE_MATCH_6}")
+      set(PACKAGE_FIND_VERSION_MAX_TWEAK "${CMAKE_MATCH_8}")
+    else()
+      message(FATAL_ERROR "_version_requested (${_version_requested}) should be a version range")
+    endif()
     set(_expected_exact 0)
+  else()
+    set (_compatibilities ${COMPATIBILITIES})
+    set(PACKAGE_FIND_VERSION ${_version_requested})
+    if("${PACKAGE_FIND_VERSION}" MATCHES [[(^([0-9]+)(\.([0-9]+)(\.([0-9]+)(\.([0-9]+))?)?)?)?$]])
+      set(PACKAGE_FIND_VERSION_MAJOR "${CMAKE_MATCH_2}")
+      set(PACKAGE_FIND_VERSION_MINOR "${CMAKE_MATCH_4}")
+      set(PACKAGE_FIND_VERSION_PATCH "${CMAKE_MATCH_6}")
+      set(PACKAGE_FIND_VERSION_TWEAK "${CMAKE_MATCH_8}")
+    else()
+      message(FATAL_ERROR "_version_requested (${_version_requested}) should be a version number")
+    endif()
+
+    if ("${_version_installed}" STREQUAL "${_version_requested}")
+      set(_expected_exact 1)
+    else()
+      set(_expected_exact 0)
+    endif()
   endif()
 
   unset(PACKAGE_VERSION_COMPATIBLE)
@@ -882,3 +920,54 @@ test_write_basic_config_version_file(4.5.6.7  9.9.9.0  0  0  0  0) # Request [ne
 test_write_basic_config_version_file(4.5.6.7  9.9.9.2  0  0  0  0) # Request [newer major].[newer minor].[newer patch].[older tweak]
 test_write_basic_config_version_file(4.5.6.7  9.9.9.7  0  0  0  0) # Request [newer major].[newer minor].[newer patch].[same tweak]
 test_write_basic_config_version_file(4.5.6.7  9.9.9.9  0  0  0  0) # Request [newer major].[newer minor].[newer patch].[newer tweak]
+
+test_write_basic_config_version_file(4        0...5       1  0  0  0)
+test_write_basic_config_version_file(4        2...5       1  0  0  0)
+test_write_basic_config_version_file(4        2...4       1  0  0  0)
+test_write_basic_config_version_file(4        4...<5      1  1  0  0)
+test_write_basic_config_version_file(4        9...10      0  0  0  0)
+
+test_write_basic_config_version_file(4        0.1...5     1  0  0  0)
+test_write_basic_config_version_file(4        2.1...5     1  0  0  0)
+test_write_basic_config_version_file(4        2.8...5     1  0  0  0)
+test_write_basic_config_version_file(4        2.1...4     1  0  0  0)
+test_write_basic_config_version_file(4        2.8...4     1  0  0  0)
+test_write_basic_config_version_file(4        4.0...<5    1  1  0  0)
+test_write_basic_config_version_file(4        4.8...<5    0  0  0  0)
+test_write_basic_config_version_file(4        4.1...5     0  0  0  0)
+test_write_basic_config_version_file(4        4.8...5     0  0  0  0)
+test_write_basic_config_version_file(4        9.1...10    0  0  0  0)
+test_write_basic_config_version_file(4        9.8...10    0  0  0  0)
+
+
+test_write_basic_config_version_file(4.5      0.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5      2.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5      2.8...5     1  0  0  0)
+test_write_basic_config_version_file(4.5      2.1...4     0  0  0  0)
+test_write_basic_config_version_file(4.5      2.8...4     0  0  0  0)
+test_write_basic_config_version_file(4.5      2.8...4.8   1  0  0  0)
+test_write_basic_config_version_file(4.5      4.1...<5    1  1  0  0)
+test_write_basic_config_version_file(4.5      4.8...<5    0  0  0  0)
+test_write_basic_config_version_file(4.5      4.5...4.5.8 1  1  1  0)
+test_write_basic_config_version_file(4.5      4.5...<4.6  1  1  1  0)
+test_write_basic_config_version_file(4.5      4.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5      4.8...5     0  0  0  0)
+test_write_basic_config_version_file(4.5      9.1...10    0  0  0  0)
+test_write_basic_config_version_file(4.5      9.8...10    0  0  0  0)
+
+
+test_write_basic_config_version_file(4.5.6    0.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5.6    2.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5.6    2.8...5     1  0  0  0)
+test_write_basic_config_version_file(4.5.6    2.1...4     0  0  0  0)
+test_write_basic_config_version_file(4.5.6    2.8...4     0  0  0  0)
+test_write_basic_config_version_file(4.5.6    2.8...4.8   1  0  0  0)
+test_write_basic_config_version_file(4.5.6    4.1...<5    1  1  0  0)
+test_write_basic_config_version_file(4.5.6    4.8...<5    0  0  0  0)
+test_write_basic_config_version_file(4.5.6    4.5...4.5.4 0  0  0  0)
+test_write_basic_config_version_file(4.5.6    4.5...4.5.8 1  1  1  0)
+test_write_basic_config_version_file(4.5.6    4.5...<4.6  1  1  1  0)
+test_write_basic_config_version_file(4.5.6    4.1...5     1  0  0  0)
+test_write_basic_config_version_file(4.5.6    4.8...5     0  0  0  0)
+test_write_basic_config_version_file(4.5.6    9.1...10    0  0  0  0)
+test_write_basic_config_version_file(4.5.6    9.8...10    0  0  0  0)