Procházet zdrojové kódy

Autogen: Pass RCC build names and function names in info file

- The output file name of the `rcc` command get computed once
  in the AUTOGEN initializer and is passed in the info file.

- The function name for the `-name` option of `rcc` gets computed
  once in the AUTOGEN initializer and is passed along with the
  other `rcc` options in the info file.
Sebastian Holtermann před 8 roky
rodič
revize
37ef18a468

+ 2 - 2
Modules/AutogenInfo.cmake.in

@@ -30,6 +30,6 @@ 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@)
-set(AM_RCC_OPTIONS_FILES @_rcc_options_files@)
-set(AM_RCC_OPTIONS_OPTIONS @_rcc_options_options@)

+ 4 - 0
Source/cmQtAutoGenDigest.h

@@ -16,13 +16,17 @@ 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;
 };

+ 61 - 45
Source/cmQtAutoGeneratorInitializer.cxx

@@ -580,40 +580,25 @@ static std::string RccGetExecutable(cmGeneratorTarget const* target,
 
 static void SetupAutoTargetRcc(const cmQtAutoGenDigest& digest)
 {
-  cmGeneratorTarget const* target = digest.Target;
-  cmMakefile* makefile = target->Target->GetMakefile();
   std::vector<std::string> rccFiles;
-  std::vector<std::string> rccInputs;
-  std::vector<std::string> rccFileFiles;
-  std::vector<std::string> rccFileOptions;
+  std::vector<std::string> rccBuilds;
+  std::vector<std::vector<std::string>> rccOptions;
+  std::vector<std::vector<std::string>> rccInputs;
 
   for (const cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
-    const std::string absFile = qrcDigest.QrcFile;
-    // Register file
-    rccFiles.push_back(absFile);
-    // Register (known) resource files
-    {
-      std::string entriesList = "{";
-      if (!qrcDigest.Generated) {
-        entriesList += cmJoin(qrcDigest.Resources, cmQtAutoGen::listSep);
-      }
-      entriesList += "}";
-      rccInputs.push_back(entriesList);
-    }
-    // rcc options for this qrc file
-    if (!qrcDigest.Options.empty()) {
-      rccFileFiles.push_back(absFile);
-      rccFileOptions.push_back(
-        cmJoin(qrcDigest.Options, cmQtAutoGen::listSep));
-    }
+    rccFiles.push_back(qrcDigest.QrcFile);
+    rccBuilds.push_back(qrcDigest.RccFile);
+    rccOptions.push_back(qrcDigest.Options);
+    rccInputs.push_back(qrcDigest.Resources);
   }
 
+  cmMakefile* makefile = digest.Target->Target->GetMakefile();
   AddDefinitionEscaped(makefile, "_qt_rcc_executable",
-                       RccGetExecutable(target, digest.QtVersionMajor));
+                       RccGetExecutable(digest.Target, digest.QtVersionMajor));
   AddDefinitionEscaped(makefile, "_rcc_files", rccFiles);
+  AddDefinitionEscaped(makefile, "_rcc_builds", rccBuilds);
+  AddDefinitionEscaped(makefile, "_rcc_options", rccOptions);
   AddDefinitionEscaped(makefile, "_rcc_inputs", rccInputs);
-  AddDefinitionEscaped(makefile, "_rcc_options_files", rccFileFiles);
-  AddDefinitionEscaped(makefile, "_rcc_options_options", rccFileOptions);
 }
 
 void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
