[cmake-commits] king committed cmLocalGenerator.cxx 1.204 1.205 cmLocalGenerator.h 1.77 1.78 cmLocalUnixMakefileGenerator3.cxx 1.201 1.202 cmLocalVisualStudio6Generator.cxx 1.117 1.118 cmLocalVisualStudio7Generator.cxx 1.182 1.183

cmake-commits at cmake.org cmake-commits at cmake.org
Fri Mar 16 09:34:27 EST 2007


Update of /cvsroot/CMake/CMake/Source
In directory public:/mounts/ram/cvs-serv30235/Source

Modified Files:
	cmLocalGenerator.cxx cmLocalGenerator.h 
	cmLocalUnixMakefileGenerator3.cxx 
	cmLocalVisualStudio6Generator.cxx 
	cmLocalVisualStudio7Generator.cxx 
Log Message:
ENH: Added computation of object file names that are almost always short enough to not exceed the filesystem path length limitation.  This is useful when a source file from outside the tree is referenced with a long full path.  The object file name previously would contain the entire path which when combined with the build output directory could exceed the filesystem limit.  Now CMake recognizes this case and replaces enough of the beginning of the full path to the source file with an md5sum of the replaced portion to make the name fit on disk.  This addresses bug#4520.


Index: cmLocalVisualStudio7Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalVisualStudio7Generator.cxx,v
retrieving revision 1.182
retrieving revision 1.183
diff -u -d -r1.182 -r1.183
--- cmLocalVisualStudio7Generator.cxx	14 Mar 2007 20:29:10 -0000	1.182
+++ cmLocalVisualStudio7Generator.cxx	16 Mar 2007 14:34:25 -0000	1.183
@@ -1055,6 +1055,28 @@
     this->WriteVCProjBeginGroup(fout, name.c_str(), "");
     }
 
+  // Compute the maximum length of a configuration name.
+  std::string::size_type config_len_max = 0;
+  for(std::vector<std::string>::iterator i = configs->begin();
+      i != configs->end(); ++i)
+    {
+    if(i->size() > config_len_max)
+      {
+      config_len_max = i->size();
+      }
+    }
+
+  // Compute the maximum length of the full path to the intermediate
+  // files directory for any configuration.  This is used to construct
+  // object file names that do not produce paths that are too long.
+  std::string::size_type dir_len = 0;
+  dir_len += strlen(this->Makefile->GetCurrentOutputDirectory());
+  dir_len += 1;
+  dir_len += this->GetTargetDirectory(target).size();
+  dir_len += 1;
+  dir_len += config_len_max;
+  dir_len += 1;
+
   // Loop through each source in the source group.
   std::string objectName;
   for(std::vector<const cmSourceFile *>::const_iterator sf =
@@ -1066,7 +1088,7 @@
     std::string additionalDeps;
     if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
       {
-      objectName = this->GetObjectFileNameWithoutTarget(*(*sf));
+      objectName = this->GetObjectFileNameWithoutTarget(*(*sf), dir_len);
       }
     else
       {

Index: cmLocalGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalGenerator.h,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -d -r1.77 -r1.78
--- cmLocalGenerator.h	12 Mar 2007 14:26:59 -0000	1.77
+++ cmLocalGenerator.h	16 Mar 2007 14:34:25 -0000	1.78
@@ -266,8 +266,10 @@
     std::vector<std::string> const& configurationTypes);
 
   // Compute object file names.
-  std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source);
-  std::string& CreateSafeUniqueObjectFileName(const char* sin);
+  std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source,
+                                             std::string::size_type dir_len);
+  std::string& CreateSafeUniqueObjectFileName(const char* sin,
+                                              std::string::size_type dir_len);
 
   void ConfigureRelativePaths();
   std::string FindRelativePathTopSource();

