Browse Source

Autogen: Add support for generated .qrc files

Sebastian Holtermann 8 năm trước cách đây
mục cha
commit
699321bfd5

+ 90 - 41
Source/cmQtAutoGeneratorCommon.cxx

@@ -24,47 +24,62 @@ static std::string utilStripCR(std::string const& 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(const std::string& fileName,
-                             std::vector<std::string>& files)
+                             std::vector<std::string>& files,
+                             std::string* errorMessage)
 {
-  // Qrc file directory
-  std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
-  if (!qrcDir.empty()) {
-    qrcDir += '/';
-  }
-
-  // Read file into string
+  bool allGood = true;
+  // Read qrc file content into string
   std::string qrcContents;
   {
-    std::ostringstream stream;
-    stream << cmsys::ifstream(fileName).rdbuf();
-    qrcContents = stream.str();
+    cmsys::ifstream ifs(fileName.c_str());
+    if (ifs) {
+      std::ostringstream osst;
+      osst << ifs.rdbuf();
+      qrcContents = osst.str();
+    } else {
+      if (errorMessage != CM_NULLPTR) {
+        std::ostringstream ost;
+        ost << "AutoRcc: Error: Rcc file not readable:\n"
+            << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
+        *errorMessage = ost.str();
+      }
+      allGood = false;
+    }
   }
-
-  cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
-  cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
-
-  size_t offset = 0;
-  while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
-    std::string qrcEntry = fileMatchRegex.match(1);
-    offset += qrcEntry.size();
-    {
-      fileReplaceRegex.find(qrcEntry);
-      std::string tag = fileReplaceRegex.match(1);
-      qrcEntry = qrcEntry.substr(tag.size());
+  if (allGood) {
+    // qrc file directory
+    std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
+    if (!qrcDir.empty()) {
+      qrcDir += '/';
     }
-    if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
-      qrcEntry = qrcDir + qrcEntry;
+
+    cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
+    cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
+
+    size_t offset = 0;
+    while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
+      std::string qrcEntry = fileMatchRegex.match(1);
+      offset += qrcEntry.size();
+      {
+        fileReplaceRegex.find(qrcEntry);
+        std::string tag = fileReplaceRegex.match(1);
+        qrcEntry = qrcEntry.substr(tag.size());
+      }
+      if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
+        qrcEntry = qrcDir + qrcEntry;
+      }
+      files.push_back(qrcEntry);
     }
-    files.push_back(qrcEntry);
   }
-  return true;
+  return allGood;
 }
 
 /// @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(const std::string& rccCommand,
                              const std::string& fileName,
-                             std::vector<std::string>& files)
+                             std::vector<std::string>& files,
+                             std::string* errorMessage)
 {
   if (rccCommand.empty()) {
     cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n");
@@ -104,11 +119,14 @@ static bool RccListInputsQt5(const std::string& rccCommand,
                                       CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
   }
   if (!result || retVal) {
-    std::ostringstream err;
-    err << "AUTOGEN: error: Rcc list process for " << fileName << " failed:\n"
-        << rccStdOut << "\n"
-        << rccStdErr << std::endl;
-    cmSystemTools::Error(err.str().c_str());
+    if (errorMessage != CM_NULLPTR) {
+      std::ostringstream ost;
+      ost << "AutoRcc: Error: Rcc list process for " << fileName
+          << " failed:\n"
+          << rccStdOut << "\n"
+          << rccStdErr << "\n";
+      *errorMessage = ost.str();
+    }
     return false;
   }
 
@@ -134,10 +152,12 @@ static bool RccListInputsQt5(const std::string& rccCommand,
 
         std::string::size_type pos = eline.find(searchString);
         if (pos == std::string::npos) {
-          std::ostringstream err;
-          err << "AUTOGEN: error: Rcc lists unparsable output " << eline
-              << std::endl;
-          cmSystemTools::Error(err.str().c_str());
+          if (errorMessage != CM_NULLPTR) {
+            std::ostringstream ost;
+            ost << "AutoRcc: Error: Rcc lists unparsable output:\n"
+                << cmQtAutoGeneratorCommon::Quoted(eline) << "\n";
+            *errorMessage = ost.str();
+          }
           return false;
         }
         pos += searchString.length();
@@ -154,13 +174,42 @@ static bool RccListInputsQt5(const std::string& rccCommand,
 
 const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@";
 
+std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text)
+{
+  static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
+                                 "\b", "\\b",  "\f", "\\f",  "\n", "\\n",
+                                 "\r", "\\r",  "\t", "\\t",  "\v", "\\v" };
+
+  std::string res = text;
+  for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep);
+       it += 2) {
+    cmSystemTools::ReplaceString(res, *it, *(it + 1));
+  }
+  res = '"' + res;
+  res += '"';
+  return res;
+}
+
 bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion,
                                             const std::string& rccCommand,
                                             const std::string& fileName,
