Am 21.07.2016 um 17:40 schrieb Brad King:
On 04/22/2016 09:37 AM, Brad King wrote:
The rest of the changes are now in 'master'.  Thanks for working on this!

Unfortunately I've had to revert some of these changes due to
regressions they cause.  See issue here:

  https://gitlab.kitware.com/cmake/cmake/issues/16209

Hi,
I have prepared an other approach which uses checksum suffixes
instead of nested directory generation.
This was tested on my Debian/amd64/Makefile setup.

-- From the commit:
Subject: [PATCH] QtAutogen fix for too deep nested directory generation.

Instead of generating moc_* and qrc_* files in subdirectories
that reflect their source's location in the source tree
the files get generated solely in the TARGET_NAME_automoc.dir/
but get a Base64 encoded checksum suffix that was generated
from their source path and a few more seed strings.
--

Please review.

-Sebastian

>From 3cdb41e57e45ae145066b18a00aac53c9801b332 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <sebh...@xwmw.org>
Date: Tue, 26 Jul 2016 16:39:12 +0200
Subject: [PATCH] QtAutogen fix for too deep nested directory generation.

Instead of generating moc_* and qrc_* files in subdirectories
that reflect their source's location in the source tree
the files get generated solely in the TARGET_NAME_automoc.dir/
but get a Base64 encoded checksum suffix that was generated
from their source path and a few more seed strings.
---
 Source/cmQtAutoGeneratorInitializer.cxx |  80 +++---------
 Source/cmQtAutoGenerators.cxx           | 217 +++++++++++++++++++++++---------
 Source/cmQtAutoGenerators.h             |  26 +++-
 3 files changed, 202 insertions(+), 121 deletions(-)

diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx
index dd19760..fcc9367 100644
--- a/Source/cmQtAutoGeneratorInitializer.cxx
+++ b/Source/cmQtAutoGeneratorInitializer.cxx
@@ -12,6 +12,7 @@
 ============================================================================*/
 
 #include "cmQtAutoGeneratorInitializer.h"
+#include "cmQtAutoGenerators.h"
 
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -53,49 +54,25 @@ static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target)
   return targetDir;
 }
 
