ENH: Implemented support for include/complain regular expressions for dependency scanning. This now includes the possibility that scanning will return failure and the build will stop.

This commit is contained in:
Brad King 2005-02-07 16:11:01 -05:00
parent c44e6d30e5
commit 337ad802c6
5 changed files with 73 additions and 25 deletions

View File

@ -42,7 +42,7 @@ cmDepends::~cmDepends()
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmDepends::Write() bool cmDepends::Write()
{ {
// Try to generate dependencies for the target file. // Try to generate dependencies for the target file.
cmGeneratedFileStream fout(m_DependsMakeFile.c_str()); cmGeneratedFileStream fout(m_DependsMakeFile.c_str());
@ -52,6 +52,11 @@ void cmDepends::Write()
// Dependencies were generated. Touch the mark file. // Dependencies were generated. Touch the mark file.
std::ofstream fmark(m_DependsMarkFile.c_str()); std::ofstream fmark(m_DependsMarkFile.c_str());
fmark << "Dependencies updated for " << m_TargetFile.c_str() << std::endl; fmark << "Dependencies updated for " << m_TargetFile.c_str() << std::endl;
return true;
}
else
{
return false;
} }
} }

View File

@ -37,7 +37,7 @@ public:
virtual ~cmDepends(); virtual ~cmDepends();
/** Write dependencies for the target file. */ /** Write dependencies for the target file. */
void Write(); bool Write();
/** Check dependencies for the target file. */ /** Check dependencies for the target file. */
void Check(); void Check();

View File

