Browse Source

Merge topic 'autogen-digests'

6739a125 Autogen: Doc: Add Visual Studio PRE_BUILD note to cmake-qt.rst
2be0acb7 Autogen: Tests: Add AUTOGEN_TARGET_DEPENDS test to mocDepends tests
734d236c Autogen: Smarter target dependency computation
2e4dab08 Autogen: Set CM_DISABLE_COPY in cmQtAutoGenerators
c330d641 Autogen: Replace CM_AUTO_PTR with std::unique_ptr
9468e926 Autogen: Refactor logging
2ba1b281 Autogen: More use of scoped lambdas
0f9080e2 Autogen: More use of scoped lambdas
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1198
Brad King 8 years ago
parent
commit
e5c1a7dfb3

+ 18 - 0
Help/manual/cmake-qt.7.rst

@@ -214,6 +214,24 @@ overrides options from the :prop_tgt:`AUTORCC_OPTIONS` target property.
 Source files can be excluded from :prop_tgt:`AUTORCC` processing by
 enabling :prop_sf:`SKIP_AUTORCC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 
+Visual Studio Generators
+========================
+
+When using the :manual:`Visual Studio generators <cmake-generators(7)>`
+CMake tries to use a ``PRE_BUILD``
+:command:`custom command <add_custom_command>` instead
+of a :command:`custom target <add_custom_target>` for autogen.
+``PRE_BUILD`` can't be used when the autogen target depends on files.
+This happens when
+
+- :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` is enabled and the origin target
+  depends on :prop_sf:`GENERATED` files which aren't excluded from autogen by
+  :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN`
+  or :policy:`CMP0071`
+- :prop_tgt:`AUTORCC` is enabled and a ``.qrc`` file is listed in
+  the origin target sources
+- :prop_tgt:`AUTOGEN_TARGET_DEPENDS` lists a source file
+
 qtmain.lib on Windows
 =====================
 

+ 4 - 3
Modules/AutogenInfo.cmake.in

@@ -9,6 +9,7 @@ set(AM_SOURCES @_sources@)
 set(AM_HEADERS @_headers@)
 # Qt environment
 set(AM_QT_VERSION_MAJOR @_qt_version_major@)
+set(AM_QT_VERSION_MINOR @_qt_version_minor@)
 set(AM_QT_MOC_EXECUTABLE @_qt_moc_executable@)
 set(AM_QT_UIC_EXECUTABLE @_qt_uic_executable@)
 set(AM_QT_RCC_EXECUTABLE @_qt_rcc_executable@)
@@ -28,7 +29,7 @@ set(AM_UIC_OPTIONS_FILES @_qt_uic_options_files@)
 set(AM_UIC_OPTIONS_OPTIONS @_qt_uic_options_options@)
 set(AM_UIC_SEARCH_PATHS @_uic_search_paths@)
 # RCC settings
-set(AM_RCC_SOURCES @_rcc_files@ )
+set(AM_RCC_SOURCES @_rcc_files@)
+set(AM_RCC_BUILDS @_rcc_builds@)
+set(AM_RCC_OPTIONS @_rcc_options@)
 set(AM_RCC_INPUTS @_rcc_inputs@)
-set(AM_RCC_OPTIONS_FILES @_rcc_options_files@)
-set(AM_RCC_OPTIONS_OPTIONS @_rcc_options_options@)

+ 3 - 2
Source/CMakeLists.txt

@@ -307,8 +307,9 @@ set(SRCS
   cmPropertyDefinitionMap.h
   cmPropertyMap.cxx
   cmPropertyMap.h
-  cmQtAutoGeneratorCommon.cxx
-  cmQtAutoGeneratorCommon.h
+  cmQtAutoGen.cxx
+  cmQtAutoGen.h
+  cmQtAutoGenDigest.h
   cmQtAutoGeneratorInitializer.cxx
   cmQtAutoGeneratorInitializer.h
   cmQtAutoGenerators.cxx

+ 37 - 37
Source/cmGlobalGenerator.cxx

@@ -1263,8 +1263,7 @@ bool cmGlobalGenerator::Compute()
 #ifdef CMAKE_BUILD_WITH_CMAKE
   // Iterate through all targets and set up automoc for those which have
   // the AUTOMOC, AUTOUIC or AUTORCC property set
-  std::vector<cmGeneratorTarget const*> autogenTargets =
-    this->CreateQtAutoGeneratorsTargets();
+  cmQtAutoGenDigestUPV autogenDigests = this->CreateQtAutoGeneratorsTargets();
 #endif
 
   unsigned int i;
@@ -1287,11 +1286,10 @@ bool cmGlobalGenerator::Compute()
   }
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
-  for (std::vector<cmGeneratorTarget const*>::iterator it =
-         autogenTargets.begin();
-       it != autogenTargets.end(); ++it) {
-    cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*it);
+  for (const cmQtAutoGenDigestUP& digest : autogenDigests) {
+    cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*digest);
   }
+  autogenDigests.clear();
 #endif
 
   for (i = 0; i < this->LocalGenerators.size(); ++i) {
@@ -1427,24 +1425,16 @@ bool cmGlobalGenerator::ComputeTargetDepends()
   return true;
 }
 
-std::vector<const cmGeneratorTarget*>
-cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
+cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
 {
-  std::vector<const cmGeneratorTarget*> autogenTargets;
+  cmQtAutoGenDigestUPV autogenDigests;
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
-  for (std::vector<cmLocalGenerator*>::const_iterator lgit =
-         this->LocalGenerators.begin();
-       lgit != this->LocalGenerators.end(); ++lgit) {
-    cmLocalGenerator* localGen = *lgit;
+  for (cmLocalGenerator* localGen : this->LocalGenerators) {
     const std::vector<cmGeneratorTarget*>& targets =
       localGen->GetGeneratorTargets();
     // Find targets that require AUTOGEN processing
-    std::vector<cmGeneratorTarget*> filteredTargets;
-    filteredTargets.reserve(targets.size());
-    for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
-         ti != targets.end(); ++ti) {
-      cmGeneratorTarget* target = *ti;
+    for (cmGeneratorTarget* target : targets) {
       if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
         continue;
       }
@@ -1455,33 +1445,43 @@ cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
           target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
         continue;
       }
-      if ((!target->GetPropertyAsBool("AUTOMOC") &&
-           !target->GetPropertyAsBool("AUTOUIC") &&
-           !target->GetPropertyAsBool("AUTORCC")) ||
-          target->IsImported()) {
+      if (target->IsImported()) {
         continue;
       }
-      // don't do anything if there is no Qt4 or Qt5Core (which contains moc)
-      cmMakefile* mf = target->Target->GetMakefile();
-      std::string qtMajorVersion = mf->GetSafeDefinition("QT_VERSION_MAJOR");
-      if (qtMajorVersion == "") {
-        qtMajorVersion = mf->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+
+      const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC");
+      const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC");
+      const bool rccEnabled = target->GetPropertyAsBool("AUTORCC");
+      if (!mocEnabled && !uicEnabled && !rccEnabled) {
+        continue;
       }
-      if (qtMajorVersion != "4" && qtMajorVersion != "5") {
+
+      std::string qtVersionMajor =
+        cmQtAutoGeneratorInitializer::GetQtMajorVersion(target);
+      // don't do anything if there is no Qt4 or Qt5Core (which contains moc)
+      if (qtVersionMajor != "4" && qtVersionMajor != "5") {
         continue;
       }
-      filteredTargets.push_back(target);
-    }
-    // Initialize AUTOGEN targets
-    for (std::vector<cmGeneratorTarget*>::iterator ti =
-           filteredTargets.begin();
-         ti != filteredTargets.end(); ++ti) {
-      cmQtAutoGeneratorInitializer::InitializeAutogenTarget(localGen, *ti);
-      autogenTargets.push_back(*ti);
+
+      {
+        cmQtAutoGenDigestUP digest(new cmQtAutoGenDigest(target));
+        digest->QtVersionMajor = std::move(qtVersionMajor);
+        digest->QtVersionMinor =
+          cmQtAutoGeneratorInitializer::GetQtMinorVersion(
+            target, digest->QtVersionMajor);
+        digest->MocEnabled = mocEnabled;
+        digest->UicEnabled = uicEnabled;
+        digest->RccEnabled = rccEnabled;
+        autogenDigests.emplace_back(std::move(digest));
+      }
     }
   }
+  // Initialize autogen targets
+  for (const cmQtAutoGenDigestUP& digest : autogenDigests) {
+    cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest);
+  }
 #endif
-  return autogenTargets;
+  return autogenDigests;
 }
 
 cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(

+ 3 - 1
Source/cmGlobalGenerator.h

@@ -15,6 +15,7 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmExportSetMap.h"
+#include "cmQtAutoGenDigest.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -422,7 +423,8 @@ protected:
 
   virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
 
-  std::vector<const cmGeneratorTarget*> CreateQtAutoGeneratorsTargets();
+  // Qt auto generators
+  cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets();
 
   std::string SelectMakeProgram(const std::string& makeProgram,
                                 const std::string& makeDefault = "") const;

+ 122 - 18
Source/cmQtAutoGeneratorCommon.cxx → Source/cmQtAutoGen.cxx

@@ -1,17 +1,79 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmQtAutoGeneratorCommon.h"
+#include "cmQtAutoGen.h"
 #include "cmAlgorithms.h"
 #include "cmSystemTools.h"
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include <algorithm>
 #include <sstream>
 #include <stddef.h>
 
+// - Static variables
+
+const std::string genNameGen = "AutoGen";
+const std::string genNameMoc = "AutoMoc";
+const std::string genNameUic = "AutoUic";
+const std::string genNameRcc = "AutoRcc";
+
 // - Static functions
 
+/// @brief Merges newOpts into baseOpts
+/// @arg valueOpts list of options that accept a value
+void MergeOptions(std::vector<std::string>& baseOpts,
+                  const std::vector<std::string>& newOpts,
+                  const std::vector<std::string>& valueOpts, bool isQt5)
+{
+  typedef std::vector<std::string>::iterator Iter;
+  typedef std::vector<std::string>::const_iterator CIter;
+  if (newOpts.empty()) {
+    return;
+  }
+  if (baseOpts.empty()) {
+    baseOpts = newOpts;
+    return;
+  }
+
+  std::vector<std::string> extraOpts;
+  for (CIter fit = newOpts.begin(), fitEnd = newOpts.end(); fit != fitEnd;
+       ++fit) {
+    const std::string& newOpt = *fit;
+    Iter existIt = std::find(baseOpts.begin(), baseOpts.end(), newOpt);
+    if (existIt != baseOpts.end()) {
+      if (newOpt.size() >= 2) {
+        // Acquire the option name
+        std::string optName;
+        {
+          auto oit = newOpt.begin();
+          if (*oit == '-') {
+            ++oit;
+            if (isQt5 && (*oit == '-')) {
+              ++oit;
+            }
+            optName.assign(oit, newOpt.end());
+          }
+        }
+        // Test if this is a value option and change the existing value
+        if (!optName.empty() && (std::find(valueOpts.begin(), valueOpts.end(),
+                                           optName) != valueOpts.end())) {
+          const Iter existItNext(existIt + 1);
+          const CIter fitNext(fit + 1);
+          if ((existItNext != baseOpts.end()) && (fitNext != fitEnd)) {
+            *existItNext = *fitNext;
+            ++fit;
+          }
+        }
+      }
+    } else {
+      extraOpts.push_back(newOpt);
+    }
+  }
+  // Append options
+  baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end());
+}
+
 static std::string utilStripCR(std::string const& line)
 {
   // Strip CR characters rcc may have printed (possibly more than one!).
@@ -40,8 +102,8 @@ static bool RccListInputsQt4(const std::string& fileName,
     } else {
       if (errorMessage != nullptr) {
         std::ostringstream ost;
-        ost << "AutoRcc: Error: Rcc file not readable:\n"
-            << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
+        ost << "rcc file not readable:\n"
+            << "  " << cmQtAutoGen::Quoted(fileName) << "\n";
         *errorMessage = ost.str();
       }
       allGood = false;
@@ -49,7 +111,7 @@ static bool RccListInputsQt4(const std::string& fileName,
   }
   if (allGood) {
     // qrc file directory
-    std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
+    std::string qrcDir(cmSystemTools::GetFilenamePath(fileName));
     if (!qrcDir.empty()) {
       qrcDir += '/';
     }
@@ -83,7 +145,7 @@ static bool RccListInputsQt5(const std::string& rccCommand,
                              std::string* errorMessage)
 {
   if (rccCommand.empty()) {
-    cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n");
+    cmSystemTools::Error("rcc executable not available");
     return false;
   }
 
@@ -122,7 +184,7 @@ static bool RccListInputsQt5(const std::string& rccCommand,
   if (!result || retVal) {
     if (errorMessage != nullptr) {
       std::ostringstream ost;
-      ost << "AutoRcc: Error: Rcc list process for " << fileName
+      ost << "rcc list process for " << cmQtAutoGen::Quoted(fileName)
           << " failed:\n"
           << rccStdOut << "\n"
           << rccStdErr << "\n";
@@ -155,8 +217,8 @@ static bool RccListInputsQt5(const std::string& rccCommand,
         if (pos == std::string::npos) {
           if (errorMessage != nullptr) {
             std::ostringstream ost;
-            ost << "AutoRcc: Error: Rcc lists unparsable output:\n"
-                << cmQtAutoGeneratorCommon::Quoted(eline) << "\n";
+            ost << "rcc lists unparsable output:\n"
+                << cmQtAutoGen::Quoted(eline) << "\n";
             *errorMessage = ost.str();
           }
           return false;
@@ -173,9 +235,29 @@ static bool RccListInputsQt5(const std::string& rccCommand,
 
 // - Class definitions
 
-const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@";
+const std::string cmQtAutoGen::listSep = "@LSEP@";
+
+const std::string& cmQtAutoGen::GeneratorName(GeneratorType type)
+{
+  switch (type) {
+    case GeneratorType::GEN:
+      return genNameGen;
+    case GeneratorType::MOC:
+      return genNameMoc;
+    case GeneratorType::UIC:
+      return genNameUic;
+    case GeneratorType::RCC:
+      return genNameRcc;
+  }
+  return genNameGen;
+}
+
+std::string cmQtAutoGen::GeneratorNameUpper(GeneratorType genType)
+{
+  return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType));
+}
 
-std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text)
+std::string cmQtAutoGen::Quoted(const std::string& text)
 {
   static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
                                  "\b", "\\b",  "\f", "\\f",  "\n", "\\n",
@@ -191,14 +273,36 @@ std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text)
   return res;
 }
 
-bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion,
-                                            const std::string& rccCommand,
-                                            const std::string& fileName,
-                                            std::vector<std::string>& files,
-                                            std::string* errorMessage)
+void cmQtAutoGen::UicMergeOptions(std::vector<std::string>& baseOpts,
+                                  const std::vector<std::string>& newOpts,
+                                  bool isQt5)
+{
+  static const std::vector<std::string> valueOpts = {
+    "tr",      "translate", "postfix", "generator",
+    "include", // Since Qt 5.3
+    "g"
+  };
+  MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+}
+
+void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
+                                  const std::vector<std::string>& newOpts,
+                                  bool isQt5)
+{
+  static const std::vector<std::string> valueOpts = { "name", "root",
+                                                      "compress",
+                                                      "threshold" };
+  MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+}
+
+bool cmQtAutoGen::RccListInputs(const std::string& qtMajorVersion,
+                                const std::string& rccCommand,
+                                const std::string& fileName,
+                                std::vector<std::string>& files,
+                                std::string* errorMessage)
 {
   bool allGood = false;
-  if (cmsys::SystemTools::FileExists(fileName.c_str())) {
+  if (cmSystemTools::FileExists(fileName.c_str())) {
     if (qtMajorVersion == "4") {
       allGood = RccListInputsQt4(fileName, files, errorMessage);
     } else {
@@ -207,8 +311,8 @@ bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion,
   } else {
     if (errorMessage != nullptr) {
       std::ostringstream ost;
-      ost << "AutoRcc: Error: Rcc file does not exist:\n"
-          << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
+      ost << "rcc file does not exist:\n"
+          << "  " << cmQtAutoGen::Quoted(fileName) << "\n";
       *errorMessage = ost.str();
     }
   }

+ 23 - 5
Source/cmQtAutoGeneratorCommon.h → Source/cmQtAutoGen.h

@@ -1,31 +1,49 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmQtAutoGeneratorCommon_h
-#define cmQtAutoGeneratorCommon_h
+#ifndef cmQtAutoGen_h
+#define cmQtAutoGen_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <string>
 #include <vector>
 
-class cmQtAutoGeneratorCommon
+/** \class cmQtAutoGen
+ * \brief Class used as namespace for QtAutogen related types  and functions
+ */
+class cmQtAutoGen
 {
-  // - Types and statics
 public:
-  static const char* listSep;
+  static const std::string listSep;
 
   enum GeneratorType
   {
+    GEN, // General
     MOC,
     UIC,
     RCC
   };
 
 public:
+  /// @brief Returns the generator name
+  static const std::string& GeneratorName(GeneratorType genType);
+  /// @brief Returns the generator name in upper case
+  static std::string GeneratorNameUpper(GeneratorType genType);
+
   /// @brief Returns a the string escaped and enclosed in quotes
   ///
   static std::string Quoted(const std::string& text);
 
+  /// @brief Merges newOpts into baseOpts
+  static void UicMergeOptions(std::vector<std::string>& baseOpts,
+                              const std::vector<std::string>& newOpts,
+                              bool isQt5);
+
+  /// @brief Merges newOpts into baseOpts
+  static void RccMergeOptions(std::vector<std::string>& baseOpts,
+                              const std::vector<std::string>& newOpts,
+                              bool isQt5);
+
   /// @brief Reads the resource files list from from a .qrc file
   /// @arg fileName Must be the absolute path of the .qrc file
   /// @return True if the rcc file was successfully parsed

+ 64 - 0
Source/cmQtAutoGenDigest.h

@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmQtAutoGenDigest_h
+#define cmQtAutoGenDigest_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmGeneratorTarget;
+
+class cmQtAutoGenDigestQrc
+{
+public:
+  cmQtAutoGenDigestQrc()
+    : Generated(false)
+    , Unique(false)
+  {
+  }
+
+public:
+  std::string QrcFile;
+  std::string QrcName;
+  std::string PathChecksum;
+  std::string RccFile;
+  bool Generated;
+  bool Unique;
+  std::vector<std::string> Options;
+  std::vector<std::string> Resources;
+};
+
+/** \class cmQtAutoGenDigest
+ * \brief Filtered set of QtAutogen variables for a specific target
+ */
+class cmQtAutoGenDigest
+{
+public:
+  cmQtAutoGenDigest(cmGeneratorTarget* target)
+    : Target(target)
+    , MocEnabled(false)
+    , UicEnabled(false)
+    , RccEnabled(false)
+  {
+  }
+
+public:
+  cmGeneratorTarget* Target;
+  std::string QtVersionMajor;
+  std::string QtVersionMinor;
+  bool MocEnabled;
+  bool UicEnabled;
+  bool RccEnabled;
+  std::vector<std::string> Headers;
+  std::vector<std::string> Sources;
+  std::vector<cmQtAutoGenDigestQrc> Qrcs;
+};
+
+// Utility types
+typedef std::unique_ptr<cmQtAutoGenDigest> cmQtAutoGenDigestUP;
+typedef std::vector<cmQtAutoGenDigestUP> cmQtAutoGenDigestUPV;
+
+#endif

File diff suppressed because it is too large
+ 418 - 433
Source/cmQtAutoGeneratorInitializer.cxx


+ 9 - 4
Source/cmQtAutoGeneratorInitializer.h

@@ -4,16 +4,21 @@
 #define cmQtAutoGeneratorInitializer_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
+#include "cmQtAutoGenDigest.h"
+
+#include <string>
 
 class cmGeneratorTarget;
-class cmLocalGenerator;
 
 class cmQtAutoGeneratorInitializer
 {
 public:
-  static void InitializeAutogenTarget(cmLocalGenerator* localGen,
-                                      cmGeneratorTarget* target);
-  static void SetupAutoGenerateTarget(cmGeneratorTarget const* target);
+  static std::string GetQtMajorVersion(cmGeneratorTarget const* target);
+  static std::string GetQtMinorVersion(cmGeneratorTarget const* target,
+                                       const std::string& qtVersionMajor);
+
+  static void InitializeAutogenTarget(cmQtAutoGenDigest& digest);
+  static void SetupAutoGenerateTarget(cmQtAutoGenDigest const& digest);
 };
 
 #endif

File diff suppressed because it is too large
+ 319 - 382
Source/cmQtAutoGenerators.cxx


+ 65 - 27
Source/cmQtAutoGenerators.h

@@ -6,18 +6,19 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmFilePathChecksum.h"
+#include "cmQtAutoGen.h"
 #include "cmsys/RegularExpression.hxx"
 
 #include <map>
 #include <set>
 #include <string>
-#include <utility>
 #include <vector>
 
 class cmMakefile;
 
 class cmQtAutoGenerators
 {
+  CM_DISABLE_COPY(cmQtAutoGenerators)
 public:
   cmQtAutoGenerators();
   bool Run(const std::string& targetDirectory, const std::string& config);
@@ -25,13 +26,35 @@ public:
 private:
   // -- Types
 
-  /// @brief Used to extract additional dependencies from content text
-  struct MocDependFilter
+  /// @brief Search key plus regular expression pair
+  struct KeyRegExp
   {
-    std::string key;
-    cmsys::RegularExpression regExp;
+    KeyRegExp() = default;
+
+    KeyRegExp(const char* key, const char* regExp)
+      : Key(key)
+      , RegExp(regExp)
+    {
+    }
+
+    KeyRegExp(const std::string& key, const std::string& regExp)
+      : Key(key)
+      , RegExp(regExp)
+    {
+    }
+
+    std::string Key;
+    cmsys::RegularExpression RegExp;
+  };
+
+  /// @brief RCC job
+  struct RccJob
+  {
+    std::string QrcFile;
+    std::string RccFile;
+    std::vector<std::string> Options;
+    std::vector<std::string> Inputs;
   };
-  typedef std::pair<std::string, cmsys::RegularExpression> MocMacroFilter;
 
   // -- Configuration
   bool MocDependFilterPush(const std::string& key, const std::string& regExp);
@@ -90,6 +113,9 @@ private:
     const std::string& fileName, const std::string& contentText,
     std::map<std::string, std::vector<std::string>>& includedUis);
 
+  std::string MocMacroNamesString() const;
+  std::string MocHeaderSuffixesString() const;
+
   bool MocParseSourceContent(
     const std::string& absFilename, const std::string& contentText,
     std::map<std::string, std::string>& mocsIncluded,
@@ -122,18 +148,31 @@ private:
 
   // -- Rcc file generation
   bool RccGenerateAll();
-  bool RccGenerateFile(const std::string& qrcInputFile,
-                       const std::string& qrcOutputFile, bool unique_n);
+  bool RccGenerateFile(const RccJob& rccJob);
 
-  // -- Logging
-  void LogErrorNameCollision(
-    const std::string& message,
-    const std::multimap<std::string, std::string>& collisions) const;
+  // -- Log info
   void LogBold(const std::string& message) const;
-  void LogInfo(const std::string& message) const;
-  void LogWarning(const std::string& message) const;
-  void LogError(const std::string& message) const;
-  void LogCommand(const std::vector<std::string>& command) const;
+  void LogInfo(cmQtAutoGen::GeneratorType genType,
+               const std::string& message) const;
+  // -- Log warning
+  void LogWarning(cmQtAutoGen::GeneratorType genType,
+                  const std::string& message) const;
+  void LogFileWarning(cmQtAutoGen::GeneratorType genType,
+                      const std::string& filename,
+                      const std::string& message) const;
+  // -- Log error
+  void LogError(cmQtAutoGen::GeneratorType genType,
+                const std::string& message) const;
+  void LogFileError(cmQtAutoGen::GeneratorType genType,
+                    const std::string& filename,
+                    const std::string& message) const;
+  void LogCommandError(cmQtAutoGen::GeneratorType genType,
+                       const std::string& message,
+                       const std::vector<std::string>& command,
+                       const std::string& output) const;
+  void LogNameCollisionError(
+    cmQtAutoGen::GeneratorType genType, const std::string& message,
+    const std::multimap<std::string, std::string>& collisions) const;
 
   // -- Utility
   bool NameCollisionTest(
@@ -142,14 +181,14 @@ private:
   std::string ChecksumedPath(const std::string& sourceFile,
                              const std::string& basePrefix,
                              const std::string& baseSuffix) const;
-  bool MakeParentDirectory(const char* logPrefix,
+  bool MakeParentDirectory(cmQtAutoGen::GeneratorType genType,
                            const std::string& filename) const;
   bool FileDiffers(const std::string& filename, const std::string& content);
-  bool FileWrite(const char* logPrefix, const std::string& filename,
-                 const std::string& content);
+  bool FileWrite(cmQtAutoGen::GeneratorType genType,
+                 const std::string& filename, const std::string& content);
 
-  bool RunCommand(const std::vector<std::string>& command, std::string& output,
-                  bool verbose = true) const;
+  bool RunCommand(const std::vector<std::string>& command,
+                  std::string& output) const;
 
   bool FindHeader(std::string& header, const std::string& testBasePath) const;
 
@@ -169,6 +208,7 @@ private:
   std::string AutogenIncludeDir;
   // -- Qt environment
   std::string QtMajorVersion;
+  std::string QtMinorVersion;
   std::string MocExecutable;
   std::string UicExecutable;
   std::string RccExecutable;
@@ -200,23 +240,21 @@ private:
   std::vector<std::string> MocDefinitions;
   std::vector<std::string> MocOptions;
   std::vector<std::string> MocPredefsCmd;
-  std::vector<MocDependFilter> MocDependFilters;
-  std::vector<MocMacroFilter> MocMacroFilters;
+  std::vector<KeyRegExp> MocDependFilters;
+  std::vector<KeyRegExp> MocMacroFilters;
   cmsys::RegularExpression MocRegExpInclude;
   // -- Uic
   bool UicSettingsChanged;
   bool UicRunFailed;
   std::vector<std::string> UicSkipList;
   std::vector<std::string> UicTargetOptions;
-  std::map<std::string, std::string> UicOptions;
+  std::map<std::string, std::vector<std::string>> UicOptions;
   std::vector<std::string> UicSearchPaths;
   cmsys::RegularExpression UicRegExpInclude;
   // -- Rcc
   bool RccSettingsChanged;
   bool RccRunFailed;
-  std::vector<std::string> RccSources;
-  std::map<std::string, std::string> RccOptions;
-  std::map<std::string, std::vector<std::string>> RccInputs;
+  std::vector<RccJob> RccJobs;
 };
 
 #endif

+ 98 - 42
Tests/QtAutogen/mocDepends/CMakeLists.txt

@@ -15,81 +15,137 @@ else()
 endif()
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
 
-# -- Test 1: Depend on generated header
+# -- Test dependency on header generated by a custom command
+#
 # The ORIGIN_autogen target must depend on the same *GENERATED* source files as
 # the ORIGIN target. This is a requirement to ensure that all files for the
 # ORIGIN target are generated before the ORIGIN_autogen target is built.
 #
-# This tests the dependency of the mocDepends1_autogen target of mocDepends1
-# to the source file test1_object.hpp, which is *GENERATED* by a custom command.
-# If mocDepends1_autogen gets built *before* or in *parallel* to the
-# custom command, the build will fail. That's because test1_object.hpp,
-# which is required by mocDepends1_autogen, is only valid after the
+# This tests the dependency of the mocDepGenFile_autogen target of
+# mocDepGenFile to the source file GenFile.hpp, which is *GENERATED*
+# by a custom command.
+# If mocDepGenFile_autogen gets built *before* or in *parallel* to the
+# custom command, the build will fail. That's because GenFile.hpp,
+# which is required by mocDepGenFile_autogen, is only valid after the
 # custom command has been completed.
 #
 # The sleep seconds artificially increase the build time of the custom command
 # to simulate a slow file generation process that takes longer to run than
-# the build of the mocDepends1_autogen target.
+# the build of the mocDepGenFile_autogen target.
 add_custom_command(
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test1_object.hpp
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/test1_object.hpp
+  OUTPUT ${CBD}/GenFile.hpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/GenFile.hpp
   COMMAND ${CMAKE_COMMAND} -E sleep 3
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/object.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/test1_object.hpp)
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/GenFile.hpp)
+
+add_executable(mocDepGenFile testGenFile.cpp ${CBD}/GenFile.hpp)
+target_link_libraries(mocDepGenFile ${QT_CORE_TARGET})
+set_target_properties(mocDepGenFile PROPERTIES AUTOMOC TRUE)
 
-add_executable(mocDepends1 test1.cpp ${CMAKE_CURRENT_BINARY_DIR}/test1_object.hpp)
-target_link_libraries(mocDepends1 ${QT_CORE_TARGET})
-set_target_properties(mocDepends1 PROPERTIES AUTOMOC TRUE)
 
-# -- Test 2: Depend on header generating target
+# -- Test dependency on header generating custom target
+#
 # The ORIGIN_autogen target must depend on the same user defined targets
 # as the ORIGIN target. This is a requirement to ensure that all files for the
 # ORIGIN target are generated before the ORIGIN_autogen target is built.
 #
-# This tests the dependency of the mocDepends2_autogen target of mocDepends2
-# to the utility target mocDepends2Object. If mocDepends2_autogen gets built
-# *before* or in *parallel* to mocDepends2Object, the build will fail. That's
-# because test2_object.hpp, which is required by mocDepends2_autogen,
-# is only valid after the mocDepends2Object build has been completed.
+# This tests the dependency of the mocDepTarget_autogen target of
+# mocDepTarget to the utility target mocDepTargetUtil.
+# If mocDepTarget_autogen gets built *before* or in *parallel* to
+# mocDepTargetUtil, the build will fail. That's
+# because GenTarget.hpp, which is required by mocDepTarget_autogen,
+# is only valid after the mocDepTargetUtil build has been completed.
 #
-# The sleep seconds artificially increase the build time of mocDepends2Object
+# The sleep seconds artificially increase the build time of mocDepTargetUtil
 # to simulate a slow utility target build that takes longer to run than
-# the build of the mocDepends2_autogen target.
-add_custom_target(mocDepends2Object
-  BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/test2_object.hpp
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/test2_object.hpp
+# the build of the mocDepTarget_autogen target.
+add_custom_target(mocDepTargetUtil
+  BYPRODUCTS ${CBD}/GenTarget.hpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/GenTarget.hpp
   COMMAND ${CMAKE_COMMAND} -E sleep 3
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/object.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/test2_object.hpp)
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/GenTarget.hpp)
+
+add_executable(mocDepTarget testGenTarget.cpp)
+target_link_libraries(mocDepTarget ${QT_CORE_TARGET})
+set_target_properties(mocDepTarget PROPERTIES AUTOMOC TRUE)
+add_dependencies(mocDepTarget mocDepTargetUtil)
 
-add_executable(mocDepends2 test2.cpp)
-target_link_libraries(mocDepends2 ${QT_CORE_TARGET})
-set_target_properties(mocDepends2 PROPERTIES AUTOMOC TRUE)
-add_dependencies(mocDepends2 mocDepends2Object)
 
 # -- Test 3: Depend on generated linked library
 # The ORIGIN_autogen target must depend on the same linked libraries
 # as the ORIGIN target. This is a requirement to ensure that all files for the
 # ORIGIN target are generated before the ORIGIN_autogen target is built.
 #
-# This tests the dependency of the mocDepends3_autogen target of mocDepends3
-# to the user generated library SimpleLib, which mocDepends3 links to.
-# If mocDepends3_autogen gets built *before* or in *parallel* to SimpleLib,
+# This tests the dependency of the mocDepGenLib_autogen target of mocDepGenLib
+# to the user generated library SimpleLib, which mocDepGenLib links to.
+# If mocDepGenLib_autogen gets built *before* or in *parallel* to SimpleLib,
 # the build will fail. That's because simpleLib.hpp, which is required by
-# mocDepends3_autogen, is only valid after the SimpleLib build has been
+# mocDepGenLib_autogen, is only valid after the SimpleLib build has been
 # completed.
 #
 # The sleep seconds artificially increase the build time of SimpleLib
 # to simulate a slow utility library build that takes longer to run than
-# the build of the mocDepends3_autogen target.
+# the build of the mocDepGenLib_autogen target.
 add_custom_command(
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.cpp
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp
+  OUTPUT ${CBD}/simpleLib.hpp ${CBD}/simpleLib.cpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/simpleLib.hpp
   COMMAND ${CMAKE_COMMAND} -E sleep 3
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.cpp)
-add_library(SimpleLib STATIC ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.cpp)
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/simpleLib.hpp.in ${CBD}/simpleLib.hpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/simpleLib.cpp.in ${CBD}/simpleLib.cpp)
+add_library(SimpleLib STATIC ${CBD}/simpleLib.hpp ${CBD}/simpleLib.cpp)
 target_link_libraries(SimpleLib ${QT_CORE_TARGET})
 
-add_executable(mocDepends3 test3.cpp)
-target_link_libraries(mocDepends3 SimpleLib ${QT_CORE_TARGET})
-set_target_properties(mocDepends3 PROPERTIES AUTOMOC TRUE)
+add_executable(mocDepGenLib testGenLib.cpp)
+target_link_libraries(mocDepGenLib SimpleLib ${QT_CORE_TARGET})
+set_target_properties(mocDepGenLib PROPERTIES AUTOMOC TRUE)
+
+
+# -- Test AUTOGEN_TARGET_DEPENDS with GENERATED file dependency
+#
+# This tests the dependency of the mocDepATDFile_autogen target of
+# mocDepATDTarget to the utility target mocDepATDFileUtil.
+# If mocDepATDFile_autogen gets built *before* or in *parallel* to
+# mocDepATDFileUtil, the build will fail. That's
+# because ATDFile.hpp, which is required by mocDepATDFile_autogen,
+# is only valid after the mocDepATDFileUtil build has been completed.
+#
+# The sleep seconds artificially increase the build time of
+# mocDepATDFileUtil to simulate a slow utility target build that takes
+# longer to run than the build of the mocDepATDFile_autogen target.
+add_custom_command(
+  OUTPUT ${CBD}/ATDFile.hpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/ATDFile.hpp
+  COMMAND ${CMAKE_COMMAND} -E sleep 3
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/ATDFile.hpp)
+
+add_executable(mocDepATDFile testATDFile.cpp)
+target_link_libraries(mocDepATDFile ${QT_CORE_TARGET})
+set_target_properties(mocDepATDFile PROPERTIES AUTOMOC TRUE)
+set_target_properties(mocDepATDFile PROPERTIES AUTOGEN_TARGET_DEPENDS ${CBD}/ATDFile.hpp)
+
+
+# -- Test AUTOGEN_TARGET_DEPENDS with target dependency
+#
+# This tests the dependency of the mocDepATDTarget_autogen target of
+# mocDepATDTarget to the utility target mocDepATDTargetUtil.
+# If mocDepATDTarget_autogen gets built *before* or in *parallel* to
+# mocDepATDTargetUtil, the build will fail. That's
+# because ATDTarget.hpp, which is required by mocDepATDTarget_autogen,
+# is only valid after the mocDepATDTargetUtil build has been completed.
+#
+# The sleep seconds artificially increase the build time of
+# mocDepATDTargetUtil to simulate a slow utility target build that takes
+# longer to run than the build of the mocDepATDTarget_autogen target.
+add_custom_target(mocDepATDTargetUtil
+  BYPRODUCTS ${CBD}/ATDTarget.hpp
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/ATDTarget.hpp
+  COMMAND ${CMAKE_COMMAND} -E sleep 3
+  COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/ATDTarget.hpp)
+
+add_executable(mocDepATDTarget testATDTarget.cpp)
+target_link_libraries(mocDepATDTarget ${QT_CORE_TARGET})
+set_target_properties(mocDepATDTarget PROPERTIES AUTOMOC TRUE)
+set_target_properties(mocDepATDTarget PROPERTIES AUTOGEN_TARGET_DEPENDS mocDepATDTargetUtil)

+ 0 - 0
Tests/QtAutogen/mocDepends/invalid.hpp.in → Tests/QtAutogen/mocDepends/object_invalid.hpp.in


+ 0 - 0
Tests/QtAutogen/mocDepends/object.hpp.in → Tests/QtAutogen/mocDepends/object_valid.hpp.in


+ 0 - 9
Tests/QtAutogen/mocDepends/test2.cpp

@@ -1,9 +0,0 @@
-
-#include "moc_test2_object.cpp"
-#include "test2_object.hpp"
-
-int main()
-{
-  Object obj;
-  return 0;
-}

+ 9 - 0
Tests/QtAutogen/mocDepends/testATDFile.cpp

@@ -0,0 +1,9 @@
+
+#include "ATDFile.hpp"
+#include "moc_ATDFile.cpp"
+
+int main()
+{
+  Object obj;
+  return 0;
+}

+ 9 - 0
Tests/QtAutogen/mocDepends/testATDTarget.cpp

@@ -0,0 +1,9 @@
+
+#include "ATDTarget.hpp"
+#include "moc_ATDTarget.cpp"
+
+int main()
+{
+  Object obj;
+  return 0;
+}

+ 1 - 1
Tests/QtAutogen/mocDepends/test1.cpp → Tests/QtAutogen/mocDepends/testGenFile.cpp

@@ -1,5 +1,5 @@
 
-#include "test1_object.hpp"
+#include "GenFile.hpp"
 
 int main()
 {

+ 2 - 2
Tests/QtAutogen/mocDepends/test3.cpp → Tests/QtAutogen/mocDepends/testGenLib.cpp

@@ -1,5 +1,5 @@
 
-#include "test3.hpp"
+#include "testGenLib.hpp"
 
 int main()
 {
@@ -8,5 +8,5 @@ int main()
   return 0;
 }
 
-// AUTOMOC the SimpleLib header simpleLib.hpp
+// Depend on and AUTOMOC the SimpleLib header simpleLib.hpp
 #include "moc_simpleLib.cpp"

+ 0 - 0
Tests/QtAutogen/mocDepends/test3.hpp → Tests/QtAutogen/mocDepends/testGenLib.hpp


+ 9 - 0
Tests/QtAutogen/mocDepends/testGenTarget.cpp

@@ -0,0 +1,9 @@
+
+#include "GenTarget.hpp"
+#include "moc_GenTarget.cpp"
+
+int main()
+{
+  Object obj;
+  return 0;
+}

Some files were not shown because too many files changed in this diff