ENH: Changes based on patch from Maik for better cmDependsFortran::ModulesDiffer.

This commit is contained in:
Brad King 2008-01-07 11:36:17 -05:00
parent 4b2218045d
commit e73508aa65

View File

@ -663,20 +663,76 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
return false; return false;
} }
//----------------------------------------------------------------------------
// Helper function to look for a short sequence in a stream. If this
// is later used for longer sequences it should be re-written using an
// efficient string search algorithm such as Boyer-Moore.
static
bool cmDependsFortranStreamContainsSequence(std::ifstream& ifs,
const char* seq, int len)
{
assert(len > 0);
int cur = 0;
while(cur < len)
{
// Get the next character.
int token = ifs.get();
if(!ifs)
{
return false;
}
// Check the character.
if(token == static_cast<int>(seq[cur]))
{
++cur;
}
else
{
// Assume the sequence has no repeating subsequence.
cur = 0;
}
}
// The entire sequence was matched.
return true;
}
//----------------------------------------------------------------------------
// Helper function to compare the remaining content in two streams.
static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
std::ifstream& ifs2)
{
// Compare the remaining content.
for(;;)
{
int ifs1_c = ifs1.get();
int ifs2_c = ifs2.get();
if(!ifs1 && !ifs2)
{
// We have reached the end of both streams simultaneously.
// The streams are identical.
return false;
}
if(!ifs1 || !ifs2 || ifs1_c != ifs2_c)
{
// We have reached the end of one stream before the other or
// found differing content. The streams are different.
break;
}
}
return true;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmDependsFortran::ModulesDiffer(const char* modFile, bool cmDependsFortran::ModulesDiffer(const char* modFile,
const char* stampFile, const char* stampFile,
const char* compilerId) const char* compilerId)
{ {
(void)compilerId;
/* /*
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: gnu:
A mod file is an ascii file. A mod file is an ascii file.
<bar.mod> <bar.mod>
@ -689,18 +745,27 @@ bool cmDependsFortran::ModulesDiffer(const char* modFile,
intel: intel:
A mod file is a binary file. A mod file is a binary file.
However, looking into both generated bar.mod files with a hex editor However, looking into both generated bar.mod files with a hex editor
shows that they differ only before a linefeed (0x0A) which is located shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
some bytes in front of the absoulte path to the source file. which is located some bytes in front of the absoulte path to the source
file.
sun: sun:
A mod file is a binary file. It always starts in the line of text A mod file is a binary file. Compiling twice produces identical modules.
!<ftn.mod>
Compiling twice produces identical modules anyway, so the
assumption is valid.
others: others:
TODO: is this valid for every common fortran compiler? TODO ...
*/ */
/* Compilers which do _not_ produce different mod content when the same
* source is compiled twice
* -SunPro
*/
if(std::strcmp(compilerId, "SunPro") == 0)
{
return cmSystemTools::FilesDiffer(modFile, stampFile);
}
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
std::ifstream finModFile(modFile, std::ios::in | std::ios::binary); std::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary); std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
@ -714,47 +779,59 @@ bool cmDependsFortran::ModulesDiffer(const char* modFile,
return true; return true;
} }
// Remove the first line from each file and make sure newlines were found. /* Compilers which _do_ produce different mod content when the same
std::string modLine; * source is compiled twice
bool modHasNewline = false; * -GNU
if(!cmSystemTools::GetLineFromStream(finModFile, modLine, * -Intel
&modHasNewline, 1024) || *
!modHasNewline) * Eat the stream content until all recompile only realated changes
* are left bedind.
*/
if (std::strcmp(compilerId, "GNU") == 0 )
{ {
std::cerr const char seq[1] = {'\n'};
<< "WARNING in cmDependsFortran::ModulesDiffer:\n" const int seqlen = 1;
<< "The fortran module \"" << modFile << "\" format is not known.\n"
<< "Please report this at: http://www.cmake.org/Bug\n" if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
<< "\n"; {
return true; // The module is of unexpected format. Assume it is different.
std::cerr << compilerId << " fortran module " << modFile
<< " has unexpected format." << std::endl;
return true;
}
if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
{
// The stamp must differ if the sequence is not contained.
return true;
}
} }
std::string stampLine; else if(std::strcmp(compilerId, "Intel") == 0)
bool stampHasNewline = false;
if(!cmSystemTools::GetLineFromStream(finStampFile, stampLine,
&stampHasNewline, 1024) ||
!stampHasNewline)
{ {
// The stamp file is invalid. const char seq[2] = {'\n', '\0'};
return true; const int seqlen = 2;
if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
{
// The module is of unexpected format. Assume it is different.
std::cerr << compilerId << " fortran module " << modFile
<< " has unexpected format." << std::endl;
return true;
}
if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
{
// The stamp must differ if the sequence is not contained.
return true;
}
} }
// Compare the remaining content. // Compare the remainng content. If no compiler id matched above,
for(;;) // including the case none was given, this will compare the whole
// content.
if(!cmDependsFortranStreamsDiffer(finModFile, finStampFile))
{ {
int mod_c = finModFile.get(); return false;
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. // The modules are different.