So here is the patch with tests and passing the git hooks.

Rgds
Richard

Am Dienstag, den 02.06.2015, 16:46 -0400 schrieb Brad King:
> On 06/02/2015 04:09 PM, Richard Ulrich wrote:
> > thanks for looking into it.
> > The revised version is on github and in the attachement.
> 
> Thanks.  Please "rebase -i" and squash everything down to one
> commit.  We don't need to review work-in-progress commits.
> 
> Thanks,
> -Brad
> 

From 763f5a70201e15aaf59a22afbb5d03c5dbdbf87d Mon Sep 17 00:00:00 2001
From: Richard Ulrich <ri...@paraeasy.ch>
Date: Wed, 20 May 2015 22:32:59 +0200
Subject: [PATCH] Adding regex replace rules for the node names in the
 dependency graph. #14163

This allows to strip the path from external library names.
It can also be used to group different files from the same library group
into a common node.
---
 Modules/CMakeGraphVizOptions.cmake                 |  16 ++
 Source/CMakeLists.txt                              |   2 +
 Source/cmGraphVizWriter.cxx                        |  60 ++++++-
 Source/cmGraphVizWriter.h                          |   3 +
 Source/cmRegexTools.cxx                            | 183 +++++++++++++++++++++
 Source/cmRegexTools.h                              |  65 ++++++++
 Source/cmStringCommand.cxx                         | 135 ++-------------
 Source/cmStringCommand.h                           |  10 --
 Tests/RunCMake/CMakeLists.txt                      |   1 +
 Tests/RunCMake/CommandLineGraphviz/CMakeLists.txt  |   3 +
 .../CMakeGraphVizOptions.cmake                     |   7 +
 .../graphviz_filter_even/CMakeLists.txt            |   3 +
 .../graphviz_filter_even/RunCMakeTest.cmake        |   4 +
 .../graphviz_filter_even/expected.dot              |  13 ++
 .../graphviz_filter_even-check.cmake               |  16 ++
 .../graphviz_filter_even-result.txt                |   1 +
 .../graphviz_filter_even-stderr.txt                |   0
 .../graphviz_filter_even.cmake                     |   0
 .../CMakeGraphVizOptions.cmake                     |   6 +
 .../graphviz_filter_uneven/CMakeLists.txt          |   3 +
 .../graphviz_filter_uneven/RunCMakeTest.cmake      |   4 +
 .../graphviz_filter_uneven-stderr.txt              |   1 +
 .../graphviz_filter_uneven.cmake                   |   3 +
 .../graphviz_no_filter/CMakeGraphVizOptions.cmake  |   3 +
 .../graphviz_no_filter/CMakeLists.txt              |   3 +
 .../graphviz_no_filter/RunCMakeTest.cmake          |   4 +
 .../graphviz_no_filter/expected.dot                |  15 ++
 .../graphviz_no_filter-check.cmake                 |  16 ++
 .../graphviz_no_filter-result.txt                  |   1 +
 .../graphviz_no_filter-stderr.txt                  |   0
 .../graphviz_no_filter/graphviz_no_filter.cmake    |   0
 Tests/RunCMake/CommandLineGraphviz/libs.cmake      |  24 +++
 Tests/RunCMake/CommandLineGraphviz/myapp.cpp       |   7 +
 Tests/RunCMake/CommandLineGraphviz/vendor_lib1.cpp |   6 +
 Tests/RunCMake/CommandLineGraphviz/vendor_lib2.cpp |   6 +
 35 files changed, 487 insertions(+), 137 deletions(-)
 create mode 100644 Source/cmRegexTools.cxx
 create mode 100644 Source/cmRegexTools.h
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeGraphVizOptions.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/expected.dot
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-check.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-result.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeGraphVizOptions.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeGraphVizOptions.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/expected.dot
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-check.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-result.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/libs.cmake
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/myapp.cpp
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/vendor_lib1.cpp
 create mode 100644 Tests/RunCMake/CommandLineGraphviz/vendor_lib2.cpp

diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index ff18267..0327526 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -107,6 +107,22 @@
 #
 #  * Mandatory : NO
 #  * Default   : TRUE
+#
+# .. variable:: GRAPHVIZ_NODE_FILTER
+#
+#  A list of regular replace expressions for changing the name of external
+#  library nodes.
+#  They are organized in pairs of regex and replace expression.
+#  This can be used to strip the path from external library names,
+#  or normalize the name of different files from the same library to one
+#  common name.
+#  The following is an example of an expression pair to strip the path and
+#  group by library name such as "boost" or "sigc" :
+#  "([A-Z]:)?/([^/]+/)*(lib)?([A-Za-z]+).*\\.(lib|so|dll|a)" "\\4"
+#
+#  * Mandatory : NO
+#  * Default   :
+#
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 6d012fd..af424ee 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -320,6 +320,8 @@ set(SRCS
   cmPropertyMap.h
   cmQtAutoGenerators.cxx
   cmQtAutoGenerators.h
+  cmRegexTools.h
+  cmRegexTools.cxx
   cmRST.cxx
   cmRST.h
   cmScriptGenerator.h
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index fa29b4f..0a34423 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -14,6 +14,7 @@
 #include "cmLocalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmGeneratedFileStream.h"
+#include "cmRegexTools.h"
 
 
 
@@ -147,6 +148,35 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
       }
     }
 
+  std::string nodeNameFilterRegexes;
+  __set_if_set(nodeNameFilterRegexes, "GRAPHVIZ_NODE_FILTER");
+
+  this->GraphNodeNameFilters.clear();
+  if (!nodeNameFilterRegexes.empty())
+    {
+    std::vector<std::string> nodeNameFilterRegExVector;
+    cmSystemTools::ExpandListArgument(nodeNameFilterRegexes,
+                                      nodeNameFilterRegExVector);
+    if(nodeNameFilterRegExVector.size() % 2 != 0)
+      {
+      std::cerr << "GRAPHVIZ_NODE_FILTER should contain pairs of regex and replace expressions"
+                << std::endl;
+      }
+    else
+      {
+      for(std::vector<std::string>::const_iterator
+          itvIt = nodeNameFilterRegExVector.begin();
+          itvIt != nodeNameFilterRegExVector.end();
+          ++ itvIt )
+        {
+        const std::string currentRegexString(*itvIt++);
+        const std::string currentReplaceString(*itvIt);
+
+        this->GraphNodeNameFilters.push_back(
+              std::make_pair(currentRegexString, currentReplaceString));
+        }
+      }
+    }
 }
 
 
@@ -331,10 +361,16 @@ void cmGraphVizWriter::WriteConnections(const std::string& targetName,
        llit != ll->end();
        ++ llit )
     {
-    const char* libName = llit->first.c_str();
+    std::string libName = llit->first.c_str();
     std::map<std::string, std::string>::const_iterator libNameIt =
                                           this->TargetNamesNodes.find(libName);
 
+    if(libNameIt == this->TargetNamesNodes.end())
+      {
+      libName = this->MangleNodeName(libName);
+      libNameIt = this->TargetNamesNodes.find(libName);
+      }
+
     // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used
     if(libNameIt == this->TargetNamesNodes.end())
       {
@@ -541,14 +577,16 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
           continue;
           }
 
+        const std::string libNameMangled = this->MangleNodeName(libName);
+
         std::map<std::string, const cmTarget*>::const_iterator tarIt =
-                                                this->TargetPtrs.find(libName);
+                                                this->TargetPtrs.find(libNameMangled);
         if ( tarIt == this->TargetPtrs.end() )
           {
           std::ostringstream ostr;
           ostr << this->GraphNodePrefix << cnt++;
-          this->TargetNamesNodes[libName] = ostr.str();
-          this->TargetPtrs[libName] = NULL;
+          this->TargetNamesNodes[libNameMangled] = ostr.str();
+          this->TargetPtrs[libNameMangled] = NULL;
           // str << "    \"" << ostr.c_str() << "\" [ label=\"" << libName
           // <<  "\" shape=\"ellipse\"];" << std::endl;
           }
@@ -580,6 +618,20 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
 }
 
 
