Răsfoiți Sursa

Add boolean generator expressions

Add generator expressions that combine and use boolean test results:

 $<0:...>         = empty string (ignores "...")
 $<1:...>         = content of "..."
 $<AND:?[,?]...>  = '1' if all '?' are '1', else '0'
 $<OR:?[,?]...>   = '0' if all '?' are '0', else '1'
 $<NOT:?>         = '0' if '?' is '1', else '1'

These will be useful to evaluate (future) boolean query expressions and
condition content on the results.  Include tests and documentation.
Brad King 13 ani în urmă
părinte
comite
ebf05abda1

+ 9 - 1
Source/cmDocumentGeneratorExpressions.h

@@ -16,6 +16,8 @@
   "Generator expressions are evaluted during build system generation "  \
   "to produce information specific to each build configuration.  "      \
   "Valid expressions are:\n"                                            \
+  "  $<0:...>                  = empty string (ignores \"...\")\n"      \
+  "  $<1:...>                  = content of \"...\"\n"                  \
   "  $<CONFIGURATION>          = configuration name\n"                  \
   "  $<TARGET_FILE:tgt>        = main file (.exe, .so.1.2, .a)\n"       \
   "  $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n"   \
@@ -25,6 +27,12 @@
   "versions can produce the directory and file name components:\n"      \
   "  $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n"                  \
   "  $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n"    \
-  "  $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n"
+  "  $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n"    \
+  "Boolean expressions:\n"                                              \
+  "  $<AND:?[,?]...>           = '1' if all '?' are '1', else '0'\n"    \
+  "  $<OR:?[,?]...>            = '0' if all '?' are '0', else '1'\n"    \
+  "  $<NOT:?>                  = '0' if '?' is '1', else '1'\n"         \
+  "where '?' is always either '0' or '1'.\n"                            \
+  ""
 
 #endif

+ 46 - 0
Source/cmGeneratorExpression.cxx

@@ -102,6 +102,26 @@ bool cmGeneratorExpression::Evaluate()
   return true;
 }
 
