These two hunks look like error checks added to the existing logic.
Please split these out into preceding commits with their own messages
explaining the new errors.  Please also include a

  Help/release/dev/automoc-diagnostics.rst

file with a release note explaining the new diagnostics.


Wow, this turned into a git learning session for me.
Git is as awesome as it is hard.

I've split the patch into three as suggested.

-Sebastian

>From 22f5af6aef69adc784287fb20357a98558966443 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 18:30:30 +0200
Subject: [PATCH] AUTOMOC: moc file name collision check added.

AUTOMOC searches all source *.cpp files for moc include patterns of the
form #include <moc_NAME.cpp>.  If found the moc_NAME.cpp file will be
generated from the source's header as
${CMAKE_CURRENT_BINARY_DIR}/moc_NAME.cpp.
This allows the compiler to find the moc_NAME.cpp file regardless of the
location of NAME.cpp.
Now two NAME.cpp files in different directories (e.g. a/NAME.cpp, b/NAME.cpp)
would generate the same moc_NAME.cpp file effectively overwriting the other's
one.
A check to identify such name collisions was added.
---
 Help/release/dev/automoc-diagnostics.rst | 13 ++++++++++++
 Source/cmQtAutoGenerators.cxx            | 35 ++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 Help/release/dev/automoc-diagnostics.rst

diff --git a/Help/release/dev/automoc-diagnostics.rst b/Help/release/dev/automoc-diagnostics.rst
new file mode 100644
index 0000000..39a4872
--- /dev/null
+++ b/Help/release/dev/automoc-diagnostics.rst
@@ -0,0 +1,13 @@
+automoc-diagnostics
+--------------
+
+* AUTOMOC searches all source *.cpp files for moc include patterns of the
+  form #include <moc_NAME.cpp>.  If found the moc_NAME.cpp file will be
+  generated from the source's header as
+  ${CMAKE_CURRENT_BINARY_DIR}/moc_NAME.cpp.
+  This allows the compiler to find the moc_NAME.cpp file regardless of the
+  location of NAME.cpp.
+  Now two NAME.cpp files in different directories (e.g. a/NAME.cpp, b/NAME.cpp)
+  would generate the same moc_NAME.cpp file effectively overwriting the other's
+  one.
+  A check to identify such name collisions was added.
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index ebe08b0..b2da918 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -99,6 +99,38 @@ static std::string extractSubDir(const std::string& absPath,
   return subDir;
 }
 
+/**
+ * Checks if the same value appears twice in the maps
+ */
+static void nameCollisionTest(
+                const std::map<std::string, std::string>& includedMocs,
+                const std::map<std::string, std::string>& notIncludedMocs )
+{
+  // Create new merged map
+  std::map<std::string, std::string> mocMap ( includedMocs );
+  mocMap.insert ( notIncludedMocs.begin(), notIncludedMocs.end() );
+
+  // Look for value matches in merged map
+  typedef std::map<std::string, std::string>::const_iterator Iter;
+  for ( Iter ait = mocMap.begin(); ait != mocMap.end(); ++ait )
+    {
+    for ( Iter bit = ++(Iter ( ait )); bit != mocMap.end(); ++bit )
+      {
+      if ( ait->second == bit->second )
+        {
+        std::cerr << "AUTOGEN: error: "
+                     "The same moc file will be generated "
+                     "from different sources." << std::endl
+                  << "Rename one of the source files "
+                     "to avoid this error." << std::endl
+                  << ait->first << " -> " << ait->second << std::endl
+                  << bit->first << " -> " << bit->second << std::endl;
+        ::exit(EXIT_FAILURE);
+        }
+      }
+    }
+}
+
 cmQtAutoGenerators::cmQtAutoGenerators()
 :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
 ,ColorOutput(true)
@@ -589,6 +621,9 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
   std::map<std::string, std::string> notIncludedMocs;
   this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
 
