Browse Source

Merge topic 'AutomocIncludedDotMocFileHandling'

2d11951 Merge branch 'master' into AutomocIncludedDotMocFileHandling
1eca18f automoc: add documentation for CMAKE_AUTOMOC_STRICT_MODE
bc278ce automoc: fix line length
62e223e automoc: add variable CMAKE_AUTOMOC_STRICT_MODE, to enable strict parsing
40c5167 automoc: accept even more .moc files in non-strict mode
c207f5d automoc: also accept other files when .moc is included in non-strict mode
9c0df72 automoc: add a StrictParseCppFile(), which is only qmake-compatible
174bf35 automoc: move the code for finding headers into separate function
8507eae automoc: fix handling of included _p.moc files
7ada172 automoc: some more linebreaks for the warnings for better readability
3b93e26 automoc: add extra check whether the header contains Q_PRIVATE_SLOT
4745715 Add a test case for the use of Q_PRIVATE_SLOT.
bde4edb automoc: add special handling for including basename_p.moc, with test
74ab0f6 automoc: move some code from the big parsing loop into separate functions
bc7560e automoc: add test for including a moc_abc_p.cpp file
30fd8e6 automoc: add test for including the moc file from another header
...
David Cole 14 years ago
parent
commit
d050d6b58b

+ 1 - 0
Modules/AutomocInfo.cmake.in

@@ -13,3 +13,4 @@ set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
 set(AM_QT_VERSION_MAJOR "@QT_VERSION_MAJOR@" )
 set(AM_Qt5Core_VERSION_MAJOR "@Qt5Core_VERSION_MAJOR@" )
 set(AM_TARGET_NAME "@_moc_target_name@")
+set(AM_STRICT_MODE "@_moc_strict_mode@")

+ 14 - 0
Source/cmDocumentVariables.cxx

@@ -507,6 +507,20 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
      false,
      "Variables That Change Behavior");
 
+    cm->DefineProperty
+    ("CMAKE_AUTOMOC_STRICT_MODE",  cmProperty::VARIABLE,
+     "Switch between strict and relaxed automoc mode.",
+     "When TRUE, automoc behaves exactly as described in the documentation "
+     "of the AUTOMOC target property.  "
+     "When set to FALSE, it accepts more input and tries to find the correct "
+     "input file for moc even if it differs from the documented behaviour. "
+     "In this mode it e.g. also checks whether a header file is intended to "
+     "be processed by moc when a \"foo.moc\" file has been included.\n"
+     "When using Qt4, CMAKE_AUTOMOC_STRICT_MODE is initialized to FALSE. "
+     "It also has to be set to FALSE for KDE4 compatibility.",
+     false,
+     "Variables That Change Behavior");
+
     cm->DefineProperty
     ("CMAKE_FIND_LIBRARY_PREFIXES",  cmProperty::VARIABLE,
      "Prefixes to prepend when looking for libraries.",

+ 327 - 68
Source/cmQtAutomoc.cxx

@@ -17,11 +17,70 @@
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 
-# include <cmsys/Terminal.h>
+#include <cmsys/Terminal.h>
+
+#include <string.h>
 
 #include "cmQtAutomoc.h"
 
 
+static bool containsQ_OBJECT(const std::string& text)
+{
+  // this simple check is much much faster than the regexp
+  if (strstr(text.c_str(), "Q_OBJECT") == NULL)
+    {
+    return false;
+    }
+
+  cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
+  return qObjectRegExp.find(text);
+}
+
+
+static std::string findMatchingHeader(const std::string& absPath,
+                                      const std::string& mocSubDir,
+                                      const std::string& basename,
+                                const std::list<std::string>& headerExtensions)
+{
+  std::string header;
+  for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
+      ext != headerExtensions.end();
+      ++ext)
+    {
+    std::string sourceFilePath = absPath + basename + (*ext);
+    if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
+      {
+      header = sourceFilePath;
+      break;
+      }
+    if (!mocSubDir.empty())
+      {
+      sourceFilePath = mocSubDir + basename + (*ext);
+      if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
+        {
+        header = sourceFilePath;
+        break;
+        }
+      }
+    }
+
+  return header;
+}
+
+
+static std::string extractSubDir(const std::string& absPath,
+                                 const std::string& currentMoc)
+{
+  std::string subDir;
+  if (currentMoc.find_first_of('/') != std::string::npos)
+    {
+    subDir = absPath
+                  + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
+    }
+  return subDir;
+}
+
+
 cmQtAutomoc::cmQtAutomoc()
 :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
 ,ColorOutput(true)
