Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmDependsFortran.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmDependsFortran.h"
13
14 #include "cmSystemTools.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMakefile.h"
17 #include "cmGeneratedFileStream.h"
18
19 #include "cmDependsFortranParser.h" /* Interface to parser object.  */
20
21 #include <assert.h>
22 #include <stack>
23
24 // TODO: Test compiler for the case of the mod file.  Some always
25 // use lower case and some always use upper case.  I do not know if any
26 // use the case from the source code.
27
28 //----------------------------------------------------------------------------
29 // Information about a single source file.
30 class cmDependsFortranSourceInfo
31 {
32 public:
33   // The name of the source file.
34   std::string Source;
35
36   // Set of provided and required modules.
37   std::set<cmStdString> Provides;
38   std::set<cmStdString> Requires;
39
40   // Set of files included in the translation unit.
41   std::set<cmStdString> Includes;
42 };
43
44 //----------------------------------------------------------------------------
45 // Parser methods not included in generated interface.
46
47 // Get the current buffer processed by the lexer.
48 YY_BUFFER_STATE cmDependsFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
49
50 // The parser entry point.
51 int cmDependsFortran_yyparse(yyscan_t);
52
53 //----------------------------------------------------------------------------
54 // Define parser object internal structure.
55 struct cmDependsFortranFile
56 {
57   cmDependsFortranFile(FILE* file, YY_BUFFER_STATE buffer,
58                        const std::string& dir):
59     File(file), Buffer(buffer), Directory(dir) {}
60   FILE* File;
61   YY_BUFFER_STATE Buffer;
62   std::string Directory;
63 };
64
65 struct cmDependsFortranParser_s
66 {
67   cmDependsFortranParser_s(cmDependsFortran* self,
68                            std::set<std::string>& ppDefines,
69                            cmDependsFortranSourceInfo& info);
70   ~cmDependsFortranParser_s();
71
72   // Pointer back to the main class.
73   cmDependsFortran* Self;
74
75   // Lexical scanner instance.
76   yyscan_t Scanner;
77
78   // Stack of open files in the translation unit.
79   std::stack<cmDependsFortranFile> FileStack;
80
81   // Buffer for string literals.
82   std::string TokenString;
83
84   // Flag for whether lexer is reading from inside an interface.
85   bool InInterface;
86
87   int OldStartcond;
88   std::set<std::string> PPDefinitions;
89   size_t InPPFalseBranch;
90   std::stack<bool> SkipToEnd;
91
92   // Information about the parsed source.
93   cmDependsFortranSourceInfo& Info;
94 };
95
96 //----------------------------------------------------------------------------
97 class cmDependsFortranInternals
98 {
99 public:
100   // The set of modules provided by this target.
101   std::set<cmStdString> TargetProvides;
102
103   // Map modules required by this target to locations.
104   typedef std::map<cmStdString, cmStdString> TargetRequiresMap;
105   TargetRequiresMap TargetRequires;
106
107   // Information about each object file.
108   typedef std::map<cmStdString, cmDependsFortranSourceInfo> ObjectInfoMap;
109   ObjectInfoMap ObjectInfo;
110
111   cmDependsFortranSourceInfo& CreateObjectInfo(const char* obj,
112                                                const char* src)
113     {
114     std::map<cmStdString, cmDependsFortranSourceInfo>::iterator i =
115       this->ObjectInfo.find(obj);
116     if(i == this->ObjectInfo.end())
117       {
118       std::map<cmStdString, cmDependsFortranSourceInfo>::value_type
119         entry(obj, cmDependsFortranSourceInfo());
120       i = this->ObjectInfo.insert(entry).first;
121       i->second.Source = src;
122       }
123     return i->second;
124     }
125 };
126
127 //----------------------------------------------------------------------------
128 cmDependsFortran::cmDependsFortran():
129   PPDefinitions(0), Internal(0)
130 {
131 }
132
133 //----------------------------------------------------------------------------
134 cmDependsFortran
135 ::cmDependsFortran(cmLocalGenerator* lg):
136   cmDepends(lg),
137   Internal(new cmDependsFortranInternals)
138 {
139   // Configure the include file search path.
140   this->SetIncludePathFromLanguage("Fortran");
141
142   // Get the list of definitions.
143   std::vector<std::string> definitions;
144   cmMakefile* mf = this->LocalGenerator->GetMakefile();
145   if(const char* c_defines =
146      mf->GetDefinition("CMAKE_TARGET_DEFINITIONS"))
147     {
148     cmSystemTools::ExpandListArgument(c_defines, definitions);
149     }
150
151   // translate i.e. FOO=BAR to FOO and add it to the list of defined
152   // preprocessor symbols
153   for(std::vector<std::string>::const_iterator
154       it = definitions.begin(); it != definitions.end(); ++it)
155     {
156     std::string def = *it;
157     std::string::size_type assignment = def.find("=");
158     if(assignment != std::string::npos)
159       {
160       def = it->substr(0, assignment);
161       }
162     this->PPDefinitions.push_back(def);
163     }
164 }
165
166 //----------------------------------------------------------------------------
167 cmDependsFortran::~cmDependsFortran()
168 {
169   delete this->Internal;
170 }
171
172 //----------------------------------------------------------------------------
173 bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
174                                          std::ostream&, std::ostream&)
175 {
176   // Make sure this is a scanning instance.
177   if(!src || src[0] == '\0')
178     {
179     cmSystemTools::Error("Cannot scan dependencies without an source file.");
180     return false;
181     }
182   if(!obj || obj[0] == '\0')
183     {
184     cmSystemTools::Error("Cannot scan dependencies without an object file.");
185     return false;
186     }
187
188   // Get the information object for this source.
189   cmDependsFortranSourceInfo& info =
190     this->Internal->CreateObjectInfo(obj, src);
191
192   // Make a copy of the macros defined via ADD_DEFINITIONS
193   std::set<std::string> ppDefines(this->PPDefinitions.begin(),
194                                   this->PPDefinitions.end());
195
196   // Create the parser object. The constructor takes ppMacro and info per
197   // reference, so we may look into the resulting objects later.
198   cmDependsFortranParser parser(this, ppDefines, info);
199
200   // Push on the starting file.
201   cmDependsFortranParser_FilePush(&parser, src);
202
203   // Parse the translation unit.
204   if(cmDependsFortran_yyparse(parser.Scanner) != 0)
205     {
206     // Failed to parse the file.  Report failure to write dependencies.
207     return false;
208     }
209
210   return true;
211 }
212
213 //----------------------------------------------------------------------------
214 bool cmDependsFortran::Finalize(std::ostream& makeDepends,
215                                 std::ostream& internalDepends)
216 {
217   // Prepare the module search process.
218   this->LocateModules();
219
220   // Get the directory in which stamp files will be stored.
221   const char* stamp_dir = this->TargetDirectory.c_str();
222
223   // Get the directory in which module files will be created.
224   const char* mod_dir;
225   cmMakefile* mf = this->LocalGenerator->GetMakefile();
226   if(const char* target_mod_dir =
227      mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
228     {
229     mod_dir = target_mod_dir;
230     }
231   else
232     {
233     mod_dir =
234       this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
235     }
236
237   // Actually write dependencies to the streams.
238   typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
239   ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
240   for(ObjectInfoMap::const_iterator i = objInfo.begin();
241       i != objInfo.end(); ++i)
242     {
243     if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
244                                     mod_dir, stamp_dir,
245                                     makeDepends, internalDepends))
246       {
247       return false;
248       }
249     }
250
251   // Store the list of modules provided by this target.
252   std::string fiName = this->TargetDirectory;
253   fiName += "/fortran.internal";
254   cmGeneratedFileStream fiStream(fiName.c_str());
255   fiStream << "# The fortran modules provided by this target.\n";
256   fiStream << "provides\n";
257   std::set<cmStdString> const& provides = this->Internal->TargetProvides;
258   for(std::set<cmStdString>::const_iterator i = provides.begin();
259       i != provides.end(); ++i)
260     {
261     fiStream << " " << *i << "\n";
262     }
263
264   // Create a script to clean the modules.
265   if(!provides.empty())
266     {
267     std::string fcName = this->TargetDirectory;
268     fcName += "/cmake_clean_Fortran.cmake";
269     cmGeneratedFileStream fcStream(fcName.c_str());
270     fcStream << "# Remove fortran modules provided by this target.\n";
271     fcStream << "FILE(REMOVE";
272     for(std::set<cmStdString>::const_iterator i = provides.begin();
273         i != provides.end(); ++i)
274       {
275       std::string mod_upper = mod_dir;
276       mod_upper += "/";
277       mod_upper += cmSystemTools::UpperCase(*i);
278       mod_upper += ".mod";
279       std::string mod_lower = mod_dir;
280       mod_lower += "/";
281       mod_lower += *i;
282       mod_lower += ".mod";
283       std::string stamp = stamp_dir;
284       stamp += "/";
285       stamp += *i;
286       stamp += ".mod.stamp";
287       fcStream << "\n";
288       fcStream << "  \"" <<
289         this->LocalGenerator->Convert(mod_lower.c_str(),
290                                       cmLocalGenerator::START_OUTPUT)
291                << "\"\n";
292       fcStream << "  \"" <<
293         this->LocalGenerator->Convert(mod_upper.c_str(),
294                                       cmLocalGenerator::START_OUTPUT)
295                << "\"\n";
296       fcStream << "  \"" <<
297         this->LocalGenerator->Convert(stamp.c_str(),
298                                       cmLocalGenerator::START_OUTPUT)
299                << "\"\n";
300       }
301     fcStream << "  )\n";
302     }
303   return true;
304 }
305
306 //----------------------------------------------------------------------------
307 void cmDependsFortran::LocateModules()
308 {
309   // Collect the set of modules provided and required by all sources.
310   typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
311   ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
312   for(ObjectInfoMap::const_iterator infoI = objInfo.begin();
313       infoI != objInfo.end(); ++infoI)
314     {
315     cmDependsFortranSourceInfo const& info = infoI->second;
316     for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
317         i != info.Provides.end(); ++i)
318       {
319       // Include this module in the set provided by this target.
320       this->Internal->TargetProvides.insert(*i);
321       }
322
323     for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
324         i != info.Requires.end(); ++i)
325       {
326       // Include this module in the set required by this target.
327       this->Internal->TargetRequires[*i] = "";
328       }
329     }
330
331   // Short-circuit for simple targets.
332   if(this->Internal->TargetRequires.empty())
333     {
334     return;
335     }
336
337   // Match modules provided by this target to those it requires.
338   this->MatchLocalModules();
339
340   // Load information about other targets.
341   cmMakefile* mf = this->LocalGenerator->GetMakefile();
342   std::vector<std::string> infoFiles;
343   if(const char* infoFilesValue =
344      mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES"))
345     {
346     cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
347     }
348   for(std::vector<std::string>::const_iterator i = infoFiles.begin();
349       i != infoFiles.end(); ++i)
350     {
351     std::string targetDir = cmSystemTools::GetFilenamePath(*i);
352     std::string fname = targetDir + "/fortran.internal";
353     std::ifstream fin(fname.c_str());
354     if(fin)
355       {
356       this->MatchRemoteModules(fin, targetDir.c_str());
357       }
358     }
359 }
360
361 //----------------------------------------------------------------------------
362 void cmDependsFortran::MatchLocalModules()
363 {
364   const char* stampDir = this->TargetDirectory.c_str();
365   std::set<cmStdString> const& provides = this->Internal->TargetProvides;
366   for(std::set<cmStdString>::const_iterator i = provides.begin();
367       i != provides.end(); ++i)
368     {
369     this->ConsiderModule(i->c_str(), stampDir);
370     }
371 }
372
373 //----------------------------------------------------------------------------
374 void cmDependsFortran::MatchRemoteModules(std::istream& fin,
375                                           const char* stampDir)
376 {
377   std::string line;
378   bool doing_provides = false;
379   while(cmSystemTools::GetLineFromStream(fin, line))
380     {
381     // Ignore comments and empty lines.
382     if(line.empty() || line[0] == '#' || line[0] == '\r')
383       {
384       continue;
385       }
386
387     if(line[0] == ' ')
388       {
389       if(doing_provides)
390         {
391         this->ConsiderModule(line.c_str()+1, stampDir);
392         }
393       }
394     else if(line == "provides")
395       {
396       doing_provides = true;
397       }
398     else
399       {
400       doing_provides = false;
401       }
402     }
403 }
404
405 //----------------------------------------------------------------------------
406 void cmDependsFortran::ConsiderModule(const char* name,
407                                       const char* stampDir)
408 {
409   // Locate each required module.
410   typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
411   TargetRequiresMap::iterator required =
412     this->Internal->TargetRequires.find(name);
413   if(required != this->Internal->TargetRequires.end() &&
414      required->second.empty())
415     {
416     // The module is provided by a CMake target.  It will have a stamp file.
417     std::string stampFile = stampDir;
418     stampFile += "/";
419     stampFile += name;
420     stampFile += ".mod.stamp";
421     required->second = stampFile;
422     }
423 }
424
425 //----------------------------------------------------------------------------
426 bool
427 cmDependsFortran
428 ::WriteDependenciesReal(const char *obj,
429                         cmDependsFortranSourceInfo const& info,
430                         const char* mod_dir, const char* stamp_dir,
431                         std::ostream& makeDepends,
432                         std::ostream& internalDepends)
433 {
434   typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
435
436   // Get the source file for this object.
437   const char* src = info.Source.c_str();
438
439   // Write the include dependencies to the output stream.
440   internalDepends << obj << std::endl;
441   internalDepends << " " << src << std::endl;
442   for(std::set<cmStdString>::const_iterator i = info.Includes.begin();
443       i != info.Includes.end(); ++i)
444     {
445     makeDepends << obj << ": " <<
446       this->LocalGenerator->Convert(i->c_str(),
447                                     cmLocalGenerator::HOME_OUTPUT,
448                                     cmLocalGenerator::MAKEFILE)
449                 << std::endl;
450     internalDepends << " " << i->c_str() << std::endl;
451     }
452   makeDepends << std::endl;
453
454   // Write module requirements to the output stream.
455   for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
456       i != info.Requires.end(); ++i)
457     {
458     // Require only modules not provided in the same source.
459     if(std::set<cmStdString>::const_iterator(info.Provides.find(*i)) !=
460        info.Provides.end())
461       {
462       continue;
463       }
464
465     // If the module is provided in this target special handling is
466     // needed.
467     if(this->Internal->TargetProvides.find(*i) !=
468        this->Internal->TargetProvides.end())
469       {
470       // The module is provided by a different source in the same
471       // target.  Add the proxy dependency to make sure the other
472       // source builds first.
473       std::string proxy = stamp_dir;
474       proxy += "/";
475       proxy += *i;
476       proxy += ".mod.proxy";
477       proxy = this->LocalGenerator->Convert(proxy.c_str(),
478                                             cmLocalGenerator::HOME_OUTPUT,
479                                             cmLocalGenerator::MAKEFILE);
480
481       // since we require some things add them to our list of requirements
482       makeDepends << obj << ".requires: " << proxy << std::endl;
483       }
484
485     // The object file should depend on timestamped files for the
486     // modules it uses.
487     TargetRequiresMap::const_iterator required =
488       this->Internal->TargetRequires.find(*i);
489     if(required == this->Internal->TargetRequires.end()) { abort(); }
490     if(!required->second.empty())
491       {
492       // This module is known.  Depend on its timestamp file.
493       std::string stampFile =
494         this->LocalGenerator->Convert(required->second.c_str(),
495                                       cmLocalGenerator::HOME_OUTPUT,
496                                       cmLocalGenerator::MAKEFILE);
497       makeDepends << obj << ": " << stampFile << "\n";
498       }
499     else
500       {
501       // This module is not known to CMake.  Try to locate it where
502       // the compiler will and depend on that.
503       std::string module;
504       if(this->FindModule(*i, module))
505         {
506         module =
507           this->LocalGenerator->Convert(module.c_str(),
508                                         cmLocalGenerator::HOME_OUTPUT,
509                                         cmLocalGenerator::MAKEFILE);
510         makeDepends << obj << ": " << module << "\n";
511         }
512       }
513     }
514
515   // Write provided modules to the output stream.
516   for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
517       i != info.Provides.end(); ++i)
518     {
519     std::string proxy = stamp_dir;
520     proxy += "/";
521     proxy += *i;
522     proxy += ".mod.proxy";
523     proxy = this->LocalGenerator->Convert(proxy.c_str(),
524                                           cmLocalGenerator::HOME_OUTPUT,
525                                           cmLocalGenerator::MAKEFILE);
526     makeDepends << proxy << ": " << obj << ".provides" << std::endl;
527     }
528
529   // If any modules are provided then they must be converted to stamp files.
530   if(!info.Provides.empty())
531     {
532     // Create a target to copy the module after the object file
533     // changes.
534     makeDepends << obj << ".provides.build:\n";
535     for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
536         i != info.Provides.end(); ++i)
537       {
538       // Include this module in the set provided by this target.
539       this->Internal->TargetProvides.insert(*i);
540
541       // Always use lower case for the mod stamp file name.  The
542       // cmake_copy_f90_mod will call back to this class, which will
543       // try various cases for the real mod file name.
544       std::string m = cmSystemTools::LowerCase(*i);
545       std::string modFile = mod_dir;
546       modFile += "/";
547       modFile += *i;
548       modFile =
549         this->LocalGenerator->Convert(modFile.c_str(),
550                                       cmLocalGenerator::HOME_OUTPUT,
551                                       cmLocalGenerator::SHELL);
552       std::string stampFile = stamp_dir;
553       stampFile += "/";
554       stampFile += m;
555       stampFile += ".mod.stamp";
556       stampFile =
557         this->LocalGenerator->Convert(stampFile.c_str(),
558                                       cmLocalGenerator::HOME_OUTPUT,
559                                       cmLocalGenerator::SHELL);
560       makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod "
561                   << modFile << " " << stampFile;
562       cmMakefile* mf = this->LocalGenerator->GetMakefile();
563       const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
564       if(cid && *cid)
565         {
566         makeDepends << " " << cid;
567         }
568       makeDepends << "\n";
569       }
570     // After copying the modules update the timestamp file so that
571     // copying will not be done again until the source rebuilds.
572     makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj
573                 << ".provides.build\n";
574
575     // Make sure the module timestamp rule is evaluated by the time
576     // the target finishes building.
577     std::string driver = this->TargetDirectory;
578     driver += "/build";
579     driver = this->LocalGenerator->Convert(driver.c_str(),
580                                            cmLocalGenerator::HOME_OUTPUT,
581                                            cmLocalGenerator::MAKEFILE);
582     makeDepends << driver << ": " << obj << ".provides.build\n";
583     }
584
585   return true;
586 }
587
588 //----------------------------------------------------------------------------
589 bool cmDependsFortran::FindModule(std::string const& name,
590                                   std::string& module)
591 {
592   // Construct possible names for the module file.
593   std::string mod_upper = cmSystemTools::UpperCase(name);
594   std::string mod_lower = name;
595   mod_upper += ".mod";
596   mod_lower += ".mod";
597
598   // Search the include path for the module.
599   std::string fullName;
600   for(std::vector<std::string>::const_iterator i =
601         this->IncludePath.begin(); i != this->IncludePath.end(); ++i)
602     {
603     // Try the lower-case name.
604     fullName = *i;
605     fullName += "/";
606     fullName += mod_lower;
607     if(cmSystemTools::FileExists(fullName.c_str(), true))
608       {
609       module = fullName;
610       return true;
611       }
612
613     // Try the upper-case name.
614     fullName = *i;
615     fullName += "/";
616     fullName += mod_upper;
617     if(cmSystemTools::FileExists(fullName.c_str(), true))
618       {
619       module = fullName;
620       return true;
621       }
622     }
623   return false;
624 }
625
626 //----------------------------------------------------------------------------
627 bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
628 {
629   // Implements
630   //
631   //   $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
632   //                                          [compiler-id]
633   //
634   // Note that the case of the .mod file depends on the compiler.  In
635   // the future this copy could also account for the fact that some
636   // compilers include a timestamp in the .mod file so it changes even
637   // when the interface described in the module does not.
638
639   std::string mod = args[2];
640   std::string stamp = args[3];
641   std::string compilerId;
642   if(args.size() >= 5)
643     {
644     compilerId = args[4];
645     }
646   std::string mod_dir = cmSystemTools::GetFilenamePath(mod);
647   if(!mod_dir.empty()) { mod_dir += "/"; }
648   std::string mod_upper = mod_dir;
649   mod_upper += cmSystemTools::UpperCase(cmSystemTools::GetFilenameName(mod));
650   std::string mod_lower = mod_dir;
651   mod_lower += cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(mod));
652   mod += ".mod";
653   mod_upper += ".mod";
654   mod_lower += ".mod";
655   if(cmSystemTools::FileExists(mod_upper.c_str(), true))
656     {
657     if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(),
658                                        compilerId.c_str()))
659       {
660       if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str()))
661         {
662         std::cerr << "Error copying Fortran module from \""
663                   << mod_upper.c_str() << "\" to \"" << stamp.c_str()
664                   << "\".\n";
665         return false;
666         }
667       }
668     return true;
669     }
670   else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
671     {
672     if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(),
673                                        compilerId.c_str()))
674       {
675       if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str()))
676         {
677         std::cerr << "Error copying Fortran module from \""
678                   << mod_lower.c_str() << "\" to \"" << stamp.c_str()
679                   << "\".\n";
680         return false;
681         }
682       }
683     return true;
684     }
685
686   std::cerr << "Error copying Fortran module \"" << args[2].c_str()
687             << "\".  Tried \"" << mod_upper.c_str()
688             << "\" and \"" << mod_lower.c_str() << "\".\n";
689   return false;
690 }
691
692 //----------------------------------------------------------------------------
693 // Helper function to look for a short sequence in a stream.  If this
694 // is later used for longer sequences it should be re-written using an
695 // efficient string search algorithm such as Boyer-Moore.
696 static
697 bool cmDependsFortranStreamContainsSequence(std::ifstream& ifs,
698                                             const char* seq, int len)
699 {
700   assert(len > 0);
701
702   int cur = 0;
703   while(cur < len)
704     {
705     // Get the next character.
706     int token = ifs.get();
707     if(!ifs)
708       {
709       return false;
710       }
711
712     // Check the character.
713     if(token == static_cast<int>(seq[cur]))
714       {
715       ++cur;
716       }
717     else
718       {
719       // Assume the sequence has no repeating subsequence.
720       cur = 0;
721       }
722     }
723
724   // The entire sequence was matched.
725   return true;
726 }
727
728 //----------------------------------------------------------------------------
729 // Helper function to compare the remaining content in two streams.
730 static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
731                                           std::ifstream& ifs2)
732 {
733   // Compare the remaining content.
734   for(;;)
735     {
736     int ifs1_c = ifs1.get();
737     int ifs2_c = ifs2.get();
738     if(!ifs1 && !ifs2)
739       {
740       // We have reached the end of both streams simultaneously.
741       // The streams are identical.
742       return false;
743       }
744
745     if(!ifs1 || !ifs2 || ifs1_c != ifs2_c)
746       {
747       // We have reached the end of one stream before the other or
748       // found differing content.  The streams are different.
749       break;
750       }
751     }
752
753   return true;
754 }
755
756 //----------------------------------------------------------------------------
757 bool cmDependsFortran::ModulesDiffer(const char* modFile,
758                                      const char* stampFile,
759                                      const char* compilerId)
760 {
761   /*
762   gnu:
763     A mod file is an ascii file.
764     <bar.mod>
765     FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
766     If you edit this, you'll get what you deserve.
767     ...
768     </bar.mod>
769     As you can see the first line contains the date.
770
771   intel:
772     A mod file is a binary file.
773     However, looking into both generated bar.mod files with a hex editor
774     shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
775     which is located some bytes in front of the absoulte path to the source
776     file.
777
778   sun:
779     A mod file is a binary file.  Compiling twice produces identical modules.
780
781   others:
782     TODO ...
783   */
784
785
786   /* Compilers which do _not_ produce different mod content when the same
787    * source is compiled twice
788    *   -SunPro
789    */
790   if(strcmp(compilerId, "SunPro") == 0)
791     {
792     return cmSystemTools::FilesDiffer(modFile, stampFile);
793     }
794
795 #if defined(_WIN32) || defined(__CYGWIN__)
796   std::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
797   std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
798 #else
799   std::ifstream finModFile(modFile, std::ios::in);
800   std::ifstream finStampFile(stampFile, std::ios::in);
801 #endif
802   if(!finModFile || !finStampFile)
803     {
804     // At least one of the files does not exist.  The modules differ.
805     return true;
806     }
807
808   /* Compilers which _do_ produce different mod content when the same
809    * source is compiled twice
810    *   -GNU
811    *   -Intel
812    *
813    * Eat the stream content until all recompile only related changes
814    * are left behind.
815    */
816   if (strcmp(compilerId, "GNU") == 0 )
817     {
818     const char seq[1] = {'\n'};
819     const int seqlen = 1;
820
821     if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
822       {
823       // The module is of unexpected format.  Assume it is different.
824       std::cerr << compilerId << " fortran module " << modFile
825                 << " has unexpected format." << std::endl;
826       return true;
827       }
828
829     if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
830       {
831       // The stamp must differ if the sequence is not contained.
832       return true;
833       }
834     }
835   else if(strcmp(compilerId, "Intel") == 0)
836     {
837     const char seq[2] = {'\n', '\0'};
838     const int seqlen = 2;
839
840     if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
841       {
842       // The module is of unexpected format.  Assume it is different.
843       std::cerr << compilerId << " fortran module " << modFile
844                 << " has unexpected format." << std::endl;
845       return true;
846       }
847
848     if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
849       {
850       // The stamp must differ if the sequence is not contained.
851       return true;
852       }
853     }
854
855   // Compare the remaining content.  If no compiler id matched above,
856   // including the case none was given, this will compare the whole
857   // content.
858   if(!cmDependsFortranStreamsDiffer(finModFile, finStampFile))
859     {
860     return false;
861     }
862
863    // The modules are different.
864    return true;
865 }
866
867 //----------------------------------------------------------------------------
868 bool cmDependsFortran::FindIncludeFile(const char* dir,
869                                        const char* includeName,
870                                        std::string& fileName)
871 {
872   // If the file is a full path, include it directly.
873   if(cmSystemTools::FileIsFullPath(includeName))
874     {
875     fileName = includeName;
876     return cmSystemTools::FileExists(fileName.c_str(), true);
877     }
878   else
879     {
880     // Check for the file in the directory containing the including
881     // file.
882     std::string fullName = dir;
883     fullName += "/";
884     fullName += includeName;
885     if(cmSystemTools::FileExists(fullName.c_str(), true))
886       {
887       fileName = fullName;
888       return true;
889       }
890
891     // Search the include path for the file.
892     for(std::vector<std::string>::const_iterator i = 
893           this->IncludePath.begin(); i != this->IncludePath.end(); ++i)
894       {
895       fullName = *i;
896       fullName += "/";
897       fullName += includeName;
898       if(cmSystemTools::FileExists(fullName.c_str(), true))
899         {
900         fileName = fullName;
901         return true;
902         }
903       }
904     }
905   return false;
906 }
907
908 //----------------------------------------------------------------------------
909 cmDependsFortranParser_s
910 ::cmDependsFortranParser_s(cmDependsFortran* self,
911                            std::set<std::string>& ppDefines,
912                            cmDependsFortranSourceInfo& info):
913   Self(self), PPDefinitions(ppDefines), Info(info)
914 {
915   this->InInterface = 0;
916   this->InPPFalseBranch = 0;
917
918   // Initialize the lexical scanner.
919   cmDependsFortran_yylex_init(&this->Scanner);
920   cmDependsFortran_yyset_extra(this, this->Scanner);
921
922   // Create a dummy buffer that is never read but is the fallback
923   // buffer when the last file is popped off the stack.
924   YY_BUFFER_STATE buffer =
925     cmDependsFortran_yy_create_buffer(0, 4, this->Scanner);
926   cmDependsFortran_yy_switch_to_buffer(buffer, this->Scanner);
927 }
928
929 //----------------------------------------------------------------------------
930 cmDependsFortranParser_s::~cmDependsFortranParser_s()
931 {
932   cmDependsFortran_yylex_destroy(this->Scanner);
933 }
934
935 //----------------------------------------------------------------------------
936 bool cmDependsFortranParser_FilePush(cmDependsFortranParser* parser,
937                                     const char* fname)
938 {
939   // Open the new file and push it onto the stack.  Save the old
940   // buffer with it on the stack.
941   if(FILE* file = fopen(fname, "rb"))
942     {
943     YY_BUFFER_STATE current =
944       cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
945     std::string dir = cmSystemTools::GetParentDirectory(fname);
946     cmDependsFortranFile f(file, current, dir);
947     YY_BUFFER_STATE buffer =
948       cmDependsFortran_yy_create_buffer(0, 16384, parser->Scanner);
949     cmDependsFortran_yy_switch_to_buffer(buffer, parser->Scanner);
950     parser->FileStack.push(f);
951     return 1;
952     }
953   else
954     {
955     return 0;
956     }
957 }
958
959 //----------------------------------------------------------------------------
960 bool cmDependsFortranParser_FilePop(cmDependsFortranParser* parser)
961 {
962   // Pop one file off the stack and close it.  Switch the lexer back
963   // to the next one on the stack.
964   if(parser->FileStack.empty())
965     {
966     return 0;
967     }
968   else
969     {
970     cmDependsFortranFile f = parser->FileStack.top(); parser->FileStack.pop();
971     fclose(f.File);
972     YY_BUFFER_STATE current =
973       cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
974     cmDependsFortran_yy_delete_buffer(current, parser->Scanner);
975     cmDependsFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
976     return 1;
977     }
978 }
979
980 //----------------------------------------------------------------------------
981 int cmDependsFortranParser_Input(cmDependsFortranParser* parser,
982                                  char* buffer, size_t bufferSize)
983 {
984   // Read from the file on top of the stack.  If the stack is empty,
985   // the end of the translation unit has been reached.
986   if(!parser->FileStack.empty())
987     {
988     FILE* file = parser->FileStack.top().File;
989     return (int)fread(buffer, 1, bufferSize, file);
990     }
991   return 0;
992 }
993
994 //----------------------------------------------------------------------------
995 void cmDependsFortranParser_StringStart(cmDependsFortranParser* parser)
996 {
997   parser->TokenString = "";
998 }
999
1000 //----------------------------------------------------------------------------
1001 const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser* parser)
1002 {
1003   return parser->TokenString.c_str();
1004 }
1005
1006 //----------------------------------------------------------------------------
1007 void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
1008                                          char c)
1009 {
1010   parser->TokenString += c;
1011 }
1012
1013 //----------------------------------------------------------------------------
1014 void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
1015                                            bool in)
1016 {
1017   if(parser->InPPFalseBranch)
1018     {
1019     return;
1020     }
1021
1022   parser->InInterface = in;
1023 }
1024
1025 //----------------------------------------------------------------------------
1026 bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
1027 {
1028   return parser->InInterface;
1029 }
1030
1031 //----------------------------------------------------------------------------
1032 void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
1033                                             int arg)
1034 {
1035   parser->OldStartcond = arg;
1036 }
1037
1038 //----------------------------------------------------------------------------
1039 int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser* parser)
1040 {
1041   return parser->OldStartcond;
1042 }
1043
1044 //----------------------------------------------------------------------------
1045 void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
1046 {
1047   // If there is a parser error just ignore it.  The source will not
1048   // compile and the user will edit it.  Then dependencies will have
1049   // to be regenerated anyway.
1050 }
1051
1052 //----------------------------------------------------------------------------
1053 void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
1054                                     const char* name)
1055 {
1056   if(!parser->InPPFalseBranch)
1057     {
1058     parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
1059     }
1060 }
1061
1062 //----------------------------------------------------------------------------
1063 void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
1064                                         const char* name)
1065 {
1066   if(parser->InPPFalseBranch)
1067     {
1068     return;
1069     }
1070
1071   // If processing an include statement there must be an open file.
1072   assert(!parser->FileStack.empty());
1073
1074   // Get the directory containing the source in which the include
1075   // statement appears.  This is always the first search location for
1076   // Fortran include files.
1077   std::string dir = parser->FileStack.top().Directory;
1078
1079   // Find the included file.  If it cannot be found just ignore the
1080   // problem because either the source will not compile or the user
1081   // does not care about depending on this included source.
1082   std::string fullName;
1083   if(parser->Self->FindIncludeFile(dir.c_str(), name, fullName))
1084     {
1085     // Found the included file.  Save it in the set of included files.
1086     parser->Info.Includes.insert(fullName);
1087
1088     // Parse it immediately to translate the source inline.
1089     cmDependsFortranParser_FilePush(parser, fullName.c_str());
1090     }
1091 }
1092
1093 //----------------------------------------------------------------------------
1094 void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
1095                                        const char* name)
1096 {
1097   if(!parser->InPPFalseBranch && !parser->InInterface)
1098     {
1099     parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
1100     }
1101 }
1102
1103 //----------------------------------------------------------------------------
1104 void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
1105                                        const char* macro)
1106 {
1107   if(!parser->InPPFalseBranch)
1108     {
1109     parser->PPDefinitions.insert(macro);
1110     }
1111 }
1112
1113 //----------------------------------------------------------------------------
1114 void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
1115                                       const char* macro)
1116 {
1117   if(!parser->InPPFalseBranch)
1118     {
1119     std::set<std::string>::iterator match;
1120     match = parser->PPDefinitions.find(macro);
1121     if(match != parser->PPDefinitions.end())
1122       {
1123       parser->PPDefinitions.erase(match);
1124       }
1125     }
1126 }
1127
1128 //----------------------------------------------------------------------------
1129 void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser* parser,
1130                                       const char* macro)
1131 {
1132   // A new PP branch has been opened
1133   parser->SkipToEnd.push(false);
1134
1135   if (parser->InPPFalseBranch)
1136     {
1137     parser->InPPFalseBranch++;
1138     }
1139   else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end())
1140     {
1141     parser->InPPFalseBranch=1;
1142     }
1143   else
1144     {
1145     parser->SkipToEnd.top() = true;
1146     }
1147 }
1148
1149 //----------------------------------------------------------------------------
1150 void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
1151   const char* macro)
1152 {
1153   // A new PP branch has been opened
1154   parser->SkipToEnd.push(false);
1155
1156   if (parser->InPPFalseBranch)
1157     {
1158     parser->InPPFalseBranch++;
1159     }
1160   else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end())
1161     {
1162     parser->InPPFalseBranch = 1;
1163     }
1164   else
1165     {
1166     // ignore other branches
1167     parser->SkipToEnd.top() = true;
1168     }
1169 }
1170
1171 //----------------------------------------------------------------------------
1172 void cmDependsFortranParser_RuleIf(cmDependsFortranParser* parser)
1173 {
1174   /* Note: The current parser is _not_ able to get statements like
1175    *   #if 0
1176    *   #if 1
1177    *   #if MYSMBOL
1178    *   #if defined(MYSYMBOL)
1179    *   #if defined(MYSYMBOL) && ...
1180    * right.  The same for #elif.  Thus in
1181    *   #if SYMBOL_1
1182    *     ..
1183    *   #elif SYMBOL_2
1184    *     ...
1185    *     ...
1186    *   #elif SYMBOL_N
1187    *     ..
1188    *   #else
1189    *     ..
1190    *   #endif
1191    * _all_ N+1 branches are considered.  If you got something like this
1192    *   #if defined(MYSYMBOL)
1193    *   #if !defined(MYSYMBOL)
1194    * use
1195    *   #ifdef MYSYMBOL
1196    *   #ifndef MYSYMBOL
1197    * instead.
1198    */
1199
1200   // A new PP branch has been opened
1201   // Never skip!  See note above.
1202   parser->SkipToEnd.push(false);
1203 }
1204
1205 //----------------------------------------------------------------------------
1206 void cmDependsFortranParser_RuleElif(cmDependsFortranParser* parser)
1207 {
1208   /* Note: There are parser limitations.  See the note at
1209    * cmDependsFortranParser_RuleIf(..)
1210    */
1211
1212   // Always taken unless an #ifdef or #ifndef-branch has been taken
1213   // already.  If the second condition isn't meet already
1214   // (parser->InPPFalseBranch == 0) correct it.
1215   if(!parser->SkipToEnd.empty() &&
1216      parser->SkipToEnd.top() && !parser->InPPFalseBranch)
1217     {
1218     parser->InPPFalseBranch = 1;
1219     }
1220 }
1221
1222 //----------------------------------------------------------------------------
1223 void cmDependsFortranParser_RuleElse(cmDependsFortranParser* parser)
1224 {
1225   // if the parent branch is false do nothing!
1226   if(parser->InPPFalseBranch > 1)
1227     {
1228     return;
1229     }
1230
1231   // parser->InPPFalseBranch is either 0 or 1.  We change it depending on
1232   // parser->SkipToEnd.top()
1233   if(!parser->SkipToEnd.empty() &&
1234      parser->SkipToEnd.top())
1235     {
1236     parser->InPPFalseBranch = 1;
1237     }
1238   else
1239     {
1240     parser->InPPFalseBranch = 0;
1241     }
1242 }
1243
1244 //----------------------------------------------------------------------------
1245 void cmDependsFortranParser_RuleEndif(cmDependsFortranParser* parser)
1246 {
1247   if(!parser->SkipToEnd.empty())
1248     {
1249     parser->SkipToEnd.pop();
1250     }
1251
1252   // #endif doesn't know if there was a "#else" in before, so it
1253   // always decreases InPPFalseBranch
1254   if(parser->InPPFalseBranch)
1255     {
1256     parser->InPPFalseBranch--;
1257     }
1258 }