@ -23,18 +23,23 @@ cmDependsC::cmDependsC(const char* dir, const char* targetFile):
cmDepends(dir, targetFile), cmDepends(dir, targetFile),
m_SourceFile(), m_SourceFile(),
m_IncludePath(0), m_IncludePath(0),
m_IncludeLineRegex() m_IncludeRegexLine(),
m_IncludeRegexScan(),
m_IncludeRegexComplain()
{ {
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmDependsC::cmDependsC(const char* dir, const char* targetFile, cmDependsC::cmDependsC(const char* dir, const char* targetFile,
const char* sourceFile, const char* sourceFile,
std::vector<std::string> const& includes): std::vector<std::string> const& includes,
const char* scanRegex, const char* complainRegex):
cmDepends(dir, targetFile), cmDepends(dir, targetFile),
m_SourceFile(sourceFile), m_SourceFile(sourceFile),
m_IncludePath(&includes), m_IncludePath(&includes),
m_IncludeLineRegex("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]") m_IncludeRegexLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]"),
m_IncludeRegexScan(scanRegex),
m_IncludeRegexComplain(complainRegex)
{ {
} }
@ -61,6 +66,7 @@ bool cmDependsC::WriteDependencies(std::ostream& os)
// Walk the dependency graph starting with the source file. // Walk the dependency graph starting with the source file.
bool first = true; bool first = true;
m_Unscanned.push(m_SourceFile); m_Unscanned.push(m_SourceFile);
m_Encountered.clear();
m_Encountered.insert(m_SourceFile); m_Encountered.insert(m_SourceFile);
std::set<cmStdString> dependencies; std::set<cmStdString> dependencies;
std::set<cmStdString> scanned; std::set<cmStdString> scanned;
@ -74,7 +80,10 @@ bool cmDependsC::WriteDependencies(std::ostream& os)
std::string fullName; std::string fullName;
if(first || cmSystemTools::FileIsFullPath(fname.c_str())) if(first || cmSystemTools::FileIsFullPath(fname.c_str()))
{ {
fullName = fname; if(cmSystemTools::FileExists(fname.c_str()))
{
fullName = fname;
}
} }
else else
{ {
@ -92,8 +101,16 @@ bool cmDependsC::WriteDependencies(std::ostream& os)
} }
} }
// Complain if the file cannot be found and matches the complain
// regex.
if(fullName.empty() && m_IncludeRegexComplain.find(fname.c_str()))
{
cmSystemTools::Error("Cannot find file \"", fname.c_str(), "\".");
return false;
}
// Scan the file if it was found and has not been scanned already. // Scan the file if it was found and has not been scanned already.
if(fullName.size() && (scanned.find(fullName) == scanned.end())) if(!fullName.empty() && (scanned.find(fullName) == scanned.end()))
{ {
// Record scanned files. // Record scanned files.
scanned.insert(fullName); scanned.insert(fullName);
@ -113,7 +130,6 @@ bool cmDependsC::WriteDependencies(std::ostream& os)
first = false; first = false;
} }
m_Encountered.clear();
// Write the dependencies to the output stream. // Write the dependencies to the output stream.
for(std::set<cmStdString>::iterator i=dependencies.begin(); for(std::set<cmStdString>::iterator i=dependencies.begin();
@ -228,16 +244,16 @@ void cmDependsC::Scan(std::istream& is)
std::string line; std::string line;
while(cmSystemTools::GetLineFromStream(is, line)) while(cmSystemTools::GetLineFromStream(is, line))
{ {
// Match include directives. TODO: Support include regex and // Match include directives.
// ignore regex. Possibly also support directory-based inclusion if(m_IncludeRegexLine.find(line.c_str()))
// in dependencies.
if(m_IncludeLineRegex.find(line.c_str()))
{ {
// Get the file being included. // Get the file being included.
std::string includeFile = m_IncludeLineRegex.match(1); std::string includeFile = m_IncludeRegexLine.match(1);
// Queue the file if it has not yet been encountered. // Queue the file if it has not yet been encountered and it
if(m_Encountered.find(includeFile) == m_Encountered.end()) // matches the regular expression for recursive scanning.
if(m_Encountered.find(includeFile) == m_Encountered.end() &&
m_IncludeRegexScan.find(includeFile.c_str()))
{ {
m_Encountered.insert(includeFile); m_Encountered.insert(includeFile);
m_Unscanned.push(includeFile); m_Unscanned.push(includeFile);

View File

@ -34,9 +34,10 @@ public:
/** Scanning need to know the build directory name, the relative /** Scanning need to know the build directory name, the relative
path from the build directory to the target file, the source path from the build directory to the target file, the source
file from which to start scanning, and the include file search file from which to start scanning, and the include file search
path. */ path. It also uses the include file regular expressions. */
cmDependsC(const char* dir, const char* targetFile, cmDependsC(const char* dir, const char* targetFile,
const char* sourceFile, std::vector<std::string> const& includes); const char* sourceFile, std::vector<std::string> const& includes,
const char* scanRegex, const char* complainRegex);
/** Virtual destructor to cleanup subclasses properly. */ /** Virtual destructor to cleanup subclasses properly. */
virtual ~cmDependsC(); virtual ~cmDependsC();
@ -56,7 +57,12 @@ protected:
std::vector<std::string> const* m_IncludePath; std::vector<std::string> const* m_IncludePath;
// Regular expression to identify C preprocessor include directives. // Regular expression to identify C preprocessor include directives.
cmsys::RegularExpression m_IncludeLineRegex; cmsys::RegularExpression m_IncludeRegexLine;
// Regular expressions to choose which include files to scan
// recursively and which to complain about not finding.
cmsys::RegularExpression m_IncludeRegexScan;
cmsys::RegularExpression m_IncludeRegexComplain;
// Data structures for dependency graph walk. // Data structures for dependency graph walk.
std::set<cmStdString> m_Encountered; std::set<cmStdString> m_Encountered;

View File

@ -234,6 +234,7 @@ void cmLocalUnixMakefileGenerator2::GenerateCMakefile()
<< "SET(CMAKE_MAKEFILE_OUTPUTS\n" << "SET(CMAKE_MAKEFILE_OUTPUTS\n"
<< " \"" << this->ConvertToRelativePath(makefileName.c_str()).c_str() << "\"\n" << " \"" << this->ConvertToRelativePath(makefileName.c_str()).c_str() << "\"\n"
<< " \"" << this->ConvertToRelativePath(check.c_str()).c_str() << "\"\n" << " \"" << this->ConvertToRelativePath(check.c_str()).c_str() << "\"\n"
<< " \"CMakeDirectoryInformation.cmake\"\n"
<< " )\n\n"; << " )\n\n";
// Set the set of files to check for dependency integrity. // Set the set of files to check for dependency integrity.
@ -525,8 +526,7 @@ cmLocalUnixMakefileGenerator2
// touch the corresponding depends file after scanning dependencies. // touch the corresponding depends file after scanning dependencies.
cmOStringStream depCmd; cmOStringStream depCmd;
// TODO: Account for source file properties and directory-level // TODO: Account for source file properties and directory-level
// definitions when scanning for dependencies. Also account for // definitions when scanning for dependencies.
// include/ignore regular expressions.
depCmd << "$(CMAKE_COMMAND) -E cmake_depends " << lang << " " depCmd << "$(CMAKE_COMMAND) -E cmake_depends " << lang << " "
<< this->ConvertToRelativeOutputPath(obj.c_str()) << " " << this->ConvertToRelativeOutputPath(obj.c_str()) << " "
<< this->ConvertToRelativeOutputPath(source.GetFullPath().c_str()); << this->ConvertToRelativeOutputPath(source.GetFullPath().c_str());
@ -2854,20 +2854,41 @@ cmLocalUnixMakefileGenerator2
} }
} }
// Get the include file regular expression.
std::string includeRegexScan = "^.*$";
std::string includeRegexComplain = "^$";
if(haveDirectoryInfo)
{
std::string scanRegexVar = "CMAKE_";
scanRegexVar += lang;
scanRegexVar += "_INCLUDE_REGEX_SCAN";
if(const char* scanRegex = mf->GetDefinition(scanRegexVar.c_str()))
{
includeRegexScan = scanRegex;
}
std::string complainRegexVar = "CMAKE_";
complainRegexVar += lang;
complainRegexVar += "_INCLUDE_REGEX_COMPLAIN";
if(const char* complainRegex = mf->GetDefinition(complainRegexVar.c_str()))
{
includeRegexComplain = complainRegex;
}
}
// Dispatch the scan for each language. // Dispatch the scan for each language.
if(lang == "C" || lang == "CXX" || lang == "RC") if(lang == "C" || lang == "CXX" || lang == "RC")
{ {
// TODO: Handle RC (resource files) dependencies correctly. // TODO: Handle RC (resource files) dependencies correctly.
cmDependsC scanner(".", objFile, srcFile, includes); cmDependsC scanner(".", objFile, srcFile, includes,
scanner.Write(); includeRegexScan.c_str(), includeRegexComplain.c_str());
return true; return scanner.Write();
true;
} }
#ifdef CMAKE_BUILD_WITH_CMAKE #ifdef CMAKE_BUILD_WITH_CMAKE
else if(lang == "Fortran") else if(lang == "Fortran")
{ {
cmDependsFortran scanner(".", objFile, srcFile, includes); cmDependsFortran scanner(".", objFile, srcFile, includes);
scanner.Write(); return scanner.Write();
return true;
} }
#endif #endif
return false; return false;