-                                            std::vector<std::string>& files)
+                                            std::vector<std::string>& files,
+                                            std::string* errorMessage)
 {
-  if (qtMajorVersion == "4") {
-    return RccListInputsQt4(fileName, files);
+  bool allGood = false;
+  if (cmsys::SystemTools::FileExists(fileName.c_str())) {
+    if (qtMajorVersion == "4") {
+      allGood = RccListInputsQt4(fileName, files, errorMessage);
+    } else {
+      allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage);
+    }
+  } else {
+    if (errorMessage != CM_NULLPTR) {
+      std::ostringstream ost;
+      ost << "AutoRcc: Error: Rcc file does not exist:\n"
+          << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
+      *errorMessage = ost.str();
+    }
   }
-  return RccListInputsQt5(rccCommand, fileName, files);
+  return allGood;
 }

+ 6 - 1
Source/cmQtAutoGeneratorCommon.h

@@ -17,13 +17,18 @@ public:
   static const char* listSep;
 
 public:
+  /// @brief Returns a the string escaped and enclosed in quotes
+  ///
+  static std::string Quoted(const std::string& text);
+
   /// @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(const std::string& qtMajorVersion,
                             const std::string& rccCommand,
                             const std::string& fileName,
-                            std::vector<std::string>& files);
+                            std::vector<std::string>& files,
+                            std::string* errorMessage = CM_NULLPTR);
 };
 
 #endif

+ 11 - 4
Source/cmQtAutoGeneratorInitializer.cxx

@@ -490,13 +490,15 @@ static void RccSetupAutoTarget(cmGeneratorTarget const* target,
         // qrc file entries
         {
           std::string entriesList = "{";
+          // Read input file list only for non generated .qrc files.
           if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
+            std::string error;
             std::vector<std::string> files;
             if (cmQtAutoGeneratorCommon::RccListInputs(
-                  qtMajorVersion, rccCommand, absFile, files)) {
+                  qtMajorVersion, rccCommand, absFile, files, &error)) {
               entriesList += cmJoin(files, cmQtAutoGeneratorCommon::listSep);
             } else {
-              return;
+              cmSystemTools::Error(error.c_str());
             }
           }
           entriesList += "}";
