From fdf169be3a9e78e55d4c87b8341c2bddfca6a57f Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 11 Mar 2008 17:25:49 -0400 Subject: [PATCH] BUG: Fixes to VS8/VS9 project regeneration rules - ZERO_CHECK should check all stamps in case of parallel build (fixes complex test failure) - ZERO_CHECK should not appear when CMAKE_SUPPRESS_REGENERATION is on (fixes bug 6490) --- Source/cmGlobalVisualStudio8Generator.cxx | 156 +++++++++++++--------- Source/cmake.cxx | 50 ++++++- Source/cmake.h | 1 + 3 files changed, 142 insertions(+), 65 deletions(-) diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 52225aa64..f88f14f54 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -19,6 +19,7 @@ #include "cmLocalVisualStudio7Generator.h" #include "cmMakefile.h" #include "cmake.h" +#include "cmGeneratedFileStream.h" //---------------------------------------------------------------------------- cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator() @@ -131,6 +132,13 @@ void cmGlobalVisualStudio8Generator::Generate() cmLocalVisualStudio7Generator* lg = static_cast(generators[0]); cmMakefile* mf = lg->GetMakefile(); + + // Skip the target if no regeneration is to be done. + if(mf->IsOn("CMAKE_SUPPRESS_REGENERATION")) + { + continue; + } + std::string cmake_command = mf->GetRequiredDefinition("CMAKE_COMMAND"); cmCustomCommandLines noCommandLines; mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, @@ -144,72 +152,94 @@ void cmGlobalVisualStudio8Generator::Generate() continue; } - // Add a custom rule to re-run CMake if any input files changed. - const char* suppRegenRule = - mf->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); - if(!cmSystemTools::IsOn(suppRegenRule)) + // Create a list of all stamp files for this project. + std::vector stamps; + std::string stampList = cmake::GetCMakeFilesDirectoryPostSlash(); + stampList += "generate.stamp.list"; + { + std::string stampListFile = + generators[0]->GetMakefile()->GetCurrentOutputDirectory(); + stampListFile += "/"; + stampListFile += stampList; + std::string stampFile; + cmGeneratedFileStream fout(stampList.c_str()); + for(std::vector::const_iterator + gi = generators.begin(); gi != generators.end(); ++gi) { - // Collect the input files used to generate all targets in this - // project. - std::vector listFiles; - for(unsigned int j = 0; j < generators.size(); ++j) - { - cmMakefile* lmf = generators[j]->GetMakefile(); - listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(), - lmf->GetListFiles().end()); - } - // Sort the list of input files and remove duplicates. - std::sort(listFiles.begin(), listFiles.end(), - std::less()); - std::vector::iterator new_end = - std::unique(listFiles.begin(), listFiles.end()); - listFiles.erase(new_end, listFiles.end()); - - // Create a rule to re-run CMake. - std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash(); - stampName += "generate.stamp"; - const char* dsprule = mf->GetRequiredDefinition("CMAKE_COMMAND"); - cmCustomCommandLine commandLine; - commandLine.push_back(dsprule); - std::string argH = "-H"; - argH += lg->Convert(mf->GetHomeDirectory(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::UNCHANGED, true); - commandLine.push_back(argH); - std::string argB = "-B"; - argB += lg->Convert(mf->GetHomeOutputDirectory(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::UNCHANGED, true); - commandLine.push_back(argB); - commandLine.push_back("--check-stamp-file"); - commandLine.push_back(stampName.c_str()); - commandLine.push_back("--vs-solution-file"); - commandLine.push_back("\"$(SolutionPath)\""); - cmCustomCommandLines commandLines; - commandLines.push_back(commandLine); - - // Add the rule. Note that we cannot use the CMakeLists.txt - // file as the main dependency because it would get - // overwritten by the CreateVCProjBuildRule. - // (this could be avoided with per-target source files) - const char* no_main_dependency = 0; - const char* no_working_directory = 0; - mf->AddCustomCommandToOutput( - stampName.c_str(), listFiles, - no_main_dependency, commandLines, "Checking Build System", - no_working_directory, true); - std::string ruleName = stampName; - ruleName += ".rule"; - if(cmSourceFile* file = mf->GetSource(ruleName.c_str())) - { - tgt->AddSourceFile(file); - } - else - { - cmSystemTools::Error("Error adding rule for ", stampName.c_str()); - } + stampFile = (*gi)->GetMakefile()->GetCurrentOutputDirectory(); + stampFile += "/"; + stampFile += cmake::GetCMakeFilesDirectoryPostSlash(); + stampFile += "generate.stamp"; + stampFile = generators[0]->Convert(stampFile.c_str(), + cmLocalGenerator::START_OUTPUT); + fout << stampFile << "\n"; + stamps.push_back(stampFile); } } + + // Add a custom rule to re-run CMake if any input files changed. + { + // Collect the input files used to generate all targets in this + // project. + std::vector listFiles; + for(unsigned int j = 0; j < generators.size(); ++j) + { + cmMakefile* lmf = generators[j]->GetMakefile(); + listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(), + lmf->GetListFiles().end()); + } + // Sort the list of input files and remove duplicates. + std::sort(listFiles.begin(), listFiles.end(), + std::less()); + std::vector::iterator new_end = + std::unique(listFiles.begin(), listFiles.end()); + listFiles.erase(new_end, listFiles.end()); + + // Create a rule to re-run CMake. + std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash(); + stampName += "generate.stamp"; + const char* dsprule = mf->GetRequiredDefinition("CMAKE_COMMAND"); + cmCustomCommandLine commandLine; + commandLine.push_back(dsprule); + std::string argH = "-H"; + argH += lg->Convert(mf->GetHomeDirectory(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::UNCHANGED, true); + commandLine.push_back(argH); + std::string argB = "-B"; + argB += lg->Convert(mf->GetHomeOutputDirectory(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::UNCHANGED, true); + commandLine.push_back(argB); + commandLine.push_back("--check-stamp-list"); + commandLine.push_back(stampList.c_str()); + commandLine.push_back("--vs-solution-file"); + commandLine.push_back("\"$(SolutionPath)\""); + cmCustomCommandLines commandLines; + commandLines.push_back(commandLine); + + // Add the rule. Note that we cannot use the CMakeLists.txt + // file as the main dependency because it would get + // overwritten by the CreateVCProjBuildRule. + // (this could be avoided with per-target source files) + const char* no_main_dependency = 0; + const char* no_working_directory = 0; + mf->AddCustomCommandToOutput( + stamps, listFiles, + no_main_dependency, commandLines, "Checking Build System", + no_working_directory, true); + std::string ruleName = stamps[0]; + ruleName += ".rule"; + if(cmSourceFile* file = mf->GetSource(ruleName.c_str())) + { + tgt->AddSourceFile(file); + } + else + { + cmSystemTools::Error("Error adding rule for ", stamps[0].c_str()); + } + } + } } // Now perform the main generation. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index f136b421d..e4d2ead72 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -111,6 +111,7 @@ #include // auto_ptr static bool cmakeCheckStampFile(const char* stampName); +static bool cmakeCheckStampList(const char* stampName); void cmNeedBackwardsCompatibility(const std::string& variable, int access_type, void*, const char*, const cmMakefile*) @@ -553,6 +554,10 @@ void cmake::SetArgs(const std::vector& args) { this->CheckStampFile = args[++i]; } + else if((i < args.size()-1) && (arg.find("--check-stamp-list",0) == 0)) + { + this->CheckStampList = args[++i]; + } #if defined(CMAKE_HAVE_VS_GENERATORS) else if((i < args.size()-1) && (arg.find("--vs-solution-file",0) == 0)) { @@ -2150,6 +2155,13 @@ int cmake::Run(const std::vector& args, bool noconfigure) return -1; } + // If we are given a stamp list file check if it is really out of date. + if(!this->CheckStampList.empty() && + cmakeCheckStampList(this->CheckStampList.c_str())) + { + return 0; + } + // If we are given a stamp file check if it is really out of date. if(!this->CheckStampFile.empty() && cmakeCheckStampFile(this->CheckStampFile.c_str())) @@ -3697,6 +3709,10 @@ static bool cmakeCheckStampFile(const char* stampName) // date. if(cmSystemTools::FileExists(stampName)) { + // Notify the user why CMake is 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 is re-running due to explicit user request.\n"; return false; } @@ -3744,8 +3760,8 @@ static bool cmakeCheckStampFile(const char* stampName) // 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 " - << "generation timestamp is up-to-date.\n"; + std::cout << "CMake does not need to re-run because " + << stampName << " is up-to-date.\n"; return true; } else @@ -3755,6 +3771,36 @@ static bool cmakeCheckStampFile(const char* stampName) } } +//---------------------------------------------------------------------------- +static bool cmakeCheckStampList(const char* stampList) +{ + // If the stamp list does not exist CMake must rerun to generate it. + if(!cmSystemTools::FileExists(stampList)) + { + std::cout << "CMake is re-running because generate.stamp.list " + << "is missing.\n"; + return false; + } + std::ifstream fin(stampList); + if(!fin) + { + std::cout << "CMake is re-running because generate.stamp.list " + << "could not be read.\n"; + return false; + } + + // Check each stamp. + std::string stampName; + while(cmSystemTools::GetLineFromStream(fin, stampName)) + { + if(!cmakeCheckStampFile(stampName.c_str())) + { + return false; + } + } + return true; +} + // For visual studio 2005 and newer manifest files need to be embeded into // exe and dll's. This code does that in such a way that incremental linking // still works. diff --git a/Source/cmake.h b/Source/cmake.h index 3670b4a20..b4d60360e 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -435,6 +435,7 @@ private: std::string CCEnvironment; std::string CheckBuildSystemArgument; std::string CheckStampFile; + std::string CheckStampList; std::string VSSolutionFile; std::string CTestCommand; std::string CPackCommand;