@@ -746,6 +731,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
         {
           cmQtAutoGenDigestQrc qrcDigest;
           qrcDigest.QrcFile = cmSystemTools::GetRealPath(fPath);
+          qrcDigest.QrcName =
+            cmSystemTools::GetFilenameWithoutLastExtension(qrcDigest.QrcFile);
           qrcDigest.Generated = sf->GetPropertyAsBool("GENERATED");
           // RCC options
           {
@@ -822,36 +809,65 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
   // Process qrc files
   if (!digest.Qrcs.empty()) {
     const bool QtV5 = (digest.QtVersionMajor == "5");
-    const cmFilePathChecksum fpathCheckSum(makefile);
     const std::string rcc = RccGetExecutable(target, digest.QtVersionMajor);
     // Target rcc options
     std::vector<std::string> optionsTarget;
     cmSystemTools::ExpandListArgument(
       GetSafeProperty(target, "AUTORCC_OPTIONS"), optionsTarget);
 
+    // Check if file name is unique
     for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
-      // RCC output file name
-      {
-        std::string rccFile = autogenBuildDir + "/";
-        rccFile += fpathCheckSum.getPart(qrcDigest.QrcFile);
-        rccFile += "/qrc_";
-        rccFile +=
-          cmSystemTools::GetFilenameWithoutLastExtension(qrcDigest.QrcFile);
-        rccFile += ".cpp";
-
-        AddGeneratedSource(target, rccFile, cmQtAutoGen::RCC);
-        autogenProvides.push_back(rccFile);
-        qrcDigest.RccFile = std::move(rccFile);
+      qrcDigest.Unique = true;
+      for (const cmQtAutoGenDigestQrc& qrcDig2 : digest.Qrcs) {
+        if ((&qrcDigest != &qrcDig2) &&
+            (qrcDigest.QrcName == qrcDig2.QrcName)) {
+          qrcDigest.Unique = false;
+          break;
+        }
       }
-      // RCC options
+    }
+    // Path checksum
+    {
+      const cmFilePathChecksum fpathCheckSum(makefile);
+      for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
+        qrcDigest.PathChecksum = fpathCheckSum.getPart(qrcDigest.QrcFile);
+      }
+    }
+    // RCC output file name
+    for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
+      std::string rccFile = autogenBuildDir + "/";
+      rccFile += qrcDigest.PathChecksum;
+      rccFile += "/qrc_";
+      rccFile += qrcDigest.QrcName;
+      rccFile += ".cpp";
+      qrcDigest.RccFile = std::move(rccFile);
+    }
+    // RCC options
+    for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
+      // Target options
+      std::vector<std::string> opts = optionsTarget;
+      // Merge computed "-name XYZ" option
       {
-        std::vector<std::string> opts = optionsTarget;
-        if (!qrcDigest.Options.empty()) {
-          cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5);
+        std::string name = qrcDigest.QrcName;
+        // Replace '-' with '_'. The former is not valid for symbol names.
+        std::replace(name.begin(), name.end(), '-', '_');
+        if (!qrcDigest.Unique) {
+          name += "_";
+          name += qrcDigest.PathChecksum;
         }
-        qrcDigest.Options = std::move(opts);
+        std::vector<std::string> nameOpts;
+        nameOpts.emplace_back("-name");
+        nameOpts.emplace_back(std::move(name));
+        cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5);
       }
-      // GENERATED or not
+      // Merge file option
+      cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5);
+      qrcDigest.Options = std::move(opts);
+    }
+    for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
+      // Register file at target
+      AddGeneratedSource(target, qrcDigest.RccFile, cmQtAutoGen::RCC);
+      autogenProvides.push_back(qrcDigest.RccFile);
       if (qrcDigest.Generated) {
         // Add GENERATED qrc file to the dependencies
         autogenDepends.insert(qrcDigest.QrcFile);

+ 86 - 133
Source/cmQtAutoGenerators.cxx

@@ -166,22 +166,6 @@ static std::string SubDirPrefix(const std::string& fileName)
   return res;
 }
 
