1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDependsFortran.cxx,v $
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. */
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
38 // The name of the soruce file.
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
) {}
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.
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.
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
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
,
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
;
132 //----------------------------------------------------------------------------
133 cmDependsFortran::cmDependsFortran():
134 PPDefinitions(0), Internal(0)
138 //----------------------------------------------------------------------------
140 ::cmDependsFortran(cmLocalGenerator
* 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.");
184 if(!obj
|| obj
[0] == '\0')
186 cmSystemTools::Error("Cannot scan dependencies without an object file.");
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.
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.
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
;
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
,
247 makeDepends
, internalDepends
))
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
;
279 mod_upper
+= cmSystemTools::UpperCase(*i
);
281 std::string mod_lower
= mod_dir
;
285 std::string stamp
= stamp_dir
;
288 stamp
+= ".mod.stamp";
291 this->LocalGenerator
->Convert(mod_lower
.c_str(),
292 cmLocalGenerator::START_OUTPUT
)
295 this->LocalGenerator
->Convert(mod_upper
.c_str(),
296 cmLocalGenerator::START_OUTPUT
)
299 this->LocalGenerator
->Convert(stamp
.c_str(),
300 cmLocalGenerator::START_OUTPUT
)
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())
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());
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
)
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')
393 this->ConsiderModule(line
.c_str()+1, stampDir
);
396 else if(line
== "provides")
398 doing_provides
= true;
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
;
422 stampFile
+= ".mod.stamp";
423 required
->second
= stampFile
;
427 //----------------------------------------------------------------------------
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()
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::SHELL
);
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::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
;
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 realated 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 remainng 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 // 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)
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;
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
--;