Przeglądaj źródła

Merge topic 'autogen-rcc-custom-command'

40434631 Autogen: Use integers instead of strings for the Qt version
be11a852 Autogen: Use project relative paths in rcc custom command comment
ab9d5896 Autogen: Detect rcc feature once during configuration
2a85b5ac Autogen: Make cmQtAutoGeneratorInitializer an instantiable class
75819b86 Autogen: Add and use cmQtAutoGenerator base class
27ed3b35 Autogen: Rename cmQtAutoGenerators to cmQtAutoGeneratorMocUic
1cd285fe Autogen: Remove rcc code from cmQtAutoGenerators
a87f82e0 Autogen: Switch to use custom commands for RCC
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1494
Brad King 8 lat temu
rodzic
commit
08ce62bee5

+ 11 - 0
Modules/AutoRccInfo.cmake.in

@@ -0,0 +1,11 @@
+# Meta
+set(ARCC_MULTI_CONFIG @_multi_config@)
+# Directories and files
+set(ARCC_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
+set(ARCC_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
+set(ARCC_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/")
+set(ARCC_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
+set(ARCC_BUILD_DIR @_build_dir@)
+# Qt environment
+set(ARCC_RCC_EXECUTABLE @_qt_rcc_executable@)
+set(ARCC_RCC_LIST_OPTIONS @_qt_rcc_list_options@)

+ 1 - 7
Modules/AutogenInfo.cmake.in

@@ -9,12 +9,11 @@ set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJ
 set(AM_BUILD_DIR @_build_dir@)
 set(AM_SOURCES @_sources@)
 set(AM_HEADERS @_headers@)
+set(AM_SETTINGS_FILE @_settings_file@)
 # 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@)
 # MOC settings
 set(AM_MOC_SKIP @_moc_skip@)
 set(AM_MOC_DEFINITIONS @_moc_compile_defs@)
@@ -30,8 +29,3 @@ set(AM_UIC_TARGET_OPTIONS @_uic_target_options@)
 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_BUILDS @_rcc_builds@)
-set(AM_RCC_OPTIONS @_rcc_options@)
-set(AM_RCC_INPUTS @_rcc_inputs@)

+ 6 - 3
Source/CMakeLists.txt

@@ -311,11 +311,14 @@ set(SRCS
   cmPropertyMap.h
   cmQtAutoGen.cxx
   cmQtAutoGen.h
-  cmQtAutoGenDigest.h
+  cmQtAutoGenerator.cxx
+  cmQtAutoGenerator.h
   cmQtAutoGeneratorInitializer.cxx
   cmQtAutoGeneratorInitializer.h
-  cmQtAutoGenerators.cxx
-  cmQtAutoGenerators.h
+  cmQtAutoGeneratorMocUic.cxx
+  cmQtAutoGeneratorMocUic.h
+  cmQtAutoGeneratorRcc.cxx
+  cmQtAutoGeneratorRcc.h
   cmRST.cxx
   cmRST.h
   cmScriptGenerator.h

+ 14 - 22
Source/cmGlobalGenerator.cxx

@@ -1314,7 +1314,10 @@ 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
-  cmQtAutoGenDigestUPV autogenDigests = this->CreateQtAutoGeneratorsTargets();
+  auto autogenInits = this->CreateQtAutoGenInitializers();
+  for (auto& autoGen : autogenInits) {
+    autoGen->InitCustomTargets();
+  }
 #endif
 
   // Add generator specific helper commands
@@ -1335,10 +1338,11 @@ bool cmGlobalGenerator::Compute()
   }
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
-  for (cmQtAutoGenDigestUP const& digest : autogenDigests) {
-    cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*digest);
+  for (auto& autoGen : autogenInits) {
+    autoGen->SetupCustomTargets();
+    autoGen.reset(nullptr);
   }
-  autogenDigests.clear();
+  autogenInits.clear();
 #endif
 
   for (cmLocalGenerator* localGen : this->LocalGenerators) {
@@ -1469,9 +1473,10 @@ bool cmGlobalGenerator::ComputeTargetDepends()
   return true;
 }
 
-cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
+std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
+cmGlobalGenerator::CreateQtAutoGenInitializers()
 {
-  cmQtAutoGenDigestUPV autogenDigests;
+  std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> autogenInits;
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
   for (cmLocalGenerator* localGen : this->LocalGenerators) {
@@ -1507,25 +1512,12 @@ cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
         continue;
       }
 
-      {
-        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));
-      }
+      autogenInits.emplace_back(new cmQtAutoGeneratorInitializer(
+        target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor));
     }
   }
-  // Initialize autogen targets
-  for (const cmQtAutoGenDigestUP& digest : autogenDigests) {
-    cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest);
-  }
 #endif
