diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 96532747a..a17fb269a 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -21,18 +21,21 @@ #include // isspace //---------------------------------------------------------------------------- -cmDependsC::cmDependsC() +cmDependsC::cmDependsC(): + m_IncludePath(0), m_GeneratedFiles(0) { } //---------------------------------------------------------------------------- // yummy look at all those constructor arguments cmDependsC::cmDependsC(std::vector const& includes, - const char* scanRegex, const char* complainRegex): + const char* scanRegex, const char* complainRegex, + std::set const& generatedFiles): m_IncludePath(&includes), m_IncludeRegexLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)([\">])"), m_IncludeRegexScan(scanRegex), - m_IncludeRegexComplain(complainRegex) + m_IncludeRegexComplain(complainRegex), + m_GeneratedFiles(&generatedFiles) { } @@ -81,13 +84,15 @@ bool cmDependsC::WriteDependencies(const char *src, std::string fullName; if(first || cmSystemTools::FileIsFullPath(current.FileName.c_str())) { - if(cmSystemTools::FileExists(current.FileName.c_str())) + if(this->FileExistsOrIsGenerated(current.FileName, scanned, + dependencies)) { fullName = current.FileName; } } else if(!current.QuotedLocation.empty() && - cmSystemTools::FileExists(current.QuotedLocation.c_str())) + this->FileExistsOrIsGenerated(current.QuotedLocation, scanned, + dependencies)) { // The include statement producing this entry was a double-quote // include and the included file is present in the directory of @@ -113,7 +118,7 @@ bool cmDependsC::WriteDependencies(const char *src, temp += current.FileName; // Look for the file in this location. - if(cmSystemTools::FileExists(temp.c_str())) + if(this->FileExistsOrIsGenerated(temp, scanned, dependencies)) { fullName = temp; break; @@ -346,3 +351,28 @@ const char* cmDependsC::ParseFileName(const char* in, std::string& name) // Return the ending position. return c; } + +//---------------------------------------------------------------------------- +bool cmDependsC::FileExistsOrIsGenerated(const std::string& fname, + std::set& scanned, + std::set& dependencies) +{ + // Check first for a generated file. + if(m_GeneratedFiles && + m_GeneratedFiles->find(fname) != m_GeneratedFiles->end()) + { + // If the file does not really exist yet pretend it has already + // been scanned. When it exists later then dependencies will be + // rescanned. + if(!cmSystemTools::FileExists(fname.c_str())) + { + scanned.insert(fname); + dependencies.insert(fname); + } + return true; + } + else + { + return cmSystemTools::FileExists(fname.c_str()); + } +} diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h index fb2b29d81..26cfc1b82 100644 --- a/Source/cmDependsC.h +++ b/Source/cmDependsC.h @@ -31,7 +31,8 @@ public: relative path from the build directory to the target file. */ cmDependsC(); cmDependsC(std::vector const& includes, - const char* scanRegex, const char* complainRegex); + const char* scanRegex, const char* complainRegex, + std::set const& generatedFiles); /** Virtual destructor to cleanup subclasses properly. */ virtual ~cmDependsC(); @@ -50,6 +51,11 @@ protected: std::string& dependee); const char* ParseFileName(const char* in, std::string& name); + // Method to test for the existence of a file. + bool FileExistsOrIsGenerated(const std::string& fname, + std::set& scanned, + std::set& dependencies); + // The include file search path. std::vector const* m_IncludePath; @@ -60,7 +66,10 @@ protected: // recursively and which to complain about not finding. cmsys::RegularExpression m_IncludeRegexScan; cmsys::RegularExpression m_IncludeRegexComplain; - + + // Set of generated files available. + std::set const* m_GeneratedFiles; + // Data structures for dependency graph walk. struct UnscannedEntry { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 2fe763d67..f68854936 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -203,6 +203,8 @@ void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile() for(std::vector::iterator i = includeDirs.begin(); i != includeDirs.end(); ++i) { + // Note: This path conversion must match that used for + // CMAKE_GENERATED_FILES so that the file names match. infoFileStream << " \"" << this->Convert(i->c_str(),HOME_OUTPUT).c_str() << "\"\n"; } @@ -231,6 +233,30 @@ void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile() << "SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})\n"; infoFileStream << "SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN})\n"; + + // Store the set of available generated files. + infoFileStream + << "\n" + << "# The set of files generated by rules in this directory:\n"; + infoFileStream + << "SET(CMAKE_GENERATED_FILES\n"; + for(std::vector::const_iterator + i = m_Makefile->GetSourceFiles().begin(); + i != m_Makefile->GetSourceFiles().end(); ++i) + { + cmSourceFile* src = *i; + if(src->GetPropertyAsBool("GENERATED")) + { + // Note: This path conversion must match that used for + // CMAKE_C_INCLUDE_PATH so that the file names match. + infoFileStream + << " \"" + << this->Convert(src->GetFullPath().c_str(), HOME_OUTPUT) + << "\"\n"; + } + } + infoFileStream + << ")\n"; } //---------------------------------------------------------------------------- @@ -546,6 +572,7 @@ cmLocalUnixMakefileGenerator3 std::string objectFile = this->Convert(obj.c_str(),START_OUTPUT,SHELL); // Construct the build message. + std::vector no_commands; std::vector commands; std::string buildEcho = "Building "; buildEcho += lang; @@ -575,6 +602,22 @@ cmLocalUnixMakefileGenerator3 flags.c_str()); } + // Add dependencies known at CMake time. + std::string relativeObjDeps = relativeObj; + relativeObjDeps += "/depend"; + this->WriteMakeRule(ruleFileStream, 0, + relativeObjDeps.c_str(), depends, no_commands); + depends.clear(); + depends.push_back(relativeObjDeps); + + // Make the target dependency scanning rule include cmake-time-known + // dependencies. The others are handled by the check-build-system + // path. + std::string depMark = this->GetRelativeTargetDirectory(target); + depMark += "/depend.make.mark"; + this->WriteMakeRule(ruleFileStream, 0, + depMark.c_str(), depends, no_commands); + // Write the rule. this->WriteMakeRule(ruleFileStream, 0, relativeObj.c_str(), depends, commands); @@ -583,7 +626,6 @@ cmLocalUnixMakefileGenerator3 // corresponding targets. std::string objectRequires = relativeObj; objectRequires += ".requires"; - std::vector no_commands; std::vector p_depends; // always provide an empty requires target this->WriteMakeRule(ruleFileStream, 0, @@ -2682,7 +2724,21 @@ cmLocalUnixMakefileGenerator3 return false; } this->WriteDisclaimer(ruleFileStream); - + + // Get the set of generated files. + std::vector generatedFilesVec; + if(haveDirectoryInfo) + { + if(const char* generated = mf->GetDefinition("CMAKE_GENERATED_FILES")) + { + cmSystemTools::ExpandListArgument(generated, generatedFilesVec); + } + } + + // Sort for efficient lookup. + std::set generatedFiles(generatedFilesVec.begin(), + generatedFilesVec.end()); + // for each language we need to scan, scan it const char *langStr = mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"); std::vector langs; @@ -2726,15 +2782,16 @@ cmLocalUnixMakefileGenerator3 includeRegexComplain = complainRegex; } } - + // Create the scanner for this language cmDepends *scanner = 0; if(lang == "C" || lang == "CXX" || lang == "RC") { // TODO: Handle RC (resource files) dependencies correctly. scanner = new cmDependsC(includes, - includeRegexScan.c_str(), - includeRegexComplain.c_str()); + includeRegexScan.c_str(), + includeRegexComplain.c_str(), + generatedFiles); } #ifdef CMAKE_BUILD_WITH_CMAKE else if(lang == "Fortran")