-static std::string GetSourceRelativePath(cmGeneratorTarget const* target,
-                                         const std::string& fileName)
+static std::string GetQrcBuildPath(cmGeneratorTarget const* target,
+                                  const std::string& qrcSourceName)
 {
-  std::string pathRel;
-  // Test if the file is child to any of the known directories
+  std::string rccOutputPath = GetAutogenTargetBuildDir(target);
+  // Create output directory
+  cmSystemTools::MakeDirectory(rccOutputPath.c_str());
+
+  rccOutputPath += "qrc_";
   {
-    const std::string fileNameReal = cmsys::SystemTools::GetRealPath(fileName);
-    std::string parentDirectory;
-    bool match(false);
-    {
-      std::string testDirs[4];
-      {
-        cmMakefile* makefile = target->Target->GetMakefile();
-        testDirs[0] = makefile->GetCurrentSourceDirectory();
-        testDirs[1] = makefile->GetCurrentBinaryDirectory();
-        testDirs[2] = makefile->GetHomeDirectory();
-        testDirs[3] = makefile->GetHomeOutputDirectory();
-      }
-      for (int ii = 0; ii != sizeof(testDirs) / sizeof(std::string); ++ii) {
-        const ::std::string testDir =
-          cmsys::SystemTools::GetRealPath(testDirs[ii]);
-        if (!testDir.empty() &&
-            cmsys::SystemTools::IsSubDirectory(fileNameReal, testDir)) {
-          parentDirectory = testDir;
-          match = true;
-          break;
-        }
-      }
-    }
-    // Use root as fallback parent directory
-    if (!match) {
-      cmsys::SystemTools::SplitPathRootComponent(fileNameReal,
-                                                 &parentDirectory);
-    }
-    pathRel = cmsys::SystemTools::RelativePath(
-      parentDirectory, cmsys::SystemTools::GetParentDirectory(fileNameReal));
+    cmMakefile* makefile = target->Target->GetMakefile();
+    rccOutputPath += cmQtAutoGeneratorUtil::BuildFileBase( qrcSourceName,
+      makefile->GetCurrentSourceDirectory(),
+      makefile->GetCurrentBinaryDirectory(),
+      makefile->GetHomeDirectory(),
+      makefile->GetHomeOutputDirectory() );
   }
-  // Sanitize relative path
-  if (!pathRel.empty()) {
-    pathRel += '/';
-    cmSystemTools::ReplaceString(pathRel, "..", "__");
-  }
-  return pathRel;
+  rccOutputPath += ".cpp";
+
+  return rccOutputPath;
 }
 
 static void SetupSourceFiles(cmGeneratorTarget const* target,
@@ -129,15 +106,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target,
       if (ext == "qrc" &&
           !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
 
-        std::string rcc_output_dir = GetAutogenTargetBuildDir(target);
-        rcc_output_dir += GetSourceRelativePath(target, absFile);
-        cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
-
-        std::string basename =
-          cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
-
-        std::string rcc_output_file = rcc_output_dir;
-        rcc_output_file += "qrc_" + basename + ".cpp";
+        const std::string rcc_output_file = GetQrcBuildPath(target, absFile);
         makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
                                  rcc_output_file.c_str(), false);
         makefile->GetOrCreateSource(rcc_output_file, true);
@@ -804,17 +773,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
         if (ext == "qrc" &&
             !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
 
-          {
-            std::string rcc_output_dir = GetAutogenTargetBuildDir(target);
-            rcc_output_dir += GetSourceRelativePath(target, absFile);
-            cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
-
-            std::string basename =
-              cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
-            std::string rcc_output_file = rcc_output_dir;
-            rcc_output_file += "qrc_" + basename + ".cpp";
-            rcc_output.push_back(rcc_output_file);
-          }
+          const std::string rcc_output_file = GetQrcBuildPath(target, absFile);
+          rcc_output.push_back(rcc_output_file);
 
           if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
             if (qtMajorVersion == "5") {
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index ac64397..9540c5c 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -20,6 +20,9 @@
 #include "cmState.h"
 #include "cmSystemTools.h"
 
+#include "cmCryptoHash.h"
+#include "cmsys/Base64.h"
+
 #include <sys/stat.h>
 
 #include <assert.h>
@@ -31,6 +34,109 @@
 #include <unistd.h>
 #endif
 
+std::string cmQtAutoGeneratorUtil::BuildFileBase(const std::string& filePath,
+                          const std::string& parenDirCSource,
+                          const std::string& parenDirCBinary,
+                          const std::string& parenDirPSource,
+                          const std::string& parenDirPBinary )
+{
+  std::string baseName;
+
+  std::string sourceFileName = cmsys::SystemTools::GetFilenameName(filePath);
+  std::string sourceBaseName =
+    cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFileName);
+
+  // Determine the relative path to a known parent directory
+  std::string sourceRelPath;
+  std::string sourceRelSeed;
+  {
+    std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath);
+    std::string parentDirectory;
+    bool parentFound(false);
+    {
+      struct TPair {
+        const std::string * dir;
+        const char * seed;
+      };
+      TPair pDirs[4] = {
+        { &parenDirCSource, "CurrentSource" },
+        { &parenDirCBinary, "CurrentBinary" },
+        { &parenDirPSource, "ProjectSource" },
+        { &parenDirPBinary, "ProjectBinary" }
+      };
+      TPair * itc = &pDirs[0];
+      TPair * ite = &pDirs[0] + ( sizeof ( pDirs ) / sizeof ( TPair ) );
+      for ( ; itc != ite; ++itc ) {
+        const ::std::string pDir = cmsys::SystemTools::GetRealPath(*(itc->dir));
+        if (cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) {
+          sourceRelSeed = itc->seed;
+          parentDirectory = pDir;
+          parentFound = true;
+          break;
+        }
+      }
+    }
+    // Use root as fallback parent directory
+    if (!parentFound) {
+      sourceRelSeed = "FileSystemRoot";
+      cmsys::SystemTools::SplitPathRootComponent(sourceNameReal,
+                                                 &parentDirectory);
+    }
+    sourceRelPath = cmsys::SystemTools::RelativePath(
+      parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal));
+  }
+
+  // Calculate the file ( seed + relative path + name ) checksum
+  std::string checksumBase64;
+  {
+    ::std::vector<unsigned char>hashBytes;
+    {
+      // Acquire hex value hash string
+      std::string hexHash = cmCryptoHash::New("SHA256")->HashString(
+            (sourceRelSeed+sourceRelPath+sourceFileName).c_str());
+      // Convert hex value string to bytes
+      hashBytes.resize ( hexHash.size()/2 );
+      for ( unsigned int ii=0; ii != hashBytes.size(); ++ii ) {
+        unsigned char byte ( 0 );
+        for ( unsigned int jj=0; jj != 2; ++jj ) {
+          unsigned char cval ( 0 );
+          switch ( hexHash[ii*2+jj] ) {
+          case '0': cval=0; break; case '1': cval=1; break;
+          case '2': cval=2; break; case '3': cval=3; break;
+          case '4': cval=4; break; case '5': cval=5; break;
+          case '6': cval=6; break; case '7': cval=7; break;
+          case '8': cval=8; break; case '9': cval=9; break;
+          case 'a': cval=10; break; case 'b': cval=11; break;
+          case 'c': cval=12; break; case 'd': cval=13; break;
+          case 'e': cval=14; break; case 'f': cval=15; break;
+          default: break;
+          }
+          byte = byte|(cval<<jj);
+        }
+        hashBytes[ii] = byte;
+      }
+    }
+    // Convert hash bytes to Base64 text string
+    {
+      ::std::vector<unsigned char> base64Bytes(hashBytes.size()*2, 0 );
+      cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0);
+      checksumBase64 = reinterpret_cast<const char *>(&base64Bytes[0]);
+    }
+  }
+
+  // Compose the file name
+  {
+    const size_t nameLength ( 14 );
+    const size_t checkSumLength ( 14 );
+    baseName.append ( sourceBaseName.substr ( 0, nameLength ) );
+    baseName.append ( "_" );
+    baseName.append ( checksumBase64.substr ( 0, checkSumLength ) );
+  }
+
+  return baseName;
+}
+
+
 static bool requiresMocing(const std::string& text, std::string& macroName)
 {
   // this simple check is much much faster than the regexp
@@ -87,6 +193,25 @@ static std::string extractSubDir(const std::string& absPath,
   return subDir;
 }
 
+
+static bool FileNameIsUnique(const std::string& filePath,
+                             const std::map<std::string, std::string>& fileMap)
+{
+  size_t count ( 0 );
+  const std::string fileName =
+    cmsys::SystemTools::GetFilenameName(filePath);
+  for (std::map<std::string, std::string>::const_iterator si = fileMap.begin();
+       si != fileMap.end(); ++si) {
+    if ( cmsys::SystemTools::GetFilenameName(si->first) == fileName ) {
+      ++count;
+      if ( count > 1 ) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 cmQtAutoGenerators::cmQtAutoGenerators()
   : Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
   , ColorOutput(true)
@@ -950,12 +1075,8 @@ void cmQtAutoGenerators::ParseHeaders(
 
       std::string macroName;
       if (requiresMocing(contents, macroName)) {
-        const std::string parentDir =
-          this->TargetBuildSubDir + this->SourceRelativePath(headerName);
-        const std::string basename =
-          cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName);
-        const std::string currentMoc = parentDir + "moc_" + basename + ".cpp";
-        notIncludedMocs[headerName] = currentMoc;
+        notIncludedMocs[headerName] =
+          this->TargetBuildSubDir + BuildFileName(headerName, "moc_", ".cpp");
       }
     }
     this->ParseForUic(headerName, contents, includedUis);
@@ -1022,7 +1143,9 @@ bool cmQtAutoGenerators::GenerateMocFiles(
       for (std::map<std::string, std::string>::const_iterator it =
              notIncludedMocs.begin();
            it != notIncludedMocs.end(); ++it) {
-        outStream << "#include \"" << it->second << "\"\n";
+        outStream << "#include \""
+                  << cmsys::SystemTools::ConvertToOutputPath(it->second)
+                  << "\"\n";
       }
     }
     outStream.flush();
@@ -1262,13 +1385,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
        si != this->RccSources.end(); ++si) {
     const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
     if (ext == ".qrc") {
-      std::string basename =
-        cmsys::SystemTools::GetFilenameWithoutLastExtension(*si);
-      std::string qrcOutputFile = this->TargetBuildSubDir +
-        this->SourceRelativePath(*si) + "qrc_" + basename + ".cpp";
-      // std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName
-      //                         + ".dir/qrc_" + basename + ".cpp";
-      qrcGenMap[*si] = qrcOutputFile;
+      qrcGenMap[*si] = (
+        this->TargetBuildSubDir + this->BuildFileName ( *si, "qrc_", ".cpp" ) );
     }
   }
 
@@ -1290,7 +1408,9 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
   for (std::map<std::string, std::string>::const_iterator si =
          qrcGenMap.begin();
        si != qrcGenMap.end(); ++si) {
-    if (!this->GenerateQrc(si->first, si->second)) {
+    if (!this->GenerateQrc(si->first, si->second,
+      FileNameIsUnique(si->first, qrcGenMap) ))
+    {
       if (this->RunRccFailed) {
         return false;
       }
@@ -1300,11 +1420,19 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
 }
 
 bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
-                                     const std::string& qrcOutputFile)
+                                     const std::string& qrcOutputFile,
+                                     bool unique_n )
 {
-  std::string relName = this->SourceRelativePath(qrcInputFile);
-  std::replace(relName.begin(), relName.end(), '/', '_');
-  relName += cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
+  std::string symbolName;
+  if ( unique_n ) {
+    symbolName =
+      cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
+  } else {
+    symbolName =
+      cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile);
+    // Remove "qrc_" at string begin
+    symbolName.erase ( 0, 4 );
+  }
 
   const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile;
 
@@ -1332,7 +1460,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
     }
 
     command.push_back("-name");
-    command.push_back(relName);
+    command.push_back(symbolName);
     command.push_back("-o");
     command.push_back(qrcBuildFile);
     command.push_back(qrcInputFile);
@@ -1357,49 +1485,20 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
   return true;
 }
 
