Difference between revisions of "CMakeCompareVersionStrings"

From KitwarePublic
Jump to navigationJump to search
(Replace content with link to new CMake community wiki)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
{{CMake/Template/Obsolete}}
{{CMake/Template/Moved}}


Please see the '''VERSION_LESS''', '''VERSION_EQUAL''', and '''VERSION_GREATER''' options to the IF() command.
This page has moved [https://gitlab.kitware.com/cmake/community/wikis/contrib/macros/CompareVersionStrings here].
 
----
 
I needed a way to compare two version strings to make sure that I had a version of a package that was sufficient for my needs.  The first go around I used regular expressions to pull out all the dot versions, create a number, and finally compare the number.
 
<pre>
SET(THREE_PART_VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+")
 
# Breaks up a string in the form n1.n2.n3 into three parts and stores
# them in major, minor, and patch.  version should be a value, not a
# variable, while major, minor and patch should be variables.
MACRO(THREE_PART_VERSION_TO_VARS version major minor patch)
  IF(${version} MATCHES ${THREE_PART_VERSION_REGEX})
    STRING(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" ${major} "${version}")
    STRING(REGEX REPLACE "^[0-9]+\\.([0-9])+\\.[0-9]+" "\\1" ${minor} "${version}")
    STRING(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" ${patch} "${version}")
  ELSE(${version} MATCHES ${THREE_PART_VERSION_REGEX})
    MESSAGE("MACRO(THREE_PART_VERSION_TO_VARS ${version} ${major} ${minor} ${patch}")
    MESSAGE(FATAL_ERROR "Problem parsing version string, I can't parse it properly.")
  ENDIF(${version} MATCHES ${THREE_PART_VERSION_REGEX})
ENDMACRO(THREE_PART_VERSION_TO_VARS)
 
THREE_PART_VERSION_TO_VARS(${version-string} major_vers minor_vers patch_vers)
MESSAGE("version        = ${major_vers}.${minor_vers}.${patch_vers}")
 
# Compute a version number
MATH(EXPR version_number "${major_vers} * 1000000 + ${minor_vers} * 1000 + ${patch_vers}" )
MESSAGE("version_number = ${version_number}")
</pre>
 
This was somewhat cumbersome, and was hard coded for three dot versions (x.y.z).  I wanted to be able to use a single macro for version strings with 1 to any number of dot versions.  In addition I wanted to be able to compare version strings with different number of dot versions (i.e. 0.99.1 and 0.99.1.2).
 
<pre>
# Computes the realtionship between two version strings.  A version
# string is a number delineated by '.'s such as 1.3.2 and 0.99.9.1.
# You can feed version strings with different number of dot versions,
# and the shorter version number will be padded with zeros: 9.2 <
# 9.2.1 will actually compare 9.2.0 < 9.2.1.
#
# Input: a_in - value, not variable
#        b_in - value, not variable
#        result_out - variable with value:
#                        -1 : a_in <  b_in
#                          0 : a_in == b_in
#                          1 : a_in >  b_in
#
# Written by James Bigler.
MACRO(COMPARE_VERSION_STRINGS a_in b_in result_out)
  # Since SEPARATE_ARGUMENTS using ' ' as the separation token,
  # replace '.' with ' ' to allow easy tokenization of the string.
  STRING(REPLACE "." " " a ${a_in})
  STRING(REPLACE "." " " b ${b_in})
  SEPARATE_ARGUMENTS(a)
  SEPARATE_ARGUMENTS(b)
 
  # Check the size of each list to see if they are equal.
  LIST(LENGTH a a_length)
  LIST(LENGTH b b_length)
 
  # Pad the shorter list with zeros.
 
  # Note that range needs to be one less than the length as the for
  # loop is inclusive (silly CMake).
  IF(a_length LESS b_length)
    # a is shorter
    SET(shorter a)
    MATH(EXPR range "${b_length} - 1")
    MATH(EXPR pad_range "${b_length} - ${a_length} - 1")
  ELSE(a_length LESS b_length)
    # b is shorter
    SET(shorter b)
    MATH(EXPR range "${a_length} - 1")
    MATH(EXPR pad_range "${a_length} - ${b_length} - 1")
  ENDIF(a_length LESS b_length)
 
  # PAD out if we need to
  IF(NOT pad_range LESS 0)
    FOREACH(pad RANGE ${pad_range})
      # Since shorter is an alias for b, we need to get to it by by dereferencing shorter.
      LIST(APPEND ${shorter} 0)
    ENDFOREACH(pad RANGE ${pad_range})
  ENDIF(NOT pad_range LESS 0)
 
  SET(result 0)
  FOREACH(index RANGE ${range})
    IF(result EQUAL 0)
      # Only continue to compare things as long as they are equal
      LIST(GET a ${index} a_version)
      LIST(GET b ${index} b_version)
      # LESS
      IF(a_version LESS b_version)
        SET(result -1)
      ENDIF(a_version LESS b_version)
      # GREATER
      IF(a_version GREATER b_version)
        SET(result 1)
      ENDIF(a_version GREATER b_version)
    ENDIF(result EQUAL 0)
  ENDFOREACH(index)
 
  # Copy out the return result
  SET(${result_out} ${result})
ENDMACRO(COMPARE_VERSION_STRINGS)
</pre>
 
I tested it with the following input:
 
<pre>
# a and b need to be passed in by value
MACRO(COMPARE_VERSION a b)
  COMPARE_VERSION_STRINGS(${a} ${b} result)
  IF(result LESS 0)
    MESSAGE("${a} <  ${b}")
  ELSE(result LESS 0)
    IF(result GREATER 0)
      MESSAGE("${a} >  ${b}")
    ELSE(result GREATER 0)
      MESSAGE("${a} == ${b}")
    ENDIF(result GREATER 0)
  ENDIF(result LESS 0)
ENDMACRO(COMPARE_VERSION)
 
  SET(version-string "1.3.31")
 
  COMPARE_VERSION(${version-string} "1.3.30")
  COMPARE_VERSION(${version-string} "1.3.31")
  COMPARE_VERSION(${version-string} "1.3.32")
  COMPARE_VERSION(${version-string} "1.2.32")
  COMPARE_VERSION(${version-string} "1.10.1")
 
  COMPARE_VERSION("9.2" "9.1")
  COMPARE_VERSION("9.2" "9.2")
  COMPARE_VERSION("9.2" "9.3")
 
  COMPARE_VERSION("9.1" "9.2")
  COMPARE_VERSION("9.2" "9.2")
  COMPARE_VERSION("9.3" "9.2")
 
  COMPARE_VERSION("9.10" "9.2")
  COMPARE_VERSION("9.2"  "9.10")
 
  COMPARE_VERSION("0.92.1.0" "0.92.1.1")
  COMPARE_VERSION("0.92.1.1" "0.92.1.1")
  COMPARE_VERSION("0.92.1.2" "0.92.1.1")
 
  COMPARE_VERSION("0.92.1.2" "0.99.1.1")
  COMPARE_VERSION("0.99.1.2" "0.92.1.1")
 
  COMPARE_VERSION("0.92.1.2" "0.99.1")
  COMPARE_VERSION("0.99.1" "0.92.1.1")
 
  COMPARE_VERSION("0.99.1.2" "0.99.1")
  COMPARE_VERSION("0.99.1" "0.99.1.1")
 
  COMPARE_VERSION( "1" "10")
  COMPARE_VERSION("10"  "1")
</pre>
 
Here's the output:
 
<pre>
1.3.31 >  1.3.30
1.3.31 == 1.3.31
1.3.31 <  1.3.32
1.3.31 >  1.2.32 (note this is 1.2 not 1.3)
1.3.31 <  1.10.1
9.2 >  9.1
9.2 == 9.2
9.2 <  9.3
9.1 <  9.2
9.2 == 9.2
9.3 >  9.2
9.10 >  9.2
9.2 <  9.10
0.92.1.0 <  0.92.1.1
0.92.1.1 == 0.92.1.1
0.92.1.2 >  0.92.1.1
0.92.1.2 <  0.99.1.1
0.99.1.2 >  0.92.1.1
0.92.1.2 <  0.99.1
0.99.1 >  0.92.1.1
0.99.1.2 >  0.99.1
0.99.1 <  0.99.1.1
1 <  10
10 >  1
</pre>
 
[[Category:CMakeMacro]]

Latest revision as of 15:41, 30 April 2018


The CMake community Wiki has moved to the Kitware GitLab Instance.

This page has moved here.