Updated formatting of documentation plus a little reorganization.
[cmake.git] / Source / cmDependsFortran.cxx
blob83755a053d151190ea3a66d0d752b8b52a9b1cb3
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDependsFortran.cxx,v $
5 Language: C++
6 Date: $Date: 2009-02-24 19:32:25 $
7 Version: $Revision: 1.49 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmDependsFortran.h"
19 #include "cmSystemTools.h"
20 #include "cmLocalGenerator.h"
21 #include "cmMakefile.h"
22 #include "cmGeneratedFileStream.h"
24 #include "cmDependsFortranParser.h" /* Interface to parser object. */
26 #include <assert.h>
27 #include <stack>
29 // TODO: Test compiler for the case of the mod file. Some always
30 // use lower case and some always use upper case. I do not know if any
31 // use the case from the source code.
33 //----------------------------------------------------------------------------
34 // Information about a single source file.
35 class cmDependsFortranSourceInfo
37 public:
38 // The name of the soruce file.
39 std::string Source;
41 // Set of provided and required modules.
42 std::set<cmStdString> Provides;
43 std::set<cmStdString> Requires;
45 // Set of files included in the translation unit.
46 std::set<cmStdString> Includes;
49 //----------------------------------------------------------------------------
50 // Parser methods not included in generated interface.
52 // Get the current buffer processed by the lexer.
53 YY_BUFFER_STATE cmDependsFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
55 // The parser entry point.
56 int cmDependsFortran_yyparse(yyscan_t);
58 //----------------------------------------------------------------------------
59 // Define parser object internal structure.
60 struct cmDependsFortranFile
62 cmDependsFortranFile(FILE* file, YY_BUFFER_STATE buffer,
63 const std::string& dir):
64 File(file), Buffer(buffer), Directory(dir) {}
65 FILE* File;
66 YY_BUFFER_STATE Buffer;
67 std::string Directory;
70 struct cmDependsFortranParser_s
72 cmDependsFortranParser_s(cmDependsFortran* self,
73 std::set<std::string>& ppDefines,
74 cmDependsFortranSourceInfo& info);
75 ~cmDependsFortranParser_s();
77 // Pointer back to the main class.
78 cmDependsFortran* Self;
80 // Lexical scanner instance.
81 yyscan_t Scanner;
83 // Stack of open files in the translation unit.
84 std::stack<cmDependsFortranFile> FileStack;
86 // Buffer for string literals.
87 std::string TokenString;
89 // Flag for whether lexer is reading from inside an interface.
90 bool InInterface;
92 int OldStartcond;
93 std::set<std::string> PPDefinitions;
94 size_t InPPFalseBranch;
95 std::stack<bool> SkipToEnd;
97 // Information about the parsed source.
98 cmDependsFortranSourceInfo& Info;
101 //----------------------------------------------------------------------------
102 class cmDependsFortranInternals
104 public:
105 // The set of modules provided by this target.
106 std::set<cmStdString> TargetProvides;
108 // Map modules required by this target to locations.
109 typedef std::map<cmStdString, cmStdString> TargetRequiresMap;
110 TargetRequiresMap TargetRequires;
112 // Information about each object file.
113 typedef std::map<cmStdString, cmDependsFortranSourceInfo> ObjectInfoMap;
114 ObjectInfoMap ObjectInfo;
116 cmDependsFortranSourceInfo& CreateObjectInfo(const char* obj,
117 const char* src)
119 std::map<cmStdString, cmDependsFortranSourceInfo>::iterator i =
120 this->ObjectInfo.find(obj);
121 if(i == this->ObjectInfo.end())
123 std::map<cmStdString, cmDependsFortranSourceInfo>::value_type
124 entry(obj, cmDependsFortranSourceInfo());
125 i = this->ObjectInfo.insert(entry).first;
126 i->second.Source = src;
128 return i->second;
132 //----------------------------------------------------------------------------
133 cmDependsFortran::cmDependsFortran():
134 PPDefinitions(0), Internal(0)
138 //----------------------------------------------------------------------------
139 cmDependsFortran
140 ::cmDependsFortran(cmLocalGenerator* lg):
141 cmDepends(lg),
142 Internal(new cmDependsFortranInternals)
144 // Configure the include file search path.
145 this->SetIncludePathFromLanguage("Fortran");
147 // Get the list of definitions.
148 std::vector<std::string> definitions;
149 cmMakefile* mf = this->LocalGenerator->GetMakefile();
150 if(const char* c_defines =
151 mf->GetDefinition("CMAKE_TARGET_DEFINITIONS"))
153 cmSystemTools::ExpandListArgument(c_defines, definitions);
156 // translate i.e. FOO=BAR to FOO and add it to the list of defined
157 // preprocessor symbols
158 for(std::vector<std::string>::const_iterator
159 it = definitions.begin(); it != definitions.end(); ++it)
161 std::string def = *it;
162 std::string::size_type assignment = def.find("=");
163 if(assignment != std::string::npos)
165 def = it->substr(0, assignment);
167 this->PPDefinitions.push_back(def);
171 //----------------------------------------------------------------------------
172 cmDependsFortran::~cmDependsFortran()
174 delete this->Internal;
177 //----------------------------------------------------------------------------
178 bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
179 std::ostream&, std::ostream&)
181 // Make sure this is a scanning instance.
182 if(!src || src[0] == '\0')
184 cmSystemTools::Error("Cannot scan dependencies without an source file.");
185 return false;
187 if(!obj || obj[0] == '\0')
189 cmSystemTools::Error("Cannot scan dependencies without an object file.");
190 return false;
193 // Get the information object for this source.
194 cmDependsFortranSourceInfo& info =
195 this->Internal->CreateObjectInfo(obj, src);
197 // Make a copy of the macros defined via ADD_DEFINITIONS
198 std::set<std::string> ppDefines(this->PPDefinitions.begin(),
199 this->PPDefinitions.end());
201 // Create the parser object. The constructor takes ppMacro and info per
202 // reference, so we may look into the resulting objects later.
203 cmDependsFortranParser parser(this, ppDefines, info);
205 // Push on the starting file.
206 cmDependsFortranParser_FilePush(&parser, src);
208 // Parse the translation unit.
209 if(cmDependsFortran_yyparse(parser.Scanner) != 0)
211 // Failed to parse the file. Report failure to write dependencies.
212 return false;
215 return true;
218 //----------------------------------------------------------------------------
219 bool cmDependsFortran::Finalize(std::ostream& makeDepends,
220 std::ostream& internalDepends)
222 // Prepare the module search process.
223 this->LocateModules();
225 // Get the directory in which stamp files will be stored.
226 const char* stamp_dir = this->TargetDirectory.c_str();
228 // Get the directory in which module files will be created.
229 const char* mod_dir;
230 cmMakefile* mf = this->LocalGenerator->GetMakefile();
231 if(const char* target_mod_dir =
232 mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
234 mod_dir = target_mod_dir;
236 else
238 mod_dir =
239 this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
242 // Actually write dependencies to the streams.
243 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
244 ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
245 for(ObjectInfoMap::const_iterator i = objInfo.begin();
246 i != objInfo.end(); ++i)
248 if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
249 mod_dir, stamp_dir,
250 makeDepends, internalDepends))
252 return false;
256 // Store the list of modules provided by this target.
257 std::string fiName = this->TargetDirectory;
258 fiName += "/fortran.internal";
259 cmGeneratedFileStream fiStream(fiName.c_str());
260 fiStream << "# The fortran modules provided by this target.\n";
261 fiStream << "provides\n";
262 std::set<cmStdString> const& provides = this->Internal->TargetProvides;
263 for(std::set<cmStdString>::const_iterator i = provides.begin();
264 i != provides.end(); ++i)
266 fiStream << " " << *i << "\n";
269 // Create a script to clean the modules.
270 if(!provides.empty())
272 std::string fcName = this->TargetDirectory;
273 fcName += "/cmake_clean_Fortran.cmake";
274 cmGeneratedFileStream fcStream(fcName.c_str());
275 fcStream << "# Remove fortran modules provided by this target.\n";
276 fcStream << "FILE(REMOVE";
277 for(std::set<cmStdString>::const_iterator i = provides.begin();
278 i != provides.end(); ++i)
280 std::string mod_upper = mod_dir;
281 mod_upper += "/";
282 mod_upper += cmSystemTools::UpperCase(*i);
283 mod_upper += ".mod";
284 std::string mod_lower = mod_dir;
285 mod_lower += "/";
286 mod_lower += *i;
287 mod_lower += ".mod";
288 std::string stamp = stamp_dir;
289 stamp += "/";
290 stamp += *i;
291 stamp += ".mod.stamp";
292 fcStream << "\n";
293 fcStream << " \"" <<
294 this->LocalGenerator->Convert(mod_lower.c_str(),
295 cmLocalGenerator::START_OUTPUT)
296 << "\"\n";
297 fcStream << " \"" <<
298 this->LocalGenerator->Convert(mod_upper.c_str(),
299 cmLocalGenerator::START_OUTPUT)
300 << "\"\n";
301 fcStream << " \"" <<
302 this->LocalGenerator->Convert(stamp.c_str(),
303 cmLocalGenerator::START_OUTPUT)
304 << "\"\n";
306 fcStream << " )\n";
308 return true;
311 //----------------------------------------------------------------------------
312 void cmDependsFortran::LocateModules()
314 // Collect the set of modules provided and required by all sources.
315 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
316 ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
317 for(ObjectInfoMap::const_iterator infoI = objInfo.begin();
318 infoI != objInfo.end(); ++infoI)
320 cmDependsFortranSourceInfo const& info = infoI->second;
321 for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
322 i != info.Provides.end(); ++i)
324 // Include this module in the set provided by this target.
325 this->Internal->TargetProvides.insert(*i);
328 for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
329 i != info.Requires.end(); ++i)
331 // Include this module in the set required by this target.
332 this->Internal->TargetRequires[*i] = "";
336 // Short-circuit for simple targets.
337 if(this->Internal->TargetRequires.empty())
339 return;
342 // Match modules provided by this target to those it requires.
343 this->MatchLocalModules();
345 // Load information about other targets.
346 cmMakefile* mf = this->LocalGenerator->GetMakefile();
347 std::vector<std::string> infoFiles;
348 if(const char* infoFilesValue =
349 mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES"))
351 cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
353 for(std::vector<std::string>::const_iterator i = infoFiles.begin();
354 i != infoFiles.end(); ++i)
356 std::string targetDir = cmSystemTools::GetFilenamePath(*i);
357 std::string fname = targetDir + "/fortran.internal";
358 std::ifstream fin(fname.c_str());
359 if(fin)
361 this->MatchRemoteModules(fin, targetDir.c_str());
366 //----------------------------------------------------------------------------
367 void cmDependsFortran::MatchLocalModules()
369 const char* stampDir = this->TargetDirectory.c_str();
370 std::set<cmStdString> const& provides = this->Internal->TargetProvides;
371 for(std::set<cmStdString>::const_iterator i = provides.begin();
372 i != provides.end(); ++i)
374 this->ConsiderModule(i->c_str(), stampDir);
378 //----------------------------------------------------------------------------
379 void cmDependsFortran::MatchRemoteModules(std::istream& fin,
380 const char* stampDir)
382 std::string line;
383 bool doing_provides = false;
384 while(cmSystemTools::GetLineFromStream(fin, line))
386 // Ignore comments and empty lines.
387 if(line.empty() || line[0] == '#' || line[0] == '\r')
389 continue;
392 if(line[0] == ' ')
394 if(doing_provides)
396 this->ConsiderModule(line.c_str()+1, stampDir);
399 else if(line == "provides")
401 doing_provides = true;
403 else
405 doing_provides = false;
410 //----------------------------------------------------------------------------
411 void cmDependsFortran::ConsiderModule(const char* name,
412 const char* stampDir)
414 // Locate each required module.
415 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
416 TargetRequiresMap::iterator required =
417 this->Internal->TargetRequires.find(name);
418 if(required != this->Internal->TargetRequires.end() &&
419 required->second.empty())
421 // The module is provided by a CMake target. It will have a stamp file.
422 std::string stampFile = stampDir;
423 stampFile += "/";
424 stampFile += name;
425 stampFile += ".mod.stamp";
426 required->second = stampFile;
430 //----------------------------------------------------------------------------
431 bool
432 cmDependsFortran
433 ::WriteDependenciesReal(const char *obj,
434 cmDependsFortranSourceInfo const& info,
435 const char* mod_dir, const char* stamp_dir,
436 std::ostream& makeDepends,
437 std::ostream& internalDepends)
439 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
441 // Get the source file for this object.
442 const char* src = info.Source.c_str();
444 // Write the include dependencies to the output stream.
445 internalDepends << obj << std::endl;
446 internalDepends << " " << src << std::endl;
447 for(std::set<cmStdString>::const_iterator i = info.Includes.begin();
448 i != info.Includes.end(); ++i)
450 makeDepends << obj << ": "
451 << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
452 << std::endl;
453 internalDepends << " " << i->c_str() << std::endl;
455 makeDepends << std::endl;
457 // Write module requirements to the output stream.
458 for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
459 i != info.Requires.end(); ++i)
461 // Require only modules not provided in the same source.
462 if(std::set<cmStdString>::const_iterator(info.Provides.find(*i)) !=
463 info.Provides.end())
465 continue;
468 // If the module is provided in this target special handling is
469 // needed.
470 if(this->Internal->TargetProvides.find(*i) !=
471 this->Internal->TargetProvides.end())
473 // The module is provided by a different source in the same
474 // target. Add the proxy dependency to make sure the other
475 // source builds first.
476 std::string proxy = stamp_dir;
477 proxy += "/";
478 proxy += *i;
479 proxy += ".mod.proxy";
480 proxy = this->LocalGenerator->Convert(proxy.c_str(),
481 cmLocalGenerator::HOME_OUTPUT,
482 cmLocalGenerator::MAKEFILE);
484 // since we require some things add them to our list of requirements
485 makeDepends << obj << ".requires: " << proxy << std::endl;
488 // The object file should depend on timestamped files for the
489 // modules it uses.
490 TargetRequiresMap::const_iterator required =
491 this->Internal->TargetRequires.find(*i);
492 if(required == this->Internal->TargetRequires.end()) { abort(); }
493 if(!required->second.empty())
495 // This module is known. Depend on its timestamp file.
496 std::string stampFile =
497 this->LocalGenerator->Convert(required->second.c_str(),
498 cmLocalGenerator::HOME_OUTPUT,
499 cmLocalGenerator::SHELL);
500 makeDepends << obj << ": " << stampFile << "\n";
502 else
504 // This module is not known to CMake. Try to locate it where
505 // the compiler will and depend on that.
506 std::string module;
507 if(this->FindModule(*i, module))
509 module =
510 this->LocalGenerator->Convert(module.c_str(),
511 cmLocalGenerator::HOME_OUTPUT,
512 cmLocalGenerator::SHELL);
513 makeDepends << obj << ": " << module << "\n";
518 // Write provided modules to the output stream.
519 for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
520 i != info.Provides.end(); ++i)
522 std::string proxy = stamp_dir;
523 proxy += "/";
524 proxy += *i;
525 proxy += ".mod.proxy";
526 proxy = this->LocalGenerator->Convert(proxy.c_str(),
527 cmLocalGenerator::HOME_OUTPUT,
528 cmLocalGenerator::MAKEFILE);
529 makeDepends << proxy << ": " << obj << ".provides" << std::endl;
532 // If any modules are provided then they must be converted to stamp files.
533 if(!info.Provides.empty())
535 // Create a target to copy the module after the object file
536 // changes.
537 makeDepends << obj << ".provides.build:\n";
538 for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
539 i != info.Provides.end(); ++i)
541 // Include this module in the set provided by this target.
542 this->Internal->TargetProvides.insert(*i);
544 // Always use lower case for the mod stamp file name. The
545 // cmake_copy_f90_mod will call back to this class, which will
546 // try various cases for the real mod file name.
547 std::string m = cmSystemTools::LowerCase(*i);
548 std::string modFile = mod_dir;
549 modFile += "/";
550 modFile += *i;
551 modFile =
552 this->LocalGenerator->Convert(modFile.c_str(),
553 cmLocalGenerator::HOME_OUTPUT,
554 cmLocalGenerator::SHELL);
555 std::string stampFile = stamp_dir;
556 stampFile += "/";
557 stampFile += m;
558 stampFile += ".mod.stamp";
559 stampFile =
560 this->LocalGenerator->Convert(stampFile.c_str(),
561 cmLocalGenerator::HOME_OUTPUT,
562 cmLocalGenerator::SHELL);
563 makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod "
564 << modFile << " " << stampFile;
565 cmMakefile* mf = this->LocalGenerator->GetMakefile();
566 const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
567 if(cid && *cid)
569 makeDepends << " " << cid;
571 makeDepends << "\n";
573 // After copying the modules update the timestamp file so that
574 // copying will not be done again until the source rebuilds.
575 makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj
576 << ".provides.build\n";
578 // Make sure the module timestamp rule is evaluated by the time
579 // the target finishes building.
580 std::string driver = this->TargetDirectory;
581 driver += "/build";
582 driver = this->LocalGenerator->Convert(driver.c_str(),
583 cmLocalGenerator::HOME_OUTPUT,
584 cmLocalGenerator::MAKEFILE);
585 makeDepends << driver << ": " << obj << ".provides.build\n";
588 return true;
591 //----------------------------------------------------------------------------
592 bool cmDependsFortran::FindModule(std::string const& name,
593 std::string& module)
595 // Construct possible names for the module file.
596 std::string mod_upper = cmSystemTools::UpperCase(name);
597 std::string mod_lower = name;
598 mod_upper += ".mod";
599 mod_lower += ".mod";
601 // Search the include path for the module.
602 std::string fullName;
603 for(std::vector<std::string>::const_iterator i =
604 this->IncludePath.begin(); i != this->IncludePath.end(); ++i)
606 // Try the lower-case name.
607 fullName = *i;
608 fullName += "/";
609 fullName += mod_lower;
610 if(cmSystemTools::FileExists(fullName.c_str(), true))
612 module = fullName;
613 return true;
616 // Try the upper-case name.
617 fullName = *i;
618 fullName += "/";
619 fullName += mod_upper;
620 if(cmSystemTools::FileExists(fullName.c_str(), true))
622 module = fullName;
623 return true;
626 return false;
629 //----------------------------------------------------------------------------
630 bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
632 // Implements
634 // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
635 // [compiler-id]
637 // Note that the case of the .mod file depends on the compiler. In
638 // the future this copy could also account for the fact that some
639 // compilers include a timestamp in the .mod file so it changes even
640 // when the interface described in the module does not.
642 std::string mod = args[2];
643 std::string stamp = args[3];
644 std::string compilerId;
645 if(args.size() >= 5)
647 compilerId = args[4];
649 std::string mod_dir = cmSystemTools::GetFilenamePath(mod);
650 if(!mod_dir.empty()) { mod_dir += "/"; }
651 std::string mod_upper = mod_dir;
652 mod_upper += cmSystemTools::UpperCase(cmSystemTools::GetFilenameName(mod));
653 std::string mod_lower = mod_dir;
654 mod_lower += cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(mod));
655 mod += ".mod";
656 mod_upper += ".mod";
657 mod_lower += ".mod";
658 if(cmSystemTools::FileExists(mod_upper.c_str(), true))
660 if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(),
661 compilerId.c_str()))
663 if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str()))
665 std::cerr << "Error copying Fortran module from \""
666 << mod_upper.c_str() << "\" to \"" << stamp.c_str()
667 << "\".\n";
668 return false;
671 return true;
673 else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
675 if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(),
676 compilerId.c_str()))
678 if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str()))
680 std::cerr << "Error copying Fortran module from \""
681 << mod_lower.c_str() << "\" to \"" << stamp.c_str()
682 << "\".\n";
683 return false;
686 return true;
689 std::cerr << "Error copying Fortran module \"" << args[2].c_str()
690 << "\". Tried \"" << mod_upper.c_str()
691 << "\" and \"" << mod_lower.c_str() << "\".\n";
692 return false;
695 //----------------------------------------------------------------------------
696 // Helper function to look for a short sequence in a stream. If this
697 // is later used for longer sequences it should be re-written using an
698 // efficient string search algorithm such as Boyer-Moore.
699 static
700 bool cmDependsFortranStreamContainsSequence(std::ifstream& ifs,
701 const char* seq, int len)
703 assert(len > 0);
705 int cur = 0;
706 while(cur < len)
708 // Get the next character.
709 int token = ifs.get();
710 if(!ifs)
712 return false;
715 // Check the character.
716 if(token == static_cast<int>(seq[cur]))
718 ++cur;
720 else
722 // Assume the sequence has no repeating subsequence.
723 cur = 0;
727 // The entire sequence was matched.
728 return true;
731 //----------------------------------------------------------------------------
732 // Helper function to compare the remaining content in two streams.
733 static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
734 std::ifstream& ifs2)
736 // Compare the remaining content.
737 for(;;)
739 int ifs1_c = ifs1.get();
740 int ifs2_c = ifs2.get();
741 if(!ifs1 && !ifs2)
743 // We have reached the end of both streams simultaneously.
744 // The streams are identical.
745 return false;
748 if(!ifs1 || !ifs2 || ifs1_c != ifs2_c)
750 // We have reached the end of one stream before the other or
751 // found differing content. The streams are different.
752 break;
756 return true;
759 //----------------------------------------------------------------------------
760 bool cmDependsFortran::ModulesDiffer(const char* modFile,
761 const char* stampFile,
762 const char* compilerId)
765 gnu:
766 A mod file is an ascii file.
767 <bar.mod>
768 FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
769 If you edit this, you'll get what you deserve.
771 </bar.mod>
772 As you can see the first line contains the date.
774 intel:
775 A mod file is a binary file.
776 However, looking into both generated bar.mod files with a hex editor
777 shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
778 which is located some bytes in front of the absoulte path to the source
779 file.
781 sun:
782 A mod file is a binary file. Compiling twice produces identical modules.
784 others:
785 TODO ...
789 /* Compilers which do _not_ produce different mod content when the same
790 * source is compiled twice
791 * -SunPro
793 if(strcmp(compilerId, "SunPro") == 0)
795 return cmSystemTools::FilesDiffer(modFile, stampFile);
798 #if defined(_WIN32) || defined(__CYGWIN__)
799 std::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
800 std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
801 #else
802 std::ifstream finModFile(modFile, std::ios::in);
803 std::ifstream finStampFile(stampFile, std::ios::in);
804 #endif
805 if(!finModFile || !finStampFile)
807 // At least one of the files does not exist. The modules differ.
808 return true;
811 /* Compilers which _do_ produce different mod content when the same
812 * source is compiled twice
813 * -GNU
814 * -Intel
816 * Eat the stream content until all recompile only realated changes
817 * are left bedind.
819 if (strcmp(compilerId, "GNU") == 0 )
821 const char seq[1] = {'\n'};
822 const int seqlen = 1;
824 if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
826 // The module is of unexpected format. Assume it is different.
827 std::cerr << compilerId << " fortran module " << modFile
828 << " has unexpected format." << std::endl;
829 return true;
832 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
834 // The stamp must differ if the sequence is not contained.
835 return true;
838 else if(strcmp(compilerId, "Intel") == 0)
840 const char seq[2] = {'\n', '\0'};
841 const int seqlen = 2;
843 if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
845 // The module is of unexpected format. Assume it is different.
846 std::cerr << compilerId << " fortran module " << modFile
847 << " has unexpected format." << std::endl;
848 return true;
851 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
853 // The stamp must differ if the sequence is not contained.
854 return true;
858 // Compare the remainng content. If no compiler id matched above,
859 // including the case none was given, this will compare the whole
860 // content.
861 if(!cmDependsFortranStreamsDiffer(finModFile, finStampFile))
863 return false;
866 // The modules are different.
867 return true;
870 //----------------------------------------------------------------------------
871 bool cmDependsFortran::FindIncludeFile(const char* dir,
872 const char* includeName,
873 std::string& fileName)
875 // If the file is a full path, include it directly.
876 if(cmSystemTools::FileIsFullPath(includeName))
878 fileName = includeName;
879 return cmSystemTools::FileExists(fileName.c_str(), true);
881 else
883 // Check for the file in the directory containing the including
884 // file.
885 std::string fullName = dir;
886 fullName += "/";
887 fullName += includeName;
888 if(cmSystemTools::FileExists(fullName.c_str(), true))
890 fileName = fullName;
891 return true;
894 // Search the include path for the file.
895 for(std::vector<std::string>::const_iterator i =
896 this->IncludePath.begin(); i != this->IncludePath.end(); ++i)
898 fullName = *i;
899 fullName += "/";
900 fullName += includeName;
901 if(cmSystemTools::FileExists(fullName.c_str(), true))
903 fileName = fullName;
904 return true;
908 return false;
911 //----------------------------------------------------------------------------
912 cmDependsFortranParser_s
913 ::cmDependsFortranParser_s(cmDependsFortran* self,
914 std::set<std::string>& ppDefines,
915 cmDependsFortranSourceInfo& info):
916 Self(self), PPDefinitions(ppDefines), Info(info)
918 this->InInterface = 0;
919 this->InPPFalseBranch = 0;
921 // Initialize the lexical scanner.
922 cmDependsFortran_yylex_init(&this->Scanner);
923 cmDependsFortran_yyset_extra(this, this->Scanner);
925 // Create a dummy buffer that is never read but is the fallback
926 // buffer when the last file is popped off the stack.
927 YY_BUFFER_STATE buffer =
928 cmDependsFortran_yy_create_buffer(0, 4, this->Scanner);
929 cmDependsFortran_yy_switch_to_buffer(buffer, this->Scanner);
932 //----------------------------------------------------------------------------
933 cmDependsFortranParser_s::~cmDependsFortranParser_s()
935 cmDependsFortran_yylex_destroy(this->Scanner);
938 //----------------------------------------------------------------------------
939 bool cmDependsFortranParser_FilePush(cmDependsFortranParser* parser,
940 const char* fname)
942 // Open the new file and push it onto the stack. Save the old
943 // buffer with it on the stack.
944 if(FILE* file = fopen(fname, "rb"))
946 YY_BUFFER_STATE current =
947 cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
948 std::string dir = cmSystemTools::GetParentDirectory(fname);
949 cmDependsFortranFile f(file, current, dir);
950 YY_BUFFER_STATE buffer =
951 cmDependsFortran_yy_create_buffer(0, 16384, parser->Scanner);
952 cmDependsFortran_yy_switch_to_buffer(buffer, parser->Scanner);
953 parser->FileStack.push(f);
954 return 1;
956 else
958 return 0;
962 //----------------------------------------------------------------------------
963 bool cmDependsFortranParser_FilePop(cmDependsFortranParser* parser)
965 // Pop one file off the stack and close it. Switch the lexer back
966 // to the next one on the stack.
967 if(parser->FileStack.empty())
969 return 0;
971 else
973 cmDependsFortranFile f = parser->FileStack.top(); parser->FileStack.pop();
974 fclose(f.File);
975 YY_BUFFER_STATE current =
976 cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
977 cmDependsFortran_yy_delete_buffer(current, parser->Scanner);
978 cmDependsFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
979 return 1;
983 //----------------------------------------------------------------------------
984 int cmDependsFortranParser_Input(cmDependsFortranParser* parser,
985 char* buffer, size_t bufferSize)
987 // Read from the file on top of the stack. If the stack is empty,
988 // the end of the translation unit has been reached.
989 if(!parser->FileStack.empty())
991 FILE* file = parser->FileStack.top().File;
992 return (int)fread(buffer, 1, bufferSize, file);
994 return 0;
997 //----------------------------------------------------------------------------
998 void cmDependsFortranParser_StringStart(cmDependsFortranParser* parser)
1000 parser->TokenString = "";
1003 //----------------------------------------------------------------------------
1004 const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser* parser)
1006 return parser->TokenString.c_str();
1009 //----------------------------------------------------------------------------
1010 void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
1011 char c)
1013 parser->TokenString += c;
1016 //----------------------------------------------------------------------------
1017 void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
1018 bool in)
1020 if(parser->InPPFalseBranch)
1022 return;
1025 parser->InInterface = in;
1028 //----------------------------------------------------------------------------
1029 bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
1031 return parser->InInterface;
1034 //----------------------------------------------------------------------------
1035 void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
1036 int arg)
1038 parser->OldStartcond = arg;
1041 //----------------------------------------------------------------------------
1042 int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser* parser)
1044 return parser->OldStartcond;
1047 //----------------------------------------------------------------------------
1048 void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
1050 // If there is a parser error just ignore it. The source will not
1051 // compile and the user will edit it. Then dependencies will have
1052 // to be regenerated anyway.
1055 //----------------------------------------------------------------------------
1056 void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
1057 const char* name)
1059 if(!parser->InPPFalseBranch)
1061 parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
1065 //----------------------------------------------------------------------------
1066 void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
1067 const char* name)
1069 if(parser->InPPFalseBranch)
1071 return;
1074 // If processing an include statement there must be an open file.
1075 assert(!parser->FileStack.empty());
1077 // Get the directory containing the source in which the include
1078 // statement appears. This is always the first search location for
1079 // Fortran include files.
1080 std::string dir = parser->FileStack.top().Directory;
1082 // Find the included file. If it cannot be found just ignore the
1083 // problem because either the source will not compile or the user
1084 // does not care about depending on this included source.
1085 std::string fullName;
1086 if(parser->Self->FindIncludeFile(dir.c_str(), name, fullName))
1088 // Found the included file. Save it in the set of included files.
1089 parser->Info.Includes.insert(fullName);
1091 // Parse it immediately to translate the source inline.
1092 cmDependsFortranParser_FilePush(parser, fullName.c_str());
1096 //----------------------------------------------------------------------------
1097 void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
1098 const char* name)
1100 if(!parser->InPPFalseBranch && !parser->InInterface)
1102 parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
1106 //----------------------------------------------------------------------------
1107 void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
1108 const char* macro)
1110 if(!parser->InPPFalseBranch)
1112 parser->PPDefinitions.insert(macro);
1116 //----------------------------------------------------------------------------
1117 void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
1118 const char* macro)
1120 if(!parser->InPPFalseBranch)
1122 std::set<std::string>::iterator match;
1123 match = parser->PPDefinitions.find(macro);
1124 if(match != parser->PPDefinitions.end())
1126 parser->PPDefinitions.erase(match);
1131 //----------------------------------------------------------------------------
1132 void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser* parser,
1133 const char* macro)
1135 // A new PP branch has been opened
1136 parser->SkipToEnd.push(false);
1138 if (parser->InPPFalseBranch)
1140 parser->InPPFalseBranch++;
1142 else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end())
1144 parser->InPPFalseBranch=1;
1146 else
1148 parser->SkipToEnd.top() = true;
1152 //----------------------------------------------------------------------------
1153 void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
1154 const char* macro)
1156 // A new PP branch has been opened
1157 parser->SkipToEnd.push(false);
1159 if (parser->InPPFalseBranch)
1161 parser->InPPFalseBranch++;
1163 else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end())
1165 parser->InPPFalseBranch = 1;
1167 else
1169 // ignore other branches
1170 parser->SkipToEnd.top() = true;
1174 //----------------------------------------------------------------------------
1175 void cmDependsFortranParser_RuleIf(cmDependsFortranParser* parser)
1177 /* Note: The current parser is _not_ able to get statements like
1178 * #if 0
1179 * #if 1
1180 * #if MYSMBOL
1181 * #if defined(MYSYMBOL)
1182 * #if defined(MYSYMBOL) && ...
1183 * right. The same for #elif. Thus in
1184 * #if SYMBOL_1
1185 * ..
1186 * #elif SYMBOL_2
1187 * ...
1188 * ...
1189 * #elif SYMBOL_N
1190 * ..
1191 * #else
1192 * ..
1193 * #endif
1194 * _all_ N+1 branches are considered. If you got something like this
1195 * #if defined(MYSYMBOL)
1196 * #if !defined(MYSYMBOL)
1197 * use
1198 * #ifdef MYSYMBOL
1199 * #ifndef MYSYMBOL
1200 * instead.
1203 // A new PP branch has been opened
1204 // Never skip! See note above.
1205 parser->SkipToEnd.push(false);
1208 //----------------------------------------------------------------------------
1209 void cmDependsFortranParser_RuleElif(cmDependsFortranParser* parser)
1211 /* Note: There are parser limitations. See the note at
1212 * cmDependsFortranParser_RuleIf(..)
1215 // Allways taken unless an #ifdef or #ifndef-branch has been taken
1216 // already. If the second condition isn't meet already
1217 // (parser->InPPFalseBranch == 0) correct it.
1218 if(!parser->SkipToEnd.empty() &&
1219 parser->SkipToEnd.top() && !parser->InPPFalseBranch)
1221 parser->InPPFalseBranch = 1;
1225 //----------------------------------------------------------------------------
1226 void cmDependsFortranParser_RuleElse(cmDependsFortranParser* parser)
1228 // if the parent branch is false do nothing!
1229 if(parser->InPPFalseBranch > 1)
1231 return;
1234 // parser->InPPFalseBranch is either 0 or 1. We change it denpending on
1235 // parser->SkipToEnd.top()
1236 if(!parser->SkipToEnd.empty() &&
1237 parser->SkipToEnd.top())
1239 parser->InPPFalseBranch = 1;
1241 else
1243 parser->InPPFalseBranch = 0;
1247 //----------------------------------------------------------------------------
1248 void cmDependsFortranParser_RuleEndif(cmDependsFortranParser* parser)
1250 if(!parser->SkipToEnd.empty())
1252 parser->SkipToEnd.pop();
1255 // #endif doesn't know if there was a "#else" in before, so it
1256 // always decreases InPPFalseBranch
1257 if(parser->InPPFalseBranch)
1259 parser->InPPFalseBranch--;