diff options
13 files changed, 100 insertions, 0 deletions
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 8f4c4fc..e3a96bd 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -293,6 +293,8 @@ String Transformations Joins the list with the content of ``string``. ``$<REMOVE_DUPLICATES:list>`` Removes duplicated items in the given ``list``. +``$<FILTER:list,INCLUDE|EXCLUDE,regex>`` + Includes or removes items from ``list`` that match the regular expression ``regex``. ``$<LOWER_CASE:string>`` Content of ``string`` converted to lower case. ``$<UPPER_CASE:string>`` diff --git a/Help/release/dev/genex_filter.rst b/Help/release/dev/genex_filter.rst new file mode 100644 index 0000000..ad23134 --- /dev/null +++ b/Help/release/dev/genex_filter.rst @@ -0,0 +1,6 @@ +genex_filter +------------ + +* A new ``$<FILTER:list,INCLUDE|EXCLUDE,regex>`` + :manual:`generator expression <cmake-generator-expressions(7)>` + has been added. diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index cef36fc..d8e1c42 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -28,6 +28,7 @@ #include <algorithm> #include <assert.h> #include <errno.h> +#include <iterator> #include <map> #include <memory> // IWYU pragma: keep #include <set> @@ -327,6 +328,51 @@ static const struct InListNode : public cmGeneratorExpressionNode } } inListNode; +static const struct FilterNode : public cmGeneratorExpressionNode +{ + FilterNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 3; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 3) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> expression requires three parameters"); + return {}; + } + + if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") { + reportError( + context, content->GetOriginalExpression(), + "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE"); + return {}; + } + + const bool exclude = parameters[1] == "EXCLUDE"; + + cmsys::RegularExpression re; + if (!re.compile(parameters[2])) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> failed to compile regex"); + return {}; + } + + std::vector<std::string> values, result; + cmSystemTools::ExpandListArgument(parameters.front(), values, true); + + std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result), + [&re, exclude](std::string const& input) { + return exclude ^ re.find(input); + }); + return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";"); + } +} filterNode; + static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode { RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default) @@ -2331,6 +2377,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "STREQUAL", &strEqualNode }, { "EQUAL", &equalNode }, { "IN_LIST", &inListNode }, + { "FILTER", &filterNode }, { "REMOVE_DUPLICATES", &removeDuplicatesNode }, { "LOWER_CASE", &lowerCaseNode }, { "UPPER_CASE", &upperCaseNode }, diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake new file mode 100644 index 0000000..605ae4d --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake @@ -0,0 +1,6 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content) + +set(expected "DO_NOT_FILTER_THIS;thisisanitem") +if(NOT content STREQUAL expected) + set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]") +endif() diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake new file mode 100644 index 0000000..b879be2 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake @@ -0,0 +1,4 @@ +cmake_policy(VERSION 3.11) + +set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING) +file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},EXCLUDE,^FILTER_THIS_.+>") diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake new file mode 100644 index 0000000..9d48d98 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake @@ -0,0 +1,6 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content) + +set(expected "FILTER_THIS_BIT;FILTER_THIS_THING") +if(NOT content STREQUAL expected) + set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]") +endif() diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake new file mode 100644 index 0000000..5e0260a --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake @@ -0,0 +1,4 @@ +cmake_policy(VERSION 3.11) + +set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING) +file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:${mylist},INCLUDE,^FILTER_THIS_.+>") diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt new file mode 100644 index 0000000..dd10925 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at FILTER-InvalidOperator.cmake:3 \(file\): + Error evaluating generator expression: + + \$<FILTER:,RM,> + + \$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake new file mode 100644 index 0000000..26f3917 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake @@ -0,0 +1,3 @@ +cmake_policy(VERSION 3.11) + +file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,RM,>") diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake new file mode 100644 index 0000000..2844484 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake @@ -0,0 +1,6 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/FILTER-generated.txt" content) + +set(expected "") +if(NOT content STREQUAL expected) + set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]") +endif() diff --git a/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake new file mode 100644 index 0000000..e0fc671 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake @@ -0,0 +1,3 @@ +cmake_policy(VERSION 3.11) + +file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,INCLUDE,>") diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 68bffa7..4202064 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -62,6 +62,10 @@ run_cmake(REMOVE_DUPLICATES-1) run_cmake(REMOVE_DUPLICATES-2) run_cmake(REMOVE_DUPLICATES-3) run_cmake(REMOVE_DUPLICATES-4) +run_cmake(FILTER-empty) +run_cmake(FILTER-InvalidOperator) +run_cmake(FILTER-Exclude) +run_cmake(FILTER-Include) run_cmake(ImportedTarget-TARGET_BUNDLE_DIR) run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR) |