-static bool FileNameIsUnique(const std::string& filePath,
-                             const std::map<std::string, std::string>& fileMap)
-{
-  size_t count(0);
-  const std::string fileName = cmSystemTools::GetFilenameName(filePath);
-  for (const auto& item : fileMap) {
-    if (cmSystemTools::GetFilenameName(item.first) == fileName) {
-      ++count;
-      if (count > 1) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
 static bool ReadAll(std::string& content, const std::string& filename)
 {
   bool success = false;
@@ -473,51 +457,51 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
 
   // - Rcc
   if (this->RccEnabled()) {
-    InfoGet(makefile, "AM_RCC_SOURCES", this->RccSources);
-    // File options
-    {
-      std::vector<std::string> rccFilesVec;
-      std::vector<std::string> rccOptionsVec;
-      InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec);
-      InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec);
-      if (rccFilesVec.size() == rccOptionsVec.size()) {
-        for (std::vector<std::string>::iterator
-               fileIt = rccFilesVec.begin(),
-               optionIt = rccOptionsVec.begin();
-             fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) {
-          // Replace item separator
-          cmSystemTools::ReplaceString(*optionIt, cmQtAutoGen::listSep, ";");
-          this->RccOptions[*fileIt] = *optionIt;
-        }
-      } else {
-        this->LogError(
-          "AutoGen: Error: RCC files/options lists size missmatch in:\n" +
-          Quoted(filename));
-        return false;
-      }
-    }
     // File lists
+    auto sources = InfoGetList(makefile, "AM_RCC_SOURCES");
+    auto builds = InfoGetList(makefile, "AM_RCC_BUILDS");
+    auto options = InfoGetLists(makefile, "AM_RCC_OPTIONS");
+    auto inputs = InfoGetLists(makefile, "AM_RCC_INPUTS");
+
+    if (sources.size() != builds.size()) {
+      std::ostringstream ost;
+      ost << "AutoRcc: Error: sources/builds list sizes missmatch ("
+          << sources.size() << "/" << builds.size() << ")"
+          << " in\n  " << Quoted(filename);
+      this->LogError(ost.str());
+      return false;
+    }
+    if (sources.size() != options.size()) {
+      std::ostringstream ost;
+      ost << "AutoRcc: Error: sources/options list sizes missmatch ("
+          << sources.size() << "/" << options.size() << ")"
+          << " in\n  " << Quoted(filename);
+      this->LogError(ost.str());
+      return false;
+    }
+    if (sources.size() != inputs.size()) {
+      std::ostringstream ost;
+      ost << "AutoRcc: Error: sources/inputs list sizes missmatch ("
+          << sources.size() << "/" << inputs.size() << ")"
+          << " in\n  " << Quoted(filename);
+      this->LogError(ost.str());
+      return false;
+    }
+
     {
-      std::vector<std::string> rccInputLists;
-      InfoGet(makefile, "AM_RCC_INPUTS", rccInputLists);
-      if (this->RccSources.size() == rccInputLists.size()) {
-        for (std::vector<std::string>::iterator
-               fileIt = this->RccSources.begin(),
-               inputIt = rccInputLists.begin();
-             fileIt != this->RccSources.end(); ++fileIt, ++inputIt) {
-          // Remove braces
-          *inputIt = inputIt->substr(1, inputIt->size() - 2);
-          // Replace item separator
-          cmSystemTools::ReplaceString(*inputIt, cmQtAutoGen::listSep, ";");
-          std::vector<std::string> rccInputFiles;
-          cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles);
-          this->RccInputs[*fileIt] = rccInputFiles;
-        }
-      } else {
-        this->LogError(
-          "AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" +
-          Quoted(filename));
-        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;
       }
     }
   }
@@ -560,8 +544,14 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile)
     if (this->RccEnabled()) {
       std::string str;
       str += this->RccExecutable;
-      str += sep;
-      str += JoinOptionsMap(this->RccOptions);
+      for (const RccJob& rccJob : this->RccJobs) {
+        str += sep;
+        str += rccJob.QrcFile;
+        str += sep;
+        str += rccJob.RccFile;
+        str += sep;
+        str += JoinOptionsList(rccJob.Options);
+      }
       str += sep;
       this->SettingsStringRcc = crypt.HashString(str);
     }
@@ -1622,33 +1612,9 @@ bool cmQtAutoGenerators::RccGenerateAll()
     return true;
   }
 
-  // generate single map with input / output names
-  std::map<std::string, std::string> qrcGenMap;
-  {
-    const std::string qrcPrefix = "qrc_";
-    const std::string qrcSuffix = this->ConfigSuffix + ".cpp";
-    for (const std::string& src : this->RccSources) {
-      qrcGenMap[src] = this->ChecksumedPath(src, qrcPrefix, qrcSuffix);
-    }
-  }
-
-  // look for name collisions
-  {
-    std::multimap<std::string, std::string> collisions;
-    if (this->NameCollisionTest(qrcGenMap, collisions)) {
-      std::ostringstream ost;
-      ost << "AutoRcc: Error: The same qrc_NAME.cpp file"
-             " will be generated from different sources.\n"
-             "To avoid this error rename the source .qrc files.\n";
-      this->LogErrorNameCollision(ost.str(), collisions);
-      return false;
-    }
-  }
-
-  // generate qrc files
-  for (const auto& item : qrcGenMap) {
-    bool unique = FileNameIsUnique(item.first, qrcGenMap);
-    if (!this->RccGenerateFile(item.first, item.second, unique)) {
+  // Generate qrc files
+  for (const RccJob& rccJob : this->RccJobs) {
+    if (!this->RccGenerateFile(rccJob)) {
       if (this->RccRunFailed) {
         return false;
       }
@@ -1660,28 +1626,37 @@ bool cmQtAutoGenerators::RccGenerateAll()
 /**
  * @return True if a rcc file was created. False may indicate an error.
  */
-bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
-                                         const std::string& rccOutputFile,
-                                         bool unique_n)
+bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob)
 {
   bool rccGenerated = false;
   bool generateRcc = this->RccSettingsChanged;
-  const std::string rccBuildFile =
-    cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, rccOutputFile);
+
+  std::string rccFileAbs;
+  if (this->ConfigSuffix.empty()) {
+    rccFileAbs = rccJob.RccFile;
+  } else {
+    rccFileAbs = SubDirPrefix(rccJob.RccFile);
+    rccFileAbs +=
+      cmSystemTools::GetFilenameWithoutLastExtension(rccJob.RccFile);
+    rccFileAbs += this->ConfigSuffix;
+    rccFileAbs += cmSystemTools::GetFilenameLastExtension(rccJob.RccFile);
+  }
+  const std::string rccFileRel = cmSystemTools::RelativePath(
+    this->AutogenBuildDir.c_str(), rccFileAbs.c_str());
 
   // Check if regeneration is required
   if (!generateRcc) {
     // Test if the resources list file is newer than build file
-    generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile);
+    generateRcc = FileAbsentOrOlder(rccFileAbs, rccJob.QrcFile);
     if (!generateRcc) {
       // Acquire input file list
       std::vector<std::string> readFiles;
-      const std::vector<std::string>* files = &this->RccInputs[rccInputFile];
+      const std::vector<std::string>* files = &rccJob.Inputs;
       if (files->empty()) {
         // Read input file list from qrc file
         std::string error;
         if (cmQtAutoGen::RccListInputs(this->QtMajorVersion,
-                                       this->RccExecutable, rccInputFile,
+                                       this->RccExecutable, rccJob.QrcFile,
                                        readFiles, &error)) {
           files = &readFiles;
         } else {
@@ -1693,7 +1668,7 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
       // Test if any input file is newer than the build file
       if (files != nullptr) {
         for (const std::string& file : *files) {
-          if (FileAbsentOrOlder(rccBuildFile, file)) {
+          if (FileAbsentOrOlder(rccFileAbs, file)) {
             generateRcc = true;
             break;
           }
@@ -1705,37 +1680,18 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
   if (generateRcc) {
     // Log
     if (this->Verbose) {
-      this->LogBold("Generating RCC source " + rccOutputFile);
+      this->LogBold("Generating RCC source " + rccFileRel);
     }
 
     // Make sure the parent directory exists
-    if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccBuildFile)) {
-      // Compose symbol name
-      std::string symbolName =
-        cmSystemTools::GetFilenameWithoutLastExtension(rccInputFile);
-      if (!unique_n) {
-        symbolName += "_";
-        symbolName += FPathChecksum.getPart(rccInputFile);
-      }
-      // Replace '-' with '_'. The former is valid for
-      // file names but not for symbol names.
-      std::replace(symbolName.begin(), symbolName.end(), '-', '_');
-
+    if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) {
       // Compose rcc command
       std::vector<std::string> cmd;
       cmd.push_back(this->RccExecutable);
-      {
-        std::map<std::string, std::string>::const_iterator optionIt =
-          this->RccOptions.find(rccInputFile);
-        if (optionIt != this->RccOptions.end()) {
-          cmSystemTools::ExpandListArgument(optionIt->second, cmd);
-        }
-      }
-      cmd.push_back("-name");
-      cmd.push_back(symbolName);
+      cmd.insert(cmd.end(), rccJob.Options.begin(), rccJob.Options.end());
       cmd.push_back("-o");
-      cmd.push_back(rccBuildFile);
-      cmd.push_back(rccInputFile);
+      cmd.push_back(rccFileAbs);
+      cmd.push_back(rccJob.QrcFile);
 
       std::string output;
       if (this->RunCommand(cmd, output)) {
@@ -1746,12 +1702,12 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
         {
           std::ostringstream ost;
           ost << "AutoRcc: Error: rcc process failed for\n";
-          ost << Quoted(rccOutputFile) << "\n";
+          ost << Quoted(rccFileRel) << "\n";
           ost << "AutoRcc: Command:\n" << QuotedCommand(cmd) << "\n";
           ost << "AutoRcc: Command output:\n" << output << "\n";
           this->LogError(ost.str());
         }
-        cmSystemTools::RemoveFile(rccBuildFile);
+        cmSystemTools::RemoveFile(rccFileAbs);
         this->RccRunFailed = true;
       }
     } else {
@@ -1762,17 +1718,14 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
   // For a multi configuration generator generate a wrapper file
   if (!this->ConfigSuffix.empty() && !this->RccRunFailed) {
     // Wrapper file name
-    const std::string cppSuffix = ".cpp";
-    const size_t suffixLength = this->ConfigSuffix.size() + cppSuffix.size();
-    const std::string wrapperFileRel =
-      rccOutputFile.substr(0, rccOutputFile.size() - suffixLength) + cppSuffix;
-    const std::string wrapperFileAbs = cmSystemTools::CollapseCombinedPath(
-      this->AutogenBuildDir, wrapperFileRel);
+    const std::string& wrapperFileAbs = rccJob.RccFile;
+    const std::string wrapperFileRel = cmSystemTools::RelativePath(
+      this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str());
     // Wrapper file content
-    std::string content =
-      "// This is an autogenerated configuration wrapper file. Do not edit.\n"
-      "#include \"";
-    content += cmSystemTools::GetFilenameName(rccBuildFile);
+    std::string content = "// This is an autogenerated configuration "
+                          "wrapper file. Do not edit.\n"
+                          "#include \"";
+    content += cmSystemTools::GetFilenameName(rccFileRel);
     content += "\"\n";
     // Write content to file
     if (this->FileDiffers(wrapperFileAbs, content)) {

+ 11 - 5
Source/cmQtAutoGenerators.h

@@ -46,6 +46,15 @@ private:
     cmsys::RegularExpression RegExp;
   };
 
+  /// @brief RCC job
+  struct RccJob
+  {
+    std::string QrcFile;
+    std::string RccFile;
+    std::vector<std::string> Options;
+    std::vector<std::string> Inputs;
+  };
+
   // -- Configuration
   bool MocDependFilterPush(const std::string& key, const std::string& regExp);
   bool ReadAutogenInfoFile(cmMakefile* makefile,
@@ -135,8 +144,7 @@ private:
 
   // -- Rcc file generation
   bool RccGenerateAll();
-  bool RccGenerateFile(const std::string& qrcInputFile,
-                       const std::string& qrcOutputFile, bool unique_n);
+  bool RccGenerateFile(const RccJob& rccJob);
 
   // -- Logging
   void LogErrorNameCollision(
@@ -227,9 +235,7 @@ private:
   // -- Rcc
   bool RccSettingsChanged;
   bool RccRunFailed;
-  std::vector<std::string> RccSources;
-  std::map<std::string, std::string> RccOptions;
-  std::map<std::string, std::vector<std::string>> RccInputs;
+  std::vector<RccJob> RccJobs;
 };
 
 #endif