ENH: Moved dependency integrity check from CheckBuildSystem over to a per-target UpdateDependencies step. This greatly reduces the startup time for make processes and allows individual targets to be built without a global dependency check.

This commit is contained in:
Brad King 2007-12-19 16:36:30 -05:00
parent c7bf320539
commit de96fd1df9
7 changed files with 94 additions and 73 deletions

View File

@ -48,7 +48,7 @@ bool cmDepends::Write(const char *src, const char *obj,
}
//----------------------------------------------------------------------------
void cmDepends::Check(const char *makeFile, const char *internalFile)
bool cmDepends::Check(const char *makeFile, const char *internalFile)
{
// Dependency checks must be done in proper working directory.
std::string oldcwd = ".";
@ -61,12 +61,14 @@ void cmDepends::Check(const char *makeFile, const char *internalFile)
}
// Check whether dependencies must be regenerated.
bool okay = true;
std::ifstream fin(internalFile);
if(!(fin && this->CheckDependencies(fin)))
{
// Clear all dependencies so they will be regenerated.
this->Clear(makeFile);
this->Clear(internalFile);
cmSystemTools::RemoveFile(internalFile);
okay = false;
}
// Restore working directory.
@ -74,6 +76,8 @@ void cmDepends::Check(const char *makeFile, const char *internalFile)
{
cmSystemTools::ChangeDirectory(oldcwd.c_str());
}
return okay;
}
//----------------------------------------------------------------------------
@ -87,12 +91,6 @@ void cmDepends::Clear(const char *file)
cmSystemTools::Stdout(msg.str().c_str());
}
// Remove the dependency mark file to be sure dependencies will be
// regenerated.
std::string markFile = file;
markFile += ".mark";
cmSystemTools::RemoveFile(markFile.c_str());
// Write an empty dependency file.
cmGeneratedFileStream depFileStream(file);
depFileStream
@ -100,6 +98,14 @@ void cmDepends::Clear(const char *file)
<< "# This may be replaced when dependencies are built." << std::endl;
}
//----------------------------------------------------------------------------
bool cmDepends::WriteDependencies(const char*, const char*,
std::ostream&, std::ostream&)
{
// This should be implemented by the subclass.
return false;
}
//----------------------------------------------------------------------------
bool cmDepends::CheckDependencies(std::istream& internalDepends)
{

View File

@ -55,8 +55,11 @@ public:
bool Write(const char *src, const char *obj,
std::ostream &makeDepends, std::ostream &internalDepends);
/** Check dependencies for the target file. */
void Check(const char *makeFile, const char* internalFile);
/** Check dependencies for the target file. Returns true if
dependencies are okay and false if they must be generated. If
they must be generated Clear has already been called to wipe out
the old dependencies. */
bool Check(const char *makeFile, const char* internalFile);
/** Clear dependencies for the target file so they will be regenerated. */
void Clear(const char *file);
@ -70,7 +73,7 @@ protected:
// Write dependencies for the target file to the given stream.
// Return true for success and false for failure.
virtual bool WriteDependencies(const char *src, const char* obj,
std::ostream& makeDepends, std::ostream& internalDepends)=0;
std::ostream& makeDepends, std::ostream& internalDepends);
// Check dependencies for the target file in the given stream.
// Return false if dependencies must be regenerated and true

View File

@ -157,13 +157,14 @@ public:
///! for existing files convert to output path and short path if spaces
std::string ConvertToOutputForExisting(const char* p);
/** Called from command-line hook to check dependencies. */
virtual void CheckDependencies(cmMakefile* /* mf */,
bool /* verbose */,
bool /* clear */) {};
/** Called from command-line hook to clear dependencies. */
virtual void ClearDependencies(cmMakefile* /* mf */,
bool /* verbose */) {}
/** Called from command-line hook to scan dependencies. */
virtual bool ScanDependencies(const char* /* tgtInfo */) { return true; }
/** Called from command-line hook to update dependencies. */
virtual bool UpdateDependencies(const char* /* tgtInfo */,
bool /*verbose*/)
{ return true; }
/** Compute the list of link libraries and directories for the given
target and configuration. */

View File

