diff options
author | Brad King <brad.king@kitware.com> | 2007-12-31 11:25:17 -0500 |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2007-12-31 11:25:17 -0500 |
commit | 1f987c06eaa083aa5eda825ad1a795fd27edf622 (patch) | |
tree | 4a7f0605e28330b341b2942e4519f264f77fac7d /Source/cmDependsFortran.cxx | |
parent | 1ebf5aa2dff6631ce1b01d62fae83bdf37253743 (diff) | |
download | cmake-1f987c06eaa083aa5eda825ad1a795fd27edf622.tar.gz |
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.
Diffstat (limited to 'Source/cmDependsFortran.cxx')
-rw-r--r-- | Source/cmDependsFortran.cxx | 122 |
1 files changed, 112 insertions, 10 deletions
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index aeb37e75ae..2dd40e251a 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -619,23 +619,29 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args) mod_lower += ".mod"; 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 \"" - << mod_upper.c_str() << "\" to \"" << stamp.c_str() - << "\".\n"; - return false; + if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str())) + { + std::cerr << "Error copying Fortran module from \"" + << mod_upper.c_str() << "\" to \"" << stamp.c_str() + << "\".\n"; + return false; + } } return 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 \"" - << mod_lower.c_str() << "\" to \"" << stamp.c_str() - << "\".\n"; - return false; + if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str())) + { + std::cerr << "Error copying Fortran module from \"" + << mod_lower.c_str() << "\" to \"" << stamp.c_str() + << "\".\n"; + return false; + } } return true; } @@ -647,6 +653,102 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args) } //---------------------------------------------------------------------------- +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, const char* includeName, std::string& fileName) |