Hi Brad,

attached is a patch with everything in one commit rebased to the most
current master commit.

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.  Please re-send your response directly to the list
> so it can be reviewed and archived publicly.
> 
> Also please "rebase -i" and squash everything down to one
> commit.  We don't need to review work-in-progress commits.
> 
> Depending on your Git comfort level, you could also make this
> two commits.  The first should do the refactoring and the
> second should add the new feature.
> 
> Thanks,
> -Brad
> 

From 5bdc65f04b85e682ccfd2285a3992d10deb0953b 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 expressions to the dependency graph.
 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 |  14 +++
 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 --
 8 files changed, 335 insertions(+), 137 deletions(-)
 create mode 100644 Source/cmRegexTools.cxx
 create mode 100644 Source/cmRegexTools.h

diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index ff18267..af6ddbb 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -107,6 +107,20 @@
 #
 #  * Mandatory : NO
 #  * Default   : TRUE
+#
+# .. variable:: GRAPHVIZ_NODE_FILTER
+#
+#  A list of regular replace expressions for chnging 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)" "\\3"
+#
+#  * Mandatory : NO
+#  * Default   : 
+#
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index a7adb51..df09dbb 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -317,6 +317,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 7f4c4c9..ffbb886 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 a7acd0e..c5ca07d 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;
 
@@ -78,6 +79,8 @@ protected:
   bool GenerateDependers;
 
   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;
-  };
 };
 
 
-- 
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