@@ -60,6 +119,12 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
     return;
     }
 
+  bool strictMode = (qtMajorVersion == "5");
+  if (makefile->IsDefinitionSet("CMAKE_AUTOMOC_STRICT_MODE"))
+    {
+    strictMode = makefile->IsOn("CMAKE_AUTOMOC_STRICT_MODE");
+    }
+
   // create a custom target for running automoc at buildtime:
   std::string automocTargetName = targetName;
   automocTargetName += "_automoc";
@@ -148,6 +213,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
   makefile->AddDefinition("_moc_options", _moc_options.c_str());
   makefile->AddDefinition("_moc_files", _moc_files.c_str());
   makefile->AddDefinition("_moc_headers", _moc_headers.c_str());
+  makefile->AddDefinition("_moc_strict_mode", strictMode ? "TRUE" : "FALSE");
 
   const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT");
   std::string inputFile = cmakeRoot;
@@ -247,6 +313,8 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile,
   this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
   this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
 
+  this->StrictMode = makefile->IsOn("AM_STRICT_MODE");
+
   return true;
 }
 
@@ -415,6 +483,23 @@ bool cmQtAutomoc::RunAutomoc()
   std::vector<std::string> sourceFiles;
   cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
 
+  std::list<std::string> headerExtensions;
+  headerExtensions.push_back(".h");
+  headerExtensions.push_back(".hpp");
+  headerExtensions.push_back(".hxx");
+#if defined(_WIN32)
+  // not case sensitive, don't add ".H"
+#elif defined(__APPLE__)
+  // detect case-sensitive filesystem
+  long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE);
+  if (caseSensitive == 1)
+  {
+    headerExtensions.push_back(".H");
+  }
+#else
+  headerExtensions.push_back(".H");
+#endif
+
   for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
        it != sourceFiles.end();
        ++it)
@@ -424,7 +509,15 @@ bool cmQtAutomoc::RunAutomoc()
       {
       std::cout << "AUTOMOC: Checking " << absFilename << std::endl;
       }
-    this->ParseCppFile(absFilename, includedMocs, headerFiles);
+    if (this->StrictMode == false)
+      {
+      this->ParseCppFile(absFilename, headerExtensions, includedMocs);
+      }
+    else
+      {
+      this->StrictParseCppFile(absFilename, headerExtensions, includedMocs);
+      }
+    this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
     }
 
   std::vector<std::string> headerFilesVec;
@@ -505,40 +598,37 @@ bool cmQtAutomoc::RunAutomoc()
 
 
 void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
