diff options
author | Brad King <brad.king@kitware.com> | 2005-01-18 22:09:05 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2005-01-18 22:09:05 (GMT) |
commit | 195cdf172e2eecdb1b7fb3c2154cfe34c14afd9f (patch) | |
tree | 41c1bbb581fed83207b8d0f6515c8ea018061a46 /Source/cmDependsC.cxx | |
parent | ed9e0626fdf7d0d97733997d3b40a886cc082ebf (diff) | |
download | CMake-195cdf172e2eecdb1b7fb3c2154cfe34c14afd9f.zip CMake-195cdf172e2eecdb1b7fb3c2154cfe34c14afd9f.tar.gz CMake-195cdf172e2eecdb1b7fb3c2154cfe34c14afd9f.tar.bz2 |
ENH: Split dependency scanning and checking into separate cmDepends superclass with language-specific subclasses such as cmDependsC.
Diffstat (limited to 'Source/cmDependsC.cxx')
-rw-r--r-- | Source/cmDependsC.cxx | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx new file mode 100644 index 0000000..a57c282 --- /dev/null +++ b/Source/cmDependsC.cxx @@ -0,0 +1,247 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "cmDependsC.h" + +#include "cmSystemTools.h" + +//---------------------------------------------------------------------------- +cmDependsC::cmDependsC(const char* dir, const char* targetFile): + cmDepends(dir, targetFile), + m_SourceFile(), + m_IncludePath(0), + m_IncludeLineRegex() +{ +} + +//---------------------------------------------------------------------------- +cmDependsC::cmDependsC(const char* dir, const char* targetFile, + const char* sourceFile, + std::vector<std::string> const& includes): + cmDepends(dir, targetFile), + m_SourceFile(sourceFile), + m_IncludePath(&includes), + m_IncludeLineRegex("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]") +{ +} + +//---------------------------------------------------------------------------- +cmDependsC::~cmDependsC() +{ +} + +//---------------------------------------------------------------------------- +bool cmDependsC::WriteDependencies(std::ostream& os) +{ + // Make sure this is a scanning instance. + if(m_SourceFile == "") + { + cmSystemTools::Error("Cannot scan dependencies without an source file."); + return false; + } + if(!m_IncludePath) + { + cmSystemTools::Error("Cannot scan dependencies without an include path."); + return false; + } + + // Walk the dependency graph starting with the source file. + bool first = true; + m_Unscanned.push(m_SourceFile); + m_Encountered.insert(m_SourceFile); + std::set<cmStdString> dependencies; + std::set<cmStdString> scanned; + while(!m_Unscanned.empty()) + { + // Get the next file to scan. + std::string fname = m_Unscanned.front(); + m_Unscanned.pop(); + + // If not a full path, find the file in the include path. + std::string fullName; + if(first || cmSystemTools::FileIsFullPath(fname.c_str())) + { + fullName = fname; + } + else + { + for(std::vector<std::string>::const_iterator i = m_IncludePath->begin(); + i != m_IncludePath->end(); ++i) + { + std::string temp = *i; + temp += "/"; + temp += fname; + if(cmSystemTools::FileExists(temp.c_str())) + { + fullName = temp; + break; + } + } + } + + // Scan the file if it was found and has not been scanned already. + if(fullName.size() && (scanned.find(fullName) == scanned.end())) + { + // 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) + { + // Add this file as a dependency. + dependencies.insert(fullName); + + // Scan this file for new dependencies. + this->Scan(fin); + } + } + + first = false; + } + m_Encountered.clear(); + + // Write the dependencies to the output stream. + for(std::set<cmStdString>::iterator i=dependencies.begin(); + i != dependencies.end(); ++i) + { + os << m_TargetFile.c_str() << ": " + << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str() + << std::endl; + } + os << std::endl; + + return true; +} + +//---------------------------------------------------------------------------- +bool cmDependsC::CheckDependencies(std::istream& is) +{ + // Parse dependencies from the stream. If any dependee is missing + // or newer than the depender then dependencies should be + // regenerated. + bool okay = true; + std::string line; + std::string depender; + std::string dependee; + while(cmSystemTools::GetLineFromStream(is, line)) + { + // Skip empty lines and comments. + std::string::size_type pos = line.find_first_not_of(" \t\r\n"); + if(pos == std::string::npos || line[pos] == '#') + { + continue; + } + + // Strip leading whitespace. + if(pos > 0) + { + line = line.substr(pos); + } + + // Skip lines too short to have a dependency. + if(line.size() < 3) + { + continue; + } + + // Find the colon on the line. Skip the first two characters to + // avoid finding the colon in a drive letter on Windows. Ignore + // the line if a colon cannot be found. + if((pos = line.find(':', 2)) == std::string::npos) + { + continue; + } + + // Split the line into depender and dependee. + depender = line.substr(0, pos); + dependee = line.substr(pos+1); + + // Strip whitespace from the dependee. + if((pos = dependee.find_first_not_of(" \t\r\n")) != std::string::npos && + pos > 0) + { + dependee = dependee.substr(pos); + } + if((pos = dependee.find_last_not_of(" \t\r\n")) != std::string::npos) + { + dependee = dependee.substr(0, pos+1); + } + + // Convert dependee to a full path. + if(!cmSystemTools::FileIsFullPath(dependee.c_str())) + { + dependee = cmSystemTools::CollapseFullPath(dependee.c_str(), + m_Directory.c_str()); + } + + // Strip whitespace from the depender. + if((pos = depender.find_last_not_of(" \t\r\n")) != std::string::npos) + { + depender = depender.substr(0, pos+1); + } + + // Convert depender to a full path. + if(!cmSystemTools::FileIsFullPath(depender.c_str())) + { + depender = cmSystemTools::CollapseFullPath(depender.c_str(), + m_Directory.c_str()); + } + + // Dependencies must be regenerated if the dependee does not exist + // or if the depender exists and is older than the dependee. + int result = 0; + if(!cmSystemTools::FileExists(dependee.c_str()) || + (cmSystemTools::FileExists(depender.c_str()) && + (!cmSystemTools::FileTimeCompare(depender.c_str(), dependee.c_str(), + &result) || result < 0))) + { + // Dependencies must be regenerated. + okay = false; + + // Remove the depender to be sure it is rebuilt. + cmSystemTools::RemoveFile(depender.c_str()); + } + } + + return okay; +} + +//---------------------------------------------------------------------------- +void cmDependsC::Scan(std::istream& is) +{ + // Read one line at a time. + std::string line; + while(cmSystemTools::GetLineFromStream(is, line)) + { + // Match include directives. TODO: Support include regex and + // ignore regex. Possibly also support directory-based inclusion + // in dependencies. + if(m_IncludeLineRegex.find(line.c_str())) + { + // Get the file being included. + std::string includeFile = m_IncludeLineRegex.match(1); + + // Queue the file if it has not yet been encountered. + if(m_Encountered.find(includeFile) == m_Encountered.end()) + { + m_Encountered.insert(includeFile); + m_Unscanned.push(includeFile); + } + } + } +} |