ENH: Hacked together a new implementation of the dependency generator code. This should support finding dependencies for individual files without doing them for the entire makefile. Use cmMakeDepend::FindDependencies() to do this.

This commit is contained in:
Brad King 2001-07-17 15:09:16 -04:00
parent c5381e8588
commit 82c1916a6d
4 changed files with 166 additions and 209 deletions

View File

@ -42,6 +42,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "cmStandardIncludes.h" #include "cmStandardIncludes.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
void cmDependInformation::AddDependencies(cmDependInformation* info)
{
if(this != info)
{
m_DependencySet.insert(info);
for (cmDependInformation::DependencySet::const_iterator
d = info->m_DependencySet.begin();
d != info->m_DependencySet.end(); ++d)
{
m_DependencySet.insert(*d);
}
}
}
cmMakeDepend::cmMakeDepend() cmMakeDepend::cmMakeDepend()
{ {
m_Verbose = false; m_Verbose = false;
@ -52,12 +67,11 @@ cmMakeDepend::cmMakeDepend()
cmMakeDepend::~cmMakeDepend() cmMakeDepend::~cmMakeDepend()
{ {
for(DependArray::iterator i = m_DependInformation.begin(); for(DependInformationMap::iterator i = m_DependInformationMap.begin();
i != m_DependInformation.end(); ++i) i != m_DependInformationMap.end(); ++i)
{ {
delete *i; delete i->second;
} }
m_DependInformation.clear();
} }
@ -76,114 +90,57 @@ void cmMakeDepend::SetMakefile(const cmMakefile* makefile)
m_Makefile->m_ComplainFileRegularExpression.c_str()); m_Makefile->m_ComplainFileRegularExpression.c_str());
// Now extract any include paths from the makefile flags // Now extract any include paths from the makefile flags
const std::vector<std::string>& includes = m_Makefile->GetIncludeDirectories(); const std::vector<std::string>& includes =
std::vector<std::string>::const_iterator j; m_Makefile->GetIncludeDirectories();
for(j = includes.begin(); j != includes.end(); ++j) for(std::vector<std::string>::const_iterator j = includes.begin();
j != includes.end(); ++j)
{ {
this->AddSearchPath(j->c_str()); this->AddSearchPath(j->c_str());
} }
// Now create cmDependInformation objects for files in the directory
const cmTargets &tgts = m_Makefile->GetTargets();
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{
const std::vector<cmSourceFile> &classes = l->second.GetSourceFiles();
for(std::vector<cmSourceFile>::const_iterator i = classes.begin();
i != classes.end(); ++i)
{
if(!i->GetIsAHeaderFileOnly())
{
cmDependInformation* info = new cmDependInformation;
info->m_FullPath = this->FullPath(i->GetFullPath().c_str());
this->AddFileToSearchPath(info->m_FullPath.c_str());
info->m_IncludeName = i->GetFullPath();
info->m_ClassFileIndex = &*i;
m_DependInformation.push_back(info);
}
}
}
} }
// Compute the depends. const cmDependInformation* cmMakeDepend::FindDependencies(const char* file)
void cmMakeDepend::GenerateDependInformation()
{ {
// The size of the m_DependInformation will change as cmDependInformation* info = this->GetDependInformation(file);
// Depend is called so do not use an iterater but rather this->GenerateDependInformation(info);
// depend on the size of the array. return info;
unsigned int j = 0;
while(j != m_DependInformation.size())
{
cmDependInformation* info = m_DependInformation[j];
// compute the depend information for the info object
// this may add more objects to the m_DependInformation
// array
this->Depend(info);
++j;
}
} }
const cmDependInformation * void cmMakeDepend::GenerateDependInformation(cmDependInformation* info)
cmMakeDepend::GetDependInformationForSourceFile(const cmSourceFile &sf) const
{ {
// Now update the depend information for each cmSourceFile // If dependencies are already done, stop now.
// in the cmMakefile m_Makefile if(info->m_DependDone)
for(DependArray::const_iterator i = m_DependInformation.begin();
i != m_DependInformation.end(); ++i)
{ {
cmDependInformation* info = *i; return;
// find the class
if(info->m_ClassFileIndex == &sf)
{
return info;
}
} }
return 0; else
}
const cmDependInformation *
cmMakeDepend::GetDependInformationForSourceFile(const char *fname) const
{
// Now update the depend information for each cmSourceFile
// in the cmMakefile m_Makefile
for(DependArray::const_iterator i = m_DependInformation.begin();
i != m_DependInformation.end(); ++i)
{ {
cmDependInformation* info = *i; // Make sure we don't visit the same file more than once.
// find the class info->m_DependDone = true;
if(info->m_FullPath == fname)
{
return info;
}
} }
return 0;
}
void cmMakeDepend::Depend(cmDependInformation* info)
{
const char* path = info->m_FullPath.c_str(); const char* path = info->m_FullPath.c_str();
if(!path) if(!path)
{ {
cmSystemTools::Error("no full path for object", 0); cmSystemTools::Error("Attempt to find dependencies for file without path!");
return; return;
} }
// If the file exists, use it to find dependency information. // If the file exists, use it to find dependency information.
if(cmSystemTools::FileExists(path)) if(cmSystemTools::FileExists(path))
{ {
// Use the real file to find its dependencies. // Use the real file to find its dependencies.
this->DependWalk(info, path); this->DependWalk(info);
info->m_DependDone = true;
return; return;
} }
// The file doesn't exist. See if the cmSourceFile for it has any files // The file doesn't exist. See if the cmSourceFile for it has any files
// specified as dependency hints. // specified as dependency hints.
if(info->m_ClassFileIndex != 0) if(info->m_cmSourceFile != 0)
{ {
// Get the cmSourceFile corresponding to this. // Get the cmSourceFile corresponding to this.
const cmSourceFile& cFile = *(info->m_ClassFileIndex); const cmSourceFile& cFile = *(info->m_cmSourceFile);
// See if there are any hints for finding dependencies for the missing // See if there are any hints for finding dependencies for the missing
// file. // file.
if(!cFile.GetDepends().empty()) if(!cFile.GetDepends().empty())
@ -212,24 +169,24 @@ void cmMakeDepend::Depend(cmDependInformation* info)
// Destroy the name of the file so that it won't be output as a // Destroy the name of the file so that it won't be output as a
// dependency. // dependency.
info->m_FullPath = ""; info->m_FullPath = "";
} }
} }
// This function actually reads the file specified and scans it for // This function actually reads the file specified and scans it for
// #include directives // #include directives
void cmMakeDepend::DependWalk(cmDependInformation* info, const char* file) void cmMakeDepend::DependWalk(cmDependInformation* info)
{ {
cmRegularExpression includeLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]"); cmRegularExpression includeLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
std::ifstream fin(file); std::ifstream fin(info->m_FullPath.c_str());
if(!fin) if(!fin)
{ {
cmSystemTools::Error("error can not open ", file); cmSystemTools::Error("Cannot open ", info->m_FullPath.c_str());
return; return;
} }
// TODO: Write real read loop (see cmSystemTools::CopyFile).
char line[255]; char line[255];
for(fin.getline(line, 255); !fin.eof()&&!fin.fail(); fin.getline(line, 255)) for(fin.getline(line, 255); fin; fin.getline(line, 255))
{ {
if(includeLine.find(line)) if(includeLine.find(line))
{ {
@ -243,7 +200,7 @@ void cmMakeDepend::DependWalk(cmDependInformation* info, const char* file)
std::string message = "Skipping "; std::string message = "Skipping ";
message += includeFile; message += includeFile;
message += " for file "; message += " for file ";
message += file; message += info->m_FullPath.c_str();
cmSystemTools::Error(message.c_str(), 0); cmSystemTools::Error(message.c_str(), 0);
} }
continue; continue;
@ -258,68 +215,60 @@ void cmMakeDepend::DependWalk(cmDependInformation* info, const char* file)
void cmMakeDepend::AddDependency(cmDependInformation* info, const char* file) void cmMakeDepend::AddDependency(cmDependInformation* info, const char* file)
{ {
// find the index of the include file in the cmDependInformation* dependInfo = this->GetDependInformation(file);
// m_DependInformation array, if it is not this->GenerateDependInformation(dependInfo);
// there then FindInformation will create it info->AddDependencies(dependInfo);
int index = this->FindInformation(file);
// add the index to the depends of the current
// depend info object
info->m_IndexSet.insert(index);
// Get the depend information object for the include file
cmDependInformation* dependInfo = m_DependInformation[index];
// if the depends are not known for an include file, then compute them
// recursively
if(!dependInfo->m_DependDone)
{
// stop the recursion here
dependInfo->m_DependDone = true;
this->Depend(dependInfo);
}
// add the depends of the included file to the includer
info->MergeInfo(dependInfo);
} }
cmDependInformation* cmMakeDepend::GetDependInformation(const char* file)
// Find the cmDependInformation array index of the
// given include file. Create a new cmDependInformation
// object if one is not found
int cmMakeDepend::FindInformation(const char* fname)
{ {
unsigned int i = 0; // Get the full path for the file so that lookup is unambiguous.
std::string fullPath = this->FullPath(file);
while(i < m_DependInformation.size()) // Try to find the file's instance of cmDependInformation.
DependInformationMap::const_iterator result =
m_DependInformationMap.find(fullPath);
if(result != m_DependInformationMap.end())
{ {
if(m_DependInformation[i]->m_IncludeName == fname) // Found an instance, return it.
{ return result->second;
return i; }
} else
++i; {
// Didn't find an instance. Create a new one and save it.
cmDependInformation* info = new cmDependInformation;
info->m_FullPath = fullPath;
info->m_IncludeName = file;
m_DependInformationMap[fullPath] = info;
return info;
} }
cmDependInformation* newinfo = new cmDependInformation;
newinfo->m_FullPath = this->FullPath(fname);
// Add the directory where this file was found to the search path
// may have been foo/bar.h, but bar may include files from the foo
// directory without the foo prefix
this->AddFileToSearchPath(newinfo->m_FullPath.c_str());
newinfo->m_IncludeName = fname;
m_DependInformation.push_back(newinfo);
return m_DependInformation.size()-1;
} }
// add the depend information from info to the m_IndexSet varible of this class. void cmMakeDepend::GenerateMakefileDependencies()
void cmDependInformation::MergeInfo(cmDependInformation* info)
{ {
if(this != info) // Now create cmDependInformation objects for files in the directory
const cmTargets &tgts = m_Makefile->GetTargets();
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); l++)
{ {
for (std::set<int>::const_iterator p = info->m_IndexSet.begin(); const std::vector<cmSourceFile> &classes = l->second.GetSourceFiles();
p != info->m_IndexSet.end(); ++p) for(std::vector<cmSourceFile>::const_iterator i = classes.begin();
i != classes.end(); ++i)
{ {
m_IndexSet.insert(*p); if(!i->GetIsAHeaderFileOnly())
{
cmDependInformation* info =
this->GetDependInformation(i->GetFullPath().c_str());
this->AddFileToSearchPath(info->m_FullPath.c_str());
info->m_cmSourceFile = &*i;
this->GenerateDependInformation(info);
}
} }
} }
} }
// find the full path to fname by searching the m_IncludeDirectories array // find the full path to fname by searching the m_IncludeDirectories array
std::string cmMakeDepend::FullPath(const char* fname) std::string cmMakeDepend::FullPath(const char* fname)
{ {
@ -368,4 +317,17 @@ void cmMakeDepend::AddFileToSearchPath(const char* file)
} }
} }
const cmDependInformation*
cmMakeDepend::GetDependInformationForSourceFile(const cmSourceFile &sf) const
{
for(DependInformationMap::const_iterator i = m_DependInformationMap.begin();
i != m_DependInformationMap.end(); ++i)
{
const cmDependInformation* info = i->second;
if(info->m_cmSourceFile == &sf)
{
return info;
}
}
return 0;
}

