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