瀏覽代碼

ENH: Allow VS 7 project Rebuild and Solution Rebuild to work without re-running CMake for every project during the rebuild.

Brad King 18 年之前
父節點
當前提交
34c882a9f8
共有 4 個文件被更改,包括 111 次插入5 次删除
  1. 4 2
      Source/cmGlobalVisualStudio8Generator.cxx
  2. 28 3
      Source/cmLocalVisualStudio7Generator.cxx
  3. 78 0
      Source/cmake.cxx
  4. 1 0
      Source/cmake.h

+ 4 - 2
Source/cmGlobalVisualStudio8Generator.cxx

@@ -124,6 +124,8 @@ void cmGlobalVisualStudio8Generator::Generate()
         listFiles.erase(new_end, listFiles.end());
 
         // Create a rule to re-run CMake.
+        std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash();
+        stampName += CMAKE_CHECK_BUILD_SYSTEM_TARGET ".vcproj.stamp";
         const char* dsprule = mf->GetRequiredDefinition("CMAKE_COMMAND");
         cmCustomCommandLine commandLine;
         commandLine.push_back(dsprule);
@@ -137,6 +139,8 @@ void cmGlobalVisualStudio8Generator::Generate()
                             cmLocalGenerator::START_OUTPUT,
                             cmLocalGenerator::UNCHANGED, true);
         commandLine.push_back(argB);
+        commandLine.push_back("--check-stamp-file");
+        commandLine.push_back(stampName.c_str());
         cmCustomCommandLines commandLines;
         commandLines.push_back(commandLine);
 
@@ -146,8 +150,6 @@ void cmGlobalVisualStudio8Generator::Generate()
         // target.
         const char* no_main_dependency = 0;
         const char* no_working_directory = 0;
-        std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash();
-        stampName += CMAKE_CHECK_BUILD_SYSTEM_TARGET ".vcproj.stamp";
         mf->AddCustomCommandToOutput(
           stampName.c_str(), listFiles,
           no_main_dependency, commandLines, "Checking Build System",

+ 28 - 3
Source/cmLocalVisualStudio7Generator.cxx

@@ -164,17 +164,40 @@ void cmLocalVisualStudio7Generator
   this->WriteVCProjFile(fout,lname,target);
   }
 
+  // Create a helper file so CMake can determine when it is run
+  // through the rule created by AddVCProjBuildRule whether it really
+  // needs to regenerate the project.  This file lists its own
+  // dependencies.  If any file listed in it is newer than itself then
+  // CMake must rerun.  Otherwise the project file is up to date and
+  // the stamp file can just be touched.
+  {
+  std::string depName = this->Makefile->GetStartOutputDirectory();
+  depName += cmake::GetCMakeFilesDirectory();
+  depName += "/";
+  depName += lname;
+  depName += ".vcproj.stamp.depend";
+  std::ofstream depFile(depName.c_str());
+  depFile << "# CMake dependency list for corresponding VS project.\n";
+  std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
+  for(std::vector<std::string>::const_iterator lf = listFiles.begin();
+      lf != listFiles.end(); ++lf)
+    {
+    depFile << *lf << std::endl;
+    }
+  }
+
   // Touch a timestamp file used to determine when the project file is
   // out of date.
-  std::string stampName;
-  stampName = this->Makefile->GetStartOutputDirectory();
+  {
+  std::string stampName = this->Makefile->GetStartOutputDirectory();
   stampName += cmake::GetCMakeFilesDirectory();
   cmSystemTools::MakeDirectory(stampName.c_str());
   stampName += "/";
   stampName += lname;
   stampName += ".vcproj.stamp";
   std::ofstream stamp(stampName.c_str());
-  stamp << "# CMake timestamp for " << lname << ".vcproj" << std::endl;
+  stamp << "# CMake timestamp file for corresponding VS project.\n";
+  }
 }
 
 
@@ -203,6 +226,8 @@ void cmLocalVisualStudio7Generator::AddVCProjBuildRule(cmTarget& tgt)
     this->Convert(this->Makefile->GetHomeOutputDirectory(),
                   START_OUTPUT, UNCHANGED, true);
   commandLine.push_back(args);