-                           std::map<std::string, std::string>& includedMocs,
-                           std::set<std::string>& absHeaders)
+                              const std::list<std::string>& headerExtensions,
+                              std::map<std::string, std::string>& includedMocs)
 {
   cmsys::RegularExpression mocIncludeRegExp(
               "[\n][ \t]*#[ \t]*include[ \t]+"
               "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
-  std::list<std::string> headerExtensions;
-  headerExtensions.push_back(".h");
-  headerExtensions.push_back(".hpp");
-  headerExtensions.push_back(".hxx");
-#if defined(_WIN32)
-  // not case sensitive, don't add ".H"
-#elif defined(__APPLE__)
-  // detect case-sensitive filesystem
-  long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE);
-  if (caseSensitive == 1)
-  {
-    headerExtensions.push_back(".H");
-  }
-#else
-  headerExtensions.push_back(".H");
-#endif
 
   const std::string contentsString = this->ReadAll(absFilename);
   if (contentsString.empty())
     {
-    std::cerr << "AUTOMOC: empty source file: " << absFilename << std::endl;
+    std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n"
+              << std::endl;
     return;
     }
   const std::string absPath = cmsys::SystemTools::GetFilenamePath(
                    cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
+  const std::string scannedFileBasename = cmsys::SystemTools::
+                                  GetFilenameWithoutLastExtension(absFilename);
+  const bool cppContainsQ_OBJECT = containsQ_OBJECT(contentsString);
+  bool dotMocIncluded = false;
+  bool mocUnderscoreIncluded = false;
+  std::string ownMocUnderscoreFile;
+  std::string ownDotMocFile;
+  std::string ownMocHeaderFile;
 
   std::string::size_type matchOffset = 0;
-  if (mocIncludeRegExp.find(contentsString.c_str()))
+  // first a simply string check for "moc" is *much* faster than the regexp,
+  // and if the string search already fails, we don't have to try the
+  // expensive regexp
+  if ((strstr(contentsString.c_str(), "moc") != NULL)
+                                    && (mocIncludeRegExp.find(contentsString)))
     {
     // for every moc include in the file
     do
@@ -561,78 +651,248 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
         // basename should be the part of the moc filename used for
         // finding the correct header, so we need to remove the moc_ part
         basename = basename.substr(4);
+        std::string mocSubDir = extractSubDir(absPath, currentMoc);
+        std::string headerToMoc = findMatchingHeader(
+                               absPath, mocSubDir, basename, headerExtensions);
 
-        bool headerFound = false;
-        for(std::list<std::string>::const_iterator ext =
-                                                      headerExtensions.begin();
-            ext != headerExtensions.end();
-            ++ext)
+        if (!headerToMoc.empty())
+          {
+          includedMocs[headerToMoc] = currentMoc;
+          if (basename == scannedFileBasename)
+            {
+            mocUnderscoreIncluded = true;
+            ownMocUnderscoreFile = currentMoc;
+            ownMocHeaderFile = headerToMoc;
+            }
+          }
+        else
           {
-          const std::string &sourceFilePath = absPath + basename + (*ext);
-          if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
+          std::cerr << "AUTOMOC: error: " << absFilename << " The file "
+                    << "includes the moc file \"" << currentMoc << "\", "
+                    << "but could not find header \"" << basename
+                    << '{' << this->Join(headerExtensions, ',') << "}\" ";
+          if (mocSubDir.empty())
+            {
+            std::cerr << "in " << absPath << "\n" << std::endl;
+            }
+          else
             {
-            headerFound = true;
-            includedMocs[sourceFilePath] = currentMoc;
-            break;
+            std::cerr << "neither in " << absPath
+                      << " nor in " << mocSubDir << "\n" << std::endl;
             }
+
+          ::exit(EXIT_FAILURE);
           }
-        if (!headerFound)
+        }
+      else
+        {
+        std::string fileToMoc = absFilename;
+        if ((basename != scannedFileBasename) || (cppContainsQ_OBJECT==false))
           {
-          // the moc file is in a subdir => look for the header in the
-          // same subdir
-          if (currentMoc.find_first_of('/') != std::string::npos)
+          std::string mocSubDir = extractSubDir(absPath, currentMoc);
+          std::string headerToMoc = findMatchingHeader(
+                              absPath, mocSubDir, basename, headerExtensions);
+          if (!headerToMoc.empty())
             {
-            const std::string &filepath = absPath
-                    + cmsys::SystemTools::GetFilenamePath(currentMoc)
-                    + '/' + basename;
-
-            for(std::list<std::string>::const_iterator ext =
-                                                      headerExtensions.begin();
-                ext != headerExtensions.end();
-                ++ext)
+            // this is for KDE4 compatibility:
+            fileToMoc = headerToMoc;
+            if ((cppContainsQ_OBJECT==false) &&(basename==scannedFileBasename))
               {
-              const std::string &sourceFilePath = filepath + (*ext);
-              if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
-                {
-                headerFound = true;
-                includedMocs[sourceFilePath] = currentMoc;
-                break;
-                }
+              std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
+                            "includes the moc file \"" << currentMoc <<
+                            "\", but does not contain a Q_OBJECT macro. "
+                            "Running moc on "
+                        << "\"" << headerToMoc << "\" ! Better include \"moc_"
+                        << basename << ".cpp\" for a robust build.\n"
+                        << std::endl;
               }
-            if (!headerFound)
+            else
               {
-              std::cerr << "AUTOMOC: The file \"" << absFilename
-                        << "\" includes the moc file \"" << currentMoc
-                        << "\", but neither \"" << absPath << basename
-                        << '{' << this->Join(headerExtensions, ',')
-                        << "}\" nor \"" << filepath << '{'
-                        << this->Join(headerExtensions, ',') << '}'
-                        << "\" exist." << std::endl;
-              ::exit(EXIT_FAILURE);
+              std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
+                            "includes the moc file \"" << currentMoc <<
+                            "\" instead of \"moc_" << basename << ".cpp\". "
+                            "Running moc on "
+                        << "\"" << headerToMoc << "\" ! Better include \"moc_"
+                        << basename << ".cpp\" for a robust build.\n"
+                        << std::endl;
               }
             }
           else
             {
-            std::cerr << "AUTOMOC: The file \"" << absFilename
-                      << "\" includes the moc file \"" << currentMoc
-                      << "\", but \"" << absPath << basename << '{'
-                      << this->Join(headerExtensions, ',') << '}'
-                      << "\" does not exist." << std::endl;
+            std::cerr <<"AUTOMOC: error: " << absFilename << ": The file "
+                        "includes the moc file \"" << currentMoc <<
+                        "\", which seems to be the moc file from a different "
+                        "source file. CMake also could not find a matching "
+                        "header.\n" << std::endl;
             ::exit(EXIT_FAILURE);
             }
           }
+        else
+          {
+          dotMocIncluded = true;
+          ownDotMocFile = currentMoc;
+          }
+        includedMocs[fileToMoc] = currentMoc;
+        }
+      matchOffset += mocIncludeRegExp.end();
+      } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
+    }
+
+  // In this case, check whether the scanned file itself contains a Q_OBJECT.
+  // If this is the case, the moc_foo.cpp should probably be generated from
+  // foo.cpp instead of foo.h, because otherwise it won't build.
+  // But warn, since this is not how it is supposed to be used.
+  if ((dotMocIncluded == false) && (cppContainsQ_OBJECT == true))
+    {
+    if (mocUnderscoreIncluded == true)
+      {
+      // this is for KDE4 compatibility:
+      std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
+                << "contains a Q_OBJECT macro, but does not include "
+                << "\"" << scannedFileBasename << ".moc\", but instead "
+                   "includes "
+                << "\"" << ownMocUnderscoreFile  << "\". Running moc on "
+                << "\"" << absFilename << "\" ! Better include \""
+                << scannedFileBasename << ".moc\" for a robust build.\n"
+                << std::endl;
+      includedMocs[absFilename] = ownMocUnderscoreFile;
+      includedMocs.erase(ownMocHeaderFile);
+      }
+    else
+      {
+      // otherwise always error out since it will not compile:
+      std::cerr << "AUTOMOC: error: " << absFilename << ": The file "
+                << "contains a Q_OBJECT macro, but does not include "
+                << "\"" << scannedFileBasename << ".moc\" !\n"
+                << std::endl;
+      ::exit(EXIT_FAILURE);
+      }
+    }
+
+}
+
+
+void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename,
+                              const std::list<std::string>& headerExtensions,
+                              std::map<std::string, std::string>& includedMocs)
+{
+  cmsys::RegularExpression mocIncludeRegExp(
+              "[\n][ \t]*#[ \t]*include[ \t]+"
+              "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+
+  const std::string contentsString = this->ReadAll(absFilename);
+  if (contentsString.empty())
+    {
+    std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n"
+              << std::endl;
+    return;
+    }
+  const std::string absPath = cmsys::SystemTools::GetFilenamePath(
+                   cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
+  const std::string scannedFileBasename = cmsys::SystemTools::
+                                  GetFilenameWithoutLastExtension(absFilename);
+
+  bool dotMocIncluded = false;
+
+  std::string::size_type matchOffset = 0;
+  // first a simply string check for "moc" is *much* faster than the regexp,
+  // and if the string search already fails, we don't have to try the
+  // expensive regexp
+  if ((strstr(contentsString.c_str(), "moc") != NULL)
+                                    && (mocIncludeRegExp.find(contentsString)))
+    {
+    // for every moc include in the file
+    do
+      {
+      const std::string currentMoc = mocIncludeRegExp.match(1);
+
+      std::string basename = cmsys::SystemTools::
+                                   GetFilenameWithoutLastExtension(currentMoc);
+      const bool mocUnderscoreStyle = this->StartsWith(basename, "moc_");
+
+      // If the moc include is of the moc_foo.cpp style we expect
+      // the Q_OBJECT class declaration in a header file.
+      // If the moc include is of the foo.moc style we need to look for
+      // a Q_OBJECT macro in the current source file, if it contains the
+      // macro we generate the moc file from the source file.
+      if (mocUnderscoreStyle)
+        {
+        // basename should be the part of the moc filename used for
+        // finding the correct header, so we need to remove the moc_ part
+        basename = basename.substr(4);
+        std::string mocSubDir = extractSubDir(absPath, currentMoc);
+        std::string headerToMoc = findMatchingHeader(
+                               absPath, mocSubDir, basename, headerExtensions);
+
+        if (!headerToMoc.empty())
+          {
+          includedMocs[headerToMoc] = currentMoc;
+          }
+        else
+          {
+          std::cerr << "AUTOMOC: error: " << absFilename << " The file "
+                    << "includes the moc file \"" << currentMoc << "\", "
+                    << "but could not find header \"" << basename
+                    << '{' << this->Join(headerExtensions, ',') << "}\" ";
+          if (mocSubDir.empty())
+            {
+            std::cerr << "in " << absPath << "\n" << std::endl;
+            }
+          else
+            {
+            std::cerr << "neither in " << absPath
+                      << " nor in " << mocSubDir << "\n" << std::endl;
+            }
+
+          ::exit(EXIT_FAILURE);
+          }
         }
       else
         {
+        if (basename != scannedFileBasename)
+          {
+          std::cerr <<"AUTOMOC: error: " << absFilename << ": The file "
+                      "includes the moc file \"" << currentMoc <<
+                      "\", which seems to be the moc file from a different "
+                      "source file. This is not supported. "
+                      "Include \"" << scannedFileBasename << ".moc\" to run "
+                      "moc on this source file.\n" << std::endl;
+          ::exit(EXIT_FAILURE);
+          }
+        dotMocIncluded = true;
         includedMocs[absFilename] = currentMoc;
         }
       matchOffset += mocIncludeRegExp.end();
       } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
     }
 
+  // In this case, check whether the scanned file itself contains a Q_OBJECT.
+  // If this is the case, the moc_foo.cpp should probably be generated from
+  // foo.cpp instead of foo.h, because otherwise it won't build.
+  // But warn, since this is not how it is supposed to be used.
+  if ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString)))
+    {
+    // otherwise always error out since it will not compile:
+    std::cerr << "AUTOMOC: error: " << absFilename << ": The file "
+              << "contains a Q_OBJECT macro, but does not include "
+              << "\"" << scannedFileBasename << ".moc\" !\n"
+              << std::endl;
+    ::exit(EXIT_FAILURE);
+    }
+
+}
+
+
+void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename,
+                                const std::list<std::string>& headerExtensions,
+                                std::set<std::string>& absHeaders)
+{
   // search for header files and private header files we may need to moc:
   const std::string basename =
               cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
+  const std::string absPath = cmsys::SystemTools::GetFilenamePath(
+                   cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
+
   for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
       ext != headerExtensions.end();
       ++ext)
@@ -663,7 +923,6 @@ void cmQtAutomoc::ParseHeaders(const std::set<std::string>& absHeaders,
                         const std::map<std::string, std::string>& includedMocs,
                         std::map<std::string, std::string>& notIncludedMocs)
 {
-  cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
   for(std::set<std::string>::const_iterator hIt=absHeaders.begin();
       hIt!=absHeaders.end();
       ++hIt)
@@ -682,7 +941,7 @@ void cmQtAutomoc::ParseHeaders(const std::set<std::string>& absHeaders,
 
       const std::string currentMoc = "moc_" + basename + ".cpp";
       const std::string contents = this->ReadAll(headerName);
-      if (qObjectRegExp.find(contents))
+      if (containsQ_OBJECT(contents))
         {
         //std::cout << "header contains Q_OBJECT macro";
         notIncludedMocs[headerName] = currentMoc;
@@ -759,7 +1018,7 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile,
     bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
     if (!result || retVal)
       {
-      std::cerr << "AUTOMOC: process for " << mocFilePath << " failed:\n"
+      std::cerr << "AUTOMOC: error: process for " << mocFilePath <<" failed:\n"
                 << output << std::endl;
       this->RunMocFailed = true;
       cmSystemTools::RemoveFile(mocFilePath.c_str());

+ 10 - 2
Source/cmQtAutomoc.h

@@ -39,8 +39,15 @@ private:
   bool GenerateMoc(const std::string& sourceFile,
                    const std::string& mocFileName);
   void ParseCppFile(const std::string& absFilename,
-                    std::map<std::string, std::string>& includedMocs,
-                    std::set<std::string>& absHeaders);
+                    const std::list<std::string>& headerExtensions,
+                    std::map<std::string, std::string>& includedMocs);
+  void StrictParseCppFile(const std::string& absFilename,
+                          const std::list<std::string>& headerExtensions,
+                          std::map<std::string, std::string>& includedMocs);
+  void SearchHeadersForCppFile(const std::string& absFilename,
+                               const std::list<std::string>& headerExtensions,
+                               std::set<std::string>& absHeaders);
+
   void ParseHeaders(const std::set<std::string>& absHeaders,
                     const std::map<std::string, std::string>& includedMocs,
                     std::map<std::string, std::string>& notIncludedMocs);
@@ -78,6 +85,7 @@ private:
   bool ColorOutput;
   bool RunMocFailed;
   bool GenerateAll;
+  bool StrictMode;
 
 };
 

+ 4 - 2
Source/cmTarget.cxx

@@ -161,8 +161,10 @@ void cmTarget::DefineProperties(cmake *cm)
      "This property is initialized by the value of the variable "
      "CMAKE_AUTOMOC if it is set when a target is created.\n"
      "Additional command line options for moc can be set via the "
-     "AUTOMOC_MOC_OPTIONS property."
-    );
+     "AUTOMOC_MOC_OPTIONS property.\n"
+     "By setting the CMAKE_AUTOMOC_STRICT_MODE variable to FALSE the rules "
+     "for searching the files which will be processed by moc can be relaxed. "
+     "See the documentation for this variable for more details.");
 
   cm->DefineProperty
     ("AUTOMOC_MOC_OPTIONS", cmProperty::TARGET,

+ 1 - 1
Tests/QtAutomoc/CMakeLists.txt

@@ -13,7 +13,7 @@ add_definitions(-DFOO)
 # create an executable and a library target, both requiring automoc:
 add_library(codeeditorLib STATIC codeeditor.cpp)
 
-add_executable(foo main.cpp calwidget.cpp foo.cpp)
+add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp yaf.cpp private_slot.cpp)
 
 set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE)
 