+  // Lock for moc file name collisions
+  nameCollisionTest ( includedMocs, notIncludedMocs );
+
   // run moc on all the moc's that are #included in source files
   for(std::map<std::string, std::string>::const_iterator
                                                      it = includedMocs.begin();
-- 
2.8.0.rc3

>From 9959dd5c8146a3abde6a463ebc3b7fcf14e64f9c Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 20:01:04 +0200
Subject: [PATCH] AUTOMOC check for invalid moc file includes starting with ../
 added.

Moc file includes starting with .. would result in moc files beeing
generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
---
 Help/release/dev/automoc-diagnostics.rst |  4 ++++
 Source/cmQtAutoGenerators.cxx            | 15 +++++++++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Help/release/dev/automoc-diagnostics.rst b/Help/release/dev/automoc-diagnostics.rst
index 39a4872..f0fbecb 100644
--- a/Help/release/dev/automoc-diagnostics.rst
+++ b/Help/release/dev/automoc-diagnostics.rst
@@ -11,3 +11,7 @@ automoc-diagnostics
   would generate the same moc_NAME.cpp file effectively overwriting the other's
   one.
   A check to identify such name collisions was added.
+
+* AUTOMOC check for invalid moc file includes starting with ../ added.
+  Moc file includes starting with .. would result in moc files getting
+  generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index b2da918..61b3bca 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -93,8 +93,19 @@ static std::string extractSubDir(const std::string& absPath,
   std::string subDir;
   if (currentMoc.find_first_of('/') != std::string::npos)
     {
-    subDir = absPath
-                  + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
+    std::string fileNamePath = cmsys::SystemTools::GetFilenamePath(currentMoc);
+    subDir = absPath + fileNamePath + '/';
+
+    // Moc file includes starting with .. would result in moc files getting 
+    // generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
+    if ( cmsys::SystemTools::StringStartsWith ( fileNamePath, ".." ) )
+      {
+      std::cerr << "AUTOGEN: error: moc include \"" << currentMoc
+                << "\" starting with parent directory reference "
+                   "\"..\" can't be processed."
+                << std::endl;
+      ::exit(EXIT_FAILURE);
+      }
     }
   return subDir;
 }
-- 
2.8.0.rc3

>From f4513cbbe1b02e78c14b974b85cc8cb84edffc78 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 20:18:33 +0200
Subject: [PATCH] AUTOMOC generates non included mocs in dedicated directory.

AUTOMOC generates moc files that are not included by source .cxx files
in subdirectories of ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_automoc.dir/.
---
 Source/cmQtAutoGenerators.cxx | 71 ++++++++++++++++++++++++++++++++++++++++---
 Source/cmQtAutoGenerators.h   |  4 +++
 2 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index 61b3bca..bc39e33 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -457,6 +457,10 @@ void cmQtAutoGenerators::Init()
   this->OutMocCppFilename += this->TargetName;
   this->OutMocCppFilename += ".cpp";
 
+  this->OutMocDir += this->TargetName;
+  this->OutMocDir += ".dir";
+  this->OutMocDir += '/';
+
   std::vector<std::string> cdefList;
   cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
   for(std::vector<std::string>::const_iterator it = cdefList.begin();
@@ -1150,15 +1154,15 @@ void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
         std::cout << "AUTOGEN: Checking " << headerName << std::endl;
         }
 
-      const std::string basename = cmsys::SystemTools::
-                                   GetFilenameWithoutLastExtension(headerName);
-
-      const std::string currentMoc = "moc_" + basename + ".cpp";
       std::string macroName;
       if (requiresMocing(contents, macroName))
         {
         //std::cout << "header contains Q_OBJECT macro";
-        notIncludedMocs[headerName] = currentMoc;
+        const std::string basename = cmsys::SystemTools::
+                                  GetFilenameWithoutLastExtension(headerName);
+        const std::string currentMoc = "moc_" + basename + ".cpp";
+        notIncludedMocs[headerName] = MocPathIncluderRel(headerName,
+                                                         currentMoc);
         }
       }
     this->ParseForUic(headerName, contents, includedUis);
@@ -1393,6 +1397,63 @@ bool cmQtAutoGenerators::GenerateQrc()
   return true;
 }
 
+/**
+ * Checks if headerName file is below ProjectSource or ProjectBinary
+ * and calculates the relative path plus mocFile
+ */
+std::string cmQtAutoGenerators::MocPathIncluderRel(const std::string & headerName,
+                                                   const std::string & mocFile)
+{
+  std::string parentDirectory;
+
+  // Use real paths for parent directory detection
+  ::std::string headerNameReal = cmsys::SystemTools::GetRealPath( headerName );
+    {
+    bool match ( false );
+    ::std::string testDirs[4];
+    testDirs[0] = cmsys::SystemTools::GetRealPath( this->Srcdir );
+    testDirs[1] = cmsys::SystemTools::GetRealPath( this->Builddir );
+    testDirs[2] = cmsys::SystemTools::GetRealPath( this->ProjectSourceDir );
+    testDirs[3] = cmsys::SystemTools::GetRealPath( this->ProjectBinaryDir );
+
+    // Test if the header is child to any of the known directories
+    for ( int ii=0; ii != sizeof ( testDirs ) / sizeof ( ::std::string ); ++ii )
+      {
+      ::std::string & testDir ( testDirs[ii] );
+      if (cmsys::SystemTools::IsSubDirectory(headerNameReal,
+                                             testDir) )
+        {
+        match = true;
+        parentDirectory = testDir;
+        break;
+        }
+      }
+    // Use root as fallback parent directory
+    if ( !match )
+      {
+      cmsys::SystemTools::SplitPathRootComponent(headerNameReal,
+                                                 &parentDirectory);
+      }
+    }
+
+  std::string path = this->OutMocDir;
+  // Append relative path to parent directory
+    {
+    ::std::string pathRel = cmsys::SystemTools::RelativePath(
+      parentDirectory, cmsys::SystemTools::GetParentDirectory(headerNameReal));
+    if (!pathRel.empty())
+      {
+      pathRel += '/';
+      }
+    path += pathRel;
+    }
+  // Append moc file
+  path += mocFile;
+  // Sanitize path
+  cmSystemTools::ReplaceString(path, "..", "__");
+  return path;
+}
+
 std::string cmQtAutoGenerators::Join(const std::vector<std::string>& lst,
                               char separator)
 {
diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h
index ab7b6ed..9238264 100644
--- a/Source/cmQtAutoGenerators.h
+++ b/Source/cmQtAutoGenerators.h
@@ -60,6 +60,9 @@ private:
               std::map<std::string, std::string>& notIncludedMocs,
               std::map<std::string, std::vector<std::string> >& includedUis);
 
+  std::string MocPathIncluderRel(const std::string & headerName,
+                            const std::string & mocFile);
+
   void ParseForUic(const std::string& fileName,
               const std::string& contentsString,
               std::map<std::string, std::vector<std::string> >& includedUis);
@@ -102,6 +105,7 @@ private:
   std::string OldCompileSettingsStr;
 
   std::string OutMocCppFilename;
+  std::string OutMocDir;
   std::list<std::string> MocIncludes;
   std::list<std::string> MocDefinitions;
   std::vector<std::string> MocOptions;
-- 
2.8.0.rc3

-- 

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