From ebf05abda15967f8f50dcf132f7bf84472ca6337 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 13 Aug 2012 09:49:53 -0400 Subject: [PATCH 1/2] Add boolean generator expressions Add generator expressions that combine and use boolean test results: $<0:...> = empty string (ignores "...") $<1:...> = content of "..." $ = '1' if all '?' are '1', else '0' $ = '0' if all '?' are '0', else '1' $ = '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. --- Source/cmDocumentGeneratorExpressions.h | 10 +++- Source/cmGeneratorExpression.cxx | 46 +++++++++++++++++++ Tests/CMakeLists.txt | 10 ++++ Tests/GeneratorExpression/CMakeLists.txt | 26 +++++++++++ Tests/GeneratorExpression/check.cmake | 23 ++++++++++ Tests/RunCMake/CMakeLists.txt | 1 + .../GeneratorExpression/BadAND-result.txt | 1 + .../GeneratorExpression/BadAND-stderr.txt | 17 +++++++ .../RunCMake/GeneratorExpression/BadAND.cmake | 4 ++ .../GeneratorExpression/BadNOT-result.txt | 1 + .../GeneratorExpression/BadNOT-stderr.txt | 26 +++++++++++ .../RunCMake/GeneratorExpression/BadNOT.cmake | 5 ++ .../GeneratorExpression/BadOR-result.txt | 1 + .../GeneratorExpression/BadOR-stderr.txt | 17 +++++++ .../RunCMake/GeneratorExpression/BadOR.cmake | 4 ++ .../GeneratorExpression/CMakeLists.txt | 3 ++ .../GeneratorExpression/RunCMakeTest.cmake | 5 ++ 17 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 Tests/GeneratorExpression/CMakeLists.txt create mode 100644 Tests/GeneratorExpression/check.cmake create mode 100644 Tests/RunCMake/GeneratorExpression/BadAND-result.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadAND.cmake create mode 100644 Tests/RunCMake/GeneratorExpression/BadNOT-result.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadNOT.cmake create mode 100644 Tests/RunCMake/GeneratorExpression/BadOR-result.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadOR.cmake create mode 100644 Tests/RunCMake/GeneratorExpression/CMakeLists.txt create mode 100644 Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 535901397..5d6553d46 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/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 name\n" \ " $ = main file (.exe, .so.1.2, .a)\n" \ " $ = file used to link (.a, .lib, .so)\n" \ @@ -25,6 +27,12 @@ "versions can produce the directory and file name components:\n" \ " $/$\n" \ " $/$\n" \ - " $/$\n" + " $/$\n" \ + "Boolean expressions:\n" \ + " $ = '1' if all '?' are '1', else '0'\n" \ + " $ = '0' if all '?' are '0', else '1'\n" \ + " $ = '0' if '?' is '1', else '1'\n" \ + "where '?' is always either '0' or '1'.\n" \ + "" #endif diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index f88ab0b71..ed33c7e68 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/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, "$ + -Dtest_1=$<1:content> + -Dconfig=$ + -Dtest_and_0=$ + -Dtest_and_0_0=$ + -Dtest_and_0_1=$ + -Dtest_and_1=$ + -Dtest_and_1_0=$ + -Dtest_and_1_1=$ + -Dtest_not_0=$ + -Dtest_not_1=$ + -Dtest_or_0=$ + -Dtest_or_0_0=$ + -Dtest_or_0_1=$ + -Dtest_or_1=$ + -Dtest_or_1_0=$ + -Dtest_or_1_1=$ + -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake + COMMAND ${CMAKE_COMMAND} -E echo "check done" + VERBATIM + ) diff --git a/Tests/GeneratorExpression/check.cmake b/Tests/GeneratorExpression/check.cmake new file mode 100644 index 000000000..c40b847c9 --- /dev/null +++ b/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") diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index eca96f907..3ea54f169 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/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) diff --git a/Tests/RunCMake/GeneratorExpression/BadAND-result.txt b/Tests/RunCMake/GeneratorExpression/BadAND-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadAND-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt new file mode 100644 index 000000000..ced21d806 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt @@ -0,0 +1,17 @@ +CMake Error at BadAND.cmake:1 \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 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 requires one or more comma-separated '0' or '1' values. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/GeneratorExpression/BadAND.cmake b/Tests/RunCMake/GeneratorExpression/BadAND.cmake new file mode 100644 index 000000000..792654046 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadAND.cmake @@ -0,0 +1,4 @@ +add_custom_target(check ALL COMMAND check + $ + $ + VERBATIM) diff --git a/Tests/RunCMake/GeneratorExpression/BadNOT-result.txt b/Tests/RunCMake/GeneratorExpression/BadNOT-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadNOT-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt new file mode 100644 index 000000000..5721f5fe1 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt @@ -0,0 +1,26 @@ +CMake Error at BadNOT.cmake:1 \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 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 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 requires exactly one '0' or '1' value. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/GeneratorExpression/BadNOT.cmake b/Tests/RunCMake/GeneratorExpression/BadNOT.cmake new file mode 100644 index 000000000..452293b8d --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadNOT.cmake @@ -0,0 +1,5 @@ +add_custom_target(check ALL COMMAND check + $ + $ + $ + VERBATIM) diff --git a/Tests/RunCMake/GeneratorExpression/BadOR-result.txt b/Tests/RunCMake/GeneratorExpression/BadOR-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadOR-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt new file mode 100644 index 000000000..72ef2dd3c --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt @@ -0,0 +1,17 @@ +CMake Error at BadOR.cmake:1 \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 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 requires one or more comma-separated '0' or '1' values. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/GeneratorExpression/BadOR.cmake b/Tests/RunCMake/GeneratorExpression/BadOR.cmake new file mode 100644 index 000000000..f16f56a3c --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadOR.cmake @@ -0,0 +1,4 @@ +add_custom_target(check ALL COMMAND check + $ + $ + VERBATIM) diff --git a/Tests/RunCMake/GeneratorExpression/CMakeLists.txt b/Tests/RunCMake/GeneratorExpression/CMakeLists.txt new file mode 100644 index 000000000..e8db6b05b --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake new file mode 100644 index 000000000..95b16b35c --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +run_cmake(BadOR) +run_cmake(BadAND) +run_cmake(BadNOT) From 9d9f616792ee07a460af9f0a6dc036d81b852e66 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 13 Aug 2012 10:00:32 -0400 Subject: [PATCH 2/2] Add $ boolean query generator expression This expression evaluates to '1' or '0' to indicate whether the build configuration for which the expression is evaluated matches tha named configuration. In combination with the "$<0:...>" and "$<1:...>" expressions this allows per-configuration content to be generated. --- Source/cmDocumentGeneratorExpressions.h | 1 + Source/cmGeneratorExpression.cxx | 9 +++++++++ Source/cmGeneratorExpression.h | 1 + Tests/GeneratorExpression/CMakeLists.txt | 2 ++ Tests/GeneratorExpression/check.cmake | 2 ++ Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt | 1 + Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt | 8 ++++++++ Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake | 3 +++ Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake | 1 + 9 files changed, 28 insertions(+) create mode 100644 Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt create mode 100644 Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 5d6553d46..74c673a35 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -18,6 +18,7 @@ "Valid expressions are:\n" \ " $<0:...> = empty string (ignores \"...\")\n" \ " $<1:...> = content of \"...\"\n" \ + " $ = '1' if config is \"cfg\", else '0'\n" \ " $ = configuration name\n" \ " $ = main file (.exe, .so.1.2, .a)\n" \ " $ = file used to link (.a, .lib, .so)\n" \ diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index ed33c7e68..92bbf1d82 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -14,6 +14,8 @@ #include "cmMakefile.h" #include "cmTarget.h" +#include + //---------------------------------------------------------------------------- cmGeneratorExpression::cmGeneratorExpression( cmMakefile* mf, const char* config, @@ -25,6 +27,7 @@ cmGeneratorExpression::cmGeneratorExpression( "_FILE(|_NAME|_DIR):" // Filename component. "([A-Za-z0-9_.-]+)" // Target name. ">$"); + this->TestConfig.compile("^\\$$"); } //---------------------------------------------------------------------------- @@ -162,6 +165,12 @@ bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result) { return cmGeneratorExpressionBool(expr+5, result, "OR", "0", "1"); } + else if(this->TestConfig.find(expr)) + { + result = cmsysString_strcasecmp(this->TestConfig.match(1).c_str(), + this->Config? this->Config:"") == 0 + ? "1":"0"; + } else { result = "Expression syntax not recognized."; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 1a9d4c6e9..a023eb0c9 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -51,6 +51,7 @@ private: std::vector Data; std::stack Barriers; cmsys::RegularExpression TargetInfo; + cmsys::RegularExpression TestConfig; std::set Targets; bool Evaluate(); bool Evaluate(const char* expr, std::string& result); diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 8d7d87d9c..2b135dcb5 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -12,6 +12,8 @@ add_custom_target(check ALL -Dtest_and_1=$ -Dtest_and_1_0=$ -Dtest_and_1_1=$ + -Dtest_config_0=$x> + -Dtest_config_1=$> -Dtest_not_0=$ -Dtest_not_1=$ -Dtest_or_0=$ diff --git a/Tests/GeneratorExpression/check.cmake b/Tests/GeneratorExpression/check.cmake index c40b847c9..e243d8528 100644 --- a/Tests/GeneratorExpression/check.cmake +++ b/Tests/GeneratorExpression/check.cmake @@ -13,6 +13,8 @@ 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_config_0 "0") +check(test_config_1 "1") check(test_not_0 "1") check(test_not_1 "0") check(test_or_0 "0") diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt b/Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt new file mode 100644 index 000000000..7c86b250f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at BadCONFIG.cmake:1 \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Expression syntax not recognized. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake b/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake new file mode 100644 index 000000000..0c13f8944 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake @@ -0,0 +1,3 @@ +add_custom_target(check ALL COMMAND check + $ + VERBATIM) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 95b16b35c..ed18f25bb 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -1,5 +1,6 @@ include(RunCMake) +run_cmake(BadCONFIG) run_cmake(BadOR) run_cmake(BadAND) run_cmake(BadNOT)