+ 49 - 0
Tests/QtAutomoc/abc.cpp

@@ -0,0 +1,49 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 "abc.h"
+#include "abc_p.h"
+
+#include <stdio.h>
+
+class PrintAbc : public QObject
+{
+  Q_OBJECT
+  public:
+    PrintAbc():QObject() {}
+  public slots:
+    void print() const { printf("abc\n"); }
+};
+
+Abc::Abc()
+:QObject()
+{
+}
+
+
+void Abc::doAbc()
+{
+  PrintAbc pa;
+  pa.print();
+  AbcP abcP;
+  abcP.doAbcP();
+}
+
+// check that including the moc file for the cpp file and the header works:
+#include "abc.moc"
+#include "moc_abc.cpp"
+#include "moc_abc_p.cpp"
+
+// check that including a moc file from another header works:
+#include "moc_xyz.cpp"

+ 28 - 0
Tests/QtAutomoc/abc.h

@@ -0,0 +1,28 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 ABC_H
+#define ABC_H
+
+#include <QObject>
+
+class Abc : public QObject
+{
+  Q_OBJECT
+  public:
+    Abc();
+  public slots:
+    void doAbc();
+};
+
+#endif

+ 30 - 0
Tests/QtAutomoc/abc_p.h

@@ -0,0 +1,30 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 ABC_P_H
+#define ABC_P_H
+
+#include <QObject>
+
+#include <stdio.h>
+
+class AbcP : public QObject
+{
+  Q_OBJECT
+  public:
+    AbcP() {}
+  public slots:
+    void doAbcP() { printf("I am private abc !\n"); }
+};
+
+#endif

