diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 905b96439..5977d282b 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -17,6 +17,7 @@ #include "cmDependsC.h" #include "cmSystemTools.h" +#include "cmFileTimeComparison.h" #include // isspace @@ -30,18 +31,28 @@ cmDependsC::cmDependsC(): // yummy look at all those constructor arguments cmDependsC::cmDependsC(std::vector const& includes, const char* scanRegex, const char* complainRegex, - std::set const& generatedFiles): + std::set const& generatedFiles, + const cmStdString& cacheFileName): m_IncludePath(&includes), m_IncludeRegexLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)([\">])"), m_IncludeRegexScan(scanRegex), m_IncludeRegexComplain(complainRegex), - m_GeneratedFiles(&generatedFiles) + m_GeneratedFiles(&generatedFiles), + m_cacheFileName(cacheFileName) { + this->ReadCacheFile(); } //---------------------------------------------------------------------------- cmDependsC::~cmDependsC() { + this->WriteCacheFile(); + + for (std::map::iterator it=m_fileCache.begin(); + it!=m_fileCache.end(); ++it) + { + delete it->second; + } } //---------------------------------------------------------------------------- @@ -142,42 +153,159 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj, // Record scanned files. scanned.insert(fullName); - // Try to scan the file. Just leave it out if we cannot find - // it. - std::ifstream fin(fullName.c_str()); - if(fin) + // Check whether this file is already in the cache + std::map::iterator fileIt=m_fileCache.find(fullName); + if (fileIt!=m_fileCache.end()) { - // Add this file as a dependency. + fileIt->second->used=true; dependencies.insert(fullName); - - // Scan this file for new dependencies. Pass the directory - // containing the file to handle double-quote includes. - std::string dir = cmSystemTools::GetFilenamePath(fullName); - this->Scan(fin, dir.c_str()); + for (std::list::const_iterator incIt= + fileIt->second->list.begin(); incIt!=fileIt->second->list.end(); ++incIt) + { + if (m_Encountered.find(incIt->FileName) == m_Encountered.end()) + { + m_Encountered.insert(incIt->FileName); + m_Unscanned.push(*incIt); + } + } + } + else + { + + // Try to scan the file. Just leave it out if we cannot find + // it. + std::ifstream fin(fullName.c_str()); + if(fin) + { + // Add this file as a dependency. + dependencies.insert(fullName); + + // Scan this file for new dependencies. Pass the directory + // containing the file to handle double-quote includes. + std::string dir = cmSystemTools::GetFilenamePath(fullName); + this->Scan(fin, dir.c_str(), fullName); + } } } - + first = false; } - + // Write the dependencies to the output stream. internalDepends << obj << std::endl; for(std::set::iterator i=dependencies.begin(); i != dependencies.end(); ++i) { makeDepends << obj << ": " - << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str() - << std::endl; + << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str() + << std::endl; internalDepends << " " << i->c_str() << std::endl; } makeDepends << std::endl; - + return true; } //---------------------------------------------------------------------------- -void cmDependsC::Scan(std::istream& is, const char* directory) +void cmDependsC::ReadCacheFile() { + if(m_cacheFileName.size() == 0) + { + return; + } + std::ifstream fin(m_cacheFileName.c_str()); + if(!fin) + { + return; + } + + std::string line; + cmIncludeLines* cacheEntry=0; + bool haveFileName=false; + + while(cmSystemTools::GetLineFromStream(fin, line)) + { + if (line.empty()) + { + cacheEntry=0; + haveFileName=false; + continue; + } + //the first line after an empty line is the name of the parsed file + if (haveFileName==false) + { + haveFileName=true; + int newer=0; + cmFileTimeComparison comp; + bool res=comp.FileTimeCompare(m_cacheFileName.c_str(), line.c_str(), &newer); + + if ((res==true) && (newer==1)) //cache is newer than the parsed file + { + cacheEntry=new cmIncludeLines; + m_fileCache[line]=cacheEntry; + } + } + else if (cacheEntry!=0) + { + UnscannedEntry entry; + entry.FileName = line; + if (cmSystemTools::GetLineFromStream(fin, line)) + { + if (line!="-") + { + entry.QuotedLocation=line; + } + cacheEntry->list.push_back(entry); + } + } + } +} + +//---------------------------------------------------------------------------- +void cmDependsC::WriteCacheFile() const +{ + if(m_cacheFileName.size() == 0) + { + return; + } + std::ofstream cacheOut(m_cacheFileName.c_str()); + if(!cacheOut) + { + return; + } + + for (std::map::const_iterator fileIt=m_fileCache.begin(); + fileIt!=m_fileCache.end(); ++fileIt) + { + if (fileIt->second->used) + { + cacheOut<first.c_str()<::const_iterator incIt=fileIt->second->list.begin(); + incIt!=fileIt->second->list.end(); ++incIt) + { + cacheOut<FileName.c_str()<QuotedLocation.empty()) + { + cacheOut<<"-"<QuotedLocation.c_str()<used=true; + m_fileCache[fullName]=newCacheEntry; + // Read one line at a time. std::string line; while(cmSystemTools::GetLineFromStream(is, line)) @@ -204,11 +332,14 @@ void cmDependsC::Scan(std::istream& is, const char* directory) // is included by double-quotes and the other by angle brackets. // This kind of problem will be fixed when a more // preprocessor-like implementation of this scanner is created. - if(m_Encountered.find(entry.FileName) == m_Encountered.end() && - m_IncludeRegexScan.find(entry.FileName.c_str())) + if (m_IncludeRegexScan.find(entry.FileName.c_str())) { - m_Encountered.insert(entry.FileName); - m_Unscanned.push(entry); + newCacheEntry->list.push_back(entry); + if(m_Encountered.find(entry.FileName) == m_Encountered.end()) + { + m_Encountered.insert(entry.FileName); + m_Unscanned.push(entry); + } } } } diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h index 04648fd82..e9d335f4a 100644 --- a/Source/cmDependsC.h +++ b/Source/cmDependsC.h @@ -32,7 +32,7 @@ public: cmDependsC(); cmDependsC(std::vector const& includes, const char* scanRegex, const char* complainRegex, - std::set const& generatedFiles); + std::set const& generatedFiles, const cmStdString& cachFileName); /** Virtual destructor to cleanup subclasses properly. */ virtual ~cmDependsC(); @@ -47,7 +47,7 @@ protected: std::ostream& internalDepends); // Method to scan a single file. - void Scan(std::istream& is, const char* directory); + void Scan(std::istream& is, const char* directory, const cmStdString& fullName); // Method to test for the existence of a file. bool FileExistsOrIsGenerated(const std::string& fname, @@ -74,10 +74,24 @@ protected: cmStdString FileName; cmStdString QuotedLocation; }; + + struct cmIncludeLines + { + cmIncludeLines():used(false) {} + std::list list; + bool used; + }; + std::set m_Encountered; std::queue m_Unscanned; t_CharBuffer m_Buffer; + std::map m_fileCache; + + cmStdString m_cacheFileName; + + void WriteCacheFile() const; + void ReadCacheFile(); private: cmDependsC(cmDependsC const&); // Purposely not implemented. void operator=(cmDependsC const&); // Purposely not implemented. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index c89c587fd..d00e6a10a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -2790,11 +2790,15 @@ cmLocalUnixMakefileGenerator3 cmDepends *scanner = 0; if(lang == "C" || lang == "CXX" || lang == "RC") { + std::string includeCacheFileName = dir; + includeCacheFileName += "/includecache."; + includeCacheFileName += lang; + // TODO: Handle RC (resource files) dependencies correctly. scanner = new cmDependsC(includes, includeRegexScan.c_str(), includeRegexComplain.c_str(), - generatedFiles); + generatedFiles, includeCacheFileName); } #ifdef CMAKE_BUILD_WITH_CMAKE else if(lang == "Fortran")