Imported Upstream version 2.8.11.2
[platform/upstream/cmake.git] / Source / cmQtAutomoc.cxx
index 65ecdf7..a1fa31f 100644 (file)
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include "cmLocalVisualStudioGenerator.h"
+#endif
+
 #include <cmsys/Terminal.h>
 #include <cmsys/ios/sstream>
 
@@ -44,14 +48,14 @@ static bool containsQ_OBJECT(const std::string& text)
 static std::string findMatchingHeader(const std::string& absPath,
                                       const std::string& mocSubDir,
                                       const std::string& basename,
-                                const std::list<std::string>& headerExtensions)
+                              const std::vector<std::string>& headerExtensions)
 {
   std::string header;
-  for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
+  for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
       ext != headerExtensions.end();
       ++ext)
     {
-    std::string sourceFilePath = absPath + basename + (*ext);
+    std::string sourceFilePath = absPath + basename + "." + (*ext);
     if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
       {
       header = sourceFilePath;
@@ -59,7 +63,7 @@ static std::string findMatchingHeader(const std::string& absPath,
       }
     if (!mocSubDir.empty())
       {
-      sourceFilePath = mocSubDir + basename + (*ext);
+      sourceFilePath = mocSubDir + basename + "." + (*ext);
       if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
         {
         header = sourceFilePath;
@@ -85,6 +89,18 @@ static std::string extractSubDir(const std::string& absPath,
 }
 
 
+static void copyTargetProperty(cmTarget* destinationTarget,
+                               cmTarget* sourceTarget,
+                               const char* propertyName)
+{
+  const char* propertyValue = sourceTarget->GetProperty(propertyName);
+  if (propertyValue)
+    {
+    destinationTarget->SetProperty(propertyName, propertyValue);
+    }
+}
+
+
 cmQtAutomoc::cmQtAutomoc()
 :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
 ,ColorOutput(true)
@@ -107,11 +123,9 @@ cmQtAutomoc::cmQtAutomoc()
     }
 }
 
-
-void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
+bool cmQtAutomoc::InitializeMocSourceFile(cmTarget* target)
 {
   cmMakefile* makefile = target->GetMakefile();
-  const char* targetName = target->GetName();
   // don't do anything if there is no Qt4 or Qt5Core (which contains moc):
   std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
   if (qtMajorVersion == "")
@@ -120,9 +134,30 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
     }
   if (qtMajorVersion != "4" && qtMajorVersion != "5")
     {
-    return;
+    return false;
     }
 
+  std::string automocTargetName = target->GetName();
+  automocTargetName += "_automoc";
+  std::string mocCppFile = makefile->GetCurrentOutputDirectory();
+  mocCppFile += "/";
+  mocCppFile += automocTargetName;
+  mocCppFile += ".cpp";
+  cmSourceFile* mocCppSource = makefile->GetOrCreateSource(mocCppFile.c_str(),
+                                                         true);
+  makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
+                           mocCppFile.c_str(), false);
+
+  target->AddSourceFile(mocCppSource);
+  return true;
+}
+
+void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
+{
+  cmMakefile* makefile = target->GetMakefile();
+  cmLocalGenerator* localGen = makefile->GetLocalGenerator();
+  const char* targetName = target->GetName();
+
   bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE");
 
   // create a custom target for running automoc at buildtime:
@@ -151,10 +186,44 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
   std::string automocComment = "Automoc for target ";
   automocComment += targetName;
 
-  makefile->AddUtilityCommand(automocTargetName.c_str(), true,
-                              workingDirectory.c_str(), depends,
-                              commandLines, false, automocComment.c_str());
-  target->AddUtility(automocTargetName.c_str());
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  bool usePRE_BUILD = false;
+  cmGlobalGenerator* gg = localGen->GetGlobalGenerator();
+  if(strstr(gg->GetName(), "Visual Studio"))
+    {
+    cmLocalVisualStudioGenerator* vslg =
+      static_cast<cmLocalVisualStudioGenerator*>(localGen);
+    // Under VS >= 7 use a PRE_BUILD event instead of a separate target to
+    // reduce the number of targets loaded into the IDE.
+    // This also works around a VS 11 bug that may skip updating the target:
+    //  https://connect.microsoft.com/VisualStudio/feedback/details/769495
+    usePRE_BUILD = vslg->GetVersion() >= cmLocalVisualStudioGenerator::VS7;
+    }
+  if(usePRE_BUILD)
+    {
+    // Add the pre-build command directly to bypass the OBJECT_LIBRARY
+    // rejection in cmMakefile::AddCustomCommandToTarget because we know
+    // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
+    std::vector<std::string> no_output;
+    cmCustomCommand cc(makefile, no_output, depends,
+                       commandLines, automocComment.c_str(),
+                       workingDirectory.c_str());
+    cc.SetEscapeOldStyle(false);
+    cc.SetEscapeAllowMakeVars(true);
+    target->GetPreBuildCommands().push_back(cc);
+    }
+  else
+#endif
+    {
+    cmTarget* automocTarget = makefile->AddUtilityCommand(
+                                automocTargetName.c_str(), true,
+                                workingDirectory.c_str(), depends,
+                                commandLines, false, automocComment.c_str());
+    // inherit FOLDER property from target (#13688)
+    copyTargetProperty(automocTarget, target, "FOLDER");
+
+    target->AddUtility(automocTargetName.c_str());
+    }
 
   // configure a file to get all information to automoc at buildtime:
   std::string _moc_files;
@@ -169,7 +238,8 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
       ++fileIt)
     {
     cmSourceFile* sf = *fileIt;
-    std::string absFile = sf->GetFullPath();
+    std::string absFile = cmsys::SystemTools::GetRealPath(
+                                                    sf->GetFullPath().c_str());
     bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
     bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
 
@@ -193,12 +263,35 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
       }
     }
 
-  const char* tmp = makefile->GetProperty("INCLUDE_DIRECTORIES");
-  std::string _moc_incs = (tmp!=0 ? tmp : "");
-  tmp = makefile->GetProperty("DEFINITIONS");
-  std::string _moc_defs = (tmp!=0 ? tmp : "");
+
+  std::vector<std::string> includeDirs;
+  cmGeneratorTarget gtgt(target);
+  // Get the include dirs for this target, without stripping the implicit
+  // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
+  localGen->GetIncludeDirectories(includeDirs, &gtgt, "CXX", 0, false);
+  std::string _moc_incs = "";
+  const char* sep = "";
+  for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin();
+      incDirIt != includeDirs.end();
+      ++incDirIt)
+    {
+    _moc_incs += sep;
+    sep = ";";
+    _moc_incs += *incDirIt;
+    }
+
+  const char* tmp = target->GetProperty("COMPILE_DEFINITIONS");
+  std::string _moc_compile_defs;
+  if (tmp)
+    {
+    _moc_compile_defs = target->GetCompileDefinitions(0);
+    }
   tmp = makefile->GetProperty("COMPILE_DEFINITIONS");
-  std::string _moc_compile_defs = (tmp!=0 ? tmp : "");
+  if (tmp)
+    {
+    _moc_compile_defs += ";";
+    _moc_compile_defs += tmp;
+    }
   tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS");
   std::string _moc_options = (tmp!=0 ? tmp : "");
 
@@ -210,8 +303,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
           cmLocalGenerator::EscapeForCMake(automocTargetName.c_str()).c_str());
   makefile->AddDefinition("_moc_incs",
           cmLocalGenerator::EscapeForCMake(_moc_incs.c_str()).c_str());
-  makefile->AddDefinition("_moc_defs",
-          cmLocalGenerator::EscapeForCMake(_moc_defs.c_str()).c_str());
   makefile->AddDefinition("_moc_compile_defs",
           cmLocalGenerator::EscapeForCMake(_moc_compile_defs.c_str()).c_str());
   makefile->AddDefinition("_moc_options",
@@ -229,17 +320,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
   outputFile += "/AutomocInfo.cmake";
   makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(),
                           false, true, false);
-
-  std::string mocCppFile =  makefile->GetCurrentOutputDirectory();
-  mocCppFile += "/";
-  mocCppFile += automocTargetName;
-  mocCppFile += ".cpp";
-  cmSourceFile* mocCppSource = makefile->GetOrCreateSource(mocCppFile.c_str(),
-                                                         true);
-  target->AddSourceFile(mocCppSource);
-
-  makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
-                           mocCppFile.c_str(), false);
 }
 
 
@@ -257,7 +337,7 @@ bool cmQtAutomoc::Run(const char* targetDirectory)
 
   if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5")
     {
-    success = this->RunAutomoc();
+    success = this->RunAutomoc(makefile);
     }
 
   this->WriteOldMocDefinitionsFile(targetDirectory);
@@ -314,19 +394,37 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile,
   this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
   this->MocCompileDefinitionsStr = makefile->GetSafeDefinition(
                                                  "AM_MOC_COMPILE_DEFINITIONS");
-  this->MocDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_DEFINITIONS");
   this->MocIncludesStr = makefile->GetSafeDefinition("AM_MOC_INCLUDES");
   this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
   this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
   this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
   this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
 
+  this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
+
   this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE");
 
   return true;
 }
 
 
+std::string cmQtAutomoc::MakeCompileSettingsString(cmMakefile* makefile)
+{
+  std::string s;
+  s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS");
+  s += " ~~~ ";
+  s += makefile->GetSafeDefinition("AM_MOC_INCLUDES");
+  s += " ~~~ ";
+  s += makefile->GetSafeDefinition("AM_MOC_OPTIONS");
+  s += " ~~~ ";
+  s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE"
+                                                                     : "FALSE";
+  s += " ~~~ ";
+
+  return s;
+}
+
+
 bool cmQtAutomoc::ReadOldMocDefinitionsFile(cmMakefile* makefile,
                                             const char* targetDirectory)
 {
@@ -336,8 +434,8 @@ bool cmQtAutomoc::ReadOldMocDefinitionsFile(cmMakefile* makefile,
 
   if (makefile->ReadListFile(0, filename.c_str()))
     {
-    this->OldMocDefinitionsStr =
-                         makefile->GetSafeDefinition("AM_OLD_MOC_DEFINITIONS");
+    this->OldCompileSettingsStr =
+                        makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
     }
   return true;
 }
@@ -352,9 +450,9 @@ void cmQtAutomoc::WriteOldMocDefinitionsFile(const char* targetDirectory)
   std::fstream outfile;
   outfile.open(filename.c_str(),
                std::ios::out | std::ios::trunc);
-  outfile << "set(AM_OLD_MOC_DEFINITIONS "
+  outfile << "set(AM_OLD_COMPILE_SETTINGS "
               << cmLocalGenerator::EscapeForCMake(
-                       this->Join(this->MocDefinitions, ' ').c_str()) << ")\n";
+                 this->CurrentCompileSettingsStr.c_str()) << ")\n";
 
   outfile.close();
 }
@@ -368,32 +466,11 @@ void cmQtAutomoc::Init()
 
   std::vector<std::string> cdefList;
   cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
-  if (!cdefList.empty())
-    {
-    for(std::vector<std::string>::const_iterator it = cdefList.begin();
-        it != cdefList.end();
-        ++it)
-      {
-      this->MocDefinitions.push_back("-D" + (*it));
-      }
-    }
-  else
+  for(std::vector<std::string>::const_iterator it = cdefList.begin();
+      it != cdefList.end();
+      ++it)
     {
-    std::string tmpMocDefs = this->MocDefinitionsStr;
-    cmSystemTools::ReplaceString(tmpMocDefs, " ", ";");
-
-    std::vector<std::string> defList;
-    cmSystemTools::ExpandListArgument(tmpMocDefs, defList);
-
-    for(std::vector<std::string>::const_iterator it = defList.begin();
-        it != defList.end();
-        ++it)
-      {
-      if (this->StartsWith(*it, "-D"))
-        {
-        this->MocDefinitions.push_back(*it);
-        }
-      }
+    this->MocDefinitions.push_back("-D" + (*it));
     }
 
   cmSystemTools::ExpandListArgument(this->MocOptionsStr, this->MocOptions);
@@ -468,10 +545,10 @@ void cmQtAutomoc::Init()
 }
 
 
-bool cmQtAutomoc::RunAutomoc()
+bool cmQtAutomoc::RunAutomoc(cmMakefile* makefile)
 {
   if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str())
-    || (this->OldMocDefinitionsStr != this->Join(this->MocDefinitions, ' ')))
+    || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr))
     {
     this->GenerateAll = true;
     }
@@ -492,22 +569,8 @@ 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
+  const std::vector<std::string>& headerExtensions =
+                                               makefile->GetHeaderExtensions();
 
   for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
        it != sourceFiles.end();
@@ -607,7 +670,7 @@ bool cmQtAutomoc::RunAutomoc()
 
 
 void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
-                              const std::list<std::string>& headerExtensions,
+                              const std::vector<std::string>& headerExtensions,
                               std::map<std::string, std::string>& includedMocs)
 {
   cmsys::RegularExpression mocIncludeRegExp(
@@ -785,7 +848,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
 
 
 void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename,
-                              const std::list<std::string>& headerExtensions,
+                              const std::vector<std::string>& headerExtensions,
                               std::map<std::string, std::string>& includedMocs)
 {
   cmsys::RegularExpression mocIncludeRegExp(
@@ -896,8 +959,8 @@ void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename,
 
 
 void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename,
-                                const std::list<std::string>& headerExtensions,
-                                std::set<std::string>& absHeaders)
+                              const std::vector<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 =
@@ -905,22 +968,22 @@ void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename,
   const std::string absPath = cmsys::SystemTools::GetFilenamePath(
                    cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
 
-  for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
+  for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
       ext != headerExtensions.end();
       ++ext)
     {
-    const std::string headerName = absPath + basename + (*ext);
+    const std::string headerName = absPath + basename + "." + (*ext);
     if (cmsys::SystemTools::FileExists(headerName.c_str()))
       {
       absHeaders.insert(headerName);
       break;
       }
     }
-  for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
+  for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
       ext != headerExtensions.end();
       ++ext)
     {
-    const std::string privateHeaderName = absPath+basename+"_p"+(*ext);
+    const std::string privateHeaderName = absPath+basename+"_p."+(*ext);
     if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()))
       {
       absHeaders.insert(privateHeaderName);
@@ -1041,7 +1104,8 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile,
 }
 
 
-std::string cmQtAutomoc::Join(const std::list<std::string>& lst,char separator)
+std::string cmQtAutomoc::Join(const std::vector<std::string>& lst,
+                              char separator)
 {
     if (lst.empty())
       {
@@ -1049,11 +1113,11 @@ std::string cmQtAutomoc::Join(const std::list<std::string>& lst,char separator)
       }
 
     std::string result;
-    for (std::list<std::string>::const_iterator it = lst.begin();
+    for (std::vector<std::string>::const_iterator it = lst.begin();
          it != lst.end();
          ++it)
       {
-      result += (*it) + separator;
+      result += "." + (*it) + separator;
       }
     result.erase(result.end() - 1);
     return result;