+ 28 - 0
Tests/QtAutomoc/bar.cpp

@@ -0,0 +1,28 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 "sub/bar.h"
+
+#include <stdio.h>
+
+Bar::Bar()
+:QObject()
+{
+}
+
+void Bar::doBar()
+{
+  printf("Hello bar !\n");
+}
+
+#include "sub/moc_bar.cpp"

+ 40 - 0
Tests/QtAutomoc/blub.cpp

@@ -0,0 +1,40 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 "blub.h"
+
+#include <stdio.h>
+
+class BlubBlub : public QObject
+{
+  Q_OBJECT
+  public:
+    BlubBlub():QObject() {}
+  public slots:
+    int getValue() const { return 13; }
+};
+
+Blub::Blub()
+{
+}
+
+
+void Blub::blubber()
+{
+  BlubBlub bb;
+  printf("Blub blub %d ! \n", bb.getValue());
+}
+
+// test the case that the wrong moc-file is included, it should
+// actually be "blub.moc"
+#include "moc_blub.cpp"

+ 26 - 0
Tests/QtAutomoc/blub.h

@@ -0,0 +1,26 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 BLUB_H
+#define BLUB_H
+
+#include <QObject>
+
+class Blub
+{
+  public:
+    Blub();
+    void blubber();
+};
+
+#endif