View File

@ -58,46 +58,40 @@ public:
* Construct with dependency generation marked not done; instance * Construct with dependency generation marked not done; instance
* not placed in cmMakefile's list. * not placed in cmMakefile's list.
*/ */
cmDependInformation() cmDependInformation(): m_DependDone(false), m_cmSourceFile(0) {}
{
m_DependDone = false;
m_ClassFileIndex = 0;
}
/** /**
* A set of indices into the m_DependInformation array of cmMakeDepend. * The set of files on which this one depends.
* The index represents the files that this file depends on.
* This must be a "set" to keep indices unique.
*/ */
typedef std::set<int> IndexSet; typedef std::set<cmDependInformation*> DependencySet;
IndexSet m_IndexSet; DependencySet m_DependencySet;
/**
* Full path to this file.
*/
std::string m_FullPath;
/**
* Name that the include directive uses.
*/
std::string m_IncludeName;
/**
* The index into the cmMakefile::m_Classes list.
* The index value of 0 indicates that it is not in the list.
*/
const cmSourceFile *m_ClassFileIndex;
/** /**
* This flag indicates whether dependency checking has been * This flag indicates whether dependency checking has been
* performed for this file. * performed for this file.
*/ */
bool m_DependDone; bool m_DependDone;
/**
* If this object corresponds to a cmSourceFile instance, this points
* to it.
*/
const cmSourceFile *m_cmSourceFile;
/**
* Full path to this file.
*/
std::string m_FullPath;
/**
* Name used to #include this file.
*/
std::string m_IncludeName;
/** /**
* This method adds the dependencies of another file to this one. * This method adds the dependencies of another file to this one.
*/ */
void MergeInfo(cmDependInformation*); void AddDependencies(cmDependInformation*);
}; };
@ -121,59 +115,60 @@ public:
*/ */
virtual void SetMakefile(const cmMakefile* makefile); virtual void SetMakefile(const cmMakefile* makefile);
/**
* Generate the depend information
*/
virtual void GenerateDependInformation();
/** /**
* Get the depend info struct for a source file * Get the depend info struct for a source file
*/ */
const cmDependInformation *GetDependInformationForSourceFile(const cmSourceFile &sf) const; const cmDependInformation *GetDependInformationForSourceFile(const cmSourceFile &sf) const;
const cmDependInformation *GetDependInformationForSourceFile(const char *) const;
/**
* Get the depend info struct
*/
typedef std::vector<cmDependInformation*> DependArray;
const DependArray &GetDependInformation() const {
return m_DependInformation; }
/** /**
* Add a directory to the search path for include files. * Add a directory to the search path for include files.
*/ */
virtual void AddSearchPath(const char*); virtual void AddSearchPath(const char*);
/**
* Generate dependencies for all the sources of all the targets
* in the makefile.
*/
void GenerateMakefileDependencies();
/**
* Generate dependencies for the file given. Returns a pointer to
* the cmDependInformation object for the file.
*/
const cmDependInformation* FindDependencies(const char* file);
protected: protected:
/** /**
* Add a source file to the search path. * Add a source file to the search path.
*/ */
void AddFileToSearchPath(const char* filepath); void AddFileToSearchPath(const char* filepath);
/**
* Find the index into the m_DependInformation array
* that matches the given m_IncludeName.
*/
virtual int FindInformation(const char* includeName);
/** /**
* Compute the depend information for this class. * Compute the depend information for this class.
*/ */
virtual void Depend(cmDependInformation* info); virtual void DependWalk(cmDependInformation* info);
/**
* Compute the depend information for this class.
*/
virtual void DependWalk(cmDependInformation* info, const char* file);
/** /**
* Add a dependency. Possibly walk it for more dependencies. * Add a dependency. Possibly walk it for more dependencies.
*/ */
virtual void AddDependency(cmDependInformation* info, const char* file); virtual void AddDependency(cmDependInformation* info, const char* file);
/**
* Fill in the given object with dependency information. If the
* information is already complete, nothing is done.
*/
void GenerateDependInformation(cmDependInformation* info);
/**
* Get an instance of cmDependInformation corresponding to the given file
* name.
*/
cmDependInformation* GetDependInformation(const char* file);
/** /**
* Find the full path name for the given file name. * Find the full path name for the given file name.
* This uses the include directories. * This uses the include directories.
* TODO: Cache path conversions to reduce FileExists calls.
*/ */
std::string FullPath(const char*); std::string FullPath(const char*);
@ -181,8 +176,9 @@ protected:
bool m_Verbose; bool m_Verbose;
cmRegularExpression m_IncludeFileRegularExpression; cmRegularExpression m_IncludeFileRegularExpression;
cmRegularExpression m_ComplainFileRegularExpression; cmRegularExpression m_ComplainFileRegularExpression;
DependArray m_DependInformation;
std::vector<std::string> m_IncludeDirectories; std::vector<std::string> m_IncludeDirectories;
typedef std::map<std::string, cmDependInformation*> DependInformationMap;
DependInformationMap m_DependInformationMap;
}; };
#endif #endif

