|
|
(2 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
| 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.
| | {{CMake/Template/Moved}} |
|
| |
|
| <pre>
| | This page has moved [https://gitlab.kitware.com/cmake/community/wikis/contrib/macros/CompareVersionStrings here]. |
| 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>
| |