+ 20 - 0
Tests/QtAutomoc/main.cpp

@@ -43,6 +43,11 @@
 #include "codeeditor.h"
 #include "calwidget.h"
 #include "foo.h"
+#include "blub.h"
+#include "sub/bar.h"
+#include "abc.h"
+#include "xyz.h"
+#include "yaf.h"
 
 int main(int argv, char **args)
 {
@@ -58,5 +63,20 @@ int main(int argv, char **args)
   Foo foo;
   foo.doFoo();
 
+  Blub b;
+  b.blubber();
+
+  Bar bar;
+  bar.doBar();
+
+  Abc abc;
+  abc.doAbc();
+
+  Xyz xyz;
+  xyz.doXyz();
+
+  Yaf yaf;
+  yaf.doYaf();
+
   return app.exec();
 }

+ 21 - 0
Tests/QtAutomoc/private_slot.cpp

@@ -0,0 +1,21 @@
+
+#include "private_slot.h"
+
+class PrivateSlotPrivate
+{
+public:
+
+  void privateSlot()
+  {
+
+  }
+};
+
+PrivateSlot::PrivateSlot(QObject *parent)
+  : QObject(parent),
+  d(new PrivateSlotPrivate)
+{
+
+}
+
+#include "private_slot.moc"

+ 20 - 0
Tests/QtAutomoc/private_slot.h

