|
|
@ -21,6 +21,8 @@ |
|
|
|
#include "cmMakefile.h"
|
|
|
|
#include "cmSourceFile.h"
|
|
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
cmLocalUnixMakefileGenerator2::cmLocalUnixMakefileGenerator2() |
|
|
|
{ |
|
|
@ -414,8 +416,8 @@ cmLocalUnixMakefileGenerator2 |
|
|
|
<< "# This may be replaced when dependencies are built.\n"; |
|
|
|
} |
|
|
|
|
|
|
|
// Open the rule file. This should be copy-if-different because the
|
|
|
|
// rules may depend on this file itself.
|
|
|
|
// Open the rule file for writing. This should be copy-if-different
|
|
|
|
// because the rules may depend on this file itself.
|
|
|
|
std::string ruleFileName = obj; |
|
|
|
ruleFileName += ".make"; |
|
|
|
cmGeneratedFileStream ruleFile(ruleFileName.c_str()); |
|
|
@ -437,6 +439,10 @@ cmLocalUnixMakefileGenerator2 |
|
|
|
<< this->ConvertToOutputForExisting(depFileName.c_str()).c_str() |
|
|
|
<< "\n\n"; |
|
|
|
|
|
|
|
// Identify the language of the source file.
|
|
|
|
const char* lang = |
|
|
|
m_GlobalGenerator->GetLanguageFromExtension(source.GetSourceExtension().c_str()); |
|
|
|
|
|
|
|
// Write the dependency generation rule.
|
|
|
|
std::string depTarget = obj; |
|
|
|
depTarget += ".depends"; |
|
|
@ -447,9 +453,22 @@ cmLocalUnixMakefileGenerator2 |
|
|
|
depComment += objName; |
|
|
|
depends.push_back(source.GetFullPath()); |
|
|
|
depends.push_back(ruleFileName); |
|
|
|
cmOStringStream depCmd; |
|
|
|
// TODO: Account for source file properties and directory-level
|
|
|
|
// definitions.
|
|
|
|
depCmd << "$(CMAKE_COMMAND) -E cmake_depends " << lang << " " |
|
|
|
<< this->ConvertToRelativeOutputPath(obj.c_str()) << " " |
|
|
|
<< this->ConvertToRelativeOutputPath(source.GetFullPath().c_str()); |
|
|
|
std::vector<std::string> includeDirs; |
|
|
|
this->GetIncludeDirectories(includeDirs); |
|
|
|
for(std::vector<std::string>::iterator i = includeDirs.begin(); |
|
|
|
i != includeDirs.end(); ++i) |
|
|
|
{ |
|
|
|
depCmd << " -I" << this->ConvertToRelativeOutputPath(i->c_str()); |
|
|
|
} |
|
|
|
commands.push_back(depCmd.str()); |
|
|
|
std::string touchCmd = "@touch "; |
|
|
|
touchCmd += this->ConvertToRelativeOutputPath(depTarget.c_str()); |
|
|
|
// TODO: Construct dependency generation rule and append command.
|
|
|
|
commands.push_back(touchCmd); |
|
|
|
this->OutputMakeRule(ruleFileStream, depComment.c_str(), depTarget.c_str(), |
|
|
|
depends, commands); |
|
|
@ -461,7 +480,7 @@ cmLocalUnixMakefileGenerator2 |
|
|
|
std::vector<std::string> commands; |
|
|
|
std::string buildComment = "object "; |
|
|
|
buildComment += objName; |
|
|
|
depends.push_back(depTarget); |
|
|
|
depends.push_back(source.GetFullPath()); |
|
|
|
depends.push_back(ruleFileName); |
|
|
|
std::string touchCmd = "@touch "; |
|
|
|
touchCmd += this->ConvertToRelativeOutputPath(obj.c_str()); |
|
|
@ -525,3 +544,154 @@ cmLocalUnixMakefileGenerator2 |
|
|
|
source.GetSourceExtension().c_str()); |
|
|
|
return objectName; |
|
|
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
bool |
|
|
|
cmLocalUnixMakefileGenerator2 |
|
|
|
::ScanDependencies(std::vector<std::string> const& args) |
|
|
|
{ |
|
|
|
// Format of arguments is:
|
|
|
|
// $(CMAKE_COMMAND), cmake_depends, <lang>, <obj>, <src>, [include-flags]
|
|
|
|
// The caller has ensured that all required arguments exist.
|
|
|
|
|
|
|
|
// The file to which to write dependencies.
|
|
|
|
const char* objFile = args[3].c_str(); |
|
|
|
|
|
|
|
// The source file at which to start the scan.
|
|
|
|
const char* srcFile = args[4].c_str(); |
|
|
|
|
|
|
|
// Convert the include flags to full paths.
|
|
|
|
std::vector<std::string> includes; |
|
|
|
for(unsigned int i=5; i < args.size(); ++i) |
|
|
|
{ |
|
|
|
if(args[i].substr(0, 2) == "-I") |
|
|
|
{ |
|
|
|
// Get the include path without the -I flag.
|
|
|
|
std::string inc = args[i].substr(2); |
|
|
|
includes.push_back(cmSystemTools::CollapseFullPath(inc.c_str())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Dispatch the scan for each language.
|
|
|
|
std::string const& lang = args[2]; |
|
|
|
if(lang == "C" || lang == "CXX") |
|
|
|
{ |
|
|
|
return cmLocalUnixMakefileGenerator2::ScanDependenciesC(objFile, srcFile, |
|
|
|
includes); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void |
|
|
|
cmLocalUnixMakefileGenerator2ScanDependenciesC( |
|
|
|
std::ifstream& fin, |
|
|
|
std::set<cmStdString>& encountered, |
|
|
|
std::queue<cmStdString>& unscanned) |
|
|
|
{ |
|
|
|
// 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.
|
|
|
|
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 has not been scanned already.
|
|
|
|
if(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 depMakeFile = objFile; |
|
|
|
depMakeFile += ".depends.make"; |
|
|
|
std::ofstream fout(depMakeFile.c_str()); |
|
|
|
fout << "# Dependencies for " << objFile << endl; |
|
|
|
for(std::set<cmStdString>::iterator i=dependencies.begin(); |
|
|
|
i != dependencies.end(); ++i) |
|
|
|
{ |
|
|
|
fout << objFile << " : " << i->c_str() << endl; |
|
|
|
} |
|
|
|
fout << endl; |
|
|
|
fout << "# Dependencies for " << objFile << ".depends" << endl; |
|
|
|
for(std::set<cmStdString>::iterator i=dependencies.begin(); |
|
|
|
i != dependencies.end(); ++i) |
|
|
|
{ |
|
|
|
fout << objFile << ".depends : " << i->c_str() << endl; |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |