Am 12.04.2016 um 17:40 schrieb Sebastian Holtermann:
Am 12.04.2016 um 13:43 schrieb Sebastian Holtermann:
Sorry for the noise.

I've stumbled over bug
https://cmake.org/Bug/view.php?id=12873
a few times now since I like to use same named data/view classes.

I've prepared a fix that generates all moc_xxx.cpp files
in the foo_automoc.dir subdirectory.


I had some more thoughts about this.

CMAKE_CURRENT_BINARY_DIR /
   foo_automoc.cpp
   foo_automoc.dir/data/moc_item.cpp
   foo_automoc.dir/view/moc_item.cpp
   foo_automoc.dir/moc_item.cpp

With directory based moc file generation it is complicated to allow
"#include <moc_foo.cpp>" (I've never included mocs btw.).
Putting every moc directory into the target INCLUDE_DIRECTORIES
won't help because then there would be multiple moc_item.cpp
files that match "include <moc_item.cpp>".
If per source INCLUDE_DIRECTORIES were possible it might work though.

My proposal is this:

- Moc files that are "#include<>"d get generated in
CMAKE_CURRENT_BINARY_DIR/moc_xxx.cpp as before but with
name collision test.

- Moc files not included but detected from
headers get generated in
CMAKE_CURRENT_BINARY_DIR/foo_automoc.dir/
with subdirectory support.
Since they're not included it doesn't matter where they are as long as
they don't overwrite each other.


I'll prepare another patch for this...


Here it is. Please review/commit.

To test it insert #include "moc_item.cpp" in any or many
of the item.cpp files of the attached test project.


Kind regards,
Sebastian Holtermann


>From cbc41b51685a4a35ceaa0763ba3f14e1ae425ad4 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Tue, 12 Apr 2016 20:49:50 +0200
Subject: [PATCH] Automoc generates non included mocs in dedicated directory
 with source directory tree reflection

---
 Source/cmQtAutoGenerators.cxx | 107 +++++++++++++++++++++++++++++++++++++++---
 Source/cmQtAutoGenerators.h   |   4 ++
 2 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index ebe08b0..1faab2d 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);
+    if ( fileNamePath.find ( ".." ) == std::string::npos )
+      {
+        subDir = absPath + fileNamePath + '/';
+      }
+    else
+      {
+      // We can't handle parent directories
+      std::cerr << "AUTOGEN: error: moc include \"" << currentMoc
+                << "\" contains parent directory reference \"..\""
+                << std::endl;
+      ::exit(EXIT_FAILURE);
+      }
     }
   return subDir;
 }
@@ -414,6 +425,9 @@ void cmQtAutoGenerators::Init()
   this->OutMocCppFilename += this->TargetName;
   this->OutMocCppFilename += ".cpp";
 
+  this->OutMocDirname += this->TargetName;
+  this->OutMocDirname += ".dir";
+
   std::vector<std::string> cdefList;
   cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
   for(std::vector<std::string>::const_iterator it = cdefList.begin();
@@ -589,6 +603,26 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
   std::map<std::string, std::string> notIncludedMocs;
   this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
 
+  // Check: Look for name collisions
+    {
+    typedef std::map<std::string, std::string>::const_iterator Iter;
+    for ( Iter ita = includedMocs.begin(); ita != includedMocs.end(); ++ita )
+      {
+      Iter itb = ita;
+      ++itb;
+      for ( ; itb != includedMocs.end(); ++itb )
+        {
+        if ( ita->second == itb->second )
+          {
+          std::cerr << "AUTOGEN: error: moc name collision" << std::endl
+                    << ita->first << " -> " << ita->second << std::endl
+                    << itb->first << " -> " << itb->second << std::endl;
+          ::exit(EXIT_FAILURE);
+          }
+        }
+      }
+    }
+
   // 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();
@@ -1104,15 +1138,14 @@ 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);
@@ -1347,6 +1380,66 @@ 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->OutMocDirname;
+  if (!path.empty())
+    {
+    path += '/';
+    }
+
+    // Append parent dir to header relative path
+    {
+    ::std::string pathRel = cmsys::SystemTools::RelativePath(
+      parentDirectory, cmsys::SystemTools::GetParentDirectory(headerNameReal));
+    if (!pathRel.empty())
+      {
+      pathRel += '/';
+      }
+    path += pathRel;
+    }
+  path += mocFile;
+  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..681b258 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 OutMocDirname;
   std::list<std::string> MocIncludes;
   std::list<std::string> MocDefinitions;
   std::vector<std::string> MocOptions;
-- 
2.8.0.rc3

Attachment: cmake_automoc_directory_test-2016-04-12-2.tar.gz
Description: application/gzip

-- 

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