+  commandLine.push_back("--check-stamp-file");
+  commandLine.push_back(stampName.c_str());
 
   std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
 

+ 78 - 0
Source/cmake.cxx

@@ -104,6 +104,8 @@
 
 #include <memory> // auto_ptr
 
+static bool cmakeCheckStampFile(const char* stampName);
+
 void cmNeedBackwardsCompatibility(const std::string& variable,
   int access_type, void*, const char*, const cmMakefile*)
 {
@@ -520,6 +522,10 @@ void cmake::SetArgs(const std::vector<std::string>& args)
       this->CheckBuildSystemArgument = args[++i];
       this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
       }
+    else if((i < args.size()-1) && (arg.find("--check-stamp-file",0) == 0))
+      {
+      this->CheckStampFile = args[++i];
+      }
     else if(arg.find("-V",0) == 0)
       {
         this->Verbose = true;
@@ -1994,6 +2000,13 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
     return -1;
     }
 
+  // If we are given a stamp file check if it is really out of date.
+  if(!this->CheckStampFile.empty() &&
+     cmakeCheckStampFile(this->CheckStampFile.c_str()))
+    {
+    return 0;
+    }
+
   // set the cmake command
   this->CMakeCommand = args[0];
   
@@ -3406,3 +3419,68 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
   cmSystemTools::RemoveADirectory(destPath.c_str());
   return 0;
 }
+
+//----------------------------------------------------------------------------
+static bool cmakeCheckStampFile(const char* stampName)
+{
+  // If the stamp file still exists then it must really be out of
+  // date.
+  if(cmSystemTools::FileExists(stampName))
+    {
+    return false;
+    }
+
+  // The stamp file does not exist.  Use the stamp dependencies to
+  // determine whether it is really out of date.  This works in
+  // conjunction with cmLocalVisualStudio7Generator to avoid
+  // repeatedly re-running CMake when the user rebuilds the entire
+  // solution.
+  std::string stampDepends = stampName;
+  stampDepends += ".depend";
+#if defined(_WIN32) || defined(__CYGWIN__)
+  std::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
+#else
+  std::ifstream fin(stampDepends.c_str(), std::ios::in);
+#endif
+  if(!fin)
+    {
+    // The stamp dependencies file cannot be read.  Just assume the
+    // build system is really out of date.
+    return false;
+    }
+
+  // Compare the stamp dependencies against the dependency file itself.
+  cmFileTimeComparison ftc;
+  std::string dep;
+  while(cmSystemTools::GetLineFromStream(fin, dep))
+    {
+    int result;
+    if(dep.length() >= 1 && dep[0] != '#' &&
+       (!ftc.FileTimeCompare(stampDepends.c_str(), dep.c_str(), &result)
+        || result < 0))
+      {
+      // The stamp depends file is older than this dependency.  The
+      // build system is really out of date.
+      return false;
+      }
+    }
+
+  // The build system is up to date.  The stamp file has been removed
+  // by the VS IDE due to a "rebuild" request.  Just restore it.
+  std::ofstream stamp(stampName);
+  stamp << "# CMake timestamp file for corresponding VS project.\n";
+  if(stamp)
+    {
+    // Notify the user why CMake is not re-running.  It is safe to
+    // just print to stdout here because this code is only reachable
+    // through an undocumented flag used by the VS generator.
+    std::cout << "CMake does not need to re-run because the "
+              << "project timestamp is up-to-date.\n";
+    return true;
+    }
+  else
+    {
+    cmSystemTools::Error("Cannot restore timestamp ", stampName);
+    return false;
+    }
+}

+ 1 - 0
Source/cmake.h

@@ -401,6 +401,7 @@ private:
   std::string CXXEnvironment;
   std::string CCEnvironment;
   std::string CheckBuildSystemArgument;
+  std::string CheckStampFile;
   std::string CTestCommand;
   std::string CPackCommand;
   bool ClearBuildSystem;