ENH: Changes based on patch from Maik Beckmann to copy fortran modules to timestamps only if they have really changed. This optimization should reduce extra rebuilds caused by dependencies on modules whose providers have recompiled but whose interfaces have not changed.

This commit is contained in:
Brad King 2007-12-31 11:25:17 -05:00
parent 1ebf5aa2df
commit 1f987c06ea
2 changed files with 116 additions and 10 deletions

View File

@ -619,23 +619,29 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
mod_lower += ".mod"; mod_lower += ".mod";
if(cmSystemTools::FileExists(mod_upper.c_str(), true)) if(cmSystemTools::FileExists(mod_upper.c_str(), true))
{ {
if(!cmSystemTools::CopyFileIfDifferent(mod_upper.c_str(), stamp.c_str())) if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str()))
{ {
std::cerr << "Error copying Fortran module from \"" if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str()))
<< mod_upper.c_str() << "\" to \"" << stamp.c_str() {
<< "\".\n"; std::cerr << "Error copying Fortran module from \""
return false; << mod_upper.c_str() << "\" to \"" << stamp.c_str()
<< "\".\n";
return false;
}
} }
return true; return true;
} }
else if(cmSystemTools::FileExists(mod_lower.c_str(), true)) else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
{ {
if(!cmSystemTools::CopyFileIfDifferent(mod_lower.c_str(), stamp.c_str())) if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str()))
{ {
std::cerr << "Error copying Fortran module from \"" if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str()))
<< mod_lower.c_str() << "\" to \"" << stamp.c_str() {
<< "\".\n"; std::cerr << "Error copying Fortran module from \""
return false; << mod_lower.c_str() << "\" to \"" << stamp.c_str()
<< "\".\n";
return false;
}
} }
return true; return true;
} }
@ -646,6 +652,102 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
return false; return false;
} }
//----------------------------------------------------------------------------
bool cmDependsFortran::ModulesDiffer(const char* modFile,
const char* stampFile)
{
/*
This following is valid for intel and gnu. For others this may be valid
too, but has to be proven.
ASSUMPTION: If one compiles the source foo.f90 which provides module bar,
two times then both generated bar.mod files will differ only before the
first linefeed (\n or 0x0A).
gnu:
A mod file is an ascii file.
<bar.mod>
FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
If you edit this, you'll get what you deserve.
...
</bar.mod>
As you can see the first line contains the date.
intel:
A mod file is a binary file.
However, looking into both generated bar.mod files with a hex editor
shows that they differ only before a linefeed (0x0A) which is located
some bytes in front of the absoulte path to the source file.
sun:
A mod file is a binary file. It always starts in the line of text
!<ftn.mod>
Compiling twice produces identical modules anyway, so the
assumption is valid.
others:
TODO: is this valid for every common fortran compiler?
*/
#if defined(_WIN32) || defined(__CYGWIN__)
std::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
#else
std::ifstream finModFile(modFile, std::ios::in);
std::ifstream finStampFile(stampFile, std::ios::in);
#endif
if(!finModFile || !finStampFile)
{
// At least one of the files does not exist. The modules differ.
return true;
}
// Remove the first line from each file and make sure newlines were found.
std::string modLine;
bool modHasNewline = false;
if(!cmSystemTools::GetLineFromStream(finModFile, modLine,
&modHasNewline, 1024) ||
!modHasNewline)
{
std::cerr
<< "WARNING in cmDependsFortran::ModulesDiffer:\n"
<< "The fortran module \"" << modFile << "\" format is not known.\n"
<< "Please report this at: http://www.cmake.org/Bug\n"
<< "\n";
return true;
}
std::string stampLine;
bool stampHasNewline = false;
if(!cmSystemTools::GetLineFromStream(finStampFile, stampLine,
&stampHasNewline, 1024) ||
!stampHasNewline)
{
// The stamp file is invalid.
return true;
}
// Compare the remaining content.
for(;;)
{
int mod_c = finModFile.get();
int stamp_c = finStampFile.get();
if(!finModFile && !finStampFile)
{
// We have reached the end of both files simultaneously.
// The modules are identical.
return false;
}
else if(!finModFile || !finStampFile || mod_c != stamp_c)
{
// We have reached the end of one file before the other.
// The modules are different.
break;
}
}
// The modules are different.
return true;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmDependsFortran::FindIncludeFile(const char* dir, bool cmDependsFortran::FindIncludeFile(const char* dir,
const char* includeName, const char* includeName,

View File

@ -46,6 +46,10 @@ public:
corresponding stamp file. */ corresponding stamp file. */
static bool CopyModule(const std::vector<std::string>& args); static bool CopyModule(const std::vector<std::string>& args);
/** Determine if a mod file and the corresponding mod.stamp file
are representing different module information. */
static bool ModulesDiffer(const char* modFile, const char* stampFile);
/** Method to find an included file in the include path. Fortran /** Method to find an included file in the include path. Fortran
always searches the directory containing the including source always searches the directory containing the including source
first. */ first. */