@@ -0,0 +1,20 @@
+
+#ifndef PRIVATE_SLOT_H
+#define PRIVATE_SLOT_H
+
+#include <QObject>
+
+class PrivateSlotPrivate;
+
+class PrivateSlot : public QObject
+{
+  Q_OBJECT
+public:
+  PrivateSlot(QObject *parent = 0);
+
+private:
+  PrivateSlotPrivate * const d;
+  Q_PRIVATE_SLOT(d, void privateSlot())
+};
+
+#endif

+ 28 - 0
Tests/QtAutomoc/sub/bar.h

@@ -0,0 +1,28 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 BAR_H
+#define BAR_H
+
+#include <QObject>
+
+class Bar : public QObject
+{
+  Q_OBJECT
+  public:
+    Bar();
+  public slots:
+    void doBar();
+};
+
+#endif

+ 28 - 0
Tests/QtAutomoc/xyz.cpp

@@ -0,0 +1,28 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 "xyz.h"
+
+#include <stdio.h>
+
+Xyz::Xyz()
+:QObject()
+{
+}
+
+
+void Xyz::doXyz()
+{
+  printf("This is xyz !\n");
+}

+ 28 - 0
Tests/QtAutomoc/xyz.h

@@ -0,0 +1,28 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 XYZ_H
+#define XYZ_H
+
+#include <QObject>
+
+class Xyz : public QObject
+{
+  Q_OBJECT
+  public:
+    Xyz();
+  public slots:
+    void doXyz();
+};
+
+#endif

+ 32 - 0
Tests/QtAutomoc/yaf.cpp

@@ -0,0 +1,32 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 "yaf.h"
+#include "yaf_p.h"
+
+#include <stdio.h>
+
+Yaf::Yaf()
+{
+}
+
+
+void Yaf::doYaf()
+{
+  YafP yafP;
+  yafP.doYafP();
+}
+
+// check that including a moc file from a private header the wrong way works:
+#include "yaf_p.moc"

+ 25 - 0
Tests/QtAutomoc/yaf.h

@@ -0,0 +1,25 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 YAF_H
+#define YAF_H
+
+class Yaf
+{
+  public:
+    Yaf();
+  public:
+    void doYaf();
+};
+
+#endif

+ 30 - 0
Tests/QtAutomoc/yaf_p.h

@@ -0,0 +1,30 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2004-2011 Kitware, Inc.
+  Copyright 2011 Alexander Neundorf ([email protected])
+
+  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 YAF_P_H
+#define YAF_P_H
+
+#include <QObject>
+
+#include <stdio.h>
+
+class YafP : public QObject
+{
+  Q_OBJECT
+  public:
+    YafP() {}
+  public slots:
+    void doYafP() { printf("I am yet another file !\n"); }
+};
+
+#endif