Index: cmLocalUnixMakefileGenerator3.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalUnixMakefileGenerator3.cxx,v
retrieving revision 1.201
retrieving revision 1.202
diff -u -d -r1.201 -r1.202
--- cmLocalUnixMakefileGenerator3.cxx	14 Mar 2007 20:29:10 -0000	1.201
+++ cmLocalUnixMakefileGenerator3.cxx	16 Mar 2007 14:34:25 -0000	1.202
@@ -1610,25 +1610,22 @@
                     const cmSourceFile& source,
                     std::string* nameWithoutTargetDir)
 {
-  // Get the object file name independent of target.
-  std::string objectName = this->GetObjectFileNameWithoutTarget(source);
-  if(nameWithoutTargetDir)
-    {
-    *nameWithoutTargetDir = objectName;
-    }
-
-  // Prepend the target directory.
-  std::string obj;
-  const char* fileTargetDirectory = 
-    source.GetProperty("MACOSX_PACKAGE_LOCATION");
-  if ( fileTargetDirectory )
+  if(const char* fileTargetDirectory =
+     source.GetProperty("MACOSX_PACKAGE_LOCATION"))
     {
+    // Special handling for OSX package files.
+    std::string objectName = this->GetObjectFileNameWithoutTarget(source, 0);
+    if(nameWithoutTargetDir)
+      {
+      *nameWithoutTargetDir = objectName;
+      }
     objectName = cmSystemTools::GetFilenameName(objectName.c_str());
     std::string targetName;
     std::string targetNameReal;
     std::string targetNamePDB;
     target.GetExecutableNames(targetName, targetNameReal,
                               targetNamePDB, this->ConfigurationName.c_str());
+    std::string obj;
     if ( target.GetPropertyAsBool("MACOSX_BUNDLE") )
       {
       // Construct the full path version of the names.
@@ -1644,14 +1641,32 @@
       }
     obj = cmSystemTools::RelativePath
       (this->Makefile->GetHomeOutputDirectory(), obj.c_str());
+    obj += "/";
+    obj += objectName;
+    return obj;
     }
   else
     {
-    obj = this->GetTargetDirectory(target);
+    // Start with the target directory.
+    std::string obj = this->GetTargetDirectory(target);
+    obj += "/";
+
+    // Get the object file name without the target directory.
+    std::string::size_type dir_len = 0;
+    dir_len += strlen(this->Makefile->GetCurrentOutputDirectory());
+    dir_len += 1;
+    dir_len += obj.size();
+    std::string objectName =
+      this->GetObjectFileNameWithoutTarget(source, dir_len);
+    if(nameWithoutTargetDir)
+      {
+      *nameWithoutTargetDir = objectName;
+      }
+
+    // Append the object name to the target directory.
+    obj += objectName;
+    return obj;
     }
-  obj += "/";
-  obj += objectName;
-  return obj;
 }
 
 //----------------------------------------------------------------------------

Index: cmLocalVisualStudio6Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalVisualStudio6Generator.cxx,v
retrieving revision 1.117
retrieving revision 1.118
diff -u -d -r1.117 -r1.118
--- cmLocalVisualStudio6Generator.cxx	10 Mar 2007 11:56:11 -0000	1.117
+++ cmLocalVisualStudio6Generator.cxx	16 Mar 2007 14:34:25 -0000	1.118
@@ -397,7 +397,32 @@
     {
     this->WriteDSPBeginGroup(fout, name.c_str(), "");
     }
-    
+
+  // Compute the maximum length of a configuration name.
+  std::string::size_type config_len_max = 0;
+  for(std::vector<std::string>::iterator i = this->Configurations.begin();
+      i != this->Configurations.end(); ++i)
+    {
+    // Strip the subdirectory name out of the configuration name.
+    std::string config = *i;
+    std::string::size_type pos = config.find_last_of(" ");
+    config = config.substr(pos+1, std::string::npos);
+    config = config.substr(0, config.size()-1);
+    if(config.size() > config_len_max)
+      {
+      config_len_max = config.size();
+      }
+    }
+
+  // Compute the maximum length of the full path to the intermediate
+  // files directory for any configuration.  This is used to construct
+  // object file names that do not produce paths that are too long.
+  std::string::size_type dir_len = 0;
+  dir_len += strlen(this->Makefile->GetCurrentOutputDirectory());
+  dir_len += 1;
+  dir_len += config_len_max;
+  dir_len += 1;
+
   // Loop through each source in the source group.
   for(std::vector<const cmSourceFile *>::const_iterator sf =
         sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
@@ -412,7 +437,7 @@
       {
       objectNameDir =
         cmSystemTools::GetFilenamePath(
-          this->GetObjectFileNameWithoutTarget(*(*sf)));
+          this->GetObjectFileNameWithoutTarget(*(*sf), dir_len));
       }
 
     // Add per-source file flags.

