summaryrefslogtreecommitdiffstats
path: root/Source/cmDepends.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmDepends.cxx')
-rw-r--r--Source/cmDepends.cxx282
1 files changed, 282 insertions, 0 deletions
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
new file mode 100644
index 0000000..b25e3ce
--- /dev/null
+++ b/Source/cmDepends.cxx
@@ -0,0 +1,282 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmDepends.h"
+
+#include "cmFileTimeComparison.h"
+#include "cmGeneratedFileStream.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include <cmsys/FStream.hxx>
+#include <string.h>
+
+cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir)
+ : CompileDirectory()
+ , LocalGenerator(lg)
+ , Verbose(false)
+ , FileComparison(CM_NULLPTR)
+ , TargetDirectory(targetDir)
+ , MaxPath(16384)
+ , Dependee(new char[MaxPath])
+ , Depender(new char[MaxPath])
+{
+}
+
+cmDepends::~cmDepends()
+{
+ delete[] this->Dependee;
+ delete[] this->Depender;
+}
+
+bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
+{
+ // Lookup the set of sources to scan.
+ std::string srcLang = "CMAKE_DEPENDS_CHECK_";
+ srcLang += this->Language;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ const char* srcStr = mf->GetSafeDefinition(srcLang);
+ std::vector<std::string> pairs;
+ cmSystemTools::ExpandListArgument(srcStr, pairs);
+
+ std::map<std::string, std::set<std::string> > dependencies;
+ for (std::vector<std::string>::iterator si = pairs.begin();
+ si != pairs.end();) {
+ // Get the source and object file.
+ std::string const& src = *si++;
+ if (si == pairs.end()) {
+ break;
+ }
+ std::string const& obj = *si++;
+ dependencies[obj].insert(src);
+ }
+ for (std::map<std::string, std::set<std::string> >::const_iterator it =
+ dependencies.begin();
+ it != dependencies.end(); ++it) {
+
+ // Write the dependencies for this pair.
+ if (!this->WriteDependencies(it->second, it->first, makeDepends,
+ internalDepends)) {
+ return false;
+ }
+ }
+
+ return this->Finalize(makeDepends, internalDepends);
+}
+
+bool cmDepends::Finalize(std::ostream&, std::ostream&)
+{
+ return true;
+}
+
+bool cmDepends::Check(const char* makeFile, const char* internalFile,
+ std::map<std::string, DependencyVector>& validDeps)
+{
+ // Dependency checks must be done in proper working directory.
+ std::string oldcwd = ".";
+ if (this->CompileDirectory != ".") {
+ // Get the CWD but do not call CollapseFullPath because
+ // we only need it to cd back, and the form does not matter
+ oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
+ cmSystemTools::ChangeDirectory(this->CompileDirectory);
+ }
+
+ // Check whether dependencies must be regenerated.
+ bool okay = true;
+ cmsys::ifstream fin(internalFile);
+ if (!(fin && this->CheckDependencies(fin, internalFile, validDeps))) {
+ // Clear all dependencies so they will be regenerated.
+ this->Clear(makeFile);
+ cmSystemTools::RemoveFile(internalFile);
+ okay = false;
+ }
+
+ // Restore working directory.
+ if (oldcwd != ".") {
+ cmSystemTools::ChangeDirectory(oldcwd);
+ }
+
+ return okay;
+}
+
+void cmDepends::Clear(const char* file)
+{
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(file);
+ depFileStream << "# Empty dependencies file\n"
+ << "# This may be replaced when dependencies are built."
+ << std::endl;
+}
+
+bool cmDepends::WriteDependencies(const std::set<std::string>&,
+ const std::string&, std::ostream&,
+ std::ostream&)
+{
+ // This should be implemented by the subclass.
+ return false;
+}
+
+bool cmDepends::CheckDependencies(
+ std::istream& internalDepends, const char* internalDependsFileName,
+ std::map<std::string, DependencyVector>& validDeps)
+{
+ // Parse dependencies from the stream. If any dependee is missing
+ // or newer than the depender then dependencies should be
+ // regenerated.
+ bool okay = true;
+ bool dependerExists = false;
+ DependencyVector* currentDependencies = CM_NULLPTR;
+
+ while (internalDepends.getline(this->Dependee, this->MaxPath)) {
+ if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
+ this->Dependee[0] == '\r') {
+ continue;
+ }
+ size_t len = internalDepends.gcount() - 1;
+ if (this->Dependee[len - 1] == '\r') {
+ len--;
+ this->Dependee[len] = 0;
+ }
+ if (this->Dependee[0] != ' ') {
+ memcpy(this->Depender, this->Dependee, len + 1);
+ // Calling FileExists() for the depender here saves in many cases 50%
+ // of the calls to FileExists() further down in the loop. E.g. for
+ // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
+ // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
+ dependerExists = cmSystemTools::FileExists(this->Depender);
+ // If we erase validDeps[this->Depender] by overwriting it with an empty
+ // vector, we lose dependencies for dependers that have multiple
+ // entries. No need to initialize the entry, std::map will do so on first
+ // access.
+ currentDependencies = &validDeps[this->Depender];
+ continue;
+ }
+ /*
+ // Parse the dependency line.
+ if(!this->ParseDependency(line.c_str()))
+ {
+ continue;
+ }
+ */
+
+ // Dependencies must be regenerated
+ // * if the dependee does not exist
+ // * if the depender exists and is older than the dependee.
+ // * if the depender does not exist, but the dependee is newer than the
+ // depends file
+ bool regenerate = false;
+ const char* dependee = this->Dependee + 1;
+ const char* depender = this->Depender;
+ if (currentDependencies != CM_NULLPTR) {
+ currentDependencies->push_back(dependee);
+ }
+
+ if (!cmSystemTools::FileExists(dependee)) {
+ // The dependee does not exist.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee << "\" does not exist for depender \""
+ << depender << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ } else {
+ if (dependerExists) {
+ // The dependee and depender both exist. Compare file times.
+ int result = 0;
+ if ((!this->FileComparison->FileTimeCompare(depender, dependee,
+ &result) ||
+ result < 0)) {
+ // The depender is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee << "\" is newer than depender \""
+ << depender << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ }
+ } else {
+ // The dependee exists, but the depender doesn't. Regenerate if the
+ // internalDepends file is older than the dependee.
+ int result = 0;
+ if ((!this->FileComparison->FileTimeCompare(internalDependsFileName,
+ dependee, &result) ||
+ result < 0)) {
+ // The depends-file is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee
+ << "\" is newer than depends file \""
+ << internalDependsFileName << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str().c_str());
+ }
+ }
+ }
+ }
+ if (regenerate) {
+ // Dependencies must be regenerated.
+ okay = false;
+
+ // Remove the information of this depender from the map, it needs
+ // to be rescanned
+ if (currentDependencies != CM_NULLPTR) {
+ validDeps.erase(this->Depender);
+ currentDependencies = CM_NULLPTR;
+ }
+
+ // Remove the depender to be sure it is rebuilt.
+ if (dependerExists) {
+ cmSystemTools::RemoveFile(depender);
+ dependerExists = false;
+ }
+ }
+ }
+
+ return okay;
+}
+
+void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
+{
+ // Look for the new per "TARGET_" variant first:
+ const char* includePath = CM_NULLPTR;
+ std::string includePathVar = "CMAKE_";
+ includePathVar += lang;
+ includePathVar += "_TARGET_INCLUDE_PATH";
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
+ } else {
+ // Fallback to the old directory level variable if no per-target var:
+ includePathVar = "CMAKE_";
+ includePathVar += lang;
+ includePathVar += "_INCLUDE_PATH";
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
+ }
+ }
+}