+std::string cmGraphVizWriter::MangleNodeName(std::string name) const
+{
+  for(std::vector<RegularReplace>::const_iterator it = this->GraphNodeNameFilters.begin();
+      it != this->GraphNodeNameFilters.end();
+      ++it)
+    {
+        RegexReplacer replacer(it->first, it->second);
+        name = replacer(name);
+    }
+
+  return name;
+}
+
+
 bool cmGraphVizWriter::GenerateForTargetType(cmTarget::TargetType targetType)
                                                                           const
 {
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index 64de684..263db49 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -61,6 +61,7 @@ protected:
   void WriteFooter(cmGeneratedFileStream& str) const;
 
   bool IgnoreThisTarget(const std::string& name);
+  std::string MangleNodeName(std::string name) const;
 
   bool GenerateForTargetType(cmTarget::TargetType targetType) const;
 
@@ -70,6 +71,8 @@ protected:
   std::string GraphNodePrefix;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
+  typedef std::pair<std::string, std::string> RegularReplace;
+  std::vector<RegularReplace> GraphNodeNameFilters;
 
   const std::vector<cmLocalGenerator*>& LocalGenerators;
 
diff --git a/Source/cmRegexTools.cxx b/Source/cmRegexTools.cxx
new file mode 100644
index 0000000..d514131
--- /dev/null
+++ b/Source/cmRegexTools.cxx
@@ -0,0 +1,183 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmRegexTools.h"
+#include "cmMakefile.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <vector>
+
+//----------------------------------------------------------------------------
+namespace
+{
+  class RegexReplacement
+  {
+  public:
+    RegexReplacement(const char* s): number(-1), value(s) {}
+    RegexReplacement(const std::string& s): number(-1), value(s) {}
+    RegexReplacement(int n): number(n), value() {}
+    RegexReplacement() {}
+    int number;
+    std::string value;
+  };
+}
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+RegexReplacer::RegexReplacer(std::string const& regex, std::string const& replace)
+    : Regex(regex)
+    , Replace(replace)
+    , ErrorCallback(NULL)
+    , Makefile(NULL)
+{
+
+}
+//----------------------------------------------------------------------------
+void RegexReplacer::SetErrorReportingCallBack(BaseCallBack* cb)
+{
+    ErrorCallback = cb;
+}
+//----------------------------------------------------------------------------
+void RegexReplacer::SetMakefile(cmMakefile* mf)
+{
+    Makefile = mf;
+}
+//----------------------------------------------------------------------------
+void RegexReplacer::SetError(std::string const& err) const
+{
+    if(ErrorCallback != NULL)
+        (*ErrorCallback)(err);
+}
+//----------------------------------------------------------------------------
+std::string RegexReplacer::operator()(std::string const& input) const
+{
+  // Pull apart the replace expression to find the escaped [0-9] values.
+  std::vector<RegexReplacement> replacement;
+  std::string::size_type l = 0;
+  while(l < this->Replace.length())
+    {
+    std::string::size_type r = this->Replace.find("\\", l);
+    if(r == std::string::npos)
+      {
+      r = this->Replace.length();
+      replacement.push_back(this->Replace.substr(l, r-l));
+      }
+    else
+      {
+      if(r-l > 0)
+        {
+        replacement.push_back(this->Replace.substr(l, r-l));
+        }
+      if(r == (this->Replace.length()-1))
+        {
+        this->SetError("sub-command REGEX, mode REPLACE: "
+                       "replace-expression ends in a backslash.");
+        return input;
+        }
+      if((this->Replace[r+1] >= '0') && (this->Replace[r+1] <= '9'))
+        {
+        replacement.push_back(this->Replace[r+1]-'0');
+        }
+      else if(this->Replace[r+1] == 'n')
+        {
+        replacement.push_back("\n");
+        }
+      else if(this->Replace[r+1] == '\\')
+        {
+        replacement.push_back("\\");
+        }
+      else
+        {
+        std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
+        e += this->Replace.substr(r, 2);
+        e += "\" in replace-expression.";
+        this->SetError(e);
+        return input;
+        }
+      r += 2;
+      }
+    l = r;
+    }
+
+  // Compile the regular expression.
+  cmsys::RegularExpression re;
+  if(!re.compile(this->Regex.c_str()))
+    {
+    std::string e =
+      "sub-command REGEX, mode REPLACE failed to compile regex \""+
+      this->Regex+"\".";
+    this->SetError(e);
+    return input;
+    }
+
+  // Scan through the input for all matches.
+  std::string output;
+  std::string::size_type base = 0;
+  while(re.find(input.c_str()+base))
+    {
+    if(this->Makefile != NULL)
+        this->Makefile->StoreMatches(re);
+    std::string::size_type l2 = re.start();
+    std::string::size_type r = re.end();
+
+    // Concatenate the part of the input that was not matched.
+    output += input.substr(base, l2);
+
+    // Make sure the match had some text.
+    if(r-l2 == 0)
+      {
+      std::string e = "sub-command REGEX, mode REPLACE regex \""+
+        this->Regex+"\" matched an empty string.";
+      this->SetError(e);
+      return input;
+      }
+
+    // Concatenate the replacement for the match.
+    for(unsigned int i=0; i < replacement.size(); ++i)
+      {
+      if(replacement[i].number < 0)
+        {
+        // This is just a plain-text part of the replacement.
+        output += replacement[i].value;
+        }
+      else
+        {
+        // Replace with part of the match.
+        int n = replacement[i].number;
+        std::string::size_type start = re.start(n);
+        std::string::size_type end = re.end(n);
+        std::string::size_type len = input.length()-base;
+        if((start != std::string::npos) && (end != std::string::npos) &&
+           (start <= len) && (end <= len))
+          {
+          output += input.substr(base+start, end-start);
+          }
+        else
+          {
+          std::string e =
+            "sub-command REGEX, mode REPLACE: replace expression \""+
+            this->Replace+"\" contains an out-of-range escape for regex \""+
+            this->Regex+"\".";
+          this->SetError(e);
+          return input;
+          }
+        }
+      }
+
+    // Move past the match.
+    base += r;
+    }
+
+  // Concatenate the text after the last match.
+  output += input.substr(base, input.length()-base);
+
+  return output;
+}
diff --git a/Source/cmRegexTools.h b/Source/cmRegexTools.h
new file mode 100644
index 0000000..49cd72e
--- /dev/null
+++ b/Source/cmRegexTools.h
@@ -0,0 +1,65 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmRegexTools_h
+#define cmRegexTools_h
+
+#include <string>
+
+class cmMakefile;
+
+class BaseCallBack
+{
+public:
+  virtual void operator()(const std::string&) = 0;
+  virtual ~BaseCallBack() {}
+};
+
+template<class ClassT>
+class RegexReplacerCallback : public BaseCallBack
+{
+public:
+  typedef void(ClassT::* FuncT)(const std::string&);
+
+  RegexReplacerCallback(ClassT* c, FuncT fn)
+    : _fn(fn), _c(c) {}
+
+  void operator()(const std::string& err)
+  {
+    return (_c->*_fn)(err);
+  }
+
+private:
+  FuncT _fn;
+  ClassT* _c;
+};
+
+class RegexReplacer
+{
+public:
+    RegexReplacer(std::string const& regex, std::string const& replace);
+
+    void SetErrorReportingCallBack(BaseCallBack* cb);
+    void SetMakefile(cmMakefile* mf);
+
+    std::string operator()(std::string const& input) const;
+
+private:
+    void SetError(std::string const& err) const;
+
+    std::string     Regex;
+    std::string     Replace;
+    BaseCallBack*   ErrorCallback;
+    cmMakefile*     Makefile;
+};
+
+
+#endif
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index edc6afc..48cc38e 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -11,6 +11,7 @@
 ============================================================================*/
 #include "cmStringCommand.h"
 #include "cmCryptoHash.h"
+#include "cmRegexTools.h"
 
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/SystemTools.hxx>
@@ -396,132 +397,20 @@ bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
 {
   //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
   // <output variable> <input> [<input>...])\n"
-  std::string regex = args[2];
-  std::string replace = args[3];
-  std::string outvar = args[4];
-
-  // Pull apart the replace expression to find the escaped [0-9] values.
-  std::vector<RegexReplacement> replacement;
-  std::string::size_type l = 0;
-  while(l < replace.length())
-    {
-    std::string::size_type r = replace.find("\\", l);
-    if(r == std::string::npos)
-      {
-      r = replace.length();
-      replacement.push_back(replace.substr(l, r-l));
-      }
-    else
-      {
-      if(r-l > 0)
-        {
-        replacement.push_back(replace.substr(l, r-l));
-        }
-      if(r == (replace.length()-1))
-        {
-        this->SetError("sub-command REGEX, mode REPLACE: "
-                       "replace-expression ends in a backslash.");
-        return false;
-        }
-      if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
-        {
-        replacement.push_back(replace[r+1]-'0');
-        }
-      else if(replace[r+1] == 'n')
-        {
-        replacement.push_back("\n");
-        }
-      else if(replace[r+1] == '\\')
-        {
-        replacement.push_back("\\");
-        }
-      else
-        {
-        std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
-        e += replace.substr(r, 2);
-        e += "\" in replace-expression.";
-        this->SetError(e);
-        return false;
-        }
-      r += 2;
-      }
-    l = r;
-    }
-
-  this->Makefile->ClearMatches();
-  // Compile the regular expression.
-  cmsys::RegularExpression re;
-  if(!re.compile(regex.c_str()))
-    {
-    std::string e =
-      "sub-command REGEX, mode REPLACE failed to compile regex \""+
-      regex+"\".";
-    this->SetError(e);
-    return false;
-    }
-
+  const std::string regex = args[2];
+  const std::string replace = args[3];
+  const std::string outvar = args[4];
   // Concatenate all the last arguments together.
-  std::string input = cmJoin(cmRange(args).advance(5), std::string());
-
-  // Scan through the input for all matches.
-  std::string output;
-  std::string::size_type base = 0;
-  while(re.find(input.c_str()+base))
-    {
-    this->Makefile->StoreMatches(re);
-    std::string::size_type l2 = re.start();
-    std::string::size_type r = re.end();
-
-    // Concatenate the part of the input that was not matched.
-    output += input.substr(base, l2);
-
-    // Make sure the match had some text.
-    if(r-l2 == 0)
-      {
-      std::string e = "sub-command REGEX, mode REPLACE regex \""+
-        regex+"\" matched an empty string.";
-      this->SetError(e);
-      return false;
-      }
-
-    // Concatenate the replacement for the match.
-    for(unsigned int i=0; i < replacement.size(); ++i)
-      {
-      if(replacement[i].number < 0)
-        {
-        // This is just a plain-text part of the replacement.
-        output += replacement[i].value;
-        }
-      else
-        {
-        // Replace with part of the match.
-        int n = replacement[i].number;
-        std::string::size_type start = re.start(n);
-        std::string::size_type end = re.end(n);
-        std::string::size_type len = input.length()-base;
-        if((start != std::string::npos) && (end != std::string::npos) &&
-           (start <= len) && (end <= len))
-          {
-          output += input.substr(base+start, end-start);
-          }
-        else
-          {
-          std::string e =
-            "sub-command REGEX, mode REPLACE: replace expression \""+
-            replace+"\" contains an out-of-range escape for regex \""+
-            regex+"\".";
-          this->SetError(e);
-          return false;
-          }
-        }
-      }
+  const std::string input = cmJoin(cmRange(args).advance(5), std::string());
 
-    // Move past the match.
-    base += r;
-    }
+  this->Makefile->ClearMatches();
+  // Call the implementation that was factored out
+  RegexReplacer replacer(regex, replace);
+  RegexReplacerCallback<cmCommand> callback(this, &cmCommand::SetError);
+  replacer.SetErrorReportingCallBack(&callback);
+  replacer.SetMakefile(this->Makefile);
 
-  // Concatenate the text after the last match.
-  output += input.substr(base, input.length()-base);
+  const std::string output = replacer(input);
 
   // Store the output in the provided variable.
   this->Makefile->AddDefinition(outvar, output.c_str());
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index 9c75095..de4f93f 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -76,16 +76,6 @@ protected:
   bool HandleGenexStripCommand(std::vector<std::string> const& args);
   bool HandleUuidCommand(std::vector<std::string> const& args);
 
-  class RegexReplacement
-  {
-  public:
-    RegexReplacement(const char* s): number(-1), value(s) {}
-    RegexReplacement(const std::string& s): number(-1), value(s) {}
-    RegexReplacement(int n): number(n), value() {}
-    RegexReplacement() {}
-    int number;
-    std::string value;
-  };
 };
 
 
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 592b5e4..2415ef5 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -189,6 +189,7 @@ add_RunCMake_test(target_compile_features)
 add_RunCMake_test(CheckModules)
 add_RunCMake_test(CommandLine)
 add_RunCMake_test(CommandLineTar)
+add_subdirectory(CommandLineGraphviz)
 
 add_RunCMake_test(install)
 add_RunCMake_test(CPackInstallProperties)
diff --git a/Tests/RunCMake/CommandLineGraphviz/CMakeLists.txt b/Tests/RunCMake/CommandLineGraphviz/CMakeLists.txt
new file mode 100644
index 0000000..6cb6eb2
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_RunCMake_test(graphviz_no_filter)
+add_RunCMake_test(graphviz_filter_even)
+add_RunCMake_test(graphviz_filter_uneven)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeGraphVizOptions.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeGraphVizOptions.cmake
new file mode 100644
index 0000000..9f51daf
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeGraphVizOptions.cmake
@@ -0,0 +1,7 @@
+set(GRAPHVIZ_EXTERNAL_LIBS ON)
+set(GRAPHVIZ_GENERATE_PER_TARGET FALSE)
+set(GRAPHVIZ_GENERATE_DEPENDERS FALSE)
+set(GRAPHVIZ_NODE_FILTER
+    "([A-Z]:)?/?([^/]+/)*(lib)?([A-Za-z]+).*\\.(lib|so|dll|a)" "\\4"
+    "([a-z]+)_.*" "\\1"
+)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeLists.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeLists.txt
new file mode 100644
index 0000000..91dfecf
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(graphviz_filter_even)
+include(../libs.cmake)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/RunCMakeTest.cmake
new file mode 100644
index 0000000..44268c9
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/../../RunCMake.cmake)
+
+set(RunCMake_TEST_OPTIONS --graphviz=graphviz_filter_even.dot)
+run_cmake(graphviz_filter_even)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/expected.dot b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/expected.dot
new file mode 100644
index 0000000..0e932c9
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/expected.dot
@@ -0,0 +1,13 @@
+digraph GG {
+node [
+  fontsize = "12"
+];
+    "node5" [ label="myappExt" shape="house"];
+    "node7" [ label="ext" shape="ellipse"];
+    "node5" -> "node7" // myappExt -> ext
+    "node0" [ label="myappInt" shape="house"];
+    "node3" [ label="vendor_lib1" shape="diamond"];
+    "node0" -> "node3" // myappInt -> vendor_lib1
+    "node4" [ label="vendor_lib2" shape="diamond"];
+    "node0" -> "node4" // myappInt -> vendor_lib2
+}
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-check.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-check.cmake
new file mode 100644
index 0000000..3c23bdc
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-check.cmake
@@ -0,0 +1,16 @@
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/graphviz_filter_even.dot)
+    set(RunCMake_TEST_FAILED "graphviz file not created!")
+else()
+    execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
+      ${CMAKE_CURRENT_LIST_DIR}/expected.dot
+      ${RunCMake_TEST_BINARY_DIR}/graphviz_filter_even.dot
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE stdout
+      ERROR_VARIABLE stderr
+    )
+    if(result STREQUAL 0)
+        # good
+    else()
+        set(RunCMake_TEST_FAILED "graphviz file not equal to expected!")
+    endif()
+endif()
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-result.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-stderr.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even-stderr.txt
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_even/graphviz_filter_even.cmake
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeGraphVizOptions.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeGraphVizOptions.cmake
new file mode 100644
index 0000000..ffb3d63
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeGraphVizOptions.cmake
@@ -0,0 +1,6 @@
+set(GRAPHVIZ_EXTERNAL_LIBS On)
+SET(GRAPHVIZ_GENERATE_PER_TARGET FALSE)
+SET(GRAPHVIZ_GENERATE_DEPENDERS FALSE)
+set(GRAPHVIZ_NODE_FILTER
+    "(lib)?([A-Za-z]+).*"
+)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeLists.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeLists.txt
new file mode 100644
index 0000000..38e8f5e
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(graphviz_filter_uneven)
+include(../libs.cmake)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/RunCMakeTest.cmake
new file mode 100644
index 0000000..4a8f365
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/../../RunCMake.cmake)
+
+set(RunCMake_TEST_OPTIONS --graphviz=filter_uneven.dot)
+run_cmake(graphviz_filter_uneven)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven-stderr.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven-stderr.txt
new file mode 100644
index 0000000..a3fef16
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven-stderr.txt
@@ -0,0 +1 @@
+GRAPHVIZ_NODE_FILTER should contain pairs of regex and replace expressions
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven.cmake
new file mode 100644
index 0000000..4f8cd6a
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_filter_uneven/graphviz_filter_uneven.cmake
@@ -0,0 +1,3 @@
+set(GRAPHVIZ_NODE_FILTER
+    ".*\\.(lib|so|dll|a)"
+)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeGraphVizOptions.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeGraphVizOptions.cmake
new file mode 100644
index 0000000..82398ac
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeGraphVizOptions.cmake
@@ -0,0 +1,3 @@
+set(GRAPHVIZ_EXTERNAL_LIBS On)
+set(GRAPHVIZ_GENERATE_PER_TARGET FALSE)
+set(GRAPHVIZ_GENERATE_DEPENDERS FALSE)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeLists.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeLists.txt
new file mode 100644
index 0000000..0e904dc
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(graphviz_no_filter)
+include(../libs.cmake)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/RunCMakeTest.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/RunCMakeTest.cmake
new file mode 100644
index 0000000..4b93460
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/../../RunCMake.cmake)
+
+set(RunCMake_TEST_OPTIONS --graphviz=graphviz_no_filter.dot)
+run_cmake(graphviz_no_filter)
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/expected.dot b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/expected.dot
new file mode 100644
index 0000000..ed53abf
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/expected.dot
@@ -0,0 +1,15 @@
+digraph GG {
+node [
+  fontsize = "12"
+];
+    "node5" [ label="myappExt" shape="house"];
+    "node6" [ label="ext_libA" shape="ellipse"];
+    "node5" -> "node6" // myappExt -> ext_libA
+    "node7" [ label="ext_libB" shape="ellipse"];
+    "node5" -> "node7" // myappExt -> ext_libB
+    "node0" [ label="myappInt" shape="house"];
+    "node3" [ label="vendor_lib1" shape="diamond"];
+    "node0" -> "node3" // myappInt -> vendor_lib1
+    "node4" [ label="vendor_lib2" shape="diamond"];
+    "node0" -> "node4" // myappInt -> vendor_lib2
+}
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-check.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-check.cmake
new file mode 100644
index 0000000..cc23d2f
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-check.cmake
@@ -0,0 +1,16 @@
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/graphviz_no_filter.dot)
+  set(RunCMake_TEST_FAILED "graphviz file not created!")
+else()
+    execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
+      ${CMAKE_CURRENT_LIST_DIR}/expected.dot
+      ${RunCMake_TEST_BINARY_DIR}/graphviz_no_filter.dot
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE stdout
+      ERROR_VARIABLE stderr
+    )
+    if(result STREQUAL 0)
+        # good
+    else()
+        set(RunCMake_TEST_FAILED "graphviz file not equal to expected!")
+    endif()
+endif()
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-result.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-stderr.txt b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter-stderr.txt
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter.cmake b/Tests/RunCMake/CommandLineGraphviz/graphviz_no_filter/graphviz_no_filter.cmake
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLineGraphviz/libs.cmake b/Tests/RunCMake/CommandLineGraphviz/libs.cmake
new file mode 100644
index 0000000..9aa0b94
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/libs.cmake
@@ -0,0 +1,24 @@
+
+add_library(vendor_lib1 STATIC
+    ${CMAKE_CURRENT_LIST_DIR}/vendor_lib1.cpp
+)
+
+add_library(vendor_lib2 STATIC
+    ${CMAKE_CURRENT_LIST_DIR}/vendor_lib2.cpp
+)
+
+add_executable(myappInt
+    ${CMAKE_CURRENT_LIST_DIR}/myapp.cpp
+)
+target_link_libraries(myappInt
+    vendor_lib1
+    vendor_lib2
+)
+
+add_executable(myappExt
+    ${CMAKE_CURRENT_LIST_DIR}/myapp.cpp
+)
+target_link_libraries(myappExt
+    ext_libA
+    ext_libB
+)
diff --git a/Tests/RunCMake/CommandLineGraphviz/myapp.cpp b/Tests/RunCMake/CommandLineGraphviz/myapp.cpp
new file mode 100644
index 0000000..e11cf00
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/myapp.cpp
@@ -0,0 +1,7 @@
+#include <iostream>
+
+int main(void)
+{
+	std::cout << "hello world" << std::endl;
+	return 0;
+}
diff --git a/Tests/RunCMake/CommandLineGraphviz/vendor_lib1.cpp b/Tests/RunCMake/CommandLineGraphviz/vendor_lib1.cpp
new file mode 100644
index 0000000..7aa3fff
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/vendor_lib1.cpp
@@ -0,0 +1,6 @@
+#include <iostream>
+
+void somefunc1(void)
+{
+	std::cout << "somefunc1()" << std::endl;
+}
diff --git a/Tests/RunCMake/CommandLineGraphviz/vendor_lib2.cpp b/Tests/RunCMake/CommandLineGraphviz/vendor_lib2.cpp
new file mode 100644
index 0000000..4853a8f
--- /dev/null
+++ b/Tests/RunCMake/CommandLineGraphviz/vendor_lib2.cpp
@@ -0,0 +1,6 @@
+#include <iostream>
+
+void somefunc2(void)
+{
+	std::cout << "somefunc2()" << std::endl;
+}
-- 
2.1.4

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to