瀏覽代碼

Genex: Add $<FILTER:list,INCLUDE|EXCLUDE,regex>

Sebastian Lipponer 6 年之前
父節點
當前提交
698f51abac

+ 2 - 0
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>``

+ 6 - 0
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.

+ 47 - 0
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 },

+ 6 - 0
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()

+ 4 - 0
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_.+>")

+ 6 - 0
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()

+ 4 - 0
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_.+>")

+ 1 - 0
Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt

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

+ 8 - 0
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\)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake

@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,RM,>")

+ 6 - 0
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()

+ 3 - 0
Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake

@@ -0,0 +1,3 @@
+cmake_policy(VERSION 3.11)
+
+file(GENERATE OUTPUT "FILTER-generated.txt" CONTENT "$<FILTER:,INCLUDE,>")

+ 4 - 0
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)