Index: cmLocalGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalGenerator.cxx,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- cmLocalGenerator.cxx	14 Mar 2007 20:29:10 -0000	1.204
+++ cmLocalGenerator.cxx	16 Mar 2007 14:34:25 -0000	1.205
@@ -28,6 +28,11 @@
 #include "cmTest.h"
 #include "cmake.h"
 
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+# define CM_LG_ENCODE_OBJECT_NAMES
+# include <cmsys/MD5.h>
+#endif
+
 #include <cmsys/System.h>
 
 #include <ctype.h> // for isalpha
@@ -2376,8 +2381,81 @@
     }
 }
 
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+static std::string cmLocalGeneratorMD5(const char* input)
+{
+  char md5out[32];
+  cmsysMD5* md5 = cmsysMD5_New();
+  cmsysMD5_Initialize(md5);
+  cmsysMD5_Append(md5, reinterpret_cast<unsigned char const*>(input), -1);
+  cmsysMD5_FinalizeHex(md5, md5out);
+  cmsysMD5_Delete(md5);
+  return std::string(md5out, 32);
+}
+
+static bool
+cmLocalGeneratorShortenObjectName(std::string& objName,
+                                  std::string::size_type max_len)
+{
+  // Replace the beginning of the path portion of the object name with
+  // its own md5 sum.
+  std::string::size_type pos = objName.find('/', objName.size()-max_len+32);
+  if(pos != objName.npos)
+    {
+    std::string md5name = cmLocalGeneratorMD5(objName.substr(0, pos).c_str());
+    md5name += objName.substr(pos);
+    objName = md5name;
+
+    // The object name is now short enough.
+    return true;
+    }
+  else
+    {
+    // The object name could not be shortened enough.
+    return false;
+    }
+}
+
+static bool cmLocalGeneratorCheckObjectName(std::string& objName,
+                                            std::string::size_type dir_len)
+{
+  // Choose a maximum file name length.
+#if defined(_WIN32) || defined(__CYGWIN__)
+  std::string::size_type const max_total_len = 250;
+#else
+  std::string::size_type const max_total_len = 1000;
+#endif
+
+  // Enforce the maximum file name length if possible.
+  std::string::size_type max_obj_len = max_total_len;
+  if(dir_len < max_total_len)
+    {
+    max_obj_len = max_total_len - dir_len;
+    if(objName.size() > max_obj_len)
+      {
+      // The current object file name is too long.  Try to shorten it.
+      return cmLocalGeneratorShortenObjectName(objName, max_obj_len);
+      }
+    else
+      {
+      // The object file name is short enough.
+      return true;
+      }
+    }
+  else
+    {
+    // The build directory in which the object will be stored is
+    // already too deep.
+    return false;
+    }
+}
+#endif
+
 //----------------------------------------------------------------------------
-std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(const char* sin)
+std::string&
+cmLocalGenerator
+::CreateSafeUniqueObjectFileName(const char* sin,
+                                 std::string::size_type dir_len)
 {
   // Look for an existing mapped name for this object file.
   std::map<cmStdString,cmStdString>::iterator it =
@@ -2435,6 +2513,12 @@
       while ( !done );
       }
 
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+    cmLocalGeneratorCheckObjectName(ssin, dir_len);
+#else
+    (void)dir_len;
+#endif
+
     // Insert the newly mapped object file name.
     std::map<cmStdString, cmStdString>::value_type e(sin, ssin);
     it = this->UniqueObjectNamesMap.insert(e).first;
@@ -2446,7 +2530,9 @@
 
 //----------------------------------------------------------------------------
 std::string
-cmLocalGenerator::GetObjectFileNameWithoutTarget(const cmSourceFile& source)
+cmLocalGenerator
+::GetObjectFileNameWithoutTarget(const cmSourceFile& source,
+                                 std::string::size_type dir_len)
 {
   // Construct the object file name using the full path to the source
   // file which is its only unique identification.
@@ -2517,7 +2603,7 @@
     }
 
   // Convert to a safe name.
-  return this->CreateSafeUniqueObjectFileName(objectName.c_str());
+  return this->CreateSafeUniqueObjectFileName(objectName.c_str(), dir_len);
 }
 
 //----------------------------------------------------------------------------



More information about the Cmake-commits mailing list