+//----------------------------------------------------------------------------
+static bool cmGeneratorExpressionBool(const char* c, std::string& result,
+                                      const char* name,
+                                      const char* a, const char* b)
+{
+  result = a;
+  while((c[0] == '0' || c[0] == '1') && (c[1] == ',' || c[1] == '>'))
+    {
+    if(c[0] == b[0]) { result = b; }
+    c += 2;
+    }
+  if(c[0])
+    {
+    result = name;
+    result += " requires one or more comma-separated '0' or '1' values.";
+    return false;
+    }
+  return true;
+}
+
 //----------------------------------------------------------------------------
 bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
 {
@@ -116,6 +136,32 @@ bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
     {
     result = this->Config? this->Config : "";
     }
+  else if(strncmp(expr, "$<0:",4) == 0)
+    {
+    result = "";
+    }
+  else if(strncmp(expr, "$<1:",4) == 0)
+    {
+    result = std::string(expr+4, strlen(expr)-5);
+    }
+  else if(strncmp(expr, "$<NOT:",6) == 0)
+    {
+    const char* c = expr+6;
+    if((c[0] != '0' && c[0] != '1') || c[1] != '>' || c[2])
+      {
+      result = "NOT requires exactly one '0' or '1' value.";
+      return false;
+      }
+    result = c[0] == '1'? "0" : "1";
+    }
+  else if(strncmp(expr, "$<AND:",6) == 0)
+    {
+    return cmGeneratorExpressionBool(expr+6, result, "AND", "1", "0");
+    }
+  else if(strncmp(expr, "$<OR:",5) == 0)
+    {
+    return cmGeneratorExpressionBool(expr+5, result, "OR", "0", "1");
+    }
   else
     {
     result = "Expression syntax not recognized.";

+ 10 - 0
Tests/CMakeLists.txt

@@ -551,6 +551,16 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
     FAIL_REGULAR_EXPRESSION "Unexpected: ")
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ArgumentExpansion")
 
+  add_test(GeneratorExpression  ${CMAKE_CTEST_COMMAND}
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/GeneratorExpression"
+    "${CMake_BINARY_DIR}/Tests/GeneratorExpression"
+    --build-generator ${CMAKE_TEST_GENERATOR}
+    --build-project GeneratorExpression
+    --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+    )
+  list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GeneratorExpression")
+
   add_test(CustomCommand  ${CMAKE_CTEST_COMMAND}
     --build-and-test
     "${CMake_SOURCE_DIR}/Tests/CustomCommand"

+ 26 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -0,0 +1,26 @@
+cmake_minimum_required (VERSION 2.8.8)
+project(GeneratorExpression NONE)
+
+add_custom_target(check ALL
+  COMMAND ${CMAKE_COMMAND}
+    -Dtest_0=$<0:nothing>
+    -Dtest_1=$<1:content>
+    -Dconfig=$<CONFIGURATION>
+    -Dtest_and_0=$<AND:0>
+    -Dtest_and_0_0=$<AND:0,0>
+    -Dtest_and_0_1=$<AND:0,1>
+    -Dtest_and_1=$<AND:1>
+    -Dtest_and_1_0=$<AND:1,0>
+    -Dtest_and_1_1=$<AND:1,1>
+    -Dtest_not_0=$<NOT:0>
+    -Dtest_not_1=$<NOT:1>
+    -Dtest_or_0=$<OR:0>
+    -Dtest_or_0_0=$<OR:0,0>
+    -Dtest_or_0_1=$<OR:0,1>
+    -Dtest_or_1=$<OR:1>
+    -Dtest_or_1_0=$<OR:1,0>
+    -Dtest_or_1_1=$<OR:1,1>
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
+  COMMAND ${CMAKE_COMMAND} -E echo "check done"
+  VERBATIM
+  )

+ 23 - 0
Tests/GeneratorExpression/check.cmake

@@ -0,0 +1,23 @@
+macro(check var val)
+  if(NOT "${${var}}" STREQUAL "${val}")
+    message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"")
+  endif()
+endmacro()
+
+message(STATUS "config=[${config}]")
+check(test_0 "")
+check(test_1 "content")
+check(test_and_0 "0")
+check(test_and_0_0 "0")
+check(test_and_0_1 "0")
+check(test_and_1 "1")
+check(test_and_1_0 "0")
+check(test_and_1_1 "1")
+check(test_not_0 "1")
+check(test_not_1 "0")
+check(test_or_0 "0")
+check(test_or_0_0 "0")
+check(test_or_0_1 "1")
+check(test_or_1 "1")
+check(test_or_1_0 "1")
+check(test_or_1_1 "1")

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -45,6 +45,7 @@ macro(add_RunCMake_test test)
     )
 endmacro()
 
+add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(Languages)
 add_RunCMake_test(ObjectLibrary)
 

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

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

+ 17 - 0
Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt

@@ -0,0 +1,17 @@
+CMake Error at BadAND.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<AND:>
+
+  AND requires one or more comma-separated '0' or '1' values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at BadAND.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<AND:,>
+
+  AND requires one or more comma-separated '0' or '1' values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 4 - 0
Tests/RunCMake/GeneratorExpression/BadAND.cmake

@@ -0,0 +1,4 @@
+add_custom_target(check ALL COMMAND check
+  $<AND:>
+  $<AND:,>
+  VERBATIM)

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

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

+ 26 - 0
Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt

@@ -0,0 +1,26 @@
+CMake Error at BadNOT.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<NOT:>
+
+  NOT requires exactly one '0' or '1' value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at BadNOT.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<NOT:,>
+
+  NOT requires exactly one '0' or '1' value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at BadNOT.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<NOT:0,1>
+
+  NOT requires exactly one '0' or '1' value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

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

@@ -0,0 +1,5 @@
+add_custom_target(check ALL COMMAND check
+  $<NOT:>
+  $<NOT:,>
+  $<NOT:0,1>
+  VERBATIM)

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

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

+ 17 - 0
Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt

@@ -0,0 +1,17 @@
+CMake Error at BadOR.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<OR:>
+
+  OR requires one or more comma-separated '0' or '1' values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at BadOR.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<OR:,>
+
+  OR requires one or more comma-separated '0' or '1' values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 4 - 0
Tests/RunCMake/GeneratorExpression/BadOR.cmake

@@ -0,0 +1,4 @@
+add_custom_target(check ALL COMMAND check
+  $<OR:>
+  $<OR:,>
+  VERBATIM)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

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

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(BadOR)
+run_cmake(BadAND)
+run_cmake(BadNOT)