diff options
-rw-r--r-- | Source/cmLocalUnixMakefileGenerator2.cxx | 258 | ||||
-rw-r--r-- | Source/cmLocalUnixMakefileGenerator2.h | 11 | ||||
-rw-r--r-- | Source/cmake.cxx | 37 | ||||
-rw-r--r-- | Source/cmake.h | 9 |
4 files changed, 261 insertions, 54 deletions
diff --git a/Source/cmLocalUnixMakefileGenerator2.cxx b/Source/cmLocalUnixMakefileGenerator2.cxx index 091d792..d8830e6 100644 --- a/Source/cmLocalUnixMakefileGenerator2.cxx +++ b/Source/cmLocalUnixMakefileGenerator2.cxx @@ -149,6 +149,19 @@ void cmLocalUnixMakefileGenerator2::GenerateCMakefile() << "# The corresponding makefile is:\n" << "SET(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" << makefileName.c_str() << "\"\n" + << " )\n\n"; + + // Set the set of files to check for dependency integrity. + cmakefileStream + << "# The set of files whose dependency integrity should be checked:\n" + << "SET(CMAKE_DEPENDS_CHECK\n"; + for(std::set<cmStdString>::const_iterator i = m_CheckDependFiles.begin(); + i != m_CheckDependFiles.end(); ++i) + { + cmakefileStream + << " \"" << i->c_str() << "\"\n"; + } + cmakefileStream << " )\n"; } @@ -180,20 +193,11 @@ cmLocalUnixMakefileGenerator2 } } - // If there is no dependencies file, create an empty one. - std::string depFileName = dir; - depFileName += "/"; - depFileName += target.GetName(); - depFileName += ".depends.make"; - std::string depFileNameFull = this->ConvertToFullPath(depFileName); - if(!cmSystemTools::FileExists(depFileNameFull.c_str())) - { - std::ofstream depFileStream(depFileNameFull.c_str()); - this->WriteDisclaimer(depFileStream); - depFileStream - << "# Empty dependencies file for target " << target.GetName() << ".\n" - << "# This may be replaced when dependencies are built.\n"; - } + // Generate the build-time dependencies file for this target. + std::string depBase = dir; + depBase += "/"; + depBase += target.GetName(); + std::string depMakeFile = this->GenerateDependsMakeFile(depBase.c_str()); // Open the rule file. This should be copy-if-different because the // rules may depend on this file itself. @@ -218,7 +222,7 @@ cmLocalUnixMakefileGenerator2 ruleFileStream << "# Include any dependencies generated for this rule.\n" << m_IncludeDirective << " " - << this->ConvertToOutputForExisting(depFileName.c_str()).c_str() + << this->ConvertToOutputForExisting(depMakeFile.c_str()).c_str() << "\n\n"; // Include the rule file for each object. @@ -243,7 +247,7 @@ cmLocalUnixMakefileGenerator2 // Write the dependency generation rule. { std::vector<std::string> depends; - std::vector<std::string> commands; + std::vector<std::string> no_commands; std::string depEcho = "Building dependencies for "; depEcho += target.GetName(); depEcho += "..."; @@ -258,7 +262,7 @@ cmLocalUnixMakefileGenerator2 } depends.push_back(ruleFileName); this->WriteMakeRule(ruleFileStream, 0, depEcho.c_str(), - depTarget.c_str(), depends, commands); + depTarget.c_str(), depends, no_commands); } // Write the build rule. @@ -303,23 +307,16 @@ cmLocalUnixMakefileGenerator2 // Get the full path name of the object file. std::string obj = this->GetObjectFileName(target, source); + // The object file should be checked for dependency integrity. + m_CheckDependFiles.insert(obj); + // Create the directory containing the object file. This may be a // subdirectory under the target's directory. std::string dir = cmSystemTools::GetFilenamePath(obj.c_str()); cmSystemTools::MakeDirectory(this->ConvertToFullPath(dir).c_str()); - // If there is no dependencies file, create an empty one. - std::string depFileName = obj; - depFileName += ".depends.make"; - std::string depFileNameFull = this->ConvertToFullPath(depFileName); - if(!cmSystemTools::FileExists(depFileNameFull.c_str())) - { - std::ofstream depFileStream(depFileNameFull.c_str()); - this->WriteDisclaimer(depFileStream); - depFileStream - << "# Empty dependencies file for object file " << obj.c_str() << ".\n" - << "# This may be replaced when dependencies are built.\n"; - } + // Generate the build-time dependencies file for this object file. + std::string depMakeFile = this->GenerateDependsMakeFile(obj.c_str()); // Open the rule file for writing. This should be copy-if-different // because the rules may depend on this file itself. @@ -342,7 +339,7 @@ cmLocalUnixMakefileGenerator2 ruleFileStream << "# Include any dependencies generated for this rule.\n" << m_IncludeDirective << " " - << this->ConvertToOutputForExisting(depFileName.c_str()).c_str() + << this->ConvertToOutputForExisting(depMakeFile.c_str()).c_str() << "\n\n"; // Create the list of dependencies known at cmake time. These are @@ -470,6 +467,33 @@ cmLocalUnixMakefileGenerator2 } //---------------------------------------------------------------------------- +std::string +cmLocalUnixMakefileGenerator2 +::GenerateDependsMakeFile(const char* file) +{ + // Check if the build-time dependencies file exists. + std::string depMarkFile = file; + depMarkFile += ".depends"; + std::string depMakeFile = depMarkFile; + depMakeFile += ".make"; + std::string depMakeFileFull = this->ConvertToFullPath(depMakeFile); + if(cmSystemTools::FileExists(depMakeFileFull.c_str())) + { + // The build-time dependencies file already exists. Check it. + this->CheckDependencies(m_Makefile->GetStartOutputDirectory(), file); + } + else + { + // The build-time dependencies file does not exist. Create an + // empty one. + std::string depMarkFileFull = this->ConvertToFullPath(depMarkFile); + this->WriteEmptyDependMakeFile(file, depMarkFileFull.c_str(), + depMakeFileFull.c_str()); + } + return depMakeFile; +} + +//---------------------------------------------------------------------------- void cmLocalUnixMakefileGenerator2 ::WriteMakeRule(std::ostream& os, @@ -496,7 +520,7 @@ cmLocalUnixMakefileGenerator2 m_Makefile->ExpandVariablesInString(replace); std::string::size_type lpos = 0; std::string::size_type rpos; - while((rpos = replace.find(lpos, '\n')) != std::string::npos) + while((rpos = replace.find('\n', lpos)) != std::string::npos) { os << "# " << replace.substr(lpos, rpos-lpos); lpos = rpos+1; @@ -667,7 +691,7 @@ cmLocalUnixMakefileGenerator2 cmakefileName += "/Makefile2.cmake"; std::string runRule = "@$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; - runRule += " --check-rerun "; + runRule += " --check-build-system "; runRule += this->ConvertToRelativeOutputPath(cmakefileName.c_str()); // Write the main entry point target. This must be the VERY first @@ -676,7 +700,7 @@ cmLocalUnixMakefileGenerator2 std::vector<std::string> depends; std::vector<std::string> commands; // Check the build system in this directory. - depends.push_back("cmake_check_rerun"); + depends.push_back("cmake_check_build_system"); // Recursively build dependencies. commands.push_back(this->GetRecursiveMakeCall("all.depends")); @@ -699,8 +723,8 @@ cmLocalUnixMakefileGenerator2 postEcho.c_str()); } - // Write special "cmake_check_rerun" target to run cmake with the - // --check-rerun flag. + // Write special "cmake_check_build_system" target to run cmake with + // the --check-build-system flag. { std::vector<std::string> no_depends; std::vector<std::string> commands; @@ -709,7 +733,7 @@ cmLocalUnixMakefileGenerator2 "Special rule to run CMake to check the build system " "integrity.", "Checking build system integrity...", - "cmake_check_rerun", + "cmake_check_build_system", no_depends, commands); } @@ -1633,7 +1657,7 @@ cmLocalUnixMakefileGenerator2 commands.push_back(cmd); // Check the build system in destination directory. - commands.push_back(this->GetRecursiveMakeCall("cmake_check_rerun")); + commands.push_back(this->GetRecursiveMakeCall("cmake_check_build_system")); // Build the targets's dependencies. commands.push_back(this->GetRecursiveMakeCall(dep.c_str())); @@ -1655,7 +1679,7 @@ cmLocalUnixMakefileGenerator2 // Check the build system in destination directory. cmd += " && "; - cmd += this->GetRecursiveMakeCall("cmake_check_rerun"); + cmd += this->GetRecursiveMakeCall("cmake_check_build_system"); // Build the targets's dependencies. cmd += " && "; @@ -1736,7 +1760,9 @@ cmLocalUnixMakefileGenerator2ScanDependenciesC( std::string line; while(cmSystemTools::GetLineFromStream(fin, line)) { - // Match include directives. + // Match include directives. TODO: Support include regex and + // ignore regex. Possibly also support directory-based inclusion + // in dependencies. if(includeLine.find(line.c_str())) { // Get the file being included. @@ -1848,3 +1874,157 @@ cmLocalUnixMakefileGenerator2 return true; } + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::CheckDependencies(const char* depCheck) +{ + // Get the list of files to scan. This is given through the command + // line hook cmake file. + std::vector<std::string> files; + cmSystemTools::ExpandListArgument(depCheck, files); + + // Check each file. The current working directory is already + // correct. + for(std::vector<std::string>::iterator f = files.begin(); + f != files.end(); ++f) + { + cmLocalUnixMakefileGenerator2::CheckDependencies(".", f->c_str()); + } +} + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::CheckDependencies(const char* dir, const char* file) +{ + // Check the dependencies associated with the given file whose path + // is specified relative to the given directory. If any dependency + // is missing then dependencies should be regenerated. + bool regenerate = false; + + // Construct the names of the mark and make files. + std::string depMarkFileFull = dir; + depMarkFileFull += "/"; + depMarkFileFull += file; + depMarkFileFull += ".depends"; + std::string depMakeFileFull = depMarkFileFull; + depMakeFileFull += ".make"; + + // Open the dependency makefile. + std::ifstream fin(depMakeFileFull.c_str()); + if(fin) + { + // Parse dependencies. + std::string line; + std::string depender; + std::string dependee; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + // Skip empty lines and comments. + std::string::size_type pos = line.find_first_not_of(" \t\r\n"); + if(pos == std::string::npos || line[pos] == '#') + { + continue; + } + + // Strip leading whitespace. + if(pos > 0) + { + line = line.substr(pos); + } + + // Skip lines too short to have a dependency. + if(line.size() < 2) + { + continue; + } + + // Find the colon on the line. Skip the first two characters to + // avoid finding the colon in a drive letter on Windows. Ignore + // the line if a colon cannot be found. + if((pos = line.find(':', 2)) == std::string::npos) + { + continue; + } + + // Split the line into depender and dependee. + depender = line.substr(0, pos); + dependee = line.substr(pos+1); + + // Strip whitespace from the dependee. + if((pos = dependee.find_first_not_of(" \t\r\n")) != std::string::npos && + pos > 0) + { + dependee = dependee.substr(pos); + } + if((pos = dependee.find_last_not_of(" \t\r\n")) != std::string::npos) + { + dependee = dependee.substr(0, pos+1); + } + + // Convert dependee to a full path. + if(!cmSystemTools::FileIsFullPath(dependee.c_str())) + { + dependee = cmSystemTools::CollapseFullPath(dependee.c_str(), dir); + } + + // If the dependee does not exist, we need to regenerate + // dependencies and the depender should be removed. + if(!cmSystemTools::FileExists(dependee.c_str())) + { + // Strip whitespace from the depender. + if((pos = depender.find_last_not_of(" \t\r\n")) != std::string::npos) + { + depender = depender.substr(0, pos+1); + } + + // Convert depender to a full path. + if(!cmSystemTools::FileIsFullPath(depender.c_str())) + { + depender = cmSystemTools::CollapseFullPath(depender.c_str(), dir); + } + + // Remove the depender. + cmSystemTools::RemoveFile(depender.c_str()); + + // Mark the need for regeneration. + regenerate = true; + } + } + } + else + { + // Could not open the dependencies file. It needs to be + // regenerated. + regenerate = true; + } + + // If the dependencies file needs to be regenerated, create an empty + // one and delete the mark file. + if(regenerate) + { + cmLocalUnixMakefileGenerator2 + ::WriteEmptyDependMakeFile(file, depMarkFileFull.c_str(), + depMakeFileFull.c_str()); + } +} + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteEmptyDependMakeFile(const char* file, + const char* depMarkFileFull, + const char* depMakeFileFull) +{ + // Remove the dependency mark file to be sure dependencies will be + // regenerated. + cmSystemTools::RemoveFile(depMarkFileFull); + + // Write an empty dependency file. + std::ofstream depFileStream(depMakeFileFull); + depFileStream + << "# Empty dependencies file for " << file << ".\n" + << "# This may be replaced when dependencies are built.\n"; +} diff --git a/Source/cmLocalUnixMakefileGenerator2.h b/Source/cmLocalUnixMakefileGenerator2.h index af698dd..a4bb180 100644 --- a/Source/cmLocalUnixMakefileGenerator2.h +++ b/Source/cmLocalUnixMakefileGenerator2.h @@ -50,6 +50,9 @@ public: /** Called from command-line hook to scan dependencies. */ static bool ScanDependencies(std::vector<std::string> const& args); + /** Called from command-line hook to check dependencies. */ + static void CheckDependencies(const char* depCheck); + protected: void GenerateMakefile(); @@ -57,6 +60,7 @@ protected: void GenerateTargetRuleFile(const cmTarget& target); void GenerateObjectRuleFile(const cmTarget& target, const cmSourceFile& source); + std::string GenerateDependsMakeFile(const char* file); void WriteMakeRule(std::ostream& os, const char* comment, const char* preEcho, @@ -112,6 +116,10 @@ protected: static bool ScanDependenciesC(const char* objFile, const char* srcFile, std::vector<std::string> const& includes); + static void CheckDependencies(const char* dir, const char* file); + static void WriteEmptyDependMakeFile(const char* file, + const char* depMarkFileFull, + const char* depMakeFileFull); private: // Map from target name to build directory containing it for // jump-and-build targets. @@ -121,6 +129,9 @@ private: std::string m_FilePath; }; std::map<cmStdString, RemoteTarget> m_JumpAndBuild; + + // List the files for which to check dependency integrity. + std::set<cmStdString> m_CheckDependFiles; }; #endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index c2006e9..a7e9781 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -25,11 +25,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmVariableWatch.h" # include "cmVersion.h" -#endif - - -#if defined(CMAKE_BUILD_WITH_CMAKE) -#include "cmLocalUnixMakefileGenerator2.h" +# include "cmLocalUnixMakefileGenerator2.h" #endif // only build kdevelop generator on non-windows platforms @@ -317,9 +313,9 @@ void cmake::SetArgs(const std::vector<std::string>& args) cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeOutputDirectory(path.c_str()); } - else if((i < args.size()-1) && (arg.find("--check-rerun",0) == 0)) + else if((i < args.size()-1) && (arg.find("--check-build-system",0) == 0)) { - m_CheckRerun = args[++i]; + m_CheckBuildSystem = args[++i]; } else if(arg.find("-V",0) == 0) { @@ -1268,8 +1264,8 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) if(m_ScriptMode || !m_Local || !this->CacheVersionMatches() || !cmSystemTools::FileExists(systemFile.c_str()) ) { - // Check whether we should really do a generate. - if(!this->CheckRerun()) + // Check the state of the build system to see if we need to regenerate. + if(!this->CheckBuildSystem()) { return 0; } @@ -1572,16 +1568,23 @@ void cmake::UpdateConversionPathTable() } } -int cmake::CheckRerun() +//---------------------------------------------------------------------------- +int cmake::CheckBuildSystem() { + // This method will check the integrity of the build system if the + // option was given on the command line. It reads the given file to + // determine whether CMake should rerun. If it does rerun then the + // generation step will check the integrity of dependencies. If it + // does not then we need to check the integrity here. + // If no file is provided for the check, we have to rerun. - if(m_CheckRerun.size() == 0) + if(m_CheckBuildSystem.size() == 0) { return 1; } // If the file provided does not exist, we have to rerun. - if(!cmSystemTools::FileExists(m_CheckRerun.c_str())) + if(!cmSystemTools::FileExists(m_CheckBuildSystem.c_str())) { return 1; } @@ -1594,7 +1597,7 @@ int cmake::CheckRerun() std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator()); lg->SetGlobalGenerator(&gg); cmMakefile* mf = lg->GetMakefile(); - if(!mf->ReadListFile(0, m_CheckRerun.c_str()) || + if(!mf->ReadListFile(0, m_CheckBuildSystem.c_str()) || cmSystemTools::GetErrorOccuredFlag()) { // There was an error reading the file. Just rerun. @@ -1630,6 +1633,14 @@ int cmake::CheckRerun() } } +#if defined(CMAKE_BUILD_WITH_CMAKE) + // We do not need to rerun CMake. Check dependency integrity. + if(const char* depCheck = mf->GetDefinition("CMAKE_DEPENDS_CHECK")) + { + cmLocalUnixMakefileGenerator2::CheckDependencies(depCheck); + } +#endif + // No need to rerun. return 0; } diff --git a/Source/cmake.h b/Source/cmake.h index 5bb2531..50024f7 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -286,7 +286,12 @@ protected: ///! used by Run int LocalGenerate(); - int CheckRerun(); + + /** + * Method called to check build system integrity at build time. + * Returns 1 if CMake should rerun and 0 otherwise. + */ + int CheckBuildSystem(); /** * Generate CMAKE_ROOT and CMAKE_COMMAND cache entries @@ -307,7 +312,7 @@ private: std::string m_CMakeCommand; std::string m_CXXEnvironment; std::string m_CCEnvironment; - std::string m_CheckRerun; + std::string m_CheckBuildSystem; bool m_DebugTryCompile; void UpdateConversionPathTable(); |