-std::string cmQtAutoGenerators::SourceRelativePath(const std::string& filename)
+std::string cmQtAutoGenerators::BuildFileName(const std::string& filename,
+                                              const std::string& prefix,
+                                              const std::string& suffix )
 {
-  std::string pathRel;
+  std::string buildName ( prefix );
+  buildName += cmQtAutoGeneratorUtil::BuildFileBase( filename,
+    this->Srcdir, this->Builddir, this->ProjectSourceDir,
+    this->ProjectBinaryDir );
+  buildName += suffix;
 
-  // Test if the file is child to any of the known directories
-  {
-    std::string fileNameReal = cmsys::SystemTools::GetRealPath(filename);
-    std::string parentDirectory;
-    bool match(false);
-    {
-      const ::std::string* testDirs[4];
-      testDirs[0] = &(this->Srcdir);
-      testDirs[1] = &(this->Builddir);
-      testDirs[2] = &(this->ProjectSourceDir);
-      testDirs[3] = &(this->ProjectBinaryDir);
-      for (int ii = 0; ii != sizeof(testDirs) / sizeof(const ::std::string*);
-           ++ii) {
-        const ::std::string testDir =
-          cmsys::SystemTools::GetRealPath(*(testDirs[ii]));
-        if (cmsys::SystemTools::IsSubDirectory(fileNameReal, testDir)) {
-          parentDirectory = testDir;
-          match = true;
-          break;
-        }
-      }
-    }
-    // Use root as fallback parent directory
-    if (!match) {
-      cmsys::SystemTools::SplitPathRootComponent(fileNameReal,
-                                                 &parentDirectory);
-    }
-    pathRel = cmsys::SystemTools::RelativePath(
-      parentDirectory, cmsys::SystemTools::GetParentDirectory(fileNameReal));
-  }
-
-  // Sanitize relative path
-  if (!pathRel.empty()) {
-    pathRel += '/';
-    cmSystemTools::ReplaceString(pathRel, "..", "__");
-  }
-  return pathRel;
+  return buildName;
 }
 
