cmDepends: allow multiple dependees per depender

This patch is heavily inspired by Michael Wild.

The interfaces cmDepends::Write and cmDepends::WriteDependencies where
extended to allow multiple dependees (sources) per depender (object).
cmDepends::Write first collect all dependencies into a std::set before
passing it to cmDepends::WriteDependencies.

cmDependsC::WriteDependencies also first collects all explicit and
implicit dependencies into a std::set and only then writes
depend.{internal,make}. The implementation of cmDependsFortran simply
loops over all sources and proceeds as before, whereas the cmDependsJava
implementation is as trivial as before.

This is for preventing exponential growth of depend.{internal,make} in
the next commit which fixes dependency-vector erasure in
cmDepends::CheckDependencies.

Inspired-by: Michael Wild <themiwi@users.sourceforge.net>
This commit is contained in:
Alex Neundorf 2012-09-30 17:53:01 +02:00 committed by Brad King
parent ecc77d09b8
commit e74ff7c29f
8 changed files with 75 additions and 50 deletions

View File

@ -50,6 +50,7 @@ bool cmDepends::Write(std::ostream &makeDepends,
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();)
{
@ -62,9 +63,14 @@ bool cmDepends::Write(std::ostream &makeDepends,
obj = this->LocalGenerator->Convert(obj.c_str(),
cmLocalGenerator::HOME_OUTPUT,
cmLocalGenerator::MAKEFILE);
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(src.c_str(), obj.c_str(),
if(!this->WriteDependencies(it->second, it->first,
makeDepends, internalDepends))
{
return false;
@ -134,8 +140,9 @@ void cmDepends::Clear(const char *file)
}
//----------------------------------------------------------------------------
bool cmDepends::WriteDependencies(const char*, const char*,
std::ostream&, std::ostream&)
bool cmDepends::WriteDependencies(
const std::set<std::string>&, const std::string&,
std::ostream&, std::ostream&)
{
// This should be implemented by the subclass.
return false;

View File

@ -76,8 +76,10 @@ protected:
// Write dependencies for the target file to the given stream.
// Return true for success and false for failure.
virtual bool WriteDependencies(const char *src, const char* obj,
std::ostream& makeDepends, std::ostream& internalDepends);
virtual bool WriteDependencies(const std::set<std::string>& sources,
const std::string& obj,
std::ostream& makeDepends,
std::ostream& internalDepends);
// Check dependencies for the target file in the given stream.
// Return false if dependencies must be regenerated and true

View File

@ -98,16 +98,18 @@ cmDependsC::~cmDependsC()
}
//----------------------------------------------------------------------------
bool cmDependsC::WriteDependencies(const char *src, const char *obj,
std::ostream& makeDepends, std::ostream& internalDepends)
bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
const std::string& obj,
std::ostream& makeDepends,
std::ostream& internalDepends)
{
// Make sure this is a scanning instance.
if(!src || src[0] == '\0')
if(sources.empty() || sources.begin()->empty())
{
cmSystemTools::Error("Cannot scan dependencies without a source file.");
return false;
}
if(!obj || obj[0] == '\0')
if(obj.empty())
{
cmSystemTools::Error("Cannot scan dependencies without an object file.");
return false;
@ -134,12 +136,18 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
if (!haveDeps)
{
// Walk the dependency graph starting with the source file.
bool first = true;
UnscannedEntry root;
root.FileName = src;
this->Unscanned.push(root);
int srcFiles = (int)sources.size();
this->Encountered.clear();
this->Encountered.insert(src);
for(std::set<std::string>::const_iterator srcIt = sources.begin();
srcIt != sources.end(); ++srcIt)
{
UnscannedEntry root;
root.FileName = *srcIt;
this->Unscanned.push(root);
this->Encountered.insert(*srcIt);
}
std::set<cmStdString> scanned;
// Use reserve to allocate enough memory for tempPathStr
@ -155,7 +163,8 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
// If not a full path, find the file in the include path.
std::string fullName;
if(first || cmSystemTools::FileIsFullPath(current.FileName.c_str()))
if((srcFiles>0)
|| cmSystemTools::FileIsFullPath(current.FileName.c_str()))
{
if(cmSystemTools::FileExists(current.FileName.c_str(), true))
{
@ -260,7 +269,7 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
}
}
first = false;
srcFiles--;
}
}
@ -269,7 +278,7 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
// convert the dependencies to paths relative to the home output
// directory. We must do the same here.
internalDepends << obj << std::endl;
for(std::set<cmStdString>::iterator i=dependencies.begin();
for(std::set<cmStdString>::const_iterator i=dependencies.begin();
i != dependencies.end(); ++i)
{
makeDepends << obj << ": " <<

View File

@ -33,8 +33,8 @@ public:
protected:
// Implement writing/checking methods required by superclass.
virtual bool WriteDependencies(const char *src,
const char *file,
virtual bool WriteDependencies(const std::set<std::string>& sources,
const std::string& obj,
std::ostream& makeDepends,
std::ostream& internalDepends);

View File

@ -170,44 +170,50 @@ cmDependsFortran::~cmDependsFortran()
}
//----------------------------------------------------------------------------
bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
std::ostream&, std::ostream&)
bool cmDependsFortran::WriteDependencies(
const std::set<std::string>& sources, const std::string& obj,
std::ostream&, std::ostream&)
{
// Make sure this is a scanning instance.
if(!src || src[0] == '\0')
if(sources.empty() || sources.begin()->empty())
{
cmSystemTools::Error("Cannot scan dependencies without an source file.");
cmSystemTools::Error("Cannot scan dependencies without a source file.");
return false;
}
if(!obj || obj[0] == '\0')
if(obj.empty())
{
cmSystemTools::Error("Cannot scan dependencies without an object file.");
return false;
}
// Get the information object for this source.
cmDependsFortranSourceInfo& info =
this->Internal->CreateObjectInfo(obj, src);
// Make a copy of the macros defined via ADD_DEFINITIONS
std::set<std::string> ppDefines(this->PPDefinitions.begin(),
this->PPDefinitions.end());
// Create the parser object. The constructor takes ppMacro and info per
// reference, so we may look into the resulting objects later.
cmDependsFortranParser parser(this, ppDefines, info);
// Push on the starting file.
cmDependsFortranParser_FilePush(&parser, src);
// Parse the translation unit.
if(cmDependsFortran_yyparse(parser.Scanner) != 0)
bool okay = true;
for(std::set<std::string>::const_iterator it = sources.begin();
it != sources.end(); ++it)
{
// Failed to parse the file. Report failure to write dependencies.
return false;
}
const std::string& src = *it;
// Get the information object for this source.
cmDependsFortranSourceInfo& info =
this->Internal->CreateObjectInfo(obj.c_str(), src.c_str());
return true;
// Make a copy of the macros defined via ADD_DEFINITIONS
std::set<std::string> ppDefines(this->PPDefinitions.begin(),
this->PPDefinitions.end());
// Create the parser object. The constructor takes ppMacro and info per
// reference, so we may look into the resulting objects later.
cmDependsFortranParser parser(this, ppDefines, info);
// Push on the starting file.
cmDependsFortranParser_FilePush(&parser, src.c_str());
// Parse the translation unit.
if(cmDependsFortran_yyparse(parser.Scanner) != 0)
{
// Failed to parse the file. Report failure to write dependencies.
okay = false;
}
}
return okay;
}
//----------------------------------------------------------------------------

View File

@ -66,7 +66,7 @@ protected:
// Implement writing/checking methods required by superclass.
virtual bool WriteDependencies(
const char *src, const char *file,
const std::set<std::string>& sources, const std::string& file,
std::ostream& makeDepends, std::ostream& internalDepends);
// Actually write the depenencies to the streams.

View File

@ -25,11 +25,11 @@ cmDependsJava::~cmDependsJava()
}
//----------------------------------------------------------------------------
bool cmDependsJava::WriteDependencies(const char *src, const char *,
std::ostream&, std::ostream&)
bool cmDependsJava::WriteDependencies(const std::set<std::string>& sources,
const std::string&, std::ostream&, std::ostream&)
{
// Make sure this is a scanning instance.
if(!src || src[0] == '\0')
if(sources.empty() || sources.begin()->empty())
{
cmSystemTools::Error("Cannot scan dependencies without an source file.");
return false;

View File

@ -29,7 +29,8 @@ public:
protected:
// Implement writing/checking methods required by superclass.
virtual bool WriteDependencies(const char *src, const char *file,
virtual bool WriteDependencies(
const std::set<std::string>& sources, const std::string& file,
std::ostream& makeDepends, std::ostream& internalDepends);
virtual bool CheckDependencies(std::istream& internalDepends,
const char* internalDependsFileName,