[Cmake-commits] [cmake-commits] king committed cmGlobalGenerator.cxx 1.230 1.231 cmGlobalGenerator.h 1.109 1.110 cmMakefileTargetGenerator.cxx 1.101 1.102

cmake-commits at cmake.org cmake-commits at cmake.org
Mon Jun 2 16:45:00 EDT 2008


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

Modified Files:
	cmGlobalGenerator.cxx cmGlobalGenerator.h 
	cmMakefileTargetGenerator.cxx 
Log Message:
ENH: Introduce "rule hashes" to help rebuild files when rules change.

  - In CMake 2.4 custom commands would not rebuild when rules changed.
  - In CMake 2.6.0 custom commands have a dependency on build.make
    which causes them to rebuild when changed, but also when any
    source is added or removed.  This is too often.
  - We cannot have a per-rule file because Windows filesystems
    do not deal well with lots of small files.
  - Instead we add a persistent CMakeFiles/CMakeRuleHashes.txt file
    at the top of the build tree that is updated during each
    CMake Generate step.  It records a hash of the build rule for
    each file to be built.  When the hash changes the file is
    removed so that it will be rebuilt.


Index: cmGlobalGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalGenerator.h,v
retrieving revision 1.109
retrieving revision 1.110
diff -C 2 -d -r1.109 -r1.110
*** cmGlobalGenerator.h	27 May 2008 15:18:01 -0000	1.109
--- cmGlobalGenerator.h	2 Jun 2008 20:44:58 -0000	1.110
***************
*** 246,249 ****
--- 246,253 ----
    void GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames);
  
+   void AddRuleHash(const std::vector<std::string>& outputs,
+                    const std::vector<std::string>& depends,
+                    const std::vector<std::string>& commands);
+ 
  protected:
    // for a project collect all its targets by following depend
***************
*** 314,317 ****
--- 318,326 ----
    std::map<cmStdString,cmTarget *> TotalTargets;
  
+   // Record hashes for rules and outputs.
+   struct RuleHash { char Data[32]; };
+   std::map<cmStdString, RuleHash> RuleHashes;
+   void CheckRuleHashes();
+ 
    cmExternalMakefileProjectGenerator* ExtraGenerator;
  

Index: cmGlobalGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalGenerator.cxx,v
retrieving revision 1.230
retrieving revision 1.231
diff -C 2 -d -r1.230 -r1.231
*** cmGlobalGenerator.cxx	27 May 2008 15:18:00 -0000	1.230
--- cmGlobalGenerator.cxx	2 Jun 2008 20:44:57 -0000	1.231
***************
*** 28,34 ****
--- 28,39 ----
  #include "cmExportInstallFileGenerator.h"
  #include "cmComputeTargetDepends.h"
+ #include "cmGeneratedFileStream.h"
  
  #include <cmsys/Directory.hxx>
  
+ #if defined(CMAKE_BUILD_WITH_CMAKE)
+ # include <cmsys/MD5.h>
+ #endif
+ 
  #include <stdlib.h> // required for atof
  
***************
*** 687,690 ****
--- 692,696 ----
    this->LocalGeneratorToTargetMap.clear();
    this->ProjectMap.clear();
+   this->RuleHashes.clear();
  
    // start with this directory
***************
*** 841,844 ****
--- 847,853 ----
    this->SetCurrentLocalGenerator(0);
  
+   // Update rule hashes.
+   this->CheckRuleHashes();
+ 
    if (this->ExtraGenerator != 0)
      {
***************
*** 1932,1933 ****
--- 1941,2082 ----
  }
  
