diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index e82a8fb11..8c226024c 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -284,6 +284,34 @@ namespace reducible = 1; } + //========================================================================= + enum Op { OpLess, OpEqual, OpGreater }; + bool HandleVersionCompare(Op op, const char* lhs_str, const char* rhs_str) + { + // Parse out up to 4 components. + unsigned int lhs[4] = {0,0,0,0}; + unsigned int rhs[4] = {0,0,0,0}; + sscanf(lhs_str, "%u.%u.%u.%u", &lhs[0], &lhs[1], &lhs[2], &lhs[3]); + sscanf(rhs_str, "%u.%u.%u.%u", &rhs[0], &rhs[1], &rhs[2], &rhs[3]); + + // Do component-wise comparison. + for(unsigned int i=0; i < 4; ++i) + { + if(lhs[i] < rhs[i]) + { + // lhs < rhs, so true if operation is LESS + return op == OpLess; + } + else if(lhs[i] > rhs[i]) + { + // lhs > rhs, so true if operation is GREATER + return op == OpGreater; + } + } + // lhs == rhs, so true if operation is EQUAL + return op == OpEqual; + } + //========================================================================= // level 0 processes parenthetical expressions bool HandleLevel0(std::list &newArgs, @@ -552,6 +580,26 @@ namespace reducible, arg, newArgs, argP1, argP2); } + if (argP1 != newArgs.end() && argP2 != newArgs.end() && + (*(argP1) == "VERSION_LESS" || *(argP1) == "VERSION_GREATER" || + *(argP1) == "VERSION_EQUAL")) + { + def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile); + def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile); + Op op = OpEqual; + if(*argP1 == "VERSION_LESS") + { + op = OpLess; + } + else if(*argP1 == "VERSION_GREATER") + { + op = OpGreater; + } + bool result = HandleVersionCompare(op, def, def2); + HandleBinaryOp(result, + reducible, arg, newArgs, argP1, argP2); + } + // is file A newer than file B if (argP1 != newArgs.end() && argP2 != newArgs.end() && *(argP1) == "IS_NEWER_THAN") diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index 6c23aa0f5..bc84e569d 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -177,6 +177,11 @@ public: " if(string STREQUAL string)\n" "True if the given string or variable's value is lexicographically " "less (or greater, or equal) than the string on the right.\n" + " if(version1 VERSION_LESS version2)\n" + " if(version1 VERSION_EQUAL version2)\n" + " if(version1 VERSION_GREATER version2)\n" + "Component-wise integer version number comparison (version format is " + "major[.minor[.patch[.tweak]]]).\n" " if(DEFINED variable)\n" "True if the given variable is defined. It does not matter if the " "variable is true or false just if it has been set."; diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index a3e24bb6f..1703fe7af 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -145,3 +145,20 @@ IF(NOT "${Special_VERSION_MINOR}" STREQUAL "2") MESSAGE(SEND_ERROR "Package Special is minor version [${Special_VERSION_MINOR}], not [2]") ENDIF(NOT "${Special_VERSION_MINOR}" STREQUAL "2") + +# Test version number comparison. +IF(NOT "1.2.3.4" VERSION_LESS "1.2.3.5") + MESSAGE(SEND_ERROR "1.2.3.4 VERSION_LESS 1.2.3.5 is not true!") +ENDIF() +IF(NOT "1.2" VERSION_LESS "1.10") + MESSAGE(SEND_ERROR "1.2 VERSION_LESS 1.10 is not true!") +ENDIF() +IF(NOT "1.02" VERSION_GREATER "1.1") + MESSAGE(SEND_ERROR "1.02 VERSION_GREATER 1.1 is not true!") +ENDIF() +IF("1.2.3" VERSION_GREATER "1.2.3.4") + MESSAGE(SEND_ERROR "1.2.3 VERSION_GREATER 1.2.3.4 is not false!") +ENDIF() +IF(NOT "1.2" VERSION_EQUAL "1.2.0.0") + MESSAGE(SEND_ERROR "1.2 VERSION_EQUAL 1.2.0.0 is not true!") +ENDIF()