ENH: Added build system integrity check to cmLocalUnixMakefileGenerator2. This now uses a special --check-build-system flag to cmake which replaces --check-rerun. Integrity of dependencies is also checked during generation.
This commit is contained in:
parent
674349caed
commit
81bbae1fb2
|
@ -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
|
||||
|
@ -469,6 +466,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
|
||||
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue