Explorar o código

Genex: Add `IF` generator expression

This allows a single condition to be used to choose between two
alternatives.  Without this the condition must be duplicated with
one surrounded by `NOT`.

Closes: #15585
Colby Pike %!s(int64=8) %!d(string=hai) anos
pai
achega
895f7f16a7

+ 2 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -51,6 +51,8 @@ Available logical expressions are:
   ``0`` if all ``?`` are ``0``, else ``1``
   ``0`` if all ``?`` are ``0``, else ``1``
 ``$<NOT:?>``
 ``$<NOT:?>``
   ``0`` if ``?`` is ``1``, else ``1``
   ``0`` if ``?`` is ``1``, else ``1``
+``$<IF:?,true-value...,false-value...>```
+  ``true-value...`` if ``?`` is ``1``, ``false-value...`` if ``?`` is ``0``
 ``$<STREQUAL:a,b>``
 ``$<STREQUAL:a,b>``
   ``1`` if ``a`` is STREQUAL ``b``, else ``0``
   ``1`` if ``a`` is STREQUAL ``b``, else ``0``
 ``$<EQUAL:a,b>``
 ``$<EQUAL:a,b>``

+ 7 - 0
Help/release/dev/if-genex.rst

@@ -0,0 +1,7 @@
+genex-if
+--------
+
+* A new logical generator expression for immediate-if was added:
+  ``$<IF:cond,true-value,false-value>``. It takes three arguments: One
+  condition, a true-value, and a false-value. Resolves to the true-value if the
+  condition is ``1``, and resolves to the false-value if the condition is ``0``.

+ 22 - 0
Source/cmGeneratorExpressionNode.cxx

@@ -162,6 +162,27 @@ static const struct BoolNode : public cmGeneratorExpressionNode
   }
   }
 } boolNode;
 } boolNode;
 
 
+static const struct IfNode : public cmGeneratorExpressionNode
+{
+  IfNode() {}
+
+  int NumExpectedParameters() const CM_OVERRIDE { return 3; }
+
+  std::string Evaluate(const std::vector<std::string>& parameters,
+                       cmGeneratorExpressionContext* context,
+                       const GeneratorExpressionContent* content,
+                       cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE
+  {
+    if (parameters[0] != "1" && parameters[0] != "0") {
+      reportError(context, content->GetOriginalExpression(),
+                  "First parameter to $<IF> must resolve to exactly one '0' "
+                  "or '1' value.");
+      return std::string();
+    }
+    return parameters[0] == "1" ? parameters[1] : parameters[2];
+  }
+} ifNode;
+
 static const struct StrEqualNode : public cmGeneratorExpressionNode
 static const struct StrEqualNode : public cmGeneratorExpressionNode
 {
 {
   StrEqualNode() {}
   StrEqualNode() {}
@@ -1757,6 +1778,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
     nodeMap["UPPER_CASE"] = &upperCaseNode;
     nodeMap["UPPER_CASE"] = &upperCaseNode;
     nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
     nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
     nodeMap["BOOL"] = &boolNode;
     nodeMap["BOOL"] = &boolNode;
+    nodeMap["IF"] = &ifNode;
     nodeMap["ANGLE-R"] = &angle_rNode;
     nodeMap["ANGLE-R"] = &angle_rNode;
     nodeMap["COMMA"] = &commaNode;
     nodeMap["COMMA"] = &commaNode;
     nodeMap["SEMICOLON"] = &semicolonNode;
     nodeMap["SEMICOLON"] = &semicolonNode;

+ 4 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -246,6 +246,10 @@ add_custom_target(check-part4 ALL
     # CMake as command-line argument
     # CMake as command-line argument
     -Dtest_shell_path=${path_prefix}$<SHELL_PATH:${test_shell_path}>
     -Dtest_shell_path=${path_prefix}$<SHELL_PATH:${test_shell_path}>
     -Dpath_prefix=${path_prefix}
     -Dpath_prefix=${path_prefix}
+    -Dif_1=$<IF:1,a,b>
+    -Dif_2=$<IF:0,a,b>
+    -Dif_3=$<IF:$<EQUAL:10,30>,a,b>
+    -Dif_4=$<IF:$<EQUAL:30,30>,a,b>
     -DWIN32=${WIN32}
     -DWIN32=${WIN32}
     -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
     -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part4.cmake
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part4.cmake

+ 5 - 0
Tests/GeneratorExpression/check-part4.cmake

@@ -13,3 +13,8 @@ if(WIN32)
 else()
 else()
   check(test_shell_path [[/shell/path]])
   check(test_shell_path [[/shell/path]])
 endif()
 endif()
+
+check(if_1 "a")
+check(if_2 "b")
+check(if_3 "b")
+check(if_4 "a")

+ 1 - 0
Tests/RunCMake/GeneratorExpression/BadIF-result.txt

@@ -0,0 +1 @@
+1

+ 15 - 0
Tests/RunCMake/GeneratorExpression/BadIF-stderr.txt

@@ -0,0 +1,15 @@
+CMake Error at BadIF.cmake:2 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<IF:asdf,a,b>
+
+  First parameter to \$<IF> must resolve to exactly one '0' or '1' value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at BadIF.cmake:2 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<IF:asdf,a>
+
+  \$<IF> expression requires 3 comma separated parameters, but got 2 instead.

+ 5 - 0
Tests/RunCMake/GeneratorExpression/BadIF.cmake

@@ -0,0 +1,5 @@
+
+add_custom_target(check ALL COMMAND check
+    $<IF:asdf,a,b>
+    $<IF:asdf,a>
+    )

+ 1 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -1,5 +1,6 @@
 include(RunCMake)
 include(RunCMake)
 
 
+run_cmake(BadIF)
 run_cmake(BadCONFIG)
 run_cmake(BadCONFIG)
 run_cmake(BadOR)
 run_cmake(BadOR)
 run_cmake(BadAND)
 run_cmake(BadAND)