Hi,

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.
For the attached test case you end up with

foo_automoc.cpp -- As before but includes sources below
foo_automoc.dir/data/moc_item.cpp
foo_automoc.dir/view/moc_item.cpp
foo_automoc.dir/item.cpp

This solves the same output moc problem.

What remains though is that including "moc_foo.cpp"
does not work because of missing INCLUDE_DIRECTORIES.

Kind regards,
Sebastian Holtermann

>From cf51dcf0af4744fbb40e3bb5ad253d2514325148 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <sebh...@xwmw.org>
Date: Tue, 12 Apr 2016 10:47:49 +0200
Subject: [PATCH] Automoc: Create moc files below foo_automoc.dir with respect
 to the source header project relative path

---
 Source/cmQtAutoGenerators.cxx | 90 ++++++++++++++++++++++++++++++++++++-------
 Source/cmQtAutoGenerators.h   |  3 ++
 2 files changed, 80 insertions(+), 13 deletions(-)

diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index ebe08b0..69b1e3d 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -414,6 +414,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();
@@ -637,7 +640,7 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
         {
         automocCppChanged = true;
         }
-      outStream << "#include \"" << it->second << "\"\n";
+      outStream << "#include \"" << MocPathBuildRel ( it->second ) << "\"\n";
       }
     }
 
@@ -749,7 +752,7 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
 
         if (!headerToMoc.empty())
           {
-          includedMocs[headerToMoc] = currentMoc;
+          includedMocs[headerToMoc] = MocPathIncluderRel ( absFilename, currentMoc );
           if (basename == scannedFileBasename)
             {
             mocUnderscoreIncluded = true;
@@ -826,7 +829,7 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
           dotMocIncluded = true;
           ownDotMocFile = currentMoc;
           }
-        includedMocs[fileToMoc] = currentMoc;
+        includedMocs[fileToMoc] = MocPathIncluderRel ( absFilename, currentMoc );
         }
       matchOffset += mocIncludeRegExp.end();
       } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
@@ -851,7 +854,7 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
                 << scannedFileBasename << ".moc\" for compatibility with "
                    "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
                 << std::endl;
-      includedMocs[absFilename] = ownMocUnderscoreFile;
+      includedMocs[absFilename] = MocPathIncluderRel ( absFilename, ownMocUnderscoreFile );
       includedMocs.erase(ownMocHeaderFile);
       }
     else
@@ -930,7 +933,7 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
 
         if (!headerToMoc.empty())
           {
-          includedMocs[headerToMoc] = currentMoc;
+          includedMocs[headerToMoc] = MocPathIncluderRel ( absFilename, currentMoc );
           }
         else
           {
@@ -964,7 +967,7 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
           ::exit(EXIT_FAILURE);
           }
         dotMocIncluded = true;
-        includedMocs[absFilename] = currentMoc;
+        includedMocs[absFilename] = MocPathIncluderRel ( absFilename, currentMoc );
         }
       matchOffset += mocIncludeRegExp.end();
       } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
@@ -1104,15 +1107,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);
@@ -1122,7 +1124,11 @@ void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
 bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
                               const std::string& mocFileName)
 {
-  const std::string mocFilePath = this->Builddir + mocFileName;
+  ::std::cout << "GenerateMoc: sourceFile " << sourceFile << std::endl;
+  ::std::cout << "GenerateMoc: mocFileName " << mocFileName << std::endl;
+  //const std::string mocFilePath = this->Builddir + mocFileName;
+  const std::string mocFileRel = this->MocPathBuildRel ( mocFileName );
+  const std::string mocFilePath = this->Builddir + mocFileRel;
   int sourceNewerThanMoc = 0;
   bool success = cmsys::SystemTools::FileTimeCompare(sourceFile,
                                                      mocFilePath,
@@ -1137,7 +1143,7 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
       }
 
     std::string msg = "Generating ";
-    msg += mocFileName;
+    msg += mocFileRel;
     cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
                                            |cmsysTerminal_Color_ForegroundBold,
                                      msg.c_str(), true, this->ColorOutput);
@@ -1347,6 +1353,64 @@ 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::cout << "MocPathIncluderRel: headerName " << headerName << std::endl;
+  std::cout << "MocPathIncluderRel: mocFile " << mocFile << std::endl;
+  
+  ::std::string headerDirectory;
+  //
+  // headerName comes with symlinks removed but this->ProjectSourceDir and
+  // this->ProjectBinaryDir may still contain symlinks
+  ::std::string source_dir_abs = cmsys::SystemTools::
+                                GetRealPath( this->ProjectSourceDir );
+  ::std::string project_dir_abs = cmsys::SystemTools::
+                                  GetRealPath( this->ProjectBinaryDir );
+
+  if (cmsys::SystemTools::IsSubDirectory(headerName,
+                                         source_dir_abs) )
+    {
+    headerDirectory = source_dir_abs;
+    }
+  else if (cmsys::SystemTools::IsSubDirectory(headerName,
+                                              project_dir_abs) )
+    {
+    headerDirectory = project_dir_abs;
+    }
+  else
+    {
+    cmsys::SystemTools::SplitPathRootComponent(headerName,
+                                               &headerDirectory);
+    }
+  headerDirectory = cmsys::SystemTools::RelativePath(
+    headerDirectory, cmsys::SystemTools::GetParentDirectory(headerName));
+
+  std::string path = headerDirectory;
+  if (!path.empty())
+    {
+    path += "/";
+    }
+  path += mocFile;
+  std::cout << "MocPathIncluderRel: path " << path << std::endl;
+  return path;
+}
+
+std::string cmQtAutoGenerators::MocPathBuildRel(const std::string & mocFile)
+{
+  std::string path ( this->OutMocDirname );
+  if (!path.empty())
+    {
+      path += "/";
+    }
+  path += mocFile;
+  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..b7af2cb 100644
--- a/Source/cmQtAutoGenerators.h
+++ b/Source/cmQtAutoGenerators.h
@@ -73,6 +73,8 @@ private:
   bool EndsWith(const std::string& str, const std::string& with);
   bool StartsWith(const std::string& str, const std::string& with);
 
+  std::string MocPathIncluderRel(const std::string & headerName, const std::string & mocFile);
+  std::string MocPathBuildRel(const std::string & mocFile);
   static void MergeUicOptions(std::vector<std::string> &opts,
                        const std::vector<std::string> &fileOpts, bool isQt5);
 
@@ -102,6 +104,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_test-2016-04-12-1.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