1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
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"
14 #include "cmSystemTools.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMakefile.h"
17 #include "cmGeneratedFileStream.h"
19 #include "cmDependsFortranParser.h" /* Interface to parser object. */
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.
28 //----------------------------------------------------------------------------
29 // Information about a single source file.
30 class cmDependsFortranSourceInfo
33 // The name of the source file.
36 // Set of provided and required modules.
37 std::set<cmStdString> Provides;
38 std::set<cmStdString> Requires;
40 // Set of files included in the translation unit.
41 std::set<cmStdString> Includes;
44 //----------------------------------------------------------------------------
45 // Parser methods not included in generated interface.
47 // Get the current buffer processed by the lexer.
48 YY_BUFFER_STATE cmDependsFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
50 // The parser entry point.
51 int cmDependsFortran_yyparse(yyscan_t);
53 //----------------------------------------------------------------------------
54 // Define parser object internal structure.
55 struct cmDependsFortranFile
57 cmDependsFortranFile(FILE* file, YY_BUFFER_STATE buffer,
58 const std::string& dir):
59 File(file), Buffer(buffer), Directory(dir) {}
61 YY_BUFFER_STATE Buffer;
62 std::string Directory;
65 struct cmDependsFortranParser_s
67 cmDependsFortranParser_s(cmDependsFortran* self,
68 std::set<std::string>& ppDefines,
69 cmDependsFortranSourceInfo& info);
70 ~cmDependsFortranParser_s();
72 // Pointer back to the main class.
73 cmDependsFortran* Self;
75 // Lexical scanner instance.
78 // Stack of open files in the translation unit.
79 std::stack<cmDependsFortranFile> FileStack;
81 // Buffer for string literals.
82 std::string TokenString;
84 // Flag for whether lexer is reading from inside an interface.
88 std::set<std::string> PPDefinitions;
89 size_t InPPFalseBranch;
90 std::stack<bool> SkipToEnd;
92 // Information about the parsed source.
93 cmDependsFortranSourceInfo& Info;
96 //----------------------------------------------------------------------------
97 class cmDependsFortranInternals
100 // The set of modules provided by this target.
101 std::set<cmStdString> TargetProvides;
103 // Map modules required by this target to locations.
104 typedef std::map<cmStdString, cmStdString> TargetRequiresMap;
105 TargetRequiresMap TargetRequires;
107 // Information about each object file.
108 typedef std::map<cmStdString, cmDependsFortranSourceInfo> ObjectInfoMap;
109 ObjectInfoMap ObjectInfo;
111 cmDependsFortranSourceInfo& CreateObjectInfo(const char* obj,
114 std::map<cmStdString, cmDependsFortranSourceInfo>::iterator i =
115 this->ObjectInfo.find(obj);
116 if(i == this->ObjectInfo.end())
118 std::map<cmStdString, cmDependsFortranSourceInfo>::value_type
119 entry(obj, cmDependsFortranSourceInfo());
120 i = this->ObjectInfo.insert(entry).first;
121 i->second.Source = src;
127 //----------------------------------------------------------------------------
128 cmDependsFortran::cmDependsFortran():
129 PPDefinitions(0), Internal(0)
133 //----------------------------------------------------------------------------
135 ::cmDependsFortran(cmLocalGenerator* lg):
137 Internal(new cmDependsFortranInternals)
139 // Configure the include file search path.
140 this->SetIncludePathFromLanguage("Fortran");
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"))
148 cmSystemTools::ExpandListArgument(c_defines, definitions);
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)
156 std::string def = *it;
157 std::string::size_type assignment = def.find("=");
158 if(assignment != std::string::npos)
160 def = it->substr(0, assignment);
162 this->PPDefinitions.push_back(def);
166 //----------------------------------------------------------------------------
167 cmDependsFortran::~cmDependsFortran()
169 delete this->Internal;
172 //----------------------------------------------------------------------------
173 bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
174 std::ostream&, std::ostream&)
176 // Make sure this is a scanning instance.
177 if(!src || src[0] == '\0')
179 cmSystemTools::Error("Cannot scan dependencies without an source file.");
182 if(!obj || obj[0] == '\0')
184 cmSystemTools::Error("Cannot scan dependencies without an object file.");
188 // Get the information object for this source.
189 cmDependsFortranSourceInfo& info =
190 this->Internal->CreateObjectInfo(obj, src);
192 // Make a copy of the macros defined via ADD_DEFINITIONS
193 std::set<std::string> ppDefines(this->PPDefinitions.begin(),
194 this->PPDefinitions.end());
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);
200 // Push on the starting file.
201 cmDependsFortranParser_FilePush(&parser, src);
203 // Parse the translation unit.
204 if(cmDependsFortran_yyparse(parser.Scanner) != 0)
206 // Failed to parse the file. Report failure to write dependencies.
213 //----------------------------------------------------------------------------
214 bool cmDependsFortran::Finalize(std::ostream& makeDepends,
215 std::ostream& internalDepends)
217 // Prepare the module search process.
218 this->LocateModules();
220 // Get the directory in which stamp files will be stored.
221 const char* stamp_dir = this->TargetDirectory.c_str();
223 // Get the directory in which module files will be created.
225 cmMakefile* mf = this->LocalGenerator->GetMakefile();
226 if(const char* target_mod_dir =
227 mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
229 mod_dir = target_mod_dir;
234 this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
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)
243 if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
245 makeDepends, internalDepends))
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)
261 fiStream << " " << *i << "\n";
264 // Create a script to clean the modules.
265 if(!provides.empty())
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)
275 std::string mod_upper = mod_dir;
277 mod_upper += cmSystemTools::UpperCase(*i);
279 std::string mod_lower = mod_dir;
283 std::string stamp = stamp_dir;
286 stamp += ".mod.stamp";
289 this->LocalGenerator->Convert(mod_lower.c_str(),
290 cmLocalGenerator::START_OUTPUT)
293 this->LocalGenerator->Convert(mod_upper.c_str(),
294 cmLocalGenerator::START_OUTPUT)
297 this->LocalGenerator->Convert(stamp.c_str(),
298 cmLocalGenerator::START_OUTPUT)
306 //----------------------------------------------------------------------------
307 void cmDependsFortran::LocateModules()
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)
315 cmDependsFortranSourceInfo const& info = infoI->second;
316 for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
317 i != info.Provides.end(); ++i)
319 // Include this module in the set provided by this target.
320 this->Internal->TargetProvides.insert(*i);
323 for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
324 i != info.Requires.end(); ++i)
326 // Include this module in the set required by this target.
327 this->Internal->TargetRequires[*i] = "";
331 // Short-circuit for simple targets.
332 if(this->Internal->TargetRequires.empty())
337 // Match modules provided by this target to those it requires.
338 this->MatchLocalModules();
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"))
346 cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
348 for(std::vector<std::string>::const_iterator i = infoFiles.begin();
349 i != infoFiles.end(); ++i)
351 std::string targetDir = cmSystemTools::GetFilenamePath(*i);
352 std::string fname = targetDir + "/fortran.internal";
353 std::ifstream fin(fname.c_str());
356 this->MatchRemoteModules(fin, targetDir.c_str());
361 //----------------------------------------------------------------------------
362 void cmDependsFortran::MatchLocalModules()
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)
369 this->ConsiderModule(i->c_str(), stampDir);
373 //----------------------------------------------------------------------------
374 void cmDependsFortran::MatchRemoteModules(std::istream& fin,
375 const char* stampDir)
378 bool doing_provides = false;
379 while(cmSystemTools::GetLineFromStream(fin, line))
381 // Ignore comments and empty lines.
382 if(line.empty() || line[0] == '#' || line[0] == '\r')
391 this->ConsiderModule(line.c_str()+1, stampDir);
394 else if(line == "provides")
396 doing_provides = true;
400 doing_provides = false;
405 //----------------------------------------------------------------------------
406 void cmDependsFortran::ConsiderModule(const char* name,
407 const char* stampDir)
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())
416 // The module is provided by a CMake target. It will have a stamp file.
417 std::string stampFile = stampDir;
420 stampFile += ".mod.stamp";
421 required->second = stampFile;
425 //----------------------------------------------------------------------------
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)
434 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
436 // Get the source file for this object.
437 const char* src = info.Source.c_str();
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)
445 makeDepends << obj << ": " <<
446 this->LocalGenerator->Convert(i->c_str(),
447 cmLocalGenerator::HOME_OUTPUT,
448 cmLocalGenerator::MAKEFILE)
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)) !=
465 // If the module is provided in this target special handling is
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;
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
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::MAKEFILE);
497 makeDepends << obj << ": " << stampFile << "\n";
501 // This module is not known to CMake. Try to locate it where
502 // the compiler will and depend on that.
504 if(this->FindModule(*i, module))
507 this->LocalGenerator->Convert(module.c_str(),
508 cmLocalGenerator::HOME_OUTPUT,
509 cmLocalGenerator::MAKEFILE);
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;
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
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;
549 this->LocalGenerator->Convert(modFile.c_str(),
550 cmLocalGenerator::HOME_OUTPUT,
551 cmLocalGenerator::SHELL);
552 std::string stampFile = stamp_dir;
555 stampFile += ".mod.stamp";
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");
566 makeDepends << " " << cid;
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;
579 driver = this->LocalGenerator->Convert(driver.c_str(),
580 cmLocalGenerator::HOME_OUTPUT,
581 cmLocalGenerator::MAKEFILE);
582 makeDepends << driver << ": " << obj << ".provides.build\n";
588 //----------------------------------------------------------------------------
589 bool cmDependsFortran::FindModule(std::string const& name,
592 // Construct possible names for the module file.
593 std::string mod_upper = cmSystemTools::UpperCase(name);
594 std::string mod_lower = name;
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.
606 fullName += mod_lower;
607 if(cmSystemTools::FileExists(fullName.c_str(), true))
613 // Try the upper-case name.
616 fullName += mod_upper;
617 if(cmSystemTools::FileExists(fullName.c_str(), true))
626 //----------------------------------------------------------------------------
627 bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
631 // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
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;
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));
655 if(cmSystemTools::FileExists(mod_upper.c_str(), true))
657 if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.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()
670 else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
672 if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.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()
686 std::cerr << "Error copying Fortran module \"" << args[2].c_str()
687 << "\". Tried \"" << mod_upper.c_str()
688 << "\" and \"" << mod_lower.c_str() << "\".\n";
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.
697 bool cmDependsFortranStreamContainsSequence(std::ifstream& ifs,
698 const char* seq, int len)
705 // Get the next character.
706 int token = ifs.get();
712 // Check the character.
713 if(token == static_cast<int>(seq[cur]))
719 // Assume the sequence has no repeating subsequence.
724 // The entire sequence was matched.
728 //----------------------------------------------------------------------------
729 // Helper function to compare the remaining content in two streams.
730 static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
733 // Compare the remaining content.
736 int ifs1_c = ifs1.get();
737 int ifs2_c = ifs2.get();
740 // We have reached the end of both streams simultaneously.
741 // The streams are identical.
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.
756 //----------------------------------------------------------------------------
757 bool cmDependsFortran::ModulesDiffer(const char* modFile,
758 const char* stampFile,
759 const char* compilerId)
763 A mod file is an ascii file.
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.
769 As you can see the first line contains the date.
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
779 A mod file is a binary file. Compiling twice produces identical modules.
786 /* Compilers which do _not_ produce different mod content when the same
787 * source is compiled twice
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);
799 std::ifstream finModFile(modFile, std::ios::in);
800 std::ifstream finStampFile(stampFile, std::ios::in);
802 if(!finModFile || !finStampFile)
804 // At least one of the files does not exist. The modules differ.
808 /* Compilers which _do_ produce different mod content when the same
809 * source is compiled twice
813 * Eat the stream content until all recompile only related changes
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;
829 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
831 // The stamp must differ if the sequence is not contained.
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;
848 if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
850 // The stamp must differ if the sequence is not contained.
855 // Compare the remaining content. If no compiler id matched above,
856 // including the case none was given, this will compare the whole
858 if(!cmDependsFortranStreamsDiffer(finModFile, finStampFile))
863 // The modules are different.
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);
880 // Check for the file in the directory containing the including
882 std::string fullName = dir;
884 fullName += includeName;
885 if(cmSystemTools::FileExists(fullName.c_str(), 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)
897 fullName += includeName;
898 if(cmSystemTools::FileExists(fullName.c_str(), true))
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,
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);
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())
970 cmDependsFortranFile f = parser->FileStack.top(); parser->FileStack.pop();
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);
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);
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,
1010 parser->TokenString += c;
1013 //----------------------------------------------------------------------------
1014 void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
1017 if(parser->InPPFalseBranch)
1022 parser->InInterface = in;
1025 //----------------------------------------------------------------------------
1026 bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
1028 return parser->InInterface;
1031 //----------------------------------------------------------------------------
1032 void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
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,
1056 if(!parser->InPPFalseBranch)
1058 parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
1062 //----------------------------------------------------------------------------
1063 void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
1066 if(parser->InPPFalseBranch)
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,
1097 if(!parser->InPPFalseBranch && !parser->InInterface)
1099 parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
1103 //----------------------------------------------------------------------------
1104 void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
1107 if(!parser->InPPFalseBranch)
1109 parser->PPDefinitions.insert(macro);
1113 //----------------------------------------------------------------------------
1114 void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
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,
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;
1145 parser->SkipToEnd.top() = true;
1149 //----------------------------------------------------------------------------
1150 void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
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;
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
1178 * #if defined(MYSYMBOL)
1179 * #if defined(MYSYMBOL) && ...
1180 * right. The same for #elif. Thus in
1191 * _all_ N+1 branches are considered. If you got something like this
1192 * #if defined(MYSYMBOL)
1193 * #if !defined(MYSYMBOL)
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 // 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)
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)
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())
1236 parser->InPPFalseBranch = 1;
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--;