+ //----------------------------------------------------------------------------
+ void
+ cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
+                                const std::vector<std::string>& depends,
+                                const std::vector<std::string>& commands)
+ {
+ #if defined(CMAKE_BUILD_WITH_CMAKE)
+   // Ignore if there are no outputs.
+   if(outputs.empty())
+     {
+     return;
+     }
+ 
+   // Compute a hash of the rule.
+   RuleHash hash;
+   {
+   unsigned char const* data;
+   int length;
+   cmsysMD5* sum = cmsysMD5_New();
+   cmsysMD5_Initialize(sum);
+   for(std::vector<std::string>::const_iterator i = outputs.begin();
+       i != outputs.end(); ++i)
+     {
+     data = reinterpret_cast<unsigned char const*>(i->c_str());
+     length = static_cast<int>(i->length());
+     cmsysMD5_Append(sum, data, length);
+     }
+   for(std::vector<std::string>::const_iterator i = depends.begin();
+       i != depends.end(); ++i)
+     {
+     data = reinterpret_cast<unsigned char const*>(i->c_str());
+     length = static_cast<int>(i->length());
+     cmsysMD5_Append(sum, data, length);
+     }
+   for(std::vector<std::string>::const_iterator i = commands.begin();
+       i != commands.end(); ++i)
+     {
+     data = reinterpret_cast<unsigned char const*>(i->c_str());
+     length = static_cast<int>(i->length());
+     cmsysMD5_Append(sum, data, length);
+     }
+   cmsysMD5_FinalizeHex(sum, hash.Data);
+   cmsysMD5_Delete(sum);
+   }
+ 
+   // Shorten the output name (in expected use case).
+   cmLocalGenerator* lg = this->GetLocalGenerators()[0];
+   std::string fname = lg->Convert(outputs[0].c_str(),
+                                   cmLocalGenerator::HOME_OUTPUT);
+ 
+   // Associate the hash with this output.
+   this->RuleHashes[fname] = hash;
+ #else
+   (void)outputs;
+   (void)depends;
+   (void)commands;
+ #endif
+ }
+ 
+ //----------------------------------------------------------------------------
+ void cmGlobalGenerator::CheckRuleHashes()
+ {
+ #if defined(CMAKE_BUILD_WITH_CMAKE)
+   std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
+   std::string pfile = home;
+   pfile += this->GetCMakeInstance()->GetCMakeFilesDirectory();
+   pfile += "/CMakeRuleHashes.txt";
+ 
+ #if defined(_WIN32) || defined(__CYGWIN__)
+   std::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
+ #else
+   std::ifstream fin(pfile.c_str(), std::ios::in);
+ #endif
+   std::string line;
+   std::string fname;
+   while(cmSystemTools::GetLineFromStream(fin, line))
+     {
+     // Line format is a 32-byte hex string followed by a space
+     // followed by a file name (with no escaping).
+ 
+     // Skip blank and comment lines.
+     if(line.size() < 34 || line[0] == '#')
+       {
+       continue;
+       }
+ 
+     // Get the filename.
+     fname = line.substr(33, line.npos);
+ 
+     // Look for a hash for this file's rule.
+     std::map<cmStdString, RuleHash>::const_iterator rhi =
+       this->RuleHashes.find(fname);
+     if(rhi != this->RuleHashes.end())
+       {
+       // Compare the rule hash in the file to that we were given.
+       if(strncmp(line.c_str(), rhi->second.Data, 32) != 0)
+         {
+         // The rule has changed.  Delete the output so it will be
+         // built again.
+         fname = cmSystemTools::CollapseFullPath(fname.c_str(), home.c_str());
+         cmSystemTools::RemoveFile(fname.c_str());
+         }
+       }
+     else
+       {
+       // We have no hash for a rule previously listed.  This may be a
+       // case where a user has turned off a build option and might
+       // want to turn it back on later, so do not delete the file.
+       // Instead, we keep the rule hash as long as the file exists so
+       // that if the feature is turned back on and the rule has
+       // changed the file is still rebuilt.
+       std::string fpath =
+         cmSystemTools::CollapseFullPath(fname.c_str(), home.c_str());
+       if(cmSystemTools::FileExists(fpath.c_str()))
+         {
+         RuleHash hash;
+         strncpy(hash.Data, line.c_str(), 32);
+         this->RuleHashes[fname] = hash;
+         }
+       }
+     }
+ 
+   // Now generate a new persistence file with the current hashes.
+   if(this->RuleHashes.empty())
+     {
+     cmSystemTools::RemoveFile(pfile.c_str());
+     }
+   else
+     {
+     cmGeneratedFileStream fout(pfile.c_str());
+     fout << "# Hashes of file build rules.\n";
+     for(std::map<cmStdString, RuleHash>::const_iterator
+           rhi = this->RuleHashes.begin(); rhi != this->RuleHashes.end(); ++rhi)
+       {
+       fout.write(rhi->second.Data, 32);
+       fout << " " << rhi->first << "\n";
+       }
+     }
+ #endif
+ }

Index: cmMakefileTargetGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmMakefileTargetGenerator.cxx,v
retrieving revision 1.101
retrieving revision 1.102
diff -C 2 -d -r1.101 -r1.102
*** cmMakefileTargetGenerator.cxx	21 May 2008 23:57:35 -0000	1.101
--- cmMakefileTargetGenerator.cxx	2 Jun 2008 20:44:58 -0000	1.102
***************
*** 1123,1133 ****
    this->LocalGenerator->AppendCustomDepend(depends, cc);
  
-   // Add a dependency on the rule file itself.
-   if(!cc.GetSkipRuleDepends())
-     {
-     this->LocalGenerator->AppendRuleDepend(depends,
-                                            this->BuildFileNameFull.c_str());
-     }
- 
    // Check whether we need to bother checking for a symbolic output.
    bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
--- 1123,1126 ----
***************
*** 1148,1151 ****
--- 1141,1150 ----
                                        o->c_str(), depends, commands,
                                        symbolic);
+ 
+   // If the rule has changed make sure the output is rebuilt.
+   if(!symbolic)
+     {
+     this->GlobalGenerator->AddRuleHash(cc.GetOutputs(), depends, commands);
+     }
    }
  



More information about the Cmake-commits mailing list