summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMakeLists.txt5
-rw-r--r--Source/cmDepends.cxx96
-rw-r--r--Source/cmDepends.h82
-rw-r--r--Source/cmDependsC.cxx247
-rw-r--r--Source/cmDependsC.h70
-rw-r--r--Source/cmLocalUnixMakefileGenerator2.cxx416
-rw-r--r--Source/cmLocalUnixMakefileGenerator2.h25
-rw-r--r--Source/cmake.cxx5
8 files changed, 617 insertions, 329 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index ff93eb7..4451e12 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -46,6 +46,11 @@ SET(SRCS
cmake.h
cmakewizard.cxx
cmakewizard.h
+
+ cmDepends.h
+ cmDepends.cxx
+ cmDependsC.h
+ cmDependsC.cxx
)
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
new file mode 100644
index 0000000..4933f5f
--- /dev/null
+++ b/Source/cmDepends.cxx
@@ -0,0 +1,96 @@
+/*=========================================================================
+
+ 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 "cmDepends.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+//----------------------------------------------------------------------------
+cmDepends::cmDepends(const char* dir, const char* targetFile):
+ m_Directory(dir),
+ m_TargetFile(targetFile),
+ m_DependsMakeFile(dir),
+ m_DependsMarkFile(dir)
+{
+ // Construct the path to the make and mark files. Append
+ // appropriate extensions to their names.
+ m_DependsMakeFile += "/";
+ m_DependsMarkFile += "/";
+ m_DependsMakeFile += m_TargetFile;
+ m_DependsMarkFile += m_TargetFile;
+ m_DependsMakeFile += ".depends.make";
+ m_DependsMarkFile += ".depends";
+}
+
+//----------------------------------------------------------------------------
+cmDepends::~cmDepends()
+{
+}
+
+//----------------------------------------------------------------------------
+void cmDepends::Write()
+{
+ // Try to generate dependencies for the target file.
+ cmGeneratedFileStream fout(m_DependsMakeFile.c_str());
+ fout << "# Dependencies for " << m_TargetFile.c_str() << std::endl;
+ if(this->WriteDependencies(fout) && fout)
+ {
+ // Dependencies were generated. Touch the mark file.
+ std::ofstream fmark(m_DependsMarkFile.c_str());
+ fmark << "Dependencies updated for " << m_TargetFile.c_str() << std::endl;
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmDepends::Check()
+{
+ // Check whether dependencies must be regenerated.
+ std::ifstream fin(m_DependsMakeFile.c_str());
+ if(!(fin && this->CheckDependencies(fin)))
+ {
+ // Clear all dependencies so they will be regenerated.
+ this->Clear();
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmDepends::Clear()
+{
+ // Remove the dependency mark file to be sure dependencies will be
+ // regenerated.
+ cmSystemTools::RemoveFile(m_DependsMarkFile.c_str());
+
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(m_DependsMakeFile.c_str());
+ depFileStream
+ << "# Empty dependencies file for " << m_TargetFile.c_str() << ".\n"
+ << "# This may be replaced when dependencies are built." << std::endl;
+}
+
+//----------------------------------------------------------------------------
+const char* cmDepends::GetMakeFileName()
+{
+ // Skip over the directory part of the name.
+ return m_DependsMakeFile.c_str() + m_Directory.length() + 1;
+}
+
+//----------------------------------------------------------------------------
+const char* cmDepends::GetMarkFileName()
+{
+ // Skip over the directory part of the name.
+ return m_DependsMarkFile.c_str() + m_Directory.length() + 1;
+}
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
new file mode 100644
index 0000000..00d2daf
--- /dev/null
+++ b/Source/cmDepends.h
@@ -0,0 +1,82 @@
+/*=========================================================================
+
+ 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.
+
+=========================================================================*/
+#ifndef cmDepends_h
+#define cmDepends_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmDepends
+ * \brief Dependency scanner superclass.
+ *
+ * This class is responsible for maintaining a .depends.make file in
+ * the build tree corresponding to an object file. Subclasses help it
+ * maintain dependencies for particular languages.
+ */
+class cmDepends
+{
+public:
+ /** Instances need to know the build directory name and the relative
+ path from the build directory to the target file. */
+ cmDepends(const char* dir, const char* targetFile);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ virtual ~cmDepends();
+
+ /** Write dependencies for the target file. */
+ void Write();
+
+ /** Check dependencies for the target file. */
+ void Check();
+
+ /** Clear dependencies for the target file so they will be regenerated. */
+ void Clear();
+
+ /** Get the name of the dependency make file. */
+ const char* GetMakeFileName();
+
+ /** Get the name of the dependency mark file. */
+ const char* GetMarkFileName();
+
+protected:
+
+ // Write dependencies for the target file to the given stream.
+ // Return true for success and false for failure.
+ virtual bool WriteDependencies(std::ostream& os)=0;
+
+ // Check dependencies for the target file in the given stream.
+ // Return false if dependencies must be regenerated and true
+ // otherwise.
+ virtual bool CheckDependencies(std::istream& is)=0;
+
+ // The directory in which the build rule for the target file is executed.
+ std::string m_Directory;
+
+ // The name of the target file for which dependencies are maintained.
+ std::string m_TargetFile;
+
+ // The name of the .depends.make file corresponding to the target.
+ std::string m_DependsMakeFile;
+
+ // The name of the .depends file marking when dependencies were generated.
+ std::string m_DependsMarkFile;
+
+private:
+ cmDepends(cmDepends const&); // Purposely not implemented.
+ void operator=(cmDepends const&); // Purposely not implemented.
+};
+
+#endif
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);
+ }
+ }
+ }
+}
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
new file mode 100644
index 0000000..70691b7
--- /dev/null
+++ b/Source/cmDependsC.h
@@ -0,0 +1,70 @@
+/*=========================================================================
+
+ 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.
+
+=========================================================================*/
+#ifndef cmDependsC_h
+#define cmDependsC_h
+
+#include "cmDepends.h"
+#include <cmsys/RegularExpression.hxx>
+#include <queue>
+
+/** \class cmDependsC
+ * \brief Dependency scanner for C and C++ object files.
+ */
+class cmDependsC: public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsC(const char* dir, const char* targetFile);
+
+ /** Scanning need to know the build directory name, the relative
+ path from the build directory to the target file, the source
+ file from which to start scanning, and the include file search
+ path. */
+ cmDependsC(const char* dir, const char* targetFile,
+ const char* sourceFile, std::vector<std::string> const& includes);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ virtual ~cmDependsC();
+
+protected:
+ // Implement writing/checking methods required by superclass.
+ virtual bool WriteDependencies(std::ostream& os);
+ virtual bool CheckDependencies(std::istream& is);
+
+ // Method to scan a single file.
+ void Scan(std::istream& is);
+
+ // The source file from which to start scanning.
+ std::string m_SourceFile;
+
+ // The include file search path.
+ std::vector<std::string> const* m_IncludePath;
+
+ // Regular expression to identify C preprocessor include directives.
+ cmsys::RegularExpression m_IncludeLineRegex;
+
+ // Data structures for dependency graph walk.
+ std::set<cmStdString> m_Encountered;
+ std::queue<cmStdString> m_Unscanned;
+
+private:
+ cmDependsC(cmDependsC const&); // Purposely not implemented.
+ void operator=(cmDependsC const&); // Purposely not implemented.
+};
+
+#endif
diff --git a/Source/cmLocalUnixMakefileGenerator2.cxx b/Source/cmLocalUnixMakefileGenerator2.cxx
index 73756f7..1fad7f5 100644
--- a/Source/cmLocalUnixMakefileGenerator2.cxx
+++ b/Source/cmLocalUnixMakefileGenerator2.cxx
@@ -16,17 +16,20 @@
=========================================================================*/
#include "cmLocalUnixMakefileGenerator2.h"
+#include "cmDepends.h"
+#include "cmDependsC.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
+#include <memory> // auto_ptr
#include <queue>
#include <assert.h>
// Quick-switch for generating old makefiles.
-#if 0
+#if 1
# define CMLUMG_MAKEFILE_NAME "Makefile"
#else
# define CMLUMG_WRITE_OLD_MAKEFILE
@@ -237,16 +240,33 @@ void cmLocalUnixMakefileGenerator2::GenerateCMakefile()
// Set the set of files to check for dependency integrity.
cmakefileStream
- << "# The set of files whose dependency integrity should be checked:\n"
- << "SET(CMAKE_DEPENDS_CHECK\n";
- for(std::set<cmStdString>::const_iterator i = m_CheckDependFiles.begin();
- i != m_CheckDependFiles.end(); ++i)
+ << "# The set of files whose dependency integrity should be checked:\n";
+ cmakefileStream
+ << "SET(CMAKE_DEPENDS_LANGUAGES\n";
+ for(std::map<cmStdString, IntegrityCheckSet>::const_iterator
+ l = m_CheckDependFiles.begin();
+ l != m_CheckDependFiles.end(); ++l)
{
cmakefileStream
- << " \"" << this->ConvertToRelativePath(i->c_str()).c_str() << "\"\n";
+ << " \"" << l->first.c_str() << "\"\n";
}
cmakefileStream
<< " )\n";
+ for(std::map<cmStdString, IntegrityCheckSet>::const_iterator
+ l = m_CheckDependFiles.begin();
+ l != m_CheckDependFiles.end(); ++l)
+ {
+ cmakefileStream
+ << "SET(CMAKE_DEPENDS_CHECK_" << l->first.c_str() << "\n";
+ for(std::set<cmStdString>::const_iterator i = l->second.begin();
+ i != l->second.end(); ++i)
+ {
+ cmakefileStream
+ << " \"" << this->ConvertToRelativePath(i->c_str()).c_str() << "\"\n";
+ }
+ cmakefileStream
+ << " )\n";
+ }
}
//----------------------------------------------------------------------------
@@ -278,7 +298,6 @@ cmLocalUnixMakefileGenerator2
std::string depBase = dir;
depBase += "/";
depBase += target.GetName();
- std::string depMakeFile = this->GenerateDependsMakeFile(depBase.c_str());
// Construct the rule file name.
std::string ruleFileName = dir;
@@ -302,13 +321,6 @@ cmLocalUnixMakefileGenerator2
ruleFileStream
<< "# Rule file for target " << target.GetName() << ".\n\n";
- // Include the dependencies for the target.
- ruleFileStream
- << "# Include any dependencies generated for this rule.\n"
- << m_IncludeDirective << " "
- << this->ConvertToOutputForExisting(depMakeFile.c_str()).c_str()
- << "\n\n";
-
// Include the rule file for each object.
if(!objects.empty())
{
@@ -371,19 +383,27 @@ cmLocalUnixMakefileGenerator2
// Get the full path name of the object file.
std::string obj = this->GetObjectFileName(target, source);
- // Save this in the target's list of object files.
- objects.push_back(obj);
-
- // The object file should be checked for dependency integrity.
- m_CheckDependFiles.insert(obj);
-
// Create the directory containing the object file. This may be a
// subdirectory under the target's directory.
std::string dir = cmSystemTools::GetFilenamePath(obj.c_str());
cmSystemTools::MakeDirectory(this->ConvertToFullPath(dir).c_str());
// Generate the build-time dependencies file for this object file.
- std::string depMakeFile = this->GenerateDependsMakeFile(obj.c_str());
+ std::string depMakeFile;
+ std::string depMarkFile;
+ if(!this->GenerateDependsMakeFile(lang, obj.c_str(),
+ depMakeFile, depMarkFile))
+ {
+ cmSystemTools::Error("No dependency checker available for language \"",
+ lang, "\".");
+ return;
+ }
+
+ // Save this in the target's list of object files.
+ objects.push_back(obj);
+
+ // The object file should be checked for dependency integrity.
+ m_CheckDependFiles[lang].insert(obj);
// Open the rule file for writing. This should be copy-if-different
// because the rules may depend on this file itself.
@@ -424,8 +444,6 @@ cmLocalUnixMakefileGenerator2
depends.push_back(ruleFileName);
// Write the dependency generation rule.
- std::string depTarget = obj;
- depTarget += ".depends";
{
std::string depEcho = "Scanning ";
depEcho += lang;
@@ -453,7 +471,7 @@ cmLocalUnixMakefileGenerator2
// Write the rule.
this->WriteMakeRule(ruleFileStream, 0, depEcho.c_str(),
- depTarget.c_str(), depends, commands);
+ depMarkFile.c_str(), depends, commands);
}
// Write the build rule.
@@ -676,30 +694,28 @@ cmLocalUnixMakefileGenerator2
}
//----------------------------------------------------------------------------
-std::string
+bool
cmLocalUnixMakefileGenerator2
-::GenerateDependsMakeFile(const char* file)
+::GenerateDependsMakeFile(const std::string& lang, const char* objFile,
+ std::string& depMakeFile, std::string& depMarkFile)
{
- // Check if the build-time dependencies file exists.
- std::string depMarkFile = file;
- depMarkFile += ".depends";
- std::string depMakeFile = depMarkFile;
- depMakeFile += ".make";
- std::string depMakeFileFull = this->ConvertToFullPath(depMakeFile);
- if(cmSystemTools::FileExists(depMakeFileFull.c_str()))
- {
- // The build-time dependencies file already exists. Check it.
- this->CheckDependencies(m_Makefile->GetStartOutputDirectory(), file);
- }
- else
+ // Construct a checker for the given language.
+ std::auto_ptr<cmDepends>
+ checker(this->GetDependsChecker(lang,
+ m_Makefile->GetStartOutputDirectory(),
+ objFile));
+ if(checker.get())
{
- // The build-time dependencies file does not exist. Create an
- // empty one.
- std::string depMarkFileFull = this->ConvertToFullPath(depMarkFile);
- this->WriteEmptyDependMakeFile(file, depMarkFileFull.c_str(),
- depMakeFileFull.c_str());
+ // Save the make and mark file names.
+ depMakeFile = checker->GetMakeFileName();
+ depMarkFile = checker->GetMarkFileName();
+
+ // Check the dependencies.
+ checker->Check();
+
+ return true;
}
- return depMakeFile;
+ return false;
}
//----------------------------------------------------------------------------
@@ -2687,6 +2703,19 @@ cmLocalUnixMakefileGenerator2
}
//----------------------------------------------------------------------------
+cmDepends*
+cmLocalUnixMakefileGenerator2::GetDependsChecker(const std::string& lang,
+ const char* dir,
+ const char* objFile)
+{
+ if(lang == "C" || lang == "CXX" || lang == "RC")
+ {
+ return new cmDependsC(dir, objFile);
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------------
bool
cmLocalUnixMakefileGenerator2
::ScanDependencies(std::vector<std::string> const& args)
@@ -2718,292 +2747,49 @@ cmLocalUnixMakefileGenerator2
if(lang == "C" || lang == "CXX" || lang == "RC")
{
// TODO: Handle RC (resource files) dependencies correctly.
- return cmLocalUnixMakefileGenerator2::ScanDependenciesC(objFile, srcFile,
- includes);
+ cmDependsC scanner(".", objFile, srcFile, includes);
+ scanner.Write();
+ return true;
}
return false;
}
//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator2ScanDependenciesC(
- std::ifstream& fin,
- std::set<cmStdString>& encountered,
- std::queue<cmStdString>& unscanned)
+void cmLocalUnixMakefileGenerator2::CheckDependencies(cmMakefile* mf)
{
- // Regular expression to identify C preprocessor include directives.
- cmsys::RegularExpression
- includeLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
-
- // Read one line at a time.
- std::string line;
- while(cmSystemTools::GetLineFromStream(fin, line))
- {
- // Match include directives. TODO: Support include regex and
- // ignore regex. Possibly also support directory-based inclusion
- // in dependencies.
- if(includeLine.find(line.c_str()))
- {
- // Get the file being included.
- std::string includeFile = includeLine.match(1);
-
- // Queue the file if it has not yet been encountered.
- if(encountered.find(includeFile) == encountered.end())
- {
- encountered.insert(includeFile);
- unscanned.push(includeFile);
- }
- }
- }
-}
-
-//----------------------------------------------------------------------------
-bool
-cmLocalUnixMakefileGenerator2
-::ScanDependenciesC(const char* objFile, const char* srcFile,
- std::vector<std::string> const& includes)
-{
- // Walk the dependency graph starting with the source file.
- std::set<cmStdString> dependencies;
- std::set<cmStdString> encountered;
- std::set<cmStdString> scanned;
- std::queue<cmStdString> unscanned;
- unscanned.push(srcFile);
- encountered.insert(srcFile);
- while(!unscanned.empty())
- {
- // Get the next file to scan.
- std::string fname = unscanned.front();
- unscanned.pop();
-
- // If not a full path, find the file in the include path.
- std::string fullName;
- if(cmSystemTools::FileIsFullPath(fname.c_str()))
- {
- fullName = fname;
- }
- else
- {
- for(std::vector<std::string>::const_iterator i = includes.begin();
- i != includes.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.
- cmLocalUnixMakefileGenerator2ScanDependenciesC(fin, encountered,
- unscanned);
- }
- }
- }
-
- // Write the dependencies to the output file.
- std::string depMarkFile = objFile;
- std::string depMakeFile = objFile;
- depMarkFile += ".depends";
- depMakeFile += ".depends.make";
- cmGeneratedFileStream fout(depMakeFile.c_str());
- fout << "# Dependencies for " << objFile << std::endl;
- for(std::set<cmStdString>::iterator i=dependencies.begin();
- i != dependencies.end(); ++i)
+ // Get the list of languages that may have sources to check.
+ const char* langDef = mf->GetDefinition("CMAKE_DEPENDS_LANGUAGES");
+ if(!langDef)
{
- fout << objFile << ": "
- << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
- << std::endl;
- }
- fout << std::endl;
- fout << "# Dependencies for " << depMarkFile.c_str() << std::endl;
- for(std::set<cmStdString>::iterator i=dependencies.begin();
- i != dependencies.end(); ++i)
- {
- fout << depMarkFile.c_str() << ": "
- << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
- << std::endl;
+ return;
}
+ std::vector<std::string> languages;
+ cmSystemTools::ExpandListArgument(langDef, languages);
- // If we could write the dependencies, touch the corresponding
- // depends file to mark dependencies up to date.
- if(fout)
+ // For each language get the set of files to check.
+ for(std::vector<std::string>::iterator l = languages.begin();
+ l != languages.end(); ++l)
{
- std::ofstream fmark(depMarkFile.c_str());
- fmark << "Dependencies updated for " << objFile << "\n";
- }
-
- return true;
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator2
-::CheckDependencies(const char* depCheck)
-{
- // Get the list of files to scan. This is given through the command
- // line hook cmake file.
- std::vector<std::string> files;
- cmSystemTools::ExpandListArgument(depCheck, files);
-
- // Check each file. The current working directory is already
- // correct.
- for(std::vector<std::string>::iterator f = files.begin();
- f != files.end(); ++f)
- {
- cmLocalUnixMakefileGenerator2::CheckDependencies(".", f->c_str());
- }
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator2
-::CheckDependencies(const char* dir, const char* file)
-{
- // Check the dependencies associated with the given file whose path
- // is specified relative to the given directory. If any dependency
- // is missing then dependencies should be regenerated.
- bool regenerate = false;
-
- // Construct the names of the mark and make files.
- std::string depMarkFileFull = dir;
- depMarkFileFull += "/";
- depMarkFileFull += file;
- depMarkFileFull += ".depends";
- std::string depMakeFileFull = depMarkFileFull;
- depMakeFileFull += ".make";
-
- // Open the dependency makefile.
- std::ifstream fin(depMakeFileFull.c_str());
- if(fin)
- {
- // Parse dependencies.
- std::string line;
- std::string depender;
- std::string dependee;
- while(cmSystemTools::GetLineFromStream(fin, line))
+ std::string depCheck = "CMAKE_DEPENDS_CHECK_";
+ depCheck += *l;
+ if(const char* fileDef = mf->GetDefinition(depCheck.c_str()))
{
- // 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)
+ // Check each file. The current working directory is already
+ // correct.
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(fileDef, files);
+ for(std::vector<std::string>::iterator f = files.begin();
+ f != files.end(); ++f)
{
- 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(), dir);
- }
-
- // If the dependee does not exist, we need to regenerate
- // dependencies and the depender should be removed.
- if(!cmSystemTools::FileExists(dependee.c_str()))
- {
- // Strip whitespace from the depender.
- if((pos = depender.find_last_not_of(" \t\r\n")) != std::string::npos)
+ // Construct a checker for the given language.
+ std::auto_ptr<cmDepends>
+ checker(cmLocalUnixMakefileGenerator2
+ ::GetDependsChecker(*l, ".", f->c_str()));
+ if(checker.get())
{
- depender = depender.substr(0, pos+1);
+ checker->Check();
}
-
- // Convert depender to a full path.
- if(!cmSystemTools::FileIsFullPath(depender.c_str()))
- {
- depender = cmSystemTools::CollapseFullPath(depender.c_str(), dir);
- }
-
- // Remove the depender.
- cmSystemTools::RemoveFile(depender.c_str());
-
- // Mark the need for regeneration.
- regenerate = true;
}
}
}
- else
- {
- // Could not open the dependencies file. It needs to be
- // regenerated.
- regenerate = true;
- }
-
- // If the dependencies file needs to be regenerated, create an empty
- // one and delete the mark file.
- if(regenerate)
- {
- cmLocalUnixMakefileGenerator2
- ::WriteEmptyDependMakeFile(file, depMarkFileFull.c_str(),
- depMakeFileFull.c_str());
- }
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator2
-::WriteEmptyDependMakeFile(const char* file,
- const char* depMarkFileFull,
- const char* depMakeFileFull)
-{
- // Remove the dependency mark file to be sure dependencies will be
- // regenerated.
- cmSystemTools::RemoveFile(depMarkFileFull);
-
- // Write an empty dependency file.
- cmGeneratedFileStream depFileStream(depMakeFileFull);
- depFileStream
- << "# Empty dependencies file for " << file << ".\n"
- << "# This may be replaced when dependencies are built.\n";
}
diff --git a/Source/cmLocalUnixMakefileGenerator2.h b/Source/cmLocalUnixMakefileGenerator2.h
index b867339..5597f66 100644
--- a/Source/cmLocalUnixMakefileGenerator2.h
+++ b/Source/cmLocalUnixMakefileGenerator2.h
@@ -21,6 +21,7 @@
class cmCustomCommand;
class cmDependInformation;
+class cmDepends;
class cmMakeDepend;
class cmTarget;
class cmSourceFile;
@@ -57,7 +58,7 @@ public:
static bool ScanDependencies(std::vector<std::string> const& args);
/** Called from command-line hook to check dependencies. */
- static void CheckDependencies(const char* depCheck);
+ static void CheckDependencies(cmMakefile* mf);
protected:
@@ -69,7 +70,10 @@ protected:
std::vector<std::string>& objects);
void GenerateCustomRuleFile(const cmCustomCommand& cc);
void GenerateUtilityRuleFile(const cmTarget& target);
- std::string GenerateDependsMakeFile(const char* file);
+ bool GenerateDependsMakeFile(const std::string& lang,
+ const char* objFile,
+ std::string& depMakeFile,
+ std::string& depMarkFile);
void WriteMakeRule(std::ostream& os,
const char* comment,
const char* preEcho,
@@ -163,12 +167,10 @@ protected:
std::string GetRecursiveMakeCall(const char* tgt);
void WriteJumpAndBuildRules(std::ostream& makefileStream);
- static bool ScanDependenciesC(const char* objFile, const char* srcFile,
- std::vector<std::string> const& includes);
- static void CheckDependencies(const char* dir, const char* file);
- static void WriteEmptyDependMakeFile(const char* file,
- const char* depMarkFileFull,
- const char* depMakeFileFull);
+ static cmDepends* GetDependsChecker(const std::string& lang,
+ const char* dir,
+ const char* objFile);
+
private:
// Map from target name to build directory containing it for
// jump-and-build targets.
@@ -179,8 +181,11 @@ private:
};
std::map<cmStdString, RemoteTarget> m_JumpAndBuild;
- // List the files for which to check dependency integrity.
- std::set<cmStdString> m_CheckDependFiles;
+ // List the files for which to check dependency integrity. Each
+ // language has its own list because integrity may be checked
+ // differently.
+ struct IntegrityCheckSet: public std::set<cmStdString> {};
+ std::map<cmStdString, IntegrityCheckSet> m_CheckDependFiles;
// Command used when a rule has no dependencies or commands.
std::vector<std::string> m_EmptyCommands;
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index a7e9781..9c319f1 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1635,10 +1635,7 @@ int cmake::CheckBuildSystem()
#if defined(CMAKE_BUILD_WITH_CMAKE)
// We do not need to rerun CMake. Check dependency integrity.
- if(const char* depCheck = mf->GetDefinition("CMAKE_DEPENDS_CHECK"))
- {
- cmLocalUnixMakefileGenerator2::CheckDependencies(depCheck);
- }
+ cmLocalUnixMakefileGenerator2::CheckDependencies(mf);
#endif
// No need to rerun.