-  return autogenDigests;
+  return autogenInits;
 }
 
 cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(

+ 3 - 2
Source/cmGlobalGenerator.h

@@ -15,7 +15,6 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmExportSetMap.h"
-#include "cmQtAutoGenDigest.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -33,6 +32,7 @@ class cmLinkLineComputer;
 class cmLocalGenerator;
 class cmMakefile;
 class cmOutputConverter;
+class cmQtAutoGeneratorInitializer;
 class cmSourceFile;
 class cmStateDirectory;
 class cmake;
@@ -433,7 +433,8 @@ protected:
   virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
 
   // Qt auto generators
-  cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets();
+  std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
+  CreateQtAutoGenInitializers();
 
   std::string SelectMakeProgram(const std::string& makeProgram,
                                 const std::string& makeDefault = "") const;

+ 38 - 53
Source/cmQtAutoGen.cxx

@@ -80,16 +80,6 @@ void MergeOptions(std::vector<std::string>& baseOpts,
   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!).
-  std::string::size_type cr = line.find('\r');
-  if (cr != std::string::npos) {
-    return line.substr(0, cr);
-  }
-  return line;
-}
-
 /// @brief Reads the resource files list from from a .qrc file - Qt4 version
 /// @return True if the .qrc file was successfully parsed
 static bool RccListInputsQt4(std::string const& fileName,
@@ -107,10 +97,10 @@ static bool RccListInputsQt4(std::string const& fileName,
       qrcContents = osst.str();
     } else {
       if (errorMessage != nullptr) {
-        std::ostringstream ost;
-        ost << "rcc file not readable:\n"
-            << "  " << cmQtAutoGen::Quoted(fileName) << "\n";
-        *errorMessage = ost.str();
+        std::string& err = *errorMessage;
+        err = "rcc file not readable:\n  ";
+        err += cmQtAutoGen::Quoted(fileName);
+        err += "\n";
       }
       allGood = false;
     }
@@ -146,6 +136,7 @@ static bool RccListInputsQt4(std::string const& fileName,
 /// @brief Reads the resource files list from from a .qrc file - Qt5 version
 /// @return True if the .qrc file was successfully parsed
 static bool RccListInputsQt5(std::string const& rccCommand,
+                             std::vector<std::string> const& rccListOptions,
                              std::string const& fileName,
                              std::vector<std::string>& files,
                              std::string* errorMessage)
@@ -155,24 +146,6 @@ static bool RccListInputsQt5(std::string const& rccCommand,
     return false;
   }
 
-  // Read rcc features
-  bool hasDashDashList = false;
-  {
-    std::vector<std::string> command;
-    command.push_back(rccCommand);
-    command.push_back("--help");
-    std::string rccStdOut;
-    std::string rccStdErr;
-    int retVal = 0;
-    bool result = cmSystemTools::RunSingleCommand(
-      command, &rccStdOut, &rccStdErr, &retVal, nullptr,
-      cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
-    if (result && retVal == 0 &&
-        rccStdOut.find("--list") != std::string::npos) {
-      hasDashDashList = true;
-    }
-  }
-
   std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
   std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
 
@@ -184,7 +157,8 @@ static bool RccListInputsQt5(std::string const& rccCommand,
   {
     std::vector<std::string> command;
     command.push_back(rccCommand);
-    command.push_back(hasDashDashList ? "--list" : "-list");
+    command.insert(command.end(), rccListOptions.begin(),
+                   rccListOptions.end());
     command.push_back(fileNameName);
     result = cmSystemTools::RunSingleCommand(
       command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
@@ -192,22 +166,32 @@ static bool RccListInputsQt5(std::string const& rccCommand,
   }
   if (!result || retVal) {
     if (errorMessage != nullptr) {
-      std::ostringstream ost;
-      ost << "rcc list process failed for\n  " << cmQtAutoGen::Quoted(fileName)
-          << "\n"
-          << rccStdOut << "\n"
-          << rccStdErr << "\n";
-      *errorMessage = ost.str();
+      std::string& err = *errorMessage;
+      err = "rcc list process failed for:\n  ";
+      err += cmQtAutoGen::Quoted(fileName);
+      err += "\n";
+      err += rccStdOut;
+      err += "\n";
+      err += rccStdErr;
+      err += "\n";
     }
     return false;
   }
 
+  // Lambda to strip CR characters
+  auto StripCR = [](std::string& line) {
+    std::string::size_type cr = line.find('\r');
+    if (cr != std::string::npos) {
+      line = line.substr(0, cr);
+    }
+  };
+
   // Parse rcc std output
   {
     std::istringstream ostr(rccStdOut);
     std::string oline;
     while (std::getline(ostr, oline)) {
-      oline = utilStripCR(oline);
+      StripCR(oline);
       if (!oline.empty()) {
         files.push_back(oline);
       }
@@ -218,17 +202,17 @@ static bool RccListInputsQt5(std::string const& rccCommand,
     std::istringstream estr(rccStdErr);
     std::string eline;
     while (std::getline(estr, eline)) {
-      eline = utilStripCR(eline);
+      StripCR(eline);
       if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
         static std::string searchString = "Cannot find file '";
 
         std::string::size_type pos = eline.find(searchString);
         if (pos == std::string::npos) {
           if (errorMessage != nullptr) {
-            std::ostringstream ost;
-            ost << "rcc lists unparsable output:\n"
-                << cmQtAutoGen::Quoted(eline) << "\n";
-            *errorMessage = ost.str();
+            std::string& err = *errorMessage;
+            err = "rcc lists unparsable output:\n";
+            err += cmQtAutoGen::Quoted(eline);
+            err += "\n";
           }
           return false;
         }
@@ -349,25 +333,26 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
   MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
 }
 
-bool cmQtAutoGen::RccListInputs(std::string const& qtMajorVersion,
-                                std::string const& rccCommand,
+bool cmQtAutoGen::RccListInputs(std::string const& rccCommand,
+                                std::vector<std::string> const& rccListOptions,
                                 std::string const& fileName,
                                 std::vector<std::string>& files,
                                 std::string* errorMessage)
 {
   bool allGood = false;
   if (cmSystemTools::FileExists(fileName.c_str())) {
-    if (qtMajorVersion == "4") {
+    if (rccListOptions.empty()) {
       allGood = RccListInputsQt4(fileName, files, errorMessage);
     } else {
-      allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage);
+      allGood = RccListInputsQt5(rccCommand, rccListOptions, fileName, files,
+                                 errorMessage);
     }
   } else {
     if (errorMessage != nullptr) {
-      std::ostringstream ost;
-      ost << "rcc file does not exist:\n"
-          << "  " << cmQtAutoGen::Quoted(fileName) << "\n";
-      *errorMessage = ost.str();
+      std::string& err = *errorMessage;
+      err = "rcc resource file does not exist:\n  ";
+      err += cmQtAutoGen::Quoted(fileName);
+      err += "\n";
     }
   }
   return allGood;

+ 3 - 3
Source/cmQtAutoGen.h

@@ -61,9 +61,9 @@ public:
 
   /// @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
-  static bool RccListInputs(std::string const& qtMajorVersion,
-                            std::string const& rccCommand,
+  /// @return True if the rcc file was successfully read
+  static bool RccListInputs(std::string const& rccCommand,
+                            std::vector<std::string> const& rccListOptions,
                             std::string const& fileName,
                             std::vector<std::string>& files,
                             std::string* errorMessage = nullptr);

+ 0 - 64
Source/cmQtAutoGenDigest.h

@@ -1,64 +0,0 @@
-/* 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

+ 320 - 0
Source/cmQtAutoGenerator.cxx

@@ -0,0 +1,320 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Terminal.h"
+
+#include "cmAlgorithms.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+// -- Static functions
+
+static std::string HeadLine(std::string const& title)
+{
+  std::string head = title;
+  head += '\n';
+  head.append(head.size() - 1, '-');
+  head += '\n';
+  return head;
+}
+
+static std::string QuotedCommand(std::vector<std::string> const& command)
+{
+  std::string res;
+  for (std::string const& item : command) {
+    if (!res.empty()) {
+      res.push_back(' ');
+    }
+    std::string const cesc = cmQtAutoGen::Quoted(item);
+    if (item.empty() || (cesc.size() > (item.size() + 2)) ||
+        (cesc.find(' ') != std::string::npos)) {
+      res += cesc;
+    } else {
+      res += item;
+    }
+  }
+  return res;
+}
+
+// -- Class methods
+
+cmQtAutoGenerator::cmQtAutoGenerator()
+  : Verbose(cmSystemTools::HasEnv("VERBOSE"))
+  , ColorOutput(true)
+{
+  {
+    std::string colorEnv;
+    cmSystemTools::GetEnv("COLOR", colorEnv);
+    if (!colorEnv.empty()) {
+      this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str());
+    }
+  }
+}
+
+bool cmQtAutoGenerator::Run(std::string const& infoFile,
+                            std::string const& config)
+{
+  // Info settings
+  this->InfoFile = infoFile;
+  cmSystemTools::ConvertToUnixSlashes(this->InfoFile);
+  this->InfoDir = cmSystemTools::GetFilenamePath(infoFile);
+  this->InfoConfig = config;
+
+  cmake cm(cmake::RoleScript);
+  cm.SetHomeOutputDirectory(this->InfoDir);
+  cm.SetHomeDirectory(this->InfoDir);
+  cm.GetCurrentSnapshot().SetDefaultDefinitions();
+  cmGlobalGenerator gg(&cm);
+
+  cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
+  snapshot.GetDirectory().SetCurrentBinary(this->InfoDir);
+  snapshot.GetDirectory().SetCurrentSource(this->InfoDir);
+
+  auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
+  gg.SetCurrentMakefile(makefile.get());
+
+  return this->Process(makefile.get());
+}
+
+void cmQtAutoGenerator::LogBold(std::string const& message) const
+{
+  cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+                                     cmsysTerminal_Color_ForegroundBold,
+                                   message.c_str(), true, this->ColorOutput);
+}
+
+void cmQtAutoGenerator::LogInfo(cmQtAutoGen::Generator genType,
+                                std::string const& message) const
+{
+  std::string msg = cmQtAutoGen::GeneratorName(genType);
+  msg += ": ";
+  msg += message;
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  cmSystemTools::Stdout(msg.c_str(), msg.size());
+}
+
+void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType,
+                                   std::string const& message) const
+{
+  std::string msg = cmQtAutoGen::GeneratorName(genType);
+  msg += " warning:";
+  if (message.find('\n') == std::string::npos) {
+    // Single line message
+    msg.push_back(' ');
+  } else {
+    // Multi line message
+    msg.push_back('\n');
+  }
+  // Message
+  msg += message;
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  msg.push_back('\n');
+  cmSystemTools::Stdout(msg.c_str(), msg.size());
+}
+
+void cmQtAutoGenerator::LogFileWarning(cmQtAutoGen::Generator genType,
+                                       std::string const& filename,
+                                       std::string const& message) const
+{
+  std::string msg = "  ";
+  msg += cmQtAutoGen::Quoted(filename);
+  msg.push_back('\n');
+  // Message
+  msg += message;
+  this->LogWarning(genType, msg);
+}
+
+void cmQtAutoGenerator::LogError(cmQtAutoGen::Generator genType,
+                                 std::string const& message) const
+{
+  std::string msg;
+  msg.push_back('\n');
+  msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error");
+  // Message
+  msg += message;
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  msg.push_back('\n');
+  cmSystemTools::Stderr(msg.c_str(), msg.size());
+}
+
+void cmQtAutoGenerator::LogFileError(cmQtAutoGen::Generator genType,
+                                     std::string const& filename,
+                                     std::string const& message) const
+{
+  std::string emsg = "  ";
+  emsg += cmQtAutoGen::Quoted(filename);
+  emsg += '\n';
+  // Message
+  emsg += message;
+  this->LogError(genType, emsg);
+}
+
+void cmQtAutoGenerator::LogCommandError(
+  cmQtAutoGen::Generator genType, std::string const& message,
+  std::vector<std::string> const& command, std::string const& output) const
+{
+  std::string msg;
+  msg.push_back('\n');
+  msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error");
+  msg += message;
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  msg.push_back('\n');
+  msg += HeadLine("Command");
+  msg += QuotedCommand(command);
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  msg.push_back('\n');
+  msg += HeadLine("Output");
+  msg += output;
+  if (msg.back() != '\n') {
+    msg.push_back('\n');
+  }
+  msg.push_back('\n');
+  cmSystemTools::Stderr(msg.c_str(), msg.size());
+}
+
+/**
+ * @brief Generates the parent directory of the given file on demand
+ * @return True on success
+ */
+bool cmQtAutoGenerator::MakeParentDirectory(cmQtAutoGen::Generator genType,
+                                            std::string const& filename) const
+{
+  bool success = true;
+  std::string const dirName = cmSystemTools::GetFilenamePath(filename);
+  if (!dirName.empty()) {
+    if (!cmSystemTools::MakeDirectory(dirName)) {
+      this->LogFileError(genType, filename,
+                         "Could not create parent directory");
+      success = false;
+    }
+  }
+  return success;
+}
+
+/**
+ * @brief Tests if buildFile is older than sourceFile
+ * @return True if buildFile  is older than sourceFile.
+ *         False may indicate an error.
+ */
+bool cmQtAutoGenerator::FileIsOlderThan(std::string const& buildFile,
+                                        std::string const& sourceFile,
+                                        std::string* error)
+{
+  int result = 0;
+  if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) {
+    return (result < 0);
+  }
+  if (error != nullptr) {
+    error->append(
+      "File modification time comparison failed for the files\n  ");
+    error->append(cmQtAutoGen::Quoted(buildFile));
+    error->append("\nand\n  ");
+    error->append(cmQtAutoGen::Quoted(sourceFile));
+  }
+  return false;
+}
+
+bool cmQtAutoGenerator::FileRead(std::string& content,
+                                 std::string const& filename,
+                                 std::string* error)
+{
+  bool success = false;
+  if (cmSystemTools::FileExists(filename)) {
+    std::size_t const length = cmSystemTools::FileLength(filename);
+    cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
+    if (ifs) {
+      content.resize(length);
+      ifs.read(&content.front(), content.size());
+      if (ifs) {
+        success = true;
+      } else {
+        content.clear();
+        if (error != nullptr) {
+          error->append("Reading from the file failed.");
+        }
+      }
+    } else if (error != nullptr) {
+      error->append("Opening the file for reading failed.");
+    }
+  } else if (error != nullptr) {
+    error->append("The file does not exist.");
+  }
+  return success;
+}
+
+bool cmQtAutoGenerator::FileWrite(cmQtAutoGen::Generator genType,
+                                  std::string const& filename,
+                                  std::string const& content)
+{
+  std::string error;
+  // Make sure the parent directory exists
+  if (this->MakeParentDirectory(genType, filename)) {
+    cmsys::ofstream outfile;
+    outfile.open(filename.c_str(),
+                 (std::ios::out | std::ios::binary | std::ios::trunc));
+    if (outfile) {
+      outfile << content;
+      // Check for write errors
+      if (!outfile.good()) {
+        error = "File writing failed";
+      }
+    } else {
+      error = "Opening file for writing failed";
+    }
+  }
+  if (!error.empty()) {
+    this->LogFileError(genType, filename, error);
+    return false;
+  }
+  return true;
+}
+
+bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
+                                    std::string const& content)
+{
+  bool differs = true;
+  {
+    std::string oldContents;
+    if (this->FileRead(oldContents, filename)) {
+      differs = (oldContents != content);
+    }
+  }
+  return differs;
+}
+
+/**
+ * @brief Runs a command and returns true on success
+ * @return True on success
+ */
+bool cmQtAutoGenerator::RunCommand(std::vector<std::string> const& command,
+                                   std::string& output) const
+{
+  // Log command
+  if (this->Verbose) {
+    std::string qcmd = QuotedCommand(command);
+    qcmd.push_back('\n');
+    cmSystemTools::Stdout(qcmd.c_str(), qcmd.size());
+  }
+  // Execute command
+  int retVal = 0;
+  bool res = cmSystemTools::RunSingleCommand(
+    command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE);
+  return (res && (retVal == 0));
+}

+ 76 - 0
Source/cmQtAutoGenerator.h

@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmQtAutoGenerator_h
+#define cmQtAutoGenerator_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmQtAutoGen.h"
+
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+class cmQtAutoGenerator
+{
+  CM_DISABLE_COPY(cmQtAutoGenerator)
+public:
+  cmQtAutoGenerator();
+  virtual ~cmQtAutoGenerator() = default;
+  bool Run(std::string const& infoFile, std::string const& config);
+
+  std::string const& GetInfoFile() const { return InfoFile; }
+  std::string const& GetInfoDir() const { return InfoDir; }
+  std::string const& GetInfoConfig() const { return InfoConfig; }
+  bool GetVerbose() const { return Verbose; }
+
+protected:
+  // -- Central processing
+  virtual bool Process(cmMakefile* makefile) = 0;
+
+  // -- Log info
+  void LogBold(std::string const& message) const;
+  void LogInfo(cmQtAutoGen::Generator genType,
+               std::string const& message) const;
+  // -- Log warning
+  void LogWarning(cmQtAutoGen::Generator genType,
+                  std::string const& message) const;
+  void LogFileWarning(cmQtAutoGen::Generator genType,
+                      std::string const& filename,
+                      std::string const& message) const;
+  // -- Log error
+  void LogError(cmQtAutoGen::Generator genType,
+                std::string const& message) const;
+  void LogFileError(cmQtAutoGen::Generator genType,
+                    std::string const& filename,
+                    std::string const& message) const;
+  void LogCommandError(cmQtAutoGen::Generator genType,
+                       std::string const& message,
+                       std::vector<std::string> const& command,
+                       std::string const& output) const;
+  // -- Utility
+  bool MakeParentDirectory(cmQtAutoGen::Generator genType,
+                           std::string const& filename) const;
+  bool FileIsOlderThan(std::string const& buildFile,
+                       std::string const& sourceFile,
+                       std::string* error = nullptr);
+  bool FileRead(std::string& content, std::string const& filename,
+                std::string* error = nullptr);
+  bool FileWrite(cmQtAutoGen::Generator genType, std::string const& filename,
+                 std::string const& content);
+  bool FileDiffers(std::string const& filename, std::string const& content);
+  bool RunCommand(std::vector<std::string> const& command,
+                  std::string& output) const;
+
+private:
+  // -- Info settings
+  std::string InfoFile;
+  std::string InfoDir;
+  std::string InfoConfig;
+  // -- Settings
+  bool Verbose;
+  bool ColorOutput;
+};
+
+#endif

Plik diff jest za duży
+ 263 - 570
Source/cmQtAutoGeneratorInitializer.cxx


+ 76 - 3
Source/cmQtAutoGeneratorInitializer.h

@@ -4,9 +4,12 @@
 #define cmQtAutoGeneratorInitializer_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
-#include "cmQtAutoGenDigest.h"
+#include "cmQtAutoGen.h"
 
+#include <map>
+#include <set>
 #include <string>
+#include <vector>
 
 class cmGeneratorTarget;
 
@@ -17,8 +20,78 @@ public:
   static std::string GetQtMinorVersion(cmGeneratorTarget const* target,
                                        std::string const& qtVersionMajor);
 
-  static void InitializeAutogenTarget(cmQtAutoGenDigest& digest);
-  static void SetupAutoGenerateTarget(cmQtAutoGenDigest const& digest);
+  class Qrc
+  {
+  public:
+    Qrc()
+      : Generated(false)
+      , Unique(false)
+    {
+    }
+
+  public:
+    std::string QrcFile;
+    std::string QrcName;
+    std::string PathChecksum;
+    std::string InfoFile;
+    std::string SettingsFile;
+    std::string RccFile;
+    bool Generated;
+    bool Unique;
+    std::vector<std::string> Options;
+    std::vector<std::string> Resources;
+  };
+
+public:
+  cmQtAutoGeneratorInitializer(cmGeneratorTarget* target, bool mocEnabled,
+                               bool uicEnabled, bool rccEnabled,
+                               std::string const& qtVersionMajor);
+
+  void InitCustomTargets();
+  void SetupCustomTargets();
+
+private:
+  void SetupCustomTargetsMoc();
+  void SetupCustomTargetsUic();
+
+  std::vector<std::string> AddGeneratedSource(std::string const& filename,
+                                              cmQtAutoGen::Generator genType);
+
+  bool QtVersionGreaterOrEqual(unsigned long requestMajor,
+                               unsigned long requestMinor) const;
+
+private:
+  cmGeneratorTarget* Target;
+  bool MocEnabled;
+  bool UicEnabled;
+  bool RccEnabled;
+  // Qt
+  std::string QtVersionMajor;
+  std::string QtVersionMinor;
+  std::string RccExecutable;
+  std::vector<std::string> RccListOptions;
+  // Configurations
+  std::string ConfigDefault;
+  std::vector<std::string> ConfigsList;
+  cmQtAutoGen::MultiConfig MultiConfig;
+  // Names
+  std::string AutogenTargetName;
+  std::string AutogenFolder;
+  std::string AutogenInfoFile;
+  std::string AutogenSettingsFile;
+  // Directories
+  std::string DirInfo;
+  std::string DirBuild;
+  std::string DirWork;
+  // Sources
+  std::vector<std::string> Headers;
+  std::vector<std::string> Sources;
+  std::set<std::string> MocSkip;
+  std::set<std::string> UicSkip;
+  std::map<std::string, std::string> ConfigMocIncludes;
+  std::map<std::string, std::string> ConfigMocDefines;
+  std::map<std::string, std::string> ConfigUicOptions;
+  std::vector<Qrc> Qrcs;
 };
 
 #endif

+ 92 - 691
Source/cmQtAutoGenerators.cxx → Source/cmQtAutoGeneratorMocUic.cxx

@@ -1,10 +1,8 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmQtAutoGen.h"
-#include "cmQtAutoGenerators.h"
+#include "cmQtAutoGeneratorMocUic.h"
 
-#include "cmsys/FStream.hxx"
-#include "cmsys/Terminal.h"
 #include <algorithm>
 #include <array>
 #include <list>
@@ -15,12 +13,8 @@
 
 #include "cmAlgorithms.h"
 #include "cmCryptoHash.h"
-#include "cmFilePathChecksum.h"
-#include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
-#include "cmStateDirectory.h"
-#include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -32,37 +26,9 @@
 
 static const char* SettingsKeyMoc = "AM_MOC_SETTINGS_HASH";
 static const char* SettingsKeyUic = "AM_UIC_SETTINGS_HASH";
-static const char* SettingsKeyRcc = "AM_RCC_SETTINGS_HASH";
 
 // -- Static functions
 
-static std::string HeadLine(std::string const& title)
-{
-  std::string head = title;
-  head += '\n';
-  head.append(head.size() - 1, '-');
-  head += '\n';
-  return head;
-}
-
-static std::string QuotedCommand(std::vector<std::string> const& command)
-{
-  std::string res;
-  for (std::string const& item : command) {
-    if (!res.empty()) {
-      res.push_back(' ');
-    }
-    std::string const cesc = cmQtAutoGen::Quoted(item);
-    if (item.empty() || (cesc.size() > (item.size() + 2)) ||
-        (cesc.find(' ') != std::string::npos)) {
-      res += cesc;
-    } else {
-      res += item;
-    }
-  }
-  return res;
-}
-
 static std::string SubDirPrefix(std::string const& fileName)
 {
   std::string res(cmSystemTools::GetFilenamePath(fileName));
@@ -72,56 +38,6 @@ static std::string SubDirPrefix(std::string const& fileName)
   return res;
 }
 
-static bool ReadFile(std::string& content, std::string const& filename,
-                     std::string* error = nullptr)
-{
-  bool success = false;
-  if (cmSystemTools::FileExists(filename)) {
-    std::size_t const length = cmSystemTools::FileLength(filename);
-    cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
-    if (ifs) {
-      content.resize(length);
-      ifs.read(&content.front(), content.size());
-      if (ifs) {
-        success = true;
-      } else {
-        content.clear();
-        if (error != nullptr) {
-          error->append("Reading from the file failed.");
-        }
-      }
-    } else if (error != nullptr) {
-      error->append("Opening the file for reading failed.");
-    }
-  } else if (error != nullptr) {
-    error->append("The file does not exist.");
-  }
-  return success;
-}
-
-/**
- * @brief Tests if buildFile is older than sourceFile
- * @return True if buildFile  is older than sourceFile.
- *         False may indicate an error.
- */
-static bool FileIsOlderThan(std::string const& buildFile,
-                            std::string const& sourceFile,
-                            std::string* error = nullptr)
-{
-  int result = 0;
-  if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) {
-    return (result < 0);
-  }
-  if (error != nullptr) {
-    error->append(
-      "File modification time comparison failed for the files\n  ");
-    error->append(cmQtAutoGen::Quoted(buildFile));
-    error->append("\nand\n  ");
-    error->append(cmQtAutoGen::Quoted(sourceFile));
-  }
-  return false;
-}
-
 static bool ListContains(std::vector<std::string> const& list,
                          std::string const& entry)
 {
@@ -130,25 +46,15 @@ static bool ListContains(std::vector<std::string> const& list,
 
 // -- Class methods
 
-cmQtAutoGenerators::cmQtAutoGenerators()
+cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
   : MultiConfig(cmQtAutoGen::WRAP)
   , IncludeProjectDirsBefore(false)
-  , Verbose(cmSystemTools::HasEnv("VERBOSE"))
-  , ColorOutput(true)
+  , QtVersionMajor(4)
   , MocSettingsChanged(false)
   , MocPredefsChanged(false)
   , MocRelaxedMode(false)
   , UicSettingsChanged(false)
-  , RccSettingsChanged(false)
 {
-  {
-    std::string colorEnv;
-    cmSystemTools::GetEnv("COLOR", colorEnv);
-    if (!colorEnv.empty()) {
-      this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str());
-    }
-  }
-
   // Precompile regular expressions
   this->MocRegExpInclude.compile(
     "[\n][ \t]*#[ \t]*include[ \t]+"
@@ -157,39 +63,7 @@ cmQtAutoGenerators::cmQtAutoGenerators()
                                  "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
 }
 
-bool cmQtAutoGenerators::Run(std::string const& targetDirectory,
-                             std::string const& config)
-{
-  cmake cm(cmake::RoleScript);
-  cm.SetHomeOutputDirectory(targetDirectory);
-  cm.SetHomeDirectory(targetDirectory);
-  cm.GetCurrentSnapshot().SetDefaultDefinitions();
-  cmGlobalGenerator gg(&cm);
-
-  cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
-  snapshot.GetDirectory().SetCurrentBinary(targetDirectory);
-  snapshot.GetDirectory().SetCurrentSource(targetDirectory);
-
-  auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
-  gg.SetCurrentMakefile(makefile.get());
-
-  bool success = false;
-  if (this->InitInfoFile(makefile.get(), targetDirectory, config)) {
-    // Read latest settings
-    this->SettingsFileRead(makefile.get());
-    if (this->Process()) {
-      // Write current settings
-      if (this->SettingsFileWrite()) {
-        success = true;
-      }
-    }
-  }
-  return success;
-}
-
-bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
-                                      std::string const& targetDirectory,
-                                      std::string const& config)
+bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
 {
   // -- Meta
   this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
@@ -233,12 +107,12 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
     }
     return lists;
   };
-  auto InfoGetConfig = [makefile, &config](const char* key) -> std::string {
+  auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
     const char* valueConf = nullptr;
     {
       std::string keyConf = key;
       keyConf += '_';
-      keyConf += config;
+      keyConf += this->GetInfoConfig();
       valueConf = makefile->GetDefinition(keyConf);
     }
     if (valueConf == nullptr) {
@@ -254,11 +128,8 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
   };
 
   // -- Read info file
-  this->InfoFile = cmSystemTools::CollapseFullPath(targetDirectory);
-  cmSystemTools::ConvertToUnixSlashes(this->InfoFile);
-  this->InfoFile += "/AutogenInfo.cmake";
-  if (!makefile->ReadListFile(this->InfoFile.c_str())) {
-    this->LogFileError(cmQtAutoGen::GEN, this->InfoFile,
+  if (!makefile->ReadListFile(this->GetInfoFile().c_str())) {
+    this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
                        "File processing failed");
     return false;
   }
@@ -268,7 +139,14 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
   this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
   if (this->ConfigSuffix.empty()) {
     this->ConfigSuffix = "_";
-    this->ConfigSuffix += config;
+    this->ConfigSuffix += this->GetInfoConfig();
+  }
+
+  this->SettingsFile = InfoGetConfig("AM_SETTINGS_FILE");
+  if (this->SettingsFile.empty()) {
+    this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
+                       "Settings file name missing");
+    return false;
   }
 
   // - Files and directories
@@ -280,25 +158,18 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
     InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
   this->AutogenBuildDir = InfoGet("AM_BUILD_DIR");
   if (this->AutogenBuildDir.empty()) {
-    this->LogFileError(cmQtAutoGen::GEN, this->InfoFile,
+    this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
                        "Autogen build directory missing");
     return false;
   }
 
   // - Qt environment
-  this->QtMajorVersion = InfoGet("AM_QT_VERSION_MAJOR");
-  this->QtMinorVersion = InfoGet("AM_QT_VERSION_MINOR");
+  if (!cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"),
+                                    &this->QtVersionMajor)) {
+    this->QtVersionMajor = 4;
+  }
   this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE");
   this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE");
-  this->RccExecutable = InfoGet("AM_QT_RCC_EXECUTABLE");
-
-  // Check Qt version
-  if ((this->QtMajorVersion != "4") && (this->QtMajorVersion != "5")) {
-    this->LogFileError(cmQtAutoGen::GEN, this->InfoFile,
-                       "Unsupported Qt version: " +
-                         cmQtAutoGen::Quoted(this->QtMajorVersion));
-    return false;
-  }
 
   // - Moc
   if (this->MocEnabled()) {
@@ -327,7 +198,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
       std::vector<std::string> const mocDependFilters =
         InfoGetList("AM_MOC_DEPEND_FILTERS");
       // Insert Q_PLUGIN_METADATA dependency filter
-      if (this->QtMajorVersion != "4") {
+      if (this->QtVersionMajor != 4) {
         this->MocDependFilterPush("Q_PLUGIN_METADATA",
                                   "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
                                   "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
@@ -344,7 +215,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
         }
       } else {
         this->LogFileError(
-          cmQtAutoGen::MOC, this->InfoFile,
+          cmQtAutoGen::MOC, this->GetInfoFile(),
           "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
         return false;
       }
@@ -365,7 +236,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
         std::ostringstream ost;
         ost << "files/options lists sizes missmatch (" << sources.size() << "/"
             << options.size() << ")";
-        this->LogFileError(cmQtAutoGen::UIC, this->InfoFile, ost.str());
+        this->LogFileError(cmQtAutoGen::UIC, this->GetInfoFile(), ost.str());
         return false;
       }
       auto fitEnd = sources.cend();
@@ -379,53 +250,6 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
     }
   }
 
-  // - Rcc
-  if (this->RccEnabled()) {
-    // File lists
-    auto sources = InfoGetList("AM_RCC_SOURCES");
-    auto builds = InfoGetList("AM_RCC_BUILDS");
-    auto options = InfoGetLists("AM_RCC_OPTIONS");
-    auto inputs = InfoGetLists("AM_RCC_INPUTS");
-
-    if (sources.size() != builds.size()) {
-      std::ostringstream ost;
-      ost << "sources, builds lists sizes missmatch (" << sources.size() << "/"
-          << builds.size() << ")";
-      this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str());
-      return false;
-    }
-    if (sources.size() != options.size()) {
-      std::ostringstream ost;
-      ost << "sources, options lists sizes missmatch (" << sources.size()
-          << "/" << options.size() << ")";
-      this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str());
-      return false;
-    }
-    if (sources.size() != inputs.size()) {
-      std::ostringstream ost;
-      ost << "sources, inputs lists sizes missmatch (" << sources.size() << "/"
-          << inputs.size() << ")";
-      this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str());
-      return false;
-    }
-    {
-      auto srcItEnd = sources.end();
-      auto srcIt = sources.begin();
-      auto bldIt = builds.begin();
-      auto optIt = options.begin();
-      auto inpIt = inputs.begin();
-      while (srcIt != srcItEnd) {
-        this->RccJobs.push_back(RccJob{ std::move(*srcIt), std::move(*bldIt),
-                                        std::move(*optIt),
-                                        std::move(*inpIt) });
-        ++srcIt;
-        ++bldIt;
-        ++optIt;
-        ++inpIt;
-      }
-    }
-  }
-
   // Initialize source file jobs
   {
     // Utility lambdas
@@ -585,21 +409,10 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile,
     }
   }
 
-  // - Old settings file
-  {
-    this->SettingsFile = cmSystemTools::CollapseFullPath(targetDirectory);
-    cmSystemTools::ConvertToUnixSlashes(this->SettingsFile);
-    this->SettingsFile += "/AutogenOldSettings";
-    if (this->MultiConfig != cmQtAutoGen::SINGLE) {
-      this->SettingsFile += this->ConfigSuffix;
-    }
-    this->SettingsFile += ".cmake";
-  }
-
   return true;
 }
 
-void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile)
+void cmQtAutoGeneratorMocUic::SettingsFileRead(cmMakefile* makefile)
 {
   // Compose current settings strings
   {
@@ -631,20 +444,6 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile)
       str += sep;
       this->SettingsStringUic = crypt.HashString(str);
     }
-    if (this->RccEnabled()) {
-      std::string str;
-      str += this->RccExecutable;
-      for (const RccJob& rccJob : this->RccJobs) {
-        str += sep;
-        str += rccJob.QrcFile;
-        str += sep;
-        str += rccJob.RccFile;
-        str += sep;
-        str += cmJoin(rccJob.Options, ";");
-      }
-      str += sep;
-      this->SettingsStringRcc = crypt.HashString(str);
-    }
   }
 
   // Read old settings
@@ -659,9 +458,6 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile)
       if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) {
         this->UicSettingsChanged = true;
       }