+
 /**
  * @brief Collects name collisions as output/input pairs
  * @return True if there were collisions
diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h
index 5e7fab5..398c96b 100644
--- a/Source/cmQtAutoGenerators.h
+++ b/Source/cmQtAutoGenerators.h
@@ -23,6 +23,25 @@
 
 class cmMakefile;
 
+
+/// Class with static utility functions
+///
+class cmQtAutoGeneratorUtil
+{
+  public:
+
+  // Returns a file name (without directory) that consists in part
+  // of the source file name and in part of a Base64 encoded checksum
+  // of the source file path
+  static
+  std::string BuildFileBase(const std::string& filePath,
+                            const std::string& parenDirCSource,
+                            const std::string& parenDirCBinary,
+                            const std::string& parenDirPSource,
+                            const std::string& parenDirPBinary );
+};
+
+
 class cmQtAutoGenerators
 {
 public:
@@ -51,7 +70,8 @@ private:
                   const std::string& uiOutputFile);
   bool GenerateQrcFiles();
   bool GenerateQrc(const std::string& qrcInputFile,
-                   const std::string& qrcOutputFile);
+                   const std::string& qrcOutputFile,
+                   bool unique_n );
   void ParseCppFile(
     const std::string& absFilename,
     const std::vector<std::string>& headerExtensions,
@@ -83,7 +103,9 @@ private:
 
   void Init();
 
-  std::string SourceRelativePath(const std::string& filename);
+  std::string BuildFileName(const std::string& filename,
+                            const std::string& prefix,
+                            const std::string& suffix );
 
   bool NameCollisionTest(const std::map<std::string, std::string>& genFiles,
                          std::multimap<std::string, std::string>& collisions);
-- 
2.8.1

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to