View File

@ -46,15 +46,15 @@ class cmLBDepend : public cmMakeDepend
/** /**
* Compute the depend information for this class. * Compute the depend information for this class.
*/ */
void DependWalk(cmDependInformation* info, const char* file); virtual void DependWalk(cmDependInformation* info);
}; };
void cmLBDepend::DependWalk(cmDependInformation* info, const char* file) void cmLBDepend::DependWalk(cmDependInformation* info)
{ {
std::ifstream fin(file); std::ifstream fin(info->m_FullPath.c_str());
if(!fin) if(!fin)
{ {
cmSystemTools::Error("error can not open ", file); cmSystemTools::Error("error can not open ", info->m_FullPath.c_str());
return; return;
} }
@ -98,7 +98,7 @@ void cmLBDepend::DependWalk(cmDependInformation* info, const char* file)
std::string message = "Skipping "; std::string message = "Skipping ";
message += includeFile; message += includeFile;
message += " for file "; message += " for file ";
message += file; message += info->m_FullPath.c_str();
cmSystemTools::Error(message.c_str(), 0); cmSystemTools::Error(message.c_str(), 0);
} }
continue; continue;
@ -208,28 +208,27 @@ void cmOutputRequiredFilesCommand::FinalPass()
// compute the list of files // compute the list of files
cmLBDepend md; cmLBDepend md;
md.SetMakefile(m_Makefile); md.SetMakefile(m_Makefile);
md.GenerateDependInformation();
// always expand the first argument // always expand the first argument
m_Makefile->ExpandVariablesInString(m_File); m_Makefile->ExpandVariablesInString(m_File);
m_Makefile->ExpandVariablesInString(m_OutputFile); m_Makefile->ExpandVariablesInString(m_OutputFile);
// find the depends for a file // find the depends for a file
const cmDependInformation *info = md.GetDependInformationForSourceFile(m_File.c_str()); const cmDependInformation *info = md.FindDependencies(m_File.c_str());
if (info) if (info)
{ {
// write them out // write them out
FILE *fout = fopen(m_OutputFile.c_str(),"w"); FILE *fout = fopen(m_OutputFile.c_str(),"w");
for( cmDependInformation::IndexSet::const_iterator indx = for(cmDependInformation::DependencySet::const_iterator d =
info->m_IndexSet.begin(); info->m_DependencySet.begin();
indx != info->m_IndexSet.end(); ++indx) d != info->m_DependencySet.end(); ++d)
{ {
std::string tmp = md.GetDependInformation()[*indx]->m_FullPath; std::string tmp = (*d)->m_FullPath;
std::string::size_type pos = tmp.rfind('.'); std::string::size_type pos = tmp.rfind('.');
if(pos != std::string::npos && tmp.substr(pos) == ".cxx") if(pos != std::string::npos && tmp.substr(pos) == ".cxx")
{ {
tmp = tmp.substr(0, pos); tmp = tmp.substr(0, pos);
fprintf(fout,"%s\n",md.GetDependInformation()[*indx]->m_FullPath.c_str()); fprintf(fout,"%s\n",(*d)->m_FullPath.c_str());
} }
} }
fclose(fout); fclose(fout);

View File

@ -95,7 +95,7 @@ void cmUnixMakefileGenerator::GenerateMakefile()
// Generate depends // Generate depends
cmMakeDepend md; cmMakeDepend md;
md.SetMakefile(m_Makefile); md.SetMakefile(m_Makefile);
md.GenerateDependInformation(); md.GenerateMakefileDependencies();
this->ProcessDepends(md); this->ProcessDepends(md);
// output the makefile fragment // output the makefile fragment
this->OutputMakefile("Makefile"); this->OutputMakefile("Makefile");
@ -124,15 +124,15 @@ void cmUnixMakefileGenerator::ProcessDepends(const cmMakeDepend &md)
// Now add the real dependencies for the file. // Now add the real dependencies for the file.
if (info) if (info)
{ {
for( cmDependInformation::IndexSet::const_iterator indx = for(cmDependInformation::DependencySet::const_iterator d =
info->m_IndexSet.begin(); info->m_DependencySet.begin();
indx != info->m_IndexSet.end(); ++indx) d != info->m_DependencySet.end(); ++d)
{ {
// Make sure the full path is given. If not, the dependency was // Make sure the full path is given. If not, the dependency was
// not found. // not found.
if(md.GetDependInformation()[*indx]->m_FullPath != "") if((*d)->m_FullPath != "")
{ {
i->GetDepends().push_back(md.GetDependInformation()[*indx]->m_FullPath); i->GetDepends().push_back((*d)->m_FullPath);
} }
} }
} }