-      if (!SMatch(SettingsKeyRcc, this->SettingsStringRcc)) {
-        this->RccSettingsChanged = true;
-      }
     }
     // In case any setting changed remove the old settings file.
     // This triggers a full rebuild on the next run if the current
@@ -673,16 +469,15 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile)
     // If the file could not be read re-generate everythiung.
     this->MocSettingsChanged = true;
     this->UicSettingsChanged = true;
-    this->RccSettingsChanged = true;
   }
 }
 
-bool cmQtAutoGenerators::SettingsFileWrite()
+bool cmQtAutoGeneratorMocUic::SettingsFileWrite()
 {
   bool success = true;
   // Only write if any setting changed
   if (this->SettingsChanged()) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " +
                       cmQtAutoGen::Quoted(this->SettingsFile));
     }
@@ -699,7 +494,6 @@ bool cmQtAutoGenerators::SettingsFileWrite()
       };
       SettingAppend(SettingsKeyMoc, this->SettingsStringMoc);
       SettingAppend(SettingsKeyUic, this->SettingsStringUic);
-      SettingAppend(SettingsKeyRcc, this->SettingsStringRcc);
     }
     // Write settings file
     if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) {
@@ -713,7 +507,7 @@ bool cmQtAutoGenerators::SettingsFileWrite()
   return success;
 }
 
-bool cmQtAutoGenerators::Process()
+bool cmQtAutoGeneratorMocUic::Process(cmMakefile* makefile)
 {
   // the program goes through all .cpp files to see which moc files are
   // included. It is not really interesting how the moc file is named, but
@@ -723,6 +517,12 @@ bool cmQtAutoGenerators::Process()
   // moc file is included anywhere a moc_<filename>.cpp file is created and
   // included in the mocs_compilation.cpp file.
 
+  if (!this->InitInfoFile(makefile)) {
+    return false;
+  }
+  // Read latest settings
+  this->SettingsFileRead(makefile);
+
   // Create AUTOGEN include directory
   {
     std::string const incDirAbs = cmSystemTools::CollapseCombinedPath(
@@ -758,7 +558,8 @@ bool cmQtAutoGenerators::Process()
   if (!this->UicGenerateAll()) {
     return false;
   }
-  if (!this->RccGenerateAll()) {
+
+  if (!this->SettingsFileWrite()) {
     return false;
   }
 
@@ -768,12 +569,12 @@ bool cmQtAutoGenerators::Process()
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename,
-                                         const SourceJob& job)
+bool cmQtAutoGeneratorMocUic::ParseSourceFile(std::string const& absFilename,
+                                              const SourceJob& job)
 {
   std::string contentText;
   std::string error;
-  bool success = ReadFile(contentText, absFilename, &error);
+  bool success = this->FileRead(contentText, absFilename, &error);
   if (success) {
     if (!contentText.empty()) {
       if (job.Moc) {
@@ -796,12 +597,12 @@ bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename,
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename,
-                                         const SourceJob& job)
+bool cmQtAutoGeneratorMocUic::ParseHeaderFile(std::string const& absFilename,
+                                              const SourceJob& job)
 {
   std::string contentText;
   std::string error;
-  bool success = ReadFile(contentText, absFilename, &error);
+  bool success = this->FileRead(contentText, absFilename, &error);
   if (success) {
     if (!contentText.empty()) {
       if (job.Moc) {
@@ -824,7 +625,7 @@ bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename,
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::ParsePostprocess()
+bool cmQtAutoGeneratorMocUic::ParsePostprocess()
 {
   bool success = true;
   // Read missing dependencies
@@ -832,7 +633,7 @@ bool cmQtAutoGenerators::ParsePostprocess()
     if (!item->DependsValid) {
       std::string content;
       std::string error;
-      if (ReadFile(content, item->SourceFile, &error)) {
+      if (this->FileRead(content, item->SourceFile, &error)) {
         this->MocFindDepends(item->SourceFile, content, item->Depends);
         item->DependsValid = true;
       } else {
@@ -855,7 +656,7 @@ bool cmQtAutoGenerators::ParsePostprocess()
  * @brief Tests if the file should be ignored for moc scanning
  * @return True if the file should be ignored
  */
-bool cmQtAutoGenerators::MocSkip(std::string const& absFilename) const
+bool cmQtAutoGeneratorMocUic::MocSkip(std::string const& absFilename) const
 {
   if (this->MocEnabled()) {
     // Test if the file name is on the skip list
@@ -870,8 +671,8 @@ bool cmQtAutoGenerators::MocSkip(std::string const& absFilename) const
  * @brief Tests if the C++ content requires moc processing
  * @return True if moc is required
  */
-bool cmQtAutoGenerators::MocRequired(std::string const& contentText,
-                                     std::string* macroName)
+bool cmQtAutoGeneratorMocUic::MocRequired(std::string const& contentText,
+                                          std::string* macroName)
 {
   for (KeyRegExp& filter : this->MocMacroFilters) {
     // Run a simple find string operation before the expensive
@@ -889,7 +690,7 @@ bool cmQtAutoGenerators::MocRequired(std::string const& contentText,
   return false;
 }
 
-std::string cmQtAutoGenerators::MocStringMacros() const
+std::string cmQtAutoGeneratorMocUic::MocStringMacros() const
 {
   std::string res;
   const auto itB = this->MocMacroFilters.cbegin();
@@ -911,7 +712,7 @@ std::string cmQtAutoGenerators::MocStringMacros() const
   return res;
 }
 
-std::string cmQtAutoGenerators::MocStringHeaders(
+std::string cmQtAutoGeneratorMocUic::MocStringHeaders(
   std::string const& fileBase) const
 {
   std::string res = fileBase;
@@ -921,7 +722,7 @@ std::string cmQtAutoGenerators::MocStringHeaders(
   return res;
 }
 
-std::string cmQtAutoGenerators::MocFindIncludedHeader(
+std::string cmQtAutoGeneratorMocUic::MocFindIncludedHeader(
   std::string const& sourcePath, std::string const& includeBase) const
 {
   std::string header;
@@ -944,7 +745,7 @@ std::string cmQtAutoGenerators::MocFindIncludedHeader(
   return header;
 }
 
-bool cmQtAutoGenerators::MocFindIncludedFile(
+bool cmQtAutoGeneratorMocUic::MocFindIncludedFile(
   std::string& absFile, std::string const& sourcePath,
   std::string const& includeString) const
 {
@@ -974,8 +775,8 @@ bool cmQtAutoGenerators::MocFindIncludedFile(
   return success;
 }
 
-bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key,
-                                             std::string const& regExp)
+bool cmQtAutoGeneratorMocUic::MocDependFilterPush(std::string const& key,
+                                                  std::string const& regExp)
 {
   std::string error;
   if (!key.empty()) {
@@ -1009,9 +810,9 @@ bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key,
   return true;
 }
 
-void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename,
-                                        std::string const& contentText,
-                                        std::set<std::string>& depends)
+void cmQtAutoGeneratorMocUic::MocFindDepends(std::string const& absFilename,
+                                             std::string const& contentText,
+                                             std::set<std::string>& depends)
 {
   if (this->MocDependFilters.empty() && contentText.empty()) {
     return;
@@ -1040,7 +841,7 @@ void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename,
       std::string incFile;
       if (this->MocFindIncludedFile(incFile, sourcePath, match)) {
         depends.insert(incFile);
-        if (this->Verbose) {
+        if (this->GetVerbose()) {
           this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n  " +
                           cmQtAutoGen::Quoted(absFilename) + "\n  " +
                           cmQtAutoGen::Quoted(incFile));
@@ -1057,10 +858,10 @@ void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename,
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename,
-                                               std::string const& contentText)
+bool cmQtAutoGeneratorMocUic::MocParseSourceContent(
+  std::string const& absFilename, std::string const& contentText)
 {
-  if (this->Verbose) {
+  if (this->GetVerbose()) {
     this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
   }
 
@@ -1296,10 +1097,10 @@ bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename,
   return true;
 }
 
-void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename,
-                                               std::string const& contentText)
+void cmQtAutoGeneratorMocUic::MocParseHeaderContent(
+  std::string const& absFilename, std::string const& contentText)
 {
-  if (this->Verbose) {
+  if (this->GetVerbose()) {
     this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
   }
 
@@ -1329,7 +1130,7 @@ void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename,
   }
 }
 
-bool cmQtAutoGenerators::MocGenerateAll()
+bool cmQtAutoGeneratorMocUic::MocGenerateAll()
 {
   if (!this->MocEnabled()) {
     return true;
@@ -1384,7 +1185,7 @@ bool cmQtAutoGenerators::MocGenerateAll()
   if (!this->MocPredefsCmd.empty()) {
     if (this->MocSettingsChanged ||
         !cmSystemTools::FileExists(this->MocPredefsFileAbs)) {
-      if (this->Verbose) {
+      if (this->GetVerbose()) {
         this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel);
       }
 
@@ -1419,7 +1220,7 @@ bool cmQtAutoGenerators::MocGenerateAll()
         }
       } else {
         // Touch to update the time stamp
-        if (this->Verbose) {
+        if (this->GetVerbose()) {
           this->LogInfo(cmQtAutoGen::MOC,
                         "Touching moc_predefs " + this->MocPredefsFileRel);
         }
@@ -1470,7 +1271,7 @@ bool cmQtAutoGenerators::MocGenerateAll()
 
     if (this->FileDiffers(this->MocCompFileAbs, mocs)) {
       // Actually write mocs compilation file
-      if (this->Verbose) {
+      if (this->GetVerbose()) {
         this->LogBold("Generating MOC compilation " + this->MocCompFileRel);
       }
       if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) {
@@ -1480,7 +1281,7 @@ bool cmQtAutoGenerators::MocGenerateAll()
       }
     } else if (autoNameGenerated) {
       // Only touch mocs compilation file
-      if (this->Verbose) {
+      if (this->GetVerbose()) {
         this->LogInfo(cmQtAutoGen::MOC,
                       "Touching mocs compilation " + this->MocCompFileRel);
       }
@@ -1494,8 +1295,8 @@ bool cmQtAutoGenerators::MocGenerateAll()
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
-                                         bool* generated)
+bool cmQtAutoGeneratorMocUic::MocGenerateFile(const MocJobAuto& mocJob,
+                                              bool* generated)
 {
   bool success = true;
 
@@ -1505,7 +1306,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
   bool generate = false;
   std::string generateReason;
   if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       generateReason = "Generating ";
       generateReason += cmQtAutoGen::Quoted(mocFileAbs);
       generateReason += " from its source file ";
@@ -1515,7 +1316,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
     generate = true;
   }
   if (!generate && this->MocSettingsChanged) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       generateReason = "Generating ";
       generateReason += cmQtAutoGen::Quoted(mocFileAbs);
       generateReason += " from ";
@@ -1525,7 +1326,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
     generate = true;
   }
   if (!generate && this->MocPredefsChanged) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       generateReason = "Generating ";
       generateReason += cmQtAutoGen::Quoted(mocFileAbs);
       generateReason += " from ";
@@ -1537,7 +1338,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
   if (!generate) {
     std::string error;
     if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) {
-      if (this->Verbose) {
+      if (this->GetVerbose()) {
         generateReason = "Generating ";
         generateReason += cmQtAutoGen::Quoted(mocFileAbs);
         generateReason += " because it's older than its source file ";
@@ -1556,7 +1357,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
     std::string error;
     for (std::string const& depFile : mocJob.Depends) {
       if (FileIsOlderThan(mocFileAbs, depFile, &error)) {
-        if (this->Verbose) {
+        if (this->GetVerbose()) {
           generateReason = "Generating ";
           generateReason += cmQtAutoGen::Quoted(mocFileAbs);
           generateReason += " from ";
@@ -1577,7 +1378,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
 
   if (generate) {
     // Log
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       this->LogBold("Generating MOC source " + mocJob.BuildFileRel);
       this->LogInfo(cmQtAutoGen::MOC, generateReason);
     }
@@ -1627,7 +1428,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob,
 /**
  * @brief Tests if the file name is in the skip list
  */
-bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const
+bool cmQtAutoGeneratorMocUic::UicSkip(std::string const& absFilename) const
 {
   if (this->UicEnabled()) {
     // Test if the file name is on the skip list
@@ -1638,10 +1439,10 @@ bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const
   return true;
 }
 
-bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename,
-                                         std::string const& contentText)
+bool cmQtAutoGeneratorMocUic::UicParseContent(std::string const& absFilename,
+                                              std::string const& contentText)
 {
-  if (this->Verbose) {
+  if (this->GetVerbose()) {
     this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename);
   }
 
@@ -1689,9 +1490,9 @@ bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename,
   return true;
 }
 
-bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile,
-                                             std::string const& sourceFile,
-                                             std::string const& includeString)
+bool cmQtAutoGeneratorMocUic::UicFindIncludedFile(
+  std::string& absFile, std::string const& sourceFile,
+  std::string const& includeString)
 {
   bool success = false;
   std::string searchFile =
@@ -1753,7 +1554,7 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile,
   return success;
 }
 
-bool cmQtAutoGenerators::UicGenerateAll()
+bool cmQtAutoGeneratorMocUic::UicGenerateAll()
 {
   if (!this->UicEnabled()) {
     return true;
@@ -1817,7 +1618,7 @@ bool cmQtAutoGenerators::UicGenerateAll()
 /**
  * @return True on success
  */
-bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
+bool cmQtAutoGeneratorMocUic::UicGenerateFile(const UicJob& uicJob)
 {
   bool success = true;
 
@@ -1827,7 +1628,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
   bool generate = false;
   std::string generateReason;
   if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       generateReason = "Generating ";
       generateReason += cmQtAutoGen::Quoted(uicFileAbs);
       generateReason += " from its source file ";
@@ -1837,7 +1638,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
     generate = true;
   }
   if (!generate && this->UicSettingsChanged) {
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       generateReason = "Generating ";
       generateReason += cmQtAutoGen::Quoted(uicFileAbs);
       generateReason += " from ";
@@ -1849,7 +1650,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
   if (!generate) {
     std::string error;
     if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) {
-      if (this->Verbose) {
+      if (this->GetVerbose()) {
         generateReason = "Generating ";
         generateReason += cmQtAutoGen::Quoted(uicFileAbs);
         generateReason += " because it's older than its source file ";
@@ -1865,7 +1666,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
   }
   if (generate) {
     // Log
-    if (this->Verbose) {
+    if (this->GetVerbose()) {
       this->LogBold("Generating UIC header " + uicJob.BuildFileRel);
       this->LogInfo(cmQtAutoGen::UIC, generateReason);
     }
@@ -1880,7 +1681,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
         auto optionIt = this->UicOptions.find(uicJob.SourceFile);
         if (optionIt != this->UicOptions.end()) {
           cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second,
-                                       (this->QtMajorVersion == "5"));
+                                       (this->QtVersionMajor == 5));
         }
         cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
       }
@@ -1911,413 +1712,13 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob)
   return success;
 }
 
-bool cmQtAutoGenerators::RccGenerateAll()
-{
-  if (!this->RccEnabled()) {
-    return true;
-  }
-
-  // Generate rcc files
-  for (const RccJob& rccJob : this->RccJobs) {
-    if (!this->RccGenerateFile(rccJob)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-/**
- * @return True on success
- */
-bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob)
-{
-  bool success = true;
-  bool rccGenerated = false;
-
-  std::string rccFileAbs;
-  {
-    std::string suffix;
-    switch (this->MultiConfig) {
-      case cmQtAutoGen::SINGLE:
-        break;
-      case cmQtAutoGen::WRAP:
-        suffix = "_CMAKE";
-        suffix += this->ConfigSuffix;
-        suffix += "_";
-        break;
-      case cmQtAutoGen::FULL:
-        suffix = this->ConfigSuffix;
-        break;
-    }
-    rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(rccJob.RccFile, suffix);
-  }
-  std::string const rccFileRel = cmSystemTools::RelativePath(
-    this->AutogenBuildDir.c_str(), rccFileAbs.c_str());
-
-  // Check if regeneration is required
-  bool generate = false;
-  std::string generateReason;
-  if (!cmSystemTools::FileExists(rccJob.QrcFile)) {
-    {
-      std::string error = "Could not find the file\n  ";
-      error += cmQtAutoGen::Quoted(rccJob.QrcFile);
-      this->LogError(cmQtAutoGen::RCC, error);
-    }
-    success = false;
-  }
-  if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) {
-    if (this->Verbose) {
-      generateReason = "Generating ";
-      generateReason += cmQtAutoGen::Quoted(rccFileAbs);
-      generateReason += " from its source file ";
-      generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile);
-      generateReason += " because it doesn't exist";
-    }
-    generate = true;
-  }
-  if (success && !generate && this->RccSettingsChanged) {
-    if (this->Verbose) {
-      generateReason = "Generating ";
-      generateReason += cmQtAutoGen::Quoted(rccFileAbs);
-      generateReason += " from ";
-      generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile);
-      generateReason += " because the RCC settings changed";
-    }
-    generate = true;
-  }
-  if (success && !generate) {
-    std::string error;
-    if (FileIsOlderThan(rccFileAbs, rccJob.QrcFile, &error)) {
-      if (this->Verbose) {
-        generateReason = "Generating ";
-        generateReason += cmQtAutoGen::Quoted(rccFileAbs);
-        generateReason += " because it is older than ";
-        generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile);
-      }
-      generate = true;
-    } else {
-      if (!error.empty()) {
-        this->LogError(cmQtAutoGen::RCC, error);
-        success = false;
-      }
-    }
-  }
-  if (success && !generate) {
-    // Acquire input file list
-    std::vector<std::string> readFiles;
-    std::vector<std::string> const* files = nullptr;
-    if (!rccJob.Inputs.empty()) {
-      files = &rccJob.Inputs;
-    } else {
-      // Read input file list from qrc file
-      std::string error;
-      if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, this->RccExecutable,
-                                     rccJob.QrcFile, readFiles, &error)) {
-        files = &readFiles;
-      } else {
-        this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error);
-        success = false;
-      }
-    }
-    // Test if any input file is newer than the build file
-    if (files != nullptr) {
-      std::string error;
-      for (std::string const& resFile : *files) {
-        if (!cmSystemTools::FileExists(resFile.c_str())) {
-          error = "Could not find the file\n  ";
-          error += cmQtAutoGen::Quoted(resFile);
-          error += "\nwhich is listed in\n  ";
-          error += cmQtAutoGen::Quoted(rccJob.QrcFile);
-          break;
-        }
-        if (FileIsOlderThan(rccFileAbs, resFile, &error)) {
-          if (this->Verbose) {
-            generateReason = "Generating ";
-            generateReason += cmQtAutoGen::Quoted(rccFileAbs);
-            generateReason += " from ";
-            generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile);
-            generateReason += " because it is older than ";
-            generateReason += cmQtAutoGen::Quoted(resFile);
-          }
-          generate = true;
-          break;
-        }
-        if (!error.empty()) {
-          break;
-        }
-      }
-      // Print error
-      if (!error.empty()) {
-        this->LogError(cmQtAutoGen::RCC, error);
-        success = false;
-      }
-    }
-  }
-  // Regenerate on demand
-  if (generate) {
-    // Log
-    if (this->Verbose) {
-      this->LogBold("Generating RCC source " + rccFileRel);
-      this->LogInfo(cmQtAutoGen::RCC, generateReason);
-    }
-
-    // Make sure the parent directory exists
-    if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) {
-      // Compose rcc command
-      std::vector<std::string> cmd;
-      cmd.push_back(this->RccExecutable);
-      cmd.insert(cmd.end(), rccJob.Options.begin(), rccJob.Options.end());
-      cmd.push_back("-o");
-      cmd.push_back(rccFileAbs);
-      cmd.push_back(rccJob.QrcFile);
-
-      std::string output;
-      if (this->RunCommand(cmd, output)) {
-        // Success
-        rccGenerated = true;
-      } else {
-        {
-          std::string emsg = "rcc failed for\n  ";
-          emsg += cmQtAutoGen::Quoted(rccJob.QrcFile);
-          this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output);
-        }
-        cmSystemTools::RemoveFile(rccFileAbs);
-        success = false;
-      }
-    } else {
-      // Parent directory creation failed
-      success = false;
-    }
-  }
-
-  // Generate a wrapper source file on demand
-  if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) {
-    // Wrapper file name
-    std::string const& wrapperFileAbs = rccJob.RccFile;
-    std::string const wrapperFileRel = cmSystemTools::RelativePath(
-      this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str());
-    // Wrapper file content
-    std::string content = "// This is an autogenerated configuration "
-                          "wrapper file. Changes will be overwritten.\n"
-                          "#include \"";
-    content += cmSystemTools::GetFilenameName(rccFileRel);
-    content += "\"\n";
-    // Write content to file
-    if (this->FileDiffers(wrapperFileAbs, content)) {
-      // Write new wrapper file
-      if (this->Verbose) {
-        this->LogBold("Generating RCC wrapper " + wrapperFileRel);
-      }
-      if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) {
-        this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs,
-                           "rcc wrapper file writing failed");
-        success = false;
-      }
-    } else if (rccGenerated) {
-      // Just touch the wrapper file
-      if (this->Verbose) {
-        this->LogInfo(cmQtAutoGen::RCC,
-                      "Touching RCC wrapper " + wrapperFileRel);
-      }
-      cmSystemTools::Touch(wrapperFileAbs, false);
-    }
-  }
-
-  return success;
-}
-
-void cmQtAutoGenerators::LogBold(std::string const& message) const
-{
-  cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
-                                     cmsysTerminal_Color_ForegroundBold,
-                                   message.c_str(), true, this->ColorOutput);
-}
-
-void cmQtAutoGenerators::LogInfo(cmQtAutoGen::Generator genType,
-                                 std::string const& message) const
-{
-  std::string msg = cmQtAutoGen::GeneratorName(genType);
-  msg += ": ";
-  msg += message;
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  cmSystemTools::Stdout(msg.c_str(), msg.size());
-}
-
-void cmQtAutoGenerators::LogWarning(cmQtAutoGen::Generator genType,
-                                    std::string const& message) const
-{
-  std::string msg = cmQtAutoGen::GeneratorName(genType);
-  msg += " warning:";
-  if (message.find('\n') == std::string::npos) {
-    // Single line message
-    msg.push_back(' ');
-  } else {
-    // Multi line message
-    msg.push_back('\n');
-  }
-  // Message
-  msg += message;
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  msg.push_back('\n');
-  cmSystemTools::Stdout(msg.c_str(), msg.size());
-}
-
-void cmQtAutoGenerators::LogFileWarning(cmQtAutoGen::Generator genType,
-                                        std::string const& filename,
-                                        std::string const& message) const
-{
-  std::string msg = "  ";
-  msg += cmQtAutoGen::Quoted(filename);
-  msg.push_back('\n');
-  // Message
-  msg += message;
-  this->LogWarning(genType, msg);
-}
-
-void cmQtAutoGenerators::LogError(cmQtAutoGen::Generator genType,
-                                  std::string const& message) const
-{
-  std::string msg;
-  msg.push_back('\n');
-  msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error");
-  // Message
-  msg += message;
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  msg.push_back('\n');
-  cmSystemTools::Stderr(msg.c_str(), msg.size());
-}
-
-void cmQtAutoGenerators::LogFileError(cmQtAutoGen::Generator genType,
-                                      std::string const& filename,
-                                      std::string const& message) const
-{
-  std::string emsg = "  ";
-  emsg += cmQtAutoGen::Quoted(filename);
-  emsg += '\n';
-  // Message
-  emsg += message;
-  this->LogError(genType, emsg);
-}
-
-void cmQtAutoGenerators::LogCommandError(
-  cmQtAutoGen::Generator genType, std::string const& message,
-  std::vector<std::string> const& command, std::string const& output) const
-{
-  std::string msg;
-  msg.push_back('\n');
-  msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error");
-  msg += message;
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  msg.push_back('\n');
-  msg += HeadLine("Command");
-  msg += QuotedCommand(command);
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  msg.push_back('\n');
-  msg += HeadLine("Output");
-  msg += output;
-  if (msg.back() != '\n') {
-    msg.push_back('\n');
-  }
-  msg.push_back('\n');
-  cmSystemTools::Stderr(msg.c_str(), msg.size());
-}
-
-/**
- * @brief Generates the parent directory of the given file on demand
- * @return True on success
- */
-bool cmQtAutoGenerators::MakeParentDirectory(cmQtAutoGen::Generator genType,
-                                             std::string const& filename) const
-{
-  bool success = true;
-  std::string const dirName = cmSystemTools::GetFilenamePath(filename);
-  if (!dirName.empty()) {
-    if (!cmSystemTools::MakeDirectory(dirName)) {
-      this->LogFileError(genType, filename,
-                         "Could not create parent directory");
-      success = false;
-    }
-  }
-  return success;
-}
-
-bool cmQtAutoGenerators::FileDiffers(std::string const& filename,
-                                     std::string const& content)
-{
-  bool differs = true;
-  {
-    std::string oldContents;
-    if (ReadFile(oldContents, filename)) {
-      differs = (oldContents != content);
-    }
-  }
-  return differs;
-}
-
-bool cmQtAutoGenerators::FileWrite(cmQtAutoGen::Generator genType,
-                                   std::string const& filename,
-                                   std::string const& content)
-{
-  std::string error;
-  // Make sure the parent directory exists
-  if (this->MakeParentDirectory(genType, filename)) {
-    cmsys::ofstream outfile;
-    outfile.open(filename.c_str(),
-                 (std::ios::out | std::ios::binary | std::ios::trunc));
-    if (outfile) {
-      outfile << content;
-      // Check for write errors
-      if (!outfile.good()) {
-        error = "File writing failed";
-      }
-    } else {
-      error = "Opening file for writing failed";
-    }
-  }
-  if (!error.empty()) {
-    this->LogFileError(genType, filename, error);
-    return false;
-  }
-  return true;
-}
-
-/**
- * @brief Runs a command and returns true on success
- * @return True on success
- */
-bool cmQtAutoGenerators::RunCommand(std::vector<std::string> const& command,
-                                    std::string& output) const
-{
-  // Log command
-  if (this->Verbose) {
-    std::string qcmd = QuotedCommand(command);
-    qcmd.push_back('\n');
-    cmSystemTools::Stdout(qcmd.c_str(), qcmd.size());
-  }
-  // Execute command
-  int retVal = 0;
-  bool res = cmSystemTools::RunSingleCommand(
-    command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE);
-  return (res && (retVal == 0));
-}
-
 /**
  * @brief Tries to find the header file to the given file base path by
  * appending different header extensions
  * @return True on success
  */
-bool cmQtAutoGenerators::FindHeader(std::string& header,
-                                    std::string const& testBasePath) const
+bool cmQtAutoGeneratorMocUic::FindHeader(std::string& header,
+                                         std::string const& testBasePath) const
 {
   for (std::string const& ext : this->HeaderExtensions) {
     std::string testFilePath(testBasePath);

+ 10 - 63
Source/cmQtAutoGenerators.h → Source/cmQtAutoGeneratorMocUic.h

@@ -1,12 +1,13 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmQtAutoGenerators_h
-#define cmQtAutoGenerators_h
+#ifndef cmQtAutoGeneratorMocUic_h
+#define cmQtAutoGeneratorMocUic_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmFilePathChecksum.h"
 #include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
 #include "cmsys/RegularExpression.hxx"
 
 #include <map>
@@ -17,12 +18,11 @@
 
 class cmMakefile;
 
-class cmQtAutoGenerators
+class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator
 {
-  CM_DISABLE_COPY(cmQtAutoGenerators)
+  CM_DISABLE_COPY(cmQtAutoGeneratorMocUic)
 public:
-  cmQtAutoGenerators();
-  bool Run(std::string const& targetDirectory, std::string const& config);
+  cmQtAutoGeneratorMocUic();
 
 private:
   // -- Types
@@ -80,30 +80,19 @@ private:
     std::string IncludeString;
   };
 
-  /// @brief RCC job
-  struct RccJob
-  {
-    std::string QrcFile;
-    std::string RccFile;
-    std::vector<std::string> Options;
-    std::vector<std::string> Inputs;
-  };
-
   // -- Initialization
-  bool InitInfoFile(cmMakefile* makefile, std::string const& targetDirectory,
-                    std::string const& config);
+  bool InitInfoFile(cmMakefile* makefile);
 
   // -- Settings file
   void SettingsFileRead(cmMakefile* makefile);
   bool SettingsFileWrite();
   bool SettingsChanged() const
   {
-    return (this->MocSettingsChanged || this->RccSettingsChanged ||
-            this->UicSettingsChanged);
+    return (this->MocSettingsChanged || this->UicSettingsChanged);
   }
 
   // -- Central processing
-  bool Process();
+  bool Process(cmMakefile* makefile) override;
 
   // -- Source parsing
   bool ParseSourceFile(std::string const& absFilename, const SourceJob& job);
@@ -146,54 +135,17 @@ private:
   bool UicGenerateAll();
   bool UicGenerateFile(const UicJob& uicJob);
 
-  // -- Rcc
-  bool RccEnabled() const { return !this->RccExecutable.empty(); }
-  bool RccGenerateAll();
-  bool RccGenerateFile(const RccJob& rccJob);
-
-  // -- Log info
-  void LogBold(std::string const& message) const;
-  void LogInfo(cmQtAutoGen::Generator genType,
-               std::string const& message) const;
-  // -- Log warning
-  void LogWarning(cmQtAutoGen::Generator genType,
-                  std::string const& message) const;
-  void LogFileWarning(cmQtAutoGen::Generator genType,
-                      std::string const& filename,
-                      std::string const& message) const;
-  // -- Log error
-  void LogError(cmQtAutoGen::Generator genType,
-                std::string const& message) const;
-  void LogFileError(cmQtAutoGen::Generator genType,
-                    std::string const& filename,
-                    std::string const& message) const;
-  void LogCommandError(cmQtAutoGen::Generator genType,
-                       std::string const& message,
-                       std::vector<std::string> const& command,
-                       std::string const& output) const;
-
   // -- Utility
-  bool MakeParentDirectory(cmQtAutoGen::Generator genType,
-                           std::string const& filename) const;
-  bool FileDiffers(std::string const& filename, std::string const& content);
-  bool FileWrite(cmQtAutoGen::Generator genType, std::string const& filename,
-                 std::string const& content);
   bool FindHeader(std::string& header, std::string const& testBasePath) const;
-  bool RunCommand(std::vector<std::string> const& command,
-                  std::string& output) const;
 
   // -- Meta
-  std::string InfoFile;
   std::string ConfigSuffix;
   cmQtAutoGen::MultiConfig MultiConfig;
   // -- Settings
   bool IncludeProjectDirsBefore;
-  bool Verbose;
-  bool ColorOutput;
   std::string SettingsFile;
   std::string SettingsStringMoc;
   std::string SettingsStringUic;
-  std::string SettingsStringRcc;
   // -- Directories
   std::string ProjectSourceDir;
   std::string ProjectBinaryDir;
@@ -202,11 +154,9 @@ private:
   std::string AutogenBuildDir;
   std::string AutogenIncludeDir;
   // -- Qt environment
-  std::string QtMajorVersion;
-  std::string QtMinorVersion;
+  unsigned long QtVersionMajor;
   std::string MocExecutable;
   std::string UicExecutable;
-  std::string RccExecutable;
   // -- File lists
   std::map<std::string, SourceJob> HeaderJobs;
   std::map<std::string, SourceJob> SourceJobs;
@@ -240,9 +190,6 @@ private:
   std::vector<std::string> UicSearchPaths;
   cmsys::RegularExpression UicRegExpInclude;
   std::vector<std::unique_ptr<UicJob>> UicJobs;
-  // -- Rcc
-  bool RccSettingsChanged;
-  std::vector<RccJob> RccJobs;
 };
 
 #endif

+ 425 - 0
Source/cmQtAutoGeneratorRcc.cxx

@@ -0,0 +1,425 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGeneratorRcc.h"
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+
+// -- Static variables
+
+static const char* SettingsKeyRcc = "ARCC_SETTINGS_HASH";
+
+// -- Class methods
+
+cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc()
+  : MultiConfig(cmQtAutoGen::WRAP)
+  , SettingsChanged(false)
+{
+}
+
+bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile)
+{
+  // Utility lambdas
+  auto InfoGet = [makefile](const char* key) {
+    return makefile->GetSafeDefinition(key);
+  };
+  auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
+    std::vector<std::string> list;
+    cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+    return list;
+  };
+  auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
+    const char* valueConf = nullptr;
+    {
+      std::string keyConf = key;
+      keyConf += '_';
+      keyConf += this->GetInfoConfig();
+      valueConf = makefile->GetDefinition(keyConf);
+    }
+    if (valueConf == nullptr) {
+      valueConf = makefile->GetSafeDefinition(key);
+    }
+    return std::string(valueConf);
+  };
+  auto InfoGetConfigList =
+    [&InfoGetConfig](const char* key) -> std::vector<std::string> {
+    std::vector<std::string> list;
+    cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+    return list;
+  };
+
+  // -- Read info file
+  if (!makefile->ReadListFile(this->GetInfoFile().c_str())) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "File processing failed");
+    return false;
+  }
+
+  // -- Meta
+  this->MultiConfig =
+    cmQtAutoGen::MultiConfigType(InfoGet("ARCC_MULTI_CONFIG"));
+  this->ConfigSuffix = InfoGetConfig("ARCC_CONFIG_SUFFIX");
+  if (this->ConfigSuffix.empty()) {
+    this->ConfigSuffix = "_";
+    this->ConfigSuffix += this->GetInfoConfig();
+  }
+
+  this->SettingsFile = InfoGetConfig("ARCC_SETTINGS_FILE");
+
+  // - Files and directories
+  this->ProjectSourceDir = InfoGet("ARCC_CMAKE_SOURCE_DIR");
+  this->ProjectBinaryDir = InfoGet("ARCC_CMAKE_BINARY_DIR");
+  this->CurrentSourceDir = InfoGet("ARCC_CMAKE_CURRENT_SOURCE_DIR");
+  this->CurrentBinaryDir = InfoGet("ARCC_CMAKE_CURRENT_BINARY_DIR");
+  this->AutogenBuildDir = InfoGet("ARCC_BUILD_DIR");
+
+  // - Qt environment
+  this->RccExecutable = InfoGet("ARCC_RCC_EXECUTABLE");
+  this->RccListOptions = InfoGetList("ARCC_RCC_LIST_OPTIONS");
+
+  // - Job
+  this->QrcFile = InfoGet("ARCC_SOURCE");
+  this->RccFile = InfoGet("ARCC_OUTPUT");
+  this->Options = InfoGetConfigList("ARCC_OPTIONS");
+  this->Inputs = InfoGetList("ARCC_INPUTS");
+
+  // - Validity checks
+  if (this->SettingsFile.empty()) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "Settings file name missing");
+    return false;
+  }
+  if (this->AutogenBuildDir.empty()) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "Autogen build directory missing");
+    return false;
+  }
+  if (this->RccExecutable.empty()) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "rcc executable missing");
+    return false;
+  }
+  if (this->QrcFile.empty()) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "rcc input file missing");
+    return false;
+  }
+  if (this->RccFile.empty()) {
+    this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(),
+                       "rcc output file missing");
+    return false;
+  }
+
+  // Init derived information
+  // ------------------------
+
+  // Init file path checksum generator
+  this->FilePathChecksum.setupParentDirs(
+    this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir,
+    this->ProjectBinaryDir);
+
+  return true;
+}
+
+void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile)
+{
+  // Compose current settings strings
+  {
+    cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
+    std::string const sep(" ~~~ ");
+    {
+      std::string str;
+      str += this->RccExecutable;
+      str += sep;
+      str += cmJoin(this->RccListOptions, ";");
+      str += sep;
+      str += this->QrcFile;
+      str += sep;
+      str += this->RccFile;
+      str += sep;
+      str += cmJoin(this->Options, ";");
+      str += sep;
+      str += cmJoin(this->Inputs, ";");
+      str += sep;
+      this->SettingsString = crypt.HashString(str);
+    }
+  }
+
+  // Read old settings
+  if (makefile->ReadListFile(this->SettingsFile.c_str())) {
+    {
+      auto SMatch = [makefile](const char* key, std::string const& value) {
+        return (value == makefile->GetSafeDefinition(key));
+      };
+      if (!SMatch(SettingsKeyRcc, this->SettingsString)) {
+        this->SettingsChanged = true;
+      }
+    }
+    // In case any setting changed remove the old settings file.
+    // This triggers a full rebuild on the next run if the current
+    // build is aborted before writing the current settings in the end.
+    if (this->SettingsChanged) {
+      cmSystemTools::RemoveFile(this->SettingsFile);
+    }
+  } else {
+    // If the file could not be read re-generate everythiung.
+    this->SettingsChanged = true;
+  }
+}
+
+bool cmQtAutoGeneratorRcc::SettingsFileWrite()
+{
+  bool success = true;
+  // Only write if any setting changed
+  if (this->SettingsChanged) {
+    if (this->GetVerbose()) {
+      this->LogInfo(cmQtAutoGen::RCC, "Writing settings file " +
+                      cmQtAutoGen::Quoted(this->SettingsFile));
+    }
+    // Compose settings file content
+    std::string settings;
+    {
+      auto SettingAppend = [&settings](const char* key,
+                                       std::string const& value) {
+        settings += "set(";
+        settings += key;
+        settings += " ";
+        settings += cmOutputConverter::EscapeForCMake(value);
+        settings += ")\n";
+      };
+      SettingAppend(SettingsKeyRcc, this->SettingsString);
+    }
+    // Write settings file
+    if (!this->FileWrite(cmQtAutoGen::RCC, this->SettingsFile, settings)) {
+      this->LogFileError(cmQtAutoGen::RCC, this->SettingsFile,
+                         "Settings file writing failed");
+      // Remove old settings file to trigger a full rebuild on the next run
+      cmSystemTools::RemoveFile(this->SettingsFile);
+      success = false;
+    }
+  }
+  return success;
+}
+
+bool cmQtAutoGeneratorRcc::Process(cmMakefile* makefile)
+{
+  // Read info file
+  if (!this->InfoFileRead(makefile)) {
+    return false;
+  }
+  // Read latest settings
+  this->SettingsFileRead(makefile);
+  // Generate rcc file
+  if (!this->RccGenerate()) {
+    return false;
+  }
+  // Write latest settings
+  if (!this->SettingsFileWrite()) {
+    return false;
+  }
+  return true;
+}
+
+/**
+ * @return True on success
+ */
+bool cmQtAutoGeneratorRcc::RccGenerate()
+{
+  bool success = true;
+  bool rccGenerated = false;
+
+  std::string rccFileAbs;
+  {
+    std::string suffix;
+    switch (this->MultiConfig) {
+      case cmQtAutoGen::SINGLE:
+        break;
+      case cmQtAutoGen::WRAP:
+        suffix = "_CMAKE";
+        suffix += this->ConfigSuffix;
+        suffix += "_";
+        break;
+      case cmQtAutoGen::FULL:
+        suffix = this->ConfigSuffix;
+        break;
+    }
+    rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(this->RccFile, suffix);
+  }
+  std::string const rccFileRel = cmSystemTools::RelativePath(
+    this->AutogenBuildDir.c_str(), rccFileAbs.c_str());
+
+  // Check if regeneration is required
+  bool generate = false;
+  std::string generateReason;
+  if (!cmSystemTools::FileExists(this->QrcFile)) {
+    {
+      std::string error = "Could not find the file\n  ";
+      error += cmQtAutoGen::Quoted(this->QrcFile);
+      this->LogError(cmQtAutoGen::RCC, error);
+    }
+    success = false;
+  }
+  if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) {
+    if (this->GetVerbose()) {
+      generateReason = "Generating ";
+      generateReason += cmQtAutoGen::Quoted(rccFileAbs);
+      generateReason += " from its source file ";
+      generateReason += cmQtAutoGen::Quoted(this->QrcFile);
+      generateReason += " because it doesn't exist";
+    }
+    generate = true;
+  }
+  if (success && !generate && this->SettingsChanged) {
+    if (this->GetVerbose()) {
+      generateReason = "Generating ";
+      generateReason += cmQtAutoGen::Quoted(rccFileAbs);
+      generateReason += " from ";
+      generateReason += cmQtAutoGen::Quoted(this->QrcFile);
+      generateReason += " because the RCC settings changed";
+    }
+    generate = true;
+  }
+  if (success && !generate) {
+    std::string error;
+    if (FileIsOlderThan(rccFileAbs, this->QrcFile, &error)) {
+      if (this->GetVerbose()) {
+        generateReason = "Generating ";
+        generateReason += cmQtAutoGen::Quoted(rccFileAbs);
+        generateReason += " because it is older than ";
+        generateReason += cmQtAutoGen::Quoted(this->QrcFile);
+      }
+      generate = true;
+    } else {
+      if (!error.empty()) {
+        this->LogError(cmQtAutoGen::RCC, error);
+        success = false;
+      }
+    }
+  }
+  if (success && !generate) {
+    // Acquire input file list
+    std::vector<std::string> readFiles;
+    std::vector<std::string> const* files = nullptr;
+    if (!this->Inputs.empty()) {
+      files = &this->Inputs;
+    } else {
+      // Read input file list from qrc file
+      std::string error;
+      if (cmQtAutoGen::RccListInputs(this->RccExecutable, this->RccListOptions,
+                                     this->QrcFile, readFiles, &error)) {
+        files = &readFiles;
+      } else {
+        this->LogFileError(cmQtAutoGen::RCC, this->QrcFile, error);
+        success = false;
+      }
+    }
+    // Test if any input file is newer than the build file
+    if (files != nullptr) {
+      std::string error;
+      for (std::string const& resFile : *files) {
+        if (!cmSystemTools::FileExists(resFile.c_str())) {
+          error = "Could not find the file\n  ";
+          error += cmQtAutoGen::Quoted(resFile);
+          error += "\nwhich is listed in\n  ";
+          error += cmQtAutoGen::Quoted(this->QrcFile);
+          break;
+        }
+        if (FileIsOlderThan(rccFileAbs, resFile, &error)) {
+          if (this->GetVerbose()) {
+            generateReason = "Generating ";
+            generateReason += cmQtAutoGen::Quoted(rccFileAbs);
+            generateReason += " from ";
+            generateReason += cmQtAutoGen::Quoted(this->QrcFile);
+            generateReason += " because it is older than ";
+            generateReason += cmQtAutoGen::Quoted(resFile);
+          }
+          generate = true;
+          break;
+        }
+        if (!error.empty()) {
+          break;
+        }
+      }
+      // Print error
+      if (!error.empty()) {
+        this->LogError(cmQtAutoGen::RCC, error);
+        success = false;
+      }
+    }
+  }
+  // Regenerate on demand
+  if (generate) {
+    // Log
+    if (this->GetVerbose()) {
+      this->LogBold("Generating RCC source " + rccFileRel);
+      this->LogInfo(cmQtAutoGen::RCC, generateReason);
+    }
+
+    // Make sure the parent directory exists
+    if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) {
+      // Compose rcc command
+      std::vector<std::string> cmd;
+      cmd.push_back(this->RccExecutable);
+      cmd.insert(cmd.end(), this->Options.begin(), this->Options.end());
+      cmd.push_back("-o");
+      cmd.push_back(rccFileAbs);
+      cmd.push_back(this->QrcFile);
+
+      std::string output;
+      if (this->RunCommand(cmd, output)) {
+        // Success
+        rccGenerated = true;
+      } else {
+        {
+          std::string emsg = "rcc failed for\n  ";
+          emsg += cmQtAutoGen::Quoted(this->QrcFile);
+          this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output);
+        }
+        cmSystemTools::RemoveFile(rccFileAbs);
+        success = false;
+      }
+    } else {
+      // Parent directory creation failed
+      success = false;
+    }
+  }
+
+  // Generate a wrapper source file on demand
+  if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) {
+    // Wrapper file name
+    std::string const& wrapperFileAbs = this->RccFile;
+    std::string const wrapperFileRel = cmSystemTools::RelativePath(
+      this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str());
+    // Wrapper file content
+    std::string content = "// This is an autogenerated configuration "
+                          "wrapper file. Changes will be overwritten.\n"
+                          "#include \"";
+    content += cmSystemTools::GetFilenameName(rccFileRel);
+    content += "\"\n";
+    // Write content to file
+    if (this->FileDiffers(wrapperFileAbs, content)) {
+      // Write new wrapper file
+      if (this->GetVerbose()) {
+        this->LogBold("Generating RCC wrapper " + wrapperFileRel);
+      }
+      if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) {
+        this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs,
+                           "rcc wrapper file writing failed");
+        success = false;
+      }
+    } else if (rccGenerated) {
+      // Just touch the wrapper file
+      if (this->GetVerbose()) {
+        this->LogInfo(cmQtAutoGen::RCC,
+                      "Touching RCC wrapper " + wrapperFileRel);
+      }
+      cmSystemTools::Touch(wrapperFileAbs, false);
+    }
+  }
+
+  return success;
+}

+ 56 - 0
Source/cmQtAutoGeneratorRcc.h

@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmQtAutoGeneratorRcc_h
+#define cmQtAutoGeneratorRcc_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFilePathChecksum.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+class cmQtAutoGeneratorRcc : public cmQtAutoGenerator
+{
+  CM_DISABLE_COPY(cmQtAutoGeneratorRcc)
+public:
+  cmQtAutoGeneratorRcc();
+
+private:
+  // -- Initialization & settings
+  bool InfoFileRead(cmMakefile* makefile);
+  void SettingsFileRead(cmMakefile* makefile);
+  bool SettingsFileWrite();
+  // -- Central processing
+  bool Process(cmMakefile* makefile) override;
+  bool RccGenerate();
+
+  // -- Config settings
+  std::string ConfigSuffix;
+  cmQtAutoGen::MultiConfig MultiConfig;
+  // -- Settings
+  bool SettingsChanged;
+  std::string SettingsFile;
+  std::string SettingsString;
+  // -- Directories
+  std::string ProjectSourceDir;
+  std::string ProjectBinaryDir;
+  std::string CurrentSourceDir;
+  std::string CurrentBinaryDir;
+  std::string AutogenBuildDir;
+  cmFilePathChecksum FilePathChecksum;
+  // -- Qt environment
+  std::string RccExecutable;
+  std::vector<std::string> RccListOptions;
+  // -- Job
+  std::string QrcFile;
+  std::string RccFile;
+  std::vector<std::string> Options;
+  std::vector<std::string> Inputs;
+};
+
+#endif

+ 15 - 5
Source/cmcmd.cxx

@@ -6,7 +6,8 @@
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmQtAutoGenerators.h"
+#include "cmQtAutoGeneratorMocUic.h"
+#include "cmQtAutoGeneratorRcc.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
@@ -992,11 +993,20 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
     }
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
-    if (args[1] == "cmake_autogen" && args.size() >= 4) {
-      cmQtAutoGenerators autogen;
+    if ((args[1] == "cmake_autogen") && (args.size() >= 4)) {
+      cmQtAutoGeneratorMocUic autoGen;
+      std::string const& infoDir = args[2];
       std::string const& config = args[3];
-      bool autogenSuccess = autogen.Run(args[2], config);
-      return autogenSuccess ? 0 : 1;
+      return autoGen.Run(infoDir, config) ? 0 : 1;
+    }
+    if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
+      cmQtAutoGeneratorRcc autoGen;
+      std::string const& infoFile = args[2];
+      std::string config;
+      if (args.size() > 3) {
+        config = args[3];
+      };
+      return autoGen.Run(infoFile, config) ? 0 : 1;
     }
 #endif
 

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików