STYLE: Fix line-too-long
[cmake.git] / Source / cmDependsFortran.cxx
blob62c1bcdc929b36c8fa38c4aa5ccafa35f234e3a9
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDependsFortran.cxx,v $
5 Language: C++
6 Date: $Date: 2008-05-08 14:09:14 $
7 Version: $Revision: 1.48 $
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 // Get the list of definitions.
145 std::vector<std::string> definitions;
146 cmMakefile* mf = this->LocalGenerator->GetMakefile();
147 if(const char* c_defines =
148 mf->GetDefinition("CMAKE_TARGET_DEFINITIONS"))
150 cmSystemTools::ExpandListArgument(c_defines, definitions);
153 // translate i.e. FOO=BAR to FOO and add it to the list of defined
154 // preprocessor symbols
155 for(std::vector<std::string>::const_iterator
156 it = definitions.begin(); it != definitions.end(); ++it)
158 std::string def = *it;
159 std::string::size_type assignment = def.find("=");
160 if(assignment != std::string::npos)
162 def = it->substr(0, assignment);
164 this->PPDefinitions.push_back(def);
168 //----------------------------------------------------------------------------
169 cmDependsFortran::~cmDependsFortran()
171 delete this->Internal;
174 //----------------------------------------------------------------------------
175 bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
176 std::ostream&, std::ostream&)
178 // Make sure this is a scanning instance.
179 if(!src || src[0] == '\0')
181 cmSystemTools::Error("Cannot scan dependencies without an source file.");
182 return false;
184 if(!obj || obj[0] == '\0')
186 cmSystemTools::Error("Cannot scan dependencies without an object file.");
187 return false;
190 // Get the information object for this source.
191 cmDependsFortranSourceInfo& info =
192 this->Internal->CreateObjectInfo(obj, src);
194 // Make a copy of the macros defined via ADD_DEFINITIONS
195 std::set<std::string> ppDefines(this->PPDefinitions.begin(),
196 this->PPDefinitions.end());
198 // Create the parser object. The constructor takes ppMacro and info per
199 // reference, so we may look into the resulting objects later.
200 cmDependsFortranParser parser(this, ppDefines, info);
202 // Push on the starting file.
203 cmDependsFortranParser_FilePush(&parser, src);
205 // Parse the translation unit.
206 if(cmDependsFortran_yyparse(parser.Scanner) != 0)
208 // Failed to parse the file. Report failure to write dependencies.
209 return false;
212 return true;
215 //----------------------------------------------------------------------------
216 bool cmDependsFortran::Finalize(std::ostream& makeDepends,
217 std::ostream& internalDepends)
219 // Prepare the module search process.
220 this->LocateModules();
222 // Get the directory in which stamp files will be stored.
223 const char* stamp_dir = this->TargetDirectory.c_str();
225 // Get the directory in which module files will be created.
226 const char* mod_dir;
227 cmMakefile* mf = this->LocalGenerator->GetMakefile();
228 if(const char* target_mod_dir =
229 mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
231 mod_dir = target_mod_dir;
233 else
235 mod_dir =
236 this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
239 // Actually write dependencies to the streams.
240 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
241 ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
242 for(ObjectInfoMap::const_iterator i = objInfo.begin();
243 i != objInfo.end(); ++i)
245 if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
246 mod_dir, stamp_dir,
247 makeDepends, internalDepends))
249 return false;
253 // Store the list of modules provided by this target.
254 std::string fiName = this->TargetDirectory;
255 fiName += "/fortran.internal";
256 cmGeneratedFileStream fiStream(fiName.c_str());
257 fiStream << "# The fortran modules provided by this target.\n";
258 fiStream << "provides\n";
259 std::set<cmStdString> const& provides = this->Internal->TargetProvides;
260 for(std::set<cmStdString>::const_iterator i = provides.begin();
261 i != provides.end(); ++i)
263 fiStream << " " << *i << "\n";
266 // Create a script to clean the modules.
267 if(!provides.empty())
269 std::string fcName = this->TargetDirectory;
270 fcName += "/cmake_clean_Fortran.cmake";
271 cmGeneratedFileStream fcStream(fcName.c_str());
272 fcStream << "# Remove fortran modules provided by this target.\n";
273 fcStream << "FILE(REMOVE";
274 for(std::set<cmStdString>::const_iterator i = provides.begin();
275 i != provides.end(); ++i)
277 std::string mod_upper = mod_dir;
278 mod_upper += "/";
279 mod_upper += cmSystemTools::UpperCase(*i);
280 mod_upper += ".mod";
281 std::string mod_lower = mod_dir;
282 mod_lower += "/";
283 mod_lower += *i;
284 mod_lower += ".mod";
285 std::string stamp = stamp_dir;
286 stamp += "/";
287 stamp += *i;
288 stamp += ".mod.stamp";
289 fcStream << "\n";
290 fcStream << " \"" <<
291 this->LocalGenerator->Convert(mod_lower.c_str(),
292 cmLocalGenerator::START_OUTPUT)
293 << "\"\n";
294 fcStream << " \"" <<
295 this->LocalGenerator->Convert(mod_upper.c_str(),
296 cmLocalGenerator::START_OUTPUT)
297 << "\"\n";
298 fcStream << " \"" <<
299 this->LocalGenerator->Convert(stamp.c_str(),
300 cmLocalGenerator::START_OUTPUT)
301 << "\"\n";
303 fcStream << " )\n";
305 return true;
308 //----------------------------------------------------------------------------
309 void cmDependsFortran::LocateModules()
311 // Collect the set of modules provided and required by all sources.
312 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
313 ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
314 for(ObjectInfoMap::const_iterator infoI = objInfo.begin();
315 infoI != objInfo.end(); ++infoI)
317 cmDependsFortranSourceInfo const& info = infoI->second;
318 for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
319 i != info.Provides.end(); ++i)
321 // Include this module in the set provided by this target.
322 this->Internal->TargetProvides.insert(*i);
325 for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
326 i != info.Requires.end(); ++i)
328 // Include this module in the set required by this target.
329 this->Internal->TargetRequires[*i] = "";
333 // Short-circuit for simple targets.
334 if(this->Internal->TargetRequires.empty())
336 return;
339 // Match modules provided by this target to those it requires.
340 this->MatchLocalModules();
342 // Load information about other targets.
343 cmMakefile* mf = this->LocalGenerator->GetMakefile();
344 std::vector<std::string> infoFiles;
345 if(const char* infoFilesValue =
346 mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES"))
348 cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
350 for(std::vector<std::string>::const_iterator i = infoFiles.begin();
351 i != infoFiles.end(); ++i)
353 std::string targetDir = cmSystemTools::GetFilenamePath(*i);
354 std::string fname = targetDir + "/fortran.internal";
355 std::ifstream fin(fname.c_str());
356 if(fin)
358 this->MatchRemoteModules(fin, targetDir.c_str());
363 //----------------------------------------------------------------------------
364 void cmDependsFortran::MatchLocalModules()
366 const char* stampDir = this->TargetDirectory.c_str();
367 std::set<cmStdString> const& provides = this->Internal->TargetProvides;
368 for(std::set<cmStdString>::const_iterator i = provides.begin();
369 i != provides.end(); ++i)
371 this->ConsiderModule(i->c_str(), stampDir);
375 //----------------------------------------------------------------------------
376 void cmDependsFortran::MatchRemoteModules(std::istream& fin,
377 const char* stampDir)
379 std::string line;
380 bool doing_provides = false;
381 while(cmSystemTools::GetLineFromStream(fin, line))
383 // Ignore comments and empty lines.
384 if(line.empty() || line[0] == '#' || line[0] == '\r')
386 continue;
389 if(line[0] == ' ')
391 if(doing_provides)
393 this->ConsiderModule(line.c_str()+1, stampDir);
396 else if(line == "provides")
398 doing_provides = true;
400 else
402 doing_provides = false;
407 //----------------------------------------------------------------------------
408 void cmDependsFortran::ConsiderModule(const char* name,
409 const char* stampDir)
411 // Locate each required module.
412 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
413 TargetRequiresMap::iterator required =
414 this->Internal->TargetRequires.find(name);
415 if(required != this->Internal->TargetRequires.end() &&
416 required->second.empty())
418 // The module is provided by a CMake target. It will have a stamp file.
419 std::string stampFile = stampDir;
420 stampFile += "/";
421 stampFile += name;
422 stampFile += ".mod.stamp";
423 required->second = stampFile;
427 //----------------------------------------------------------------------------
428 bool
429 cmDependsFortran
430 ::WriteDependenciesReal(const char *obj,
431 cmDependsFortranSourceInfo const& info,
432 const char* mod_dir, const char* stamp_dir,
433 std::ostream& makeDepends,
434 std::ostream& internalDepends)
436 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
438 // Get the source file for this object.
439 const char* src = info.Source.c_str();
441 // Write the include dependencies to the output stream.
442 internalDepends << obj << std::endl;
443 internalDepends << " " << src << std::endl;
444 for(std::set<cmStdString>::const_iterator i = info.Includes.begin();
445 i != info.Includes.end(); ++i)
447 makeDepends << obj << ": "
448 << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
449 << std::endl;
450 internalDepends << " " << i->c_str() << std::endl;
452 makeDepends << std::endl;
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)
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())
462 continue;
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())
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);
481 // since we require some things add them to our list of requirements
482 makeDepends << obj << ".requires: " << proxy << std::endl;
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())
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::SHELL);
497 makeDepends << obj << ": " << stampFile << "\n";
499 else
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))
506 module =
507 this->LocalGenerator->Convert(module.c_str(),
508 cmLocalGenerator::HOME_OUTPUT,
509 cmLocalGenerator::SHELL);
510 makeDepends << obj << ": " << module << "\n";
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)
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;
529 // If any modules are provided then they must be converted to stamp files.
530 if(!info.Provides.empty())
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)
538 // Include this module in the set provided by this target.
539 this->Internal->TargetProvides.insert(*i);
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)
566 makeDepends << " " << cid;
568 makeDepends << "\n";
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";
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";
585 return true;
588 //----------------------------------------------------------------------------
589 bool cmDependsFortran::FindModule(std::string const& name,
590 std::string& module)
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";
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)
603 // Try the lower-case name.
604 fullName = *i;
605 fullName += "/";
606 fullName += mod_lower;
607 if(cmSystemTools::FileExists(fullName.c_str(), true))
609 module = fullName;
610 return true;
613 // Try the upper-case name.
614 fullName = *i;
615 fullName += "/";
616 fullName += mod_upper;
617 if(cmSystemTools::FileExists(fullName.c_str(), true))
619 module = fullName;
620 return true;
623 return false;
626 //----------------------------------------------------------------------------
627 bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
629 // Implements
631 // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
632 // [compiler-id]
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.
639 std::string mod = args[2];
640 std::string stamp = args[3];
641 std::string compilerId;
642 if(args.size() >= 5)
644 compilerId = args[4];
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))
657 if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(),
658 compilerId.c_str()))
660 if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str()))
662 std::cerr << "Error copying Fortran module from \""
663 << mod_upper.c_str() << "\" to \"" << stamp.c_str()
664 << "\".\n";
665 return false;
668 return true;
670 else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
672 if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(),
673 compilerId.c_str()))
675 if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str()))
677 std::cerr << "Error copying Fortran module from \""
678 << mod_lower.c_str() << "\" to \"" << stamp.c_str()
679 << "\".\n";
680 return false;
683 return true;
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;
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)
700 assert(len > 0);
702 int cur = 0;
703 while(cur < len)
705 // Get the next character.
706 int token = ifs.get();
707 if(!ifs)
709 return false;
712 // Check the character.
713 if(token == static_cast<int>(seq[cur]))
715 ++cur;
717 else
719 // Assume the sequence has no repeating subsequence.
720 cur = 0;
724 // The entire sequence was matched.
725 return true;
728 //----------------------------------------------------------------------------
729 // Helper function to compare the remaining content in two streams.
730 static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
731 std::ifstream& ifs2)
733 // Compare the remaining content.
734 for(;;)
736 int ifs1_c = ifs1.get();
737 int ifs2_c = ifs2.get();
738 if(!ifs1 && !ifs2)
740 // We have reached the end of both streams simultaneously.
741 // The streams are identical.
742 return false;
745 if(!ifs1 || !ifs2 || ifs1_c != ifs2_c)
747 // We have reached the end of one stream before the other or
748 // found differing content. The streams are different.
749 break;
753 return true;
756 //----------------------------------------------------------------------------
757 bool cmDependsFortran::ModulesDiffer(const char* modFile,
758 const char* stampFile,
759 const char* compilerId)
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.
768 </bar.mod>
769 As you can see the first line contains the date.
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.
778 sun:
779 A mod file is a binary file. Compiling twice produces identical modules.
781 others:
782 TODO ...
786 /* Compilers which do _not_ produce different mod content when the same
787 * source is compiled twice
788 * -SunPro
790 if(strcmp(compilerId, "SunPro") == 0)
792 return cmSystemTools::FilesDiffer(modFile, stampFile);
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)
804 // At least one of the files does not exist. The modules differ.
805 return true;
808 /* Compilers which _do_ produce different mod content when the same
809 * source is compiled twice
810 * -GNU
811 * -Intel
813 * Eat the stream content until all recompile only realated changes
814 * are left bedind.
816 if (strcmp(compilerId, "GNU") == 0 )
818 const char seq[1] = {'\n'};
819 const int seqlen = 1;
821 if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
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;
829 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
831 // The stamp must differ if the sequence is not contained.
832 return true;
835 else if(strcmp(compilerId, "Intel") == 0)
837 const char seq[2] = {'\n', '\0'};
838 const int seqlen = 2;
840 if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
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;
848 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
850 // The stamp must differ if the sequence is not contained.
851 return true;
855 // Compare the remainng 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))
860 return false;
863 // The modules are different.
864 return true;
867 //----------------------------------------------------------------------------
868 bool cmDependsFortran::FindIncludeFile(const char* dir,
869 const char* includeName,
870 std::string& fileName)
872 // If the file is a full path, include it directly.
873 if(cmSystemTools::FileIsFullPath(includeName))
875 fileName = includeName;
876 return cmSystemTools::FileExists(fileName.c_str(), true);
878 else
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))
887 fileName = fullName;
888 return true;
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)
895 fullName = *i;
896 fullName += "/";
897 fullName += includeName;
898 if(cmSystemTools::FileExists(fullName.c_str(), true))
900 fileName = fullName;
901 return true;
905 return false;
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)
915 this->InInterface = 0;
916 this->InPPFalseBranch = 0;
918 // Initialize the lexical scanner.
919 cmDependsFortran_yylex_init(&this->Scanner);
920 cmDependsFortran_yyset_extra(this, this->Scanner);
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);
929 //----------------------------------------------------------------------------
930 cmDependsFortranParser_s::~cmDependsFortranParser_s()
932 cmDependsFortran_yylex_destroy(this->Scanner);
935 //----------------------------------------------------------------------------
936 bool cmDependsFortranParser_FilePush(cmDependsFortranParser* parser,
937 const char* fname)
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"))
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;
953 else
955 return 0;
959 //----------------------------------------------------------------------------
960 bool cmDependsFortranParser_FilePop(cmDependsFortranParser* parser)
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())
966 return 0;
968 else
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;
980 //----------------------------------------------------------------------------
981 int cmDependsFortranParser_Input(cmDependsFortranParser* parser,
982 char* buffer, size_t bufferSize)
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())
988 FILE* file = parser->FileStack.top().File;
989 return (int)fread(buffer, 1, bufferSize, file);
991 return 0;
994 //----------------------------------------------------------------------------
995 void cmDependsFortranParser_StringStart(cmDependsFortranParser* parser)
997 parser->TokenString = "";
1000 //----------------------------------------------------------------------------
1001 const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser* parser)
1003 return parser->TokenString.c_str();
1006 //----------------------------------------------------------------------------
1007 void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
1008 char c)
1010 parser->TokenString += c;
1013 //----------------------------------------------------------------------------
1014 void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
1015 bool in)
1017 if(parser->InPPFalseBranch)
1019 return;
1022 parser->InInterface = in;
1025 //----------------------------------------------------------------------------
1026 bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
1028 return parser->InInterface;
1031 //----------------------------------------------------------------------------
1032 void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
1033 int arg)
1035 parser->OldStartcond = arg;
1038 //----------------------------------------------------------------------------
1039 int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser* parser)
1041 return parser->OldStartcond;
1044 //----------------------------------------------------------------------------
1045 void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
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.
1052 //----------------------------------------------------------------------------
1053 void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
1054 const char* name)
1056 if(!parser->InPPFalseBranch)
1058 parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
1062 //----------------------------------------------------------------------------
1063 void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
1064 const char* name)
1066 if(parser->InPPFalseBranch)
1068 return;
1071 // If processing an include statement there must be an open file.
1072 assert(!parser->FileStack.empty());
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;
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))
1085 // Found the included file. Save it in the set of included files.
1086 parser->Info.Includes.insert(fullName);
1088 // Parse it immediately to translate the source inline.
1089 cmDependsFortranParser_FilePush(parser, fullName.c_str());
1093 //----------------------------------------------------------------------------
1094 void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
1095 const char* name)
1097 if(!parser->InPPFalseBranch && !parser->InInterface)
1099 parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
1103 //----------------------------------------------------------------------------
1104 void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
1105 const char* macro)
1107 if(!parser->InPPFalseBranch)
1109 parser->PPDefinitions.insert(macro);
1113 //----------------------------------------------------------------------------
1114 void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
1115 const char* macro)
1117 if(!parser->InPPFalseBranch)
1119 std::set<std::string>::iterator match;
1120 match = parser->PPDefinitions.find(macro);
1121 if(match != parser->PPDefinitions.end())
1123 parser->PPDefinitions.erase(match);
1128 //----------------------------------------------------------------------------
1129 void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser* parser,
1130 const char* macro)
1132 // A new PP branch has been opened
1133 parser->SkipToEnd.push(false);
1135 if (parser->InPPFalseBranch)
1137 parser->InPPFalseBranch++;
1139 else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end())
1141 parser->InPPFalseBranch=1;
1143 else
1145 parser->SkipToEnd.top() = true;
1149 //----------------------------------------------------------------------------
1150 void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
1151 const char* macro)
1153 // A new PP branch has been opened
1154 parser->SkipToEnd.push(false);
1156 if (parser->InPPFalseBranch)
1158 parser->InPPFalseBranch++;
1160 else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end())
1162 parser->InPPFalseBranch = 1;
1164 else
1166 // ignore other branches
1167 parser->SkipToEnd.top() = true;
1171 //----------------------------------------------------------------------------
1172 void cmDependsFortranParser_RuleIf(cmDependsFortranParser* parser)
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.
1200 // A new PP branch has been opened
1201 // Never skip! See note above.
1202 parser->SkipToEnd.push(false);
1205 //----------------------------------------------------------------------------
1206 void cmDependsFortranParser_RuleElif(cmDependsFortranParser* parser)
1208 /* Note: There are parser limitations. See the note at
1209 * cmDependsFortranParser_RuleIf(..)
1212 // Allways 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)
1218 parser->InPPFalseBranch = 1;
1222 //----------------------------------------------------------------------------
1223 void cmDependsFortranParser_RuleElse(cmDependsFortranParser* parser)
1225 // if the parent branch is false do nothing!
1226 if(parser->InPPFalseBranch > 1)
1228 return;
1231 // parser->InPPFalseBranch is either 0 or 1. We change it denpending on
1232 // parser->SkipToEnd.top()
1233 if(!parser->SkipToEnd.empty() &&
1234 parser->SkipToEnd.top())
1236 parser->InPPFalseBranch = 1;
1238 else
1240 parser->InPPFalseBranch = 0;
1244 //----------------------------------------------------------------------------
1245 void cmDependsFortranParser_RuleEndif(cmDependsFortranParser* parser)
1247 if(!parser->SkipToEnd.empty())
1249 parser->SkipToEnd.pop();
1252 // #endif doesn't know if there was a "#else" in before, so it
1253 // always decreases InPPFalseBranch
1254 if(parser->InPPFalseBranch)
1256 parser->InPPFalseBranch--;