summaryrefslogtreecommitdiffstats
path: root/Source/cmDependsC.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2005-01-18 22:09:05 (GMT)
committerBrad King <brad.king@kitware.com>2005-01-18 22:09:05 (GMT)
commit195cdf172e2eecdb1b7fb3c2154cfe34c14afd9f (patch)
tree41c1bbb581fed83207b8d0f6515c8ea018061a46 /Source/cmDependsC.cxx
parented9e0626fdf7d0d97733997d3b40a886cc082ebf (diff)
downloadCMake-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.cxx247
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);
+ }
+ }
+ }
+}