diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index ed28abd31c..12cfaf8c38 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -55,6 +55,8 @@ otherwise expands to nothing. ``0`` if ``?`` is ``1``, else ``1`` ``$`` ``1`` if ``a`` is STREQUAL ``b``, else ``0`` +``$`` + ``1`` if ``a`` is EQUAL ``b`` in a numeric comparison, else ``0`` ``$`` ``1`` if config is ``cfg``, else ``0``. This is a case-insensitive comparison. The mapping in :prop_tgt:`MAP_IMPORTED_CONFIG_` is also considered by diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index c8010d0fce..83d341efe6 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -19,6 +19,7 @@ #include #include +#include //---------------------------------------------------------------------------- #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510 @@ -196,6 +197,92 @@ static const struct StrEqualNode : public cmGeneratorExpressionNode } } strEqualNode; +//---------------------------------------------------------------------------- +static const struct EqualNode : public cmGeneratorExpressionNode +{ + EqualNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + std::string Evaluate(const std::vector ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const + { + char *pEnd; + + int base = 0; + bool flipSign = false; + + const char *lhs = parameters[0].c_str(); + if (cmHasLiteralPrefix(lhs, "0b")) + { + base = 2; + lhs += 2; + } + if (cmHasLiteralPrefix(lhs, "-0b")) + { + base = 2; + lhs += 3; + flipSign = true; + } + if (cmHasLiteralPrefix(lhs, "+0b")) + { + base = 2; + lhs += 3; + } + + long lnum = strtol(lhs, &pEnd, base); + if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) + { + reportError(context, content->GetOriginalExpression(), + "$ parameter " + parameters[0] + " is not a valid integer."); + return std::string(); + } + + if (flipSign) + { + lnum = -lnum; + } + + base = 0; + flipSign = false; + + const char *rhs = parameters[1].c_str(); + if (cmHasLiteralPrefix(rhs, "0b")) + { + base = 2; + rhs += 2; + } + if (cmHasLiteralPrefix(rhs, "-0b")) + { + base = 2; + rhs += 3; + flipSign = true; + } + if (cmHasLiteralPrefix(rhs, "+0b")) + { + base = 2; + rhs += 3; + } + + long rnum = strtol(rhs, &pEnd, base); + if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) + { + reportError(context, content->GetOriginalExpression(), + "$ parameter " + parameters[1] + " is not a valid integer."); + return std::string(); + } + + if (flipSign) + { + rnum = -rnum; + } + + return lnum == rnum ? "1" : "0"; + } +} equalNode; + //---------------------------------------------------------------------------- static const struct LowerCaseNode : public cmGeneratorExpressionNode { @@ -1492,6 +1579,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &targetSoNameFileDirNode; else if (identifier == "STREQUAL") return &strEqualNode; + else if (identifier == "EQUAL") + return &equalNode; else if (identifier == "LOWER_CASE") return &lowerCaseNode; else if (identifier == "UPPER_CASE") diff --git a/Tests/CompatibleInterface/CMakeLists.txt b/Tests/CompatibleInterface/CMakeLists.txt index 47e974a85f..350b5184c7 100644 --- a/Tests/CompatibleInterface/CMakeLists.txt +++ b/Tests/CompatibleInterface/CMakeLists.txt @@ -60,7 +60,7 @@ set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2) set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP1 50) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP2 250) -set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP3 0xA) +set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP3 0xa) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP4 0x1A) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP1 50) set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP2 250) @@ -75,7 +75,7 @@ target_compile_definitions(CompatibleInterface $<$,prop3>:STRING_PROP3> $<$,50>:NUMBER_MIN_PROP1=50> $<$,200>:NUMBER_MIN_PROP2=200> - $<$,0xA>:NUMBER_MIN_PROP3=0xA> + $<$,0xA>:NUMBER_MIN_PROP3=0xA> $<$,0x10>:NUMBER_MIN_PROP4=0x10> $<$,100>:NUMBER_MAX_PROP1=100> $<$,250>:NUMBER_MAX_PROP2=250> diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 892f80fd65..4fb7ecde7f 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -196,6 +196,27 @@ add_custom_target(check-part3 ALL -Dlower_case=$ -Dupper_case=$ -Dmake_c_identifier=$ + -Dequal1=$ + -Dequal2=$ + -Dequal3=$ + -Dequal4=$ + -Dequal5=$ + -Dequal6=$ + -Dequal7=$ + -Dequal8=$ + -Dequal9=$ + -Dequal10=$ + -Dequal11=$ + -Dequal12=$ + -Dequal13=$ + -Dequal14=$ + -Dequal15=$ + -Dequal16=$ + -Dequal17=$ + -Dequal18=$ + -Dequal19=$ + -Dequal20=$ + -Dequal21=$ -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part3.cmake COMMAND ${CMAKE_COMMAND} -E echo "check done (part 3 of 3)" VERBATIM diff --git a/Tests/GeneratorExpression/check-part3.cmake b/Tests/GeneratorExpression/check-part3.cmake index 3361eebd0b..2c6bf49b15 100644 --- a/Tests/GeneratorExpression/check-part3.cmake +++ b/Tests/GeneratorExpression/check-part3.cmake @@ -37,3 +37,24 @@ endforeach() check(lower_case "mi,xed") check(upper_case "MIX,ED") check(make_c_identifier "_4f_oo__bar__") +check(equal1 "0") +check(equal2 "1") +check(equal3 "1") +check(equal4 "0") +check(equal5 "1") +check(equal6 "1") +check(equal7 "1") +check(equal8 "1") +check(equal9 "0") +check(equal10 "1") +check(equal11 "1") +check(equal12 "1") +check(equal13 "1") +check(equal14 "1") +check(equal15 "1") +check(equal16 "1") +check(equal17 "0") +check(equal18 "1") +check(equal19 "1") +check(equal20 "0") +check(equal21 "1")