summaryrefslogtreecommitdiff
path: root/Source/cmGlobalGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGlobalGenerator.cxx')
-rw-r--r--Source/cmGlobalGenerator.cxx166
1 files changed, 158 insertions, 8 deletions
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 33a7f208f7..e6436e4199 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -27,9 +27,14 @@
#include "cmVersion.h"
#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
#include <assert.h>
@@ -405,23 +410,43 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
fpath = "CMake";
fpath += lang;
fpath += "Information.cmake";
- fpath = mf->GetModulesFile(fpath.c_str());
- if(!mf->ReadListFile(0,fpath.c_str()))
+ std::string informationFile = mf->GetModulesFile(fpath.c_str());
+ if (informationFile.empty())
{
cmSystemTools::Error("Could not find cmake module file:",
fpath.c_str());
}
+ else if(!mf->ReadListFile(0, informationFile.c_str()))
+ {
+ cmSystemTools::Error("Could not process cmake module file:",
+ informationFile.c_str());
+ }
}
if (needSetLanguageEnabledMaps[lang])
{
this->SetLanguageEnabledMaps(lang, mf);
}
+ std::string compilerName = "CMAKE_";
+ compilerName += lang;
+ compilerName += "_COMPILER";
+ std::string compilerLangFile = rootBin;
+ compilerLangFile += "/CMake";
+ compilerLangFile += lang;
+ compilerLangFile += "Compiler.cmake";
// Test the compiler for the language just setup
+ // (but only if a compiler has been actually found)
// At this point we should have enough info for a try compile
// which is used in the backward stuff
// If the language is untested then test it now with a try compile.
- if(needTestLanguage[lang])
+ if (!mf->IsSet(compilerName.c_str()))
+ {
+ // if the compiler did not work, then remove the
+ // CMake(LANG)Compiler.cmake file so that it will get tested the
+ // next time cmake is run
+ cmSystemTools::RemoveFile(compilerLangFile.c_str());
+ }
+ else if(needTestLanguage[lang])
{
if (!this->CMakeInstance->GetIsInTryCompile())
{
@@ -442,11 +467,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
// next time cmake is run
if(!mf->IsOn(compilerWorks.c_str()))
{
- fpath = rootBin;
- fpath += "/CMake";
- fpath += lang;
- fpath += "Compiler.cmake";
- cmSystemTools::RemoveFile(fpath.c_str());
+ cmSystemTools::RemoveFile(compilerLangFile.c_str());
}
else
{
@@ -686,6 +707,7 @@ void cmGlobalGenerator::Configure()
this->TotalTargets.clear();
this->LocalGeneratorToTargetMap.clear();
this->ProjectMap.clear();
+ this->RuleHashes.clear();
// start with this directory
cmLocalGenerator *lg = this->CreateLocalGenerator();
@@ -840,6 +862,9 @@ void cmGlobalGenerator::Generate()
}
this->SetCurrentLocalGenerator(0);
+ // Update rule hashes.
+ this->CheckRuleHashes();
+
if (this->ExtraGenerator != 0)
{
this->ExtraGenerator->Generate();
@@ -1931,3 +1956,128 @@ cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk)
return dc;
}
+//----------------------------------------------------------------------------
+void
+cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
+ std::vector<std::string>::const_iterator first,
+ std::vector<std::string>::const_iterator last)
+{
+#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 = first; i != last; ++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)first;
+ (void)last;
+#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
+}