@@ -690,8 +692,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
 #endif
               ) {
             if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
-              cmQtAutoGeneratorCommon::RccListInputs(
-                qtMajorVersion, rccCommand, absFile, depends);
+              {
+                std::string error;
+                if (!cmQtAutoGeneratorCommon::RccListInputs(
+                      qtMajorVersion, rccCommand, absFile, depends, &error)) {
+                  cmSystemTools::Error(error.c_str());
+                }
+              }
 #if defined(_WIN32) && !defined(__CYGWIN__)
               // Cannot use PRE_BUILD because the resource files themselves
               // may not be sources within the target so VS may not know the

+ 35 - 31
Source/cmQtAutoGenerators.cxx

@@ -37,23 +37,9 @@ static const char* SettingsKeyRcc = "AM_RCC_OLD_SETTINGS";
 
 // -- Static functions
 
-/**
- * @brief Returns a the string escaped and enclosed in quotes
- */
-static std::string Quoted(const std::string& text)
+inline static std::string Quoted(const std::string& text)
 {
-  static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
-                                 "\b", "\\b",  "\f", "\\f",  "\n", "\\n",
-                                 "\r", "\\r",  "\t", "\\t",  "\v", "\\v" };
-
-  std::string res = text;
-  for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep);
-       it += 2) {
-    cmSystemTools::ReplaceString(res, *it, *(it + 1));
-  }
-  res = '"' + res;
-  res += '"';
-  return res;
+  return cmQtAutoGeneratorCommon::Quoted(text);
 }
 
 static void InfoGet(cmMakefile* makefile, const char* key, std::string& value)
@@ -403,7 +389,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
       } else {
         this->LogError(
           "AutoMoc: Error: AUTOMOC_DEPEND_FILTERS list size is not "
-          "a multiple of 2");
+          "a multiple of 2 in:\n" +
+          Quoted(filename));
         return false;
       }
     }
@@ -431,8 +418,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
         }
       } else {
         this->LogError(
-          "AutoGen: Error: Uic files/options lists size missmatch in: " +
-          filename);
+          "AutoGen: Error: Uic files/options lists size missmatch in:\n" +
+          Quoted(filename));
         return false;
       }
     }
@@ -447,7 +434,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
       std::vector<std::string> rccOptionsVec;
       InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec);
       InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec);
-      if (rccFilesVec.size() != rccOptionsVec.size()) {
+      if (rccFilesVec.size() == rccOptionsVec.size()) {
         for (std::vector<std::string>::iterator
                fileIt = rccFilesVec.begin(),
                optionIt = rccOptionsVec.begin();
@@ -459,8 +446,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
         }
       } else {
         this->LogError(
-          "AutoGen: Error: RCC files/options lists size missmatch in: " +
-          filename);
+          "AutoGen: Error: RCC files/options lists size missmatch in:\n" +
+          Quoted(filename));
         return false;
       }
     }
@@ -484,8 +471,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
         }
       } else {
         this->LogError(
-          "AutoGen: Error: RCC sources/inputs lists size missmatch in: " +
-          filename);
+          "AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" +
+          Quoted(filename));
         return false;
       }
     }
@@ -1574,13 +1561,30 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
     // Test if the resources list file is newer than build file
     generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile);
     if (!generateRcc) {
-      // Test if any resource file is newer than the build file
-      const std::vector<std::string>& files = this->RccInputs[rccInputFile];
-      for (std::vector<std::string>::const_iterator it = files.begin();
-           it != files.end(); ++it) {
-        if (FileAbsentOrOlder(rccBuildFile, *it)) {
-          generateRcc = true;
-          break;
+      // Acquire input file list
+      std::vector<std::string> readFiles;
+      const std::vector<std::string>* files = &this->RccInputs[rccInputFile];
+      if (files->empty()) {
+        // Read input file list from qrc file
+        std::string error;
+        if (cmQtAutoGeneratorCommon::RccListInputs(
+              this->QtMajorVersion, this->RccExecutable, rccInputFile,
+              readFiles, &error)) {
+          files = &readFiles;
+        } else {
+          files = CM_NULLPTR;
+          this->LogError(error);
+          this->RunRccFailed = true;
+        }
+      }
+      // Test if any input file is newer than the build file
+      if (files != CM_NULLPTR) {
+        for (std::vector<std::string>::const_iterator it = files->begin();
+             it != files->end(); ++it) {
+          if (FileAbsentOrOlder(rccBuildFile, *it)) {
+            generateRcc = true;
+            break;
+          }
         }
       }
     }