@ -1223,6 +1223,40 @@ cmLocalUnixMakefileGenerator3
return ret;
}
//----------------------------------------------------------------------------
bool cmLocalUnixMakefileGenerator3::UpdateDependencies(const char* tgtInfo,
bool verbose)
{
std::string dir = cmSystemTools::GetFilenamePath(tgtInfo);
std::string internalDependFile = dir + "/depend.internal";
std::string dependFile = dir + "/depend.make";
// Check the implicit dependencies to see if they are up to date.
// The build.make file may have explicit dependencies for the object
// files but these will not affect the scanning process so they need
// not be considered.
cmDependsC checker;
checker.SetVerbose(verbose);
checker.SetFileComparison
(this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
if(!checker.Check(dependFile.c_str(), internalDependFile.c_str()))
{
// The dependencies must be regenerated.
// TODO: Make this like cmLocalUnixMakefileGenerator3::EchoDepend
std::string targetName = cmSystemTools::GetFilenameName(dir);
targetName = targetName.substr(0, targetName.length()-4);
fprintf(stdout, "Scanning dependencies of target %s\n", targetName.c_str());
return this->ScanDependencies(tgtInfo);
}
else
{
// The dependencies are already up-to-date.
return true;
}
}
//----------------------------------------------------------------------------
bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
{
@ -1403,11 +1437,6 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
}
}
// dependencies were generated, so touch the mark file
ruleFileNameFull += ".mark";
std::ofstream fmark(ruleFileNameFull.c_str());
fmark << "Dependencies updated>" << std::endl;
return true;
}
@ -1619,9 +1648,8 @@ void cmLocalUnixMakefileGenerator3
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator3::CheckDependencies(cmMakefile* mf,
bool verbose,
bool clear)
void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
bool verbose)
{
// Get the list of target files to check
const char* infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
@ -1632,27 +1660,23 @@ void cmLocalUnixMakefileGenerator3::CheckDependencies(cmMakefile* mf,
std::vector<std::string> files;
cmSystemTools::ExpandListArgument(infoDef, files);
// For each info file run the check
cmDependsC checker;
checker.SetVerbose(verbose);
checker.SetFileComparison
(this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
// Each depend information file corresponds to a target. Clear the
// dependencies for that target.
cmDepends clearer;
clearer.SetVerbose(verbose);
for(std::vector<std::string>::iterator l = files.begin();
l != files.end(); ++l)
{
// either clear or check the files
std::string dir = cmSystemTools::GetFilenamePath(l->c_str());
std::string internalDependFile = dir + "/depend.internal";
// Clear the implicit dependency makefile.
std::string dependFile = dir + "/depend.make";
if (clear)
{
checker.Clear(internalDependFile.c_str());
checker.Clear(dependFile.c_str());
}
else
{
checker.Check(dependFile.c_str(), internalDependFile.c_str());
}
clearer.Clear(dependFile.c_str());
// Remove the internal dependency check file to force
// regeneration.
std::string internalDependFile = dir + "/depend.internal";
cmSystemTools::RemoveFile(internalDependFile.c_str());
}
}

View File

@ -198,12 +198,15 @@ public:
std::string CreateMakeVariable(const char* sin, const char* s2in);
/** Called from command-line hook to scan dependencies. */
virtual bool ScanDependencies(const char* tgtInfo);
/** Called from command-line hook to bring dependencies up to date
for a target. */
virtual bool UpdateDependencies(const char* tgtInfo, bool verbose);
/** Called from command-line hook to check dependencies. */
virtual void CheckDependencies(cmMakefile* mf, bool verbose,
bool clear);
/** Called from command-line hook to scan dependencies. */
bool ScanDependencies(const char* tgtInfo);
/** Called from command-line hook to clear dependencies. */
virtual void ClearDependencies(cmMakefile* mf, bool verbose);
/** write some extra rules such as make test etc */
void WriteSpecialTargetsTop(std::ostream& makefileStream);

View File

@ -519,15 +519,6 @@ cmMakefileTargetGenerator
this->LocalGenerator->ExpandRuleVariables(*i, vars);
}
// 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->LocalGenerator->GetRelativeTargetDirectory(*this->Target);
depMark += "/depend.make.mark";
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
depMark.c_str(),
depends, no_commands, false);
// Write the rule.
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
@ -793,21 +784,6 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
this->LocalGenerator->GetRelativeTargetDirectory(*this->Target);
depTarget += "/depend";
std::string depMark = depTarget;
depMark += ".make.mark";
depends.push_back(depMark);
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
depTarget.c_str(),
depends, commands, true);
depends.clear();
// Write the dependency generation rule.
std::string depEcho = "Scanning dependencies of target ";
depEcho += this->Target->GetName();
this->LocalGenerator->AppendEcho(commands, depEcho.c_str(),
cmLocalUnixMakefileGenerator3::EchoDepend);
// Add a command to call CMake to scan dependencies. CMake will
// touch the corresponding depends file after scanning dependencies.
cmOStringStream depCmd;
@ -859,7 +835,7 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
// Write the rule.
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
depMark.c_str(),
depTarget.c_str(),
depends, commands, false);
}

View File

@ -1353,6 +1353,10 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
// Internal CMake dependency scanning support.
else if (args[1] == "cmake_depends" && args.size() >= 6)
{
// Use the make system's VERBOSE environment variable to enable
// verbose output.
bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
// Create a cmake object instance to process dependencies.
cmake cm;
std::string gen;
@ -1416,7 +1420,7 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
lgd->GetMakefile()->MakeStartDirectoriesCurrent();
// Actually scan dependencies.
return lgd->ScanDependencies(depInfo.c_str())? 0 : 2;
return lgd->UpdateDependencies(depInfo.c_str(), verbose)? 0 : 2;
}
return 1;
}
@ -2549,7 +2553,11 @@ int cmake::CheckBuildSystem()
// Check the dependencies in case source files were removed.
std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
lgd->SetGlobalGenerator(ggd.get());
lgd->CheckDependencies(mf, verbose, this->ClearBuildSystem);
if(this->ClearBuildSystem)
{
lgd->ClearDependencies(mf, verbose);
}
// Check for multiple output pairs.
ggd->CheckMultipleOutputs(mf, verbose);