1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDependsFortran.cxx,v $
6 Date: $Date: 2009-02-24 19:32:25 $
7 Version: $Revision: 1.49 $
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 // Configure the include file search path.
145 this->SetIncludePathFromLanguage("Fortran");
147 // Get the list of definitions.
148 std::vector
<std::string
> definitions
;
149 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
150 if(const char* c_defines
=
151 mf
->GetDefinition("CMAKE_TARGET_DEFINITIONS"))
153 cmSystemTools::ExpandListArgument(c_defines
, definitions
);
156 // translate i.e. FOO=BAR to FOO and add it to the list of defined
157 // preprocessor symbols
158 for(std::vector
<std::string
>::const_iterator
159 it
= definitions
.begin(); it
!= definitions
.end(); ++it
)
161 std::string def
= *it
;
162 std::string::size_type assignment
= def
.find("=");
163 if(assignment
!= std::string::npos
)
165 def
= it
->substr(0, assignment
);
167 this->PPDefinitions
.push_back(def
);
171 //----------------------------------------------------------------------------
172 cmDependsFortran::~cmDependsFortran()
174 delete this->Internal
;
177 //----------------------------------------------------------------------------
178 bool cmDependsFortran::WriteDependencies(const char *src
, const char *obj
,
179 std::ostream
&, std::ostream
&)
181 // Make sure this is a scanning instance.
182 if(!src
|| src
[0] == '\0')
184 cmSystemTools::Error("Cannot scan dependencies without an source file.");
187 if(!obj
|| obj
[0] == '\0')
189 cmSystemTools::Error("Cannot scan dependencies without an object file.");
193 // Get the information object for this source.
194 cmDependsFortranSourceInfo
& info
=
195 this->Internal
->CreateObjectInfo(obj
, src
);
197 // Make a copy of the macros defined via ADD_DEFINITIONS
198 std::set
<std::string
> ppDefines(this->PPDefinitions
.begin(),
199 this->PPDefinitions
.end());
201 // Create the parser object. The constructor takes ppMacro and info per
202 // reference, so we may look into the resulting objects later.
203 cmDependsFortranParser
parser(this, ppDefines
, info
);
205 // Push on the starting file.
206 cmDependsFortranParser_FilePush(&parser
, src
);
208 // Parse the translation unit.
209 if(cmDependsFortran_yyparse(parser
.Scanner
) != 0)
211 // Failed to parse the file. Report failure to write dependencies.
218 //----------------------------------------------------------------------------
219 bool cmDependsFortran::Finalize(std::ostream
& makeDepends
,
220 std::ostream
& internalDepends
)
222 // Prepare the module search process.
223 this->LocateModules();
225 // Get the directory in which stamp files will be stored.
226 const char* stamp_dir
= this->TargetDirectory
.c_str();
228 // Get the directory in which module files will be created.
230 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
231 if(const char* target_mod_dir
=
232 mf
->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
234 mod_dir
= target_mod_dir
;
239 this->LocalGenerator
->GetMakefile()->GetCurrentOutputDirectory();
242 // Actually write dependencies to the streams.
243 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap
;
244 ObjectInfoMap
const& objInfo
= this->Internal
->ObjectInfo
;
245 for(ObjectInfoMap::const_iterator i
= objInfo
.begin();
246 i
!= objInfo
.end(); ++i
)
248 if(!this->WriteDependenciesReal(i
->first
.c_str(), i
->second
,
250 makeDepends
, internalDepends
))
256 // Store the list of modules provided by this target.
257 std::string fiName
= this->TargetDirectory
;
258 fiName
+= "/fortran.internal";
259 cmGeneratedFileStream
fiStream(fiName
.c_str());
260 fiStream
<< "# The fortran modules provided by this target.\n";
261 fiStream
<< "provides\n";
262 std::set
<cmStdString
> const& provides
= this->Internal
->TargetProvides
;
263 for(std::set
<cmStdString
>::const_iterator i
= provides
.begin();
264 i
!= provides
.end(); ++i
)
266 fiStream
<< " " << *i
<< "\n";
269 // Create a script to clean the modules.
270 if(!provides
.empty())
272 std::string fcName
= this->TargetDirectory
;
273 fcName
+= "/cmake_clean_Fortran.cmake";
274 cmGeneratedFileStream
fcStream(fcName
.c_str());
275 fcStream
<< "# Remove fortran modules provided by this target.\n";
276 fcStream
<< "FILE(REMOVE";
277 for(std::set
<cmStdString
>::const_iterator i
= provides
.begin();
278 i
!= provides
.end(); ++i
)
280 std::string mod_upper
= mod_dir
;
282 mod_upper
+= cmSystemTools::UpperCase(*i
);
284 std::string mod_lower
= mod_dir
;
288 std::string stamp
= stamp_dir
;
291 stamp
+= ".mod.stamp";
294 this->LocalGenerator
->Convert(mod_lower
.c_str(),
295 cmLocalGenerator::START_OUTPUT
)
298 this->LocalGenerator
->Convert(mod_upper
.c_str(),
299 cmLocalGenerator::START_OUTPUT
)
302 this->LocalGenerator
->Convert(stamp
.c_str(),
303 cmLocalGenerator::START_OUTPUT
)
311 //----------------------------------------------------------------------------
312 void cmDependsFortran::LocateModules()
314 // Collect the set of modules provided and required by all sources.
315 typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap
;
316 ObjectInfoMap
const& objInfo
= this->Internal
->ObjectInfo
;
317 for(ObjectInfoMap::const_iterator infoI
= objInfo
.begin();
318 infoI
!= objInfo
.end(); ++infoI
)
320 cmDependsFortranSourceInfo
const& info
= infoI
->second
;
321 for(std::set
<cmStdString
>::const_iterator i
= info
.Provides
.begin();
322 i
!= info
.Provides
.end(); ++i
)
324 // Include this module in the set provided by this target.
325 this->Internal
->TargetProvides
.insert(*i
);
328 for(std::set
<cmStdString
>::const_iterator i
= info
.Requires
.begin();
329 i
!= info
.Requires
.end(); ++i
)
331 // Include this module in the set required by this target.
332 this->Internal
->TargetRequires
[*i
] = "";
336 // Short-circuit for simple targets.
337 if(this->Internal
->TargetRequires
.empty())
342 // Match modules provided by this target to those it requires.
343 this->MatchLocalModules();
345 // Load information about other targets.
346 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
347 std::vector
<std::string
> infoFiles
;
348 if(const char* infoFilesValue
=
349 mf
->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES"))
351 cmSystemTools::ExpandListArgument(infoFilesValue
, infoFiles
);
353 for(std::vector
<std::string
>::const_iterator i
= infoFiles
.begin();
354 i
!= infoFiles
.end(); ++i
)
356 std::string targetDir
= cmSystemTools::GetFilenamePath(*i
);
357 std::string fname
= targetDir
+ "/fortran.internal";
358 std::ifstream
fin(fname
.c_str());
361 this->MatchRemoteModules(fin
, targetDir
.c_str());
366 //----------------------------------------------------------------------------
367 void cmDependsFortran::MatchLocalModules()
369 const char* stampDir
= this->TargetDirectory
.c_str();
370 std::set
<cmStdString
> const& provides
= this->Internal
->TargetProvides
;
371 for(std::set
<cmStdString
>::const_iterator i
= provides
.begin();
372 i
!= provides
.end(); ++i
)
374 this->ConsiderModule(i
->c_str(), stampDir
);
378 //----------------------------------------------------------------------------
379 void cmDependsFortran::MatchRemoteModules(std::istream
& fin
,
380 const char* stampDir
)
383 bool doing_provides
= false;
384 while(cmSystemTools::GetLineFromStream(fin
, line
))
386 // Ignore comments and empty lines.
387 if(line
.empty() || line
[0] == '#' || line
[0] == '\r')
396 this->ConsiderModule(line
.c_str()+1, stampDir
);
399 else if(line
== "provides")
401 doing_provides
= true;
405 doing_provides
= false;
410 //----------------------------------------------------------------------------
411 void cmDependsFortran::ConsiderModule(const char* name
,
412 const char* stampDir
)
414 // Locate each required module.
415 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap
;
416 TargetRequiresMap::iterator required
=
417 this->Internal
->TargetRequires
.find(name
);
418 if(required
!= this->Internal
->TargetRequires
.end() &&
419 required
->second
.empty())
421 // The module is provided by a CMake target. It will have a stamp file.
422 std::string stampFile
= stampDir
;
425 stampFile
+= ".mod.stamp";
426 required
->second
= stampFile
;
430 //----------------------------------------------------------------------------
433 ::WriteDependenciesReal(const char *obj
,
434 cmDependsFortranSourceInfo
const& info
,
435 const char* mod_dir
, const char* stamp_dir
,
436 std::ostream
& makeDepends
,
437 std::ostream
& internalDepends
)
439 typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap
;
441 // Get the source file for this object.
442 const char* src
= info
.Source
.c_str();
444 // Write the include dependencies to the output stream.
445 internalDepends
<< obj
<< std::endl
;
446 internalDepends
<< " " << src
<< std::endl
;
447 for(std::set
<cmStdString
>::const_iterator i
= info
.Includes
.begin();
448 i
!= info
.Includes
.end(); ++i
)
450 makeDepends
<< obj
<< ": "
451 << cmSystemTools::ConvertToOutputPath(i
->c_str()).c_str()
453 internalDepends
<< " " << i
->c_str() << std::endl
;
455 makeDepends
<< std::endl
;
457 // Write module requirements to the output stream.
458 for(std::set
<cmStdString
>::const_iterator i
= info
.Requires
.begin();
459 i
!= info
.Requires
.end(); ++i
)
461 // Require only modules not provided in the same source.
462 if(std::set
<cmStdString
>::const_iterator(info
.Provides
.find(*i
)) !=
468 // If the module is provided in this target special handling is
470 if(this->Internal
->TargetProvides
.find(*i
) !=
471 this->Internal
->TargetProvides
.end())
473 // The module is provided by a different source in the same
474 // target. Add the proxy dependency to make sure the other
475 // source builds first.
476 std::string proxy
= stamp_dir
;
479 proxy
+= ".mod.proxy";
480 proxy
= this->LocalGenerator
->Convert(proxy
.c_str(),
481 cmLocalGenerator::HOME_OUTPUT
,
482 cmLocalGenerator::MAKEFILE
);
484 // since we require some things add them to our list of requirements
485 makeDepends
<< obj
<< ".requires: " << proxy
<< std::endl
;
488 // The object file should depend on timestamped files for the
490 TargetRequiresMap::const_iterator required
=
491 this->Internal
->TargetRequires
.find(*i
);
492 if(required
== this->Internal
->TargetRequires
.end()) { abort(); }
493 if(!required
->second
.empty())
495 // This module is known. Depend on its timestamp file.
496 std::string stampFile
=
497 this->LocalGenerator
->Convert(required
->second
.c_str(),
498 cmLocalGenerator::HOME_OUTPUT
,
499 cmLocalGenerator::SHELL
);
500 makeDepends
<< obj
<< ": " << stampFile
<< "\n";
504 // This module is not known to CMake. Try to locate it where
505 // the compiler will and depend on that.
507 if(this->FindModule(*i
, module
))
510 this->LocalGenerator
->Convert(module
.c_str(),
511 cmLocalGenerator::HOME_OUTPUT
,
512 cmLocalGenerator::SHELL
);
513 makeDepends
<< obj
<< ": " << module
<< "\n";
518 // Write provided modules to the output stream.
519 for(std::set
<cmStdString
>::const_iterator i
= info
.Provides
.begin();
520 i
!= info
.Provides
.end(); ++i
)
522 std::string proxy
= stamp_dir
;
525 proxy
+= ".mod.proxy";
526 proxy
= this->LocalGenerator
->Convert(proxy
.c_str(),
527 cmLocalGenerator::HOME_OUTPUT
,
528 cmLocalGenerator::MAKEFILE
);
529 makeDepends
<< proxy
<< ": " << obj
<< ".provides" << std::endl
;
532 // If any modules are provided then they must be converted to stamp files.
533 if(!info
.Provides
.empty())
535 // Create a target to copy the module after the object file
537 makeDepends
<< obj
<< ".provides.build:\n";
538 for(std::set
<cmStdString
>::const_iterator i
= info
.Provides
.begin();
539 i
!= info
.Provides
.end(); ++i
)
541 // Include this module in the set provided by this target.
542 this->Internal
->TargetProvides
.insert(*i
);
544 // Always use lower case for the mod stamp file name. The
545 // cmake_copy_f90_mod will call back to this class, which will
546 // try various cases for the real mod file name.
547 std::string m
= cmSystemTools::LowerCase(*i
);
548 std::string modFile
= mod_dir
;
552 this->LocalGenerator
->Convert(modFile
.c_str(),
553 cmLocalGenerator::HOME_OUTPUT
,
554 cmLocalGenerator::SHELL
);
555 std::string stampFile
= stamp_dir
;
558 stampFile
+= ".mod.stamp";
560 this->LocalGenerator
->Convert(stampFile
.c_str(),
561 cmLocalGenerator::HOME_OUTPUT
,
562 cmLocalGenerator::SHELL
);
563 makeDepends
<< "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod "
564 << modFile
<< " " << stampFile
;
565 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
566 const char* cid
= mf
->GetDefinition("CMAKE_Fortran_COMPILER_ID");
569 makeDepends
<< " " << cid
;
573 // After copying the modules update the timestamp file so that
574 // copying will not be done again until the source rebuilds.
575 makeDepends
<< "\t$(CMAKE_COMMAND) -E touch " << obj
576 << ".provides.build\n";
578 // Make sure the module timestamp rule is evaluated by the time
579 // the target finishes building.
580 std::string driver
= this->TargetDirectory
;
582 driver
= this->LocalGenerator
->Convert(driver
.c_str(),
583 cmLocalGenerator::HOME_OUTPUT
,
584 cmLocalGenerator::MAKEFILE
);
585 makeDepends
<< driver
<< ": " << obj
<< ".provides.build\n";
591 //----------------------------------------------------------------------------
592 bool cmDependsFortran::FindModule(std::string
const& name
,
595 // Construct possible names for the module file.
596 std::string mod_upper
= cmSystemTools::UpperCase(name
);
597 std::string mod_lower
= name
;
601 // Search the include path for the module.
602 std::string fullName
;
603 for(std::vector
<std::string
>::const_iterator i
=
604 this->IncludePath
.begin(); i
!= this->IncludePath
.end(); ++i
)
606 // Try the lower-case name.
609 fullName
+= mod_lower
;
610 if(cmSystemTools::FileExists(fullName
.c_str(), true))
616 // Try the upper-case name.
619 fullName
+= mod_upper
;
620 if(cmSystemTools::FileExists(fullName
.c_str(), true))
629 //----------------------------------------------------------------------------
630 bool cmDependsFortran::CopyModule(const std::vector
<std::string
>& args
)
634 // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
637 // Note that the case of the .mod file depends on the compiler. In
638 // the future this copy could also account for the fact that some
639 // compilers include a timestamp in the .mod file so it changes even
640 // when the interface described in the module does not.
642 std::string mod
= args
[2];
643 std::string stamp
= args
[3];
644 std::string compilerId
;
647 compilerId
= args
[4];
649 std::string mod_dir
= cmSystemTools::GetFilenamePath(mod
);
650 if(!mod_dir
.empty()) { mod_dir
+= "/"; }
651 std::string mod_upper
= mod_dir
;
652 mod_upper
+= cmSystemTools::UpperCase(cmSystemTools::GetFilenameName(mod
));
653 std::string mod_lower
= mod_dir
;
654 mod_lower
+= cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(mod
));
658 if(cmSystemTools::FileExists(mod_upper
.c_str(), true))
660 if(cmDependsFortran::ModulesDiffer(mod_upper
.c_str(), stamp
.c_str(),
663 if(!cmSystemTools::CopyFileAlways(mod_upper
.c_str(), stamp
.c_str()))
665 std::cerr
<< "Error copying Fortran module from \""
666 << mod_upper
.c_str() << "\" to \"" << stamp
.c_str()
673 else if(cmSystemTools::FileExists(mod_lower
.c_str(), true))
675 if(cmDependsFortran::ModulesDiffer(mod_lower
.c_str(), stamp
.c_str(),
678 if(!cmSystemTools::CopyFileAlways(mod_lower
.c_str(), stamp
.c_str()))
680 std::cerr
<< "Error copying Fortran module from \""
681 << mod_lower
.c_str() << "\" to \"" << stamp
.c_str()
689 std::cerr
<< "Error copying Fortran module \"" << args
[2].c_str()
690 << "\". Tried \"" << mod_upper
.c_str()
691 << "\" and \"" << mod_lower
.c_str() << "\".\n";
695 //----------------------------------------------------------------------------
696 // Helper function to look for a short sequence in a stream. If this
697 // is later used for longer sequences it should be re-written using an
698 // efficient string search algorithm such as Boyer-Moore.
700 bool cmDependsFortranStreamContainsSequence(std::ifstream
& ifs
,
701 const char* seq
, int len
)
708 // Get the next character.
709 int token
= ifs
.get();
715 // Check the character.
716 if(token
== static_cast<int>(seq
[cur
]))
722 // Assume the sequence has no repeating subsequence.
727 // The entire sequence was matched.
731 //----------------------------------------------------------------------------
732 // Helper function to compare the remaining content in two streams.
733 static bool cmDependsFortranStreamsDiffer(std::ifstream
& ifs1
,
736 // Compare the remaining content.
739 int ifs1_c
= ifs1
.get();
740 int ifs2_c
= ifs2
.get();
743 // We have reached the end of both streams simultaneously.
744 // The streams are identical.
748 if(!ifs1
|| !ifs2
|| ifs1_c
!= ifs2_c
)
750 // We have reached the end of one stream before the other or
751 // found differing content. The streams are different.
759 //----------------------------------------------------------------------------
760 bool cmDependsFortran::ModulesDiffer(const char* modFile
,
761 const char* stampFile
,
762 const char* compilerId
)
766 A mod file is an ascii file.
768 FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
769 If you edit this, you'll get what you deserve.
772 As you can see the first line contains the date.
775 A mod file is a binary file.
776 However, looking into both generated bar.mod files with a hex editor
777 shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
778 which is located some bytes in front of the absoulte path to the source
782 A mod file is a binary file. Compiling twice produces identical modules.
789 /* Compilers which do _not_ produce different mod content when the same
790 * source is compiled twice
793 if(strcmp(compilerId
, "SunPro") == 0)
795 return cmSystemTools::FilesDiffer(modFile
, stampFile
);
798 #if defined(_WIN32) || defined(__CYGWIN__)
799 std::ifstream
finModFile(modFile
, std::ios::in
| std::ios::binary
);
800 std::ifstream
finStampFile(stampFile
, std::ios::in
| std::ios::binary
);
802 std::ifstream
finModFile(modFile
, std::ios::in
);
803 std::ifstream
finStampFile(stampFile
, std::ios::in
);
805 if(!finModFile
|| !finStampFile
)
807 // At least one of the files does not exist. The modules differ.
811 /* Compilers which _do_ produce different mod content when the same
812 * source is compiled twice
816 * Eat the stream content until all recompile only realated changes
819 if (strcmp(compilerId
, "GNU") == 0 )
821 const char seq
[1] = {'\n'};
822 const int seqlen
= 1;
824 if(!cmDependsFortranStreamContainsSequence(finModFile
, seq
, seqlen
))
826 // The module is of unexpected format. Assume it is different.
827 std::cerr
<< compilerId
<< " fortran module " << modFile
828 << " has unexpected format." << std::endl
;
832 if(!cmDependsFortranStreamContainsSequence(finStampFile
, seq
, seqlen
))
834 // The stamp must differ if the sequence is not contained.
838 else if(strcmp(compilerId
, "Intel") == 0)
840 const char seq
[2] = {'\n', '\0'};
841 const int seqlen
= 2;
843 if(!cmDependsFortranStreamContainsSequence(finModFile
, seq
, seqlen
))
845 // The module is of unexpected format. Assume it is different.
846 std::cerr
<< compilerId
<< " fortran module " << modFile
847 << " has unexpected format." << std::endl
;
851 if(!cmDependsFortranStreamContainsSequence(finStampFile
, seq
, seqlen
))
853 // The stamp must differ if the sequence is not contained.
858 // Compare the remainng content. If no compiler id matched above,
859 // including the case none was given, this will compare the whole
861 if(!cmDependsFortranStreamsDiffer(finModFile
, finStampFile
))
866 // The modules are different.
870 //----------------------------------------------------------------------------
871 bool cmDependsFortran::FindIncludeFile(const char* dir
,
872 const char* includeName
,
873 std::string
& fileName
)
875 // If the file is a full path, include it directly.
876 if(cmSystemTools::FileIsFullPath(includeName
))
878 fileName
= includeName
;
879 return cmSystemTools::FileExists(fileName
.c_str(), true);
883 // Check for the file in the directory containing the including
885 std::string fullName
= dir
;
887 fullName
+= includeName
;
888 if(cmSystemTools::FileExists(fullName
.c_str(), true))
894 // Search the include path for the file.
895 for(std::vector
<std::string
>::const_iterator i
=
896 this->IncludePath
.begin(); i
!= this->IncludePath
.end(); ++i
)
900 fullName
+= includeName
;
901 if(cmSystemTools::FileExists(fullName
.c_str(), true))
911 //----------------------------------------------------------------------------
912 cmDependsFortranParser_s
913 ::cmDependsFortranParser_s(cmDependsFortran
* self
,
914 std::set
<std::string
>& ppDefines
,
915 cmDependsFortranSourceInfo
& info
):
916 Self(self
), PPDefinitions(ppDefines
), Info(info
)
918 this->InInterface
= 0;
919 this->InPPFalseBranch
= 0;
921 // Initialize the lexical scanner.
922 cmDependsFortran_yylex_init(&this->Scanner
);
923 cmDependsFortran_yyset_extra(this, this->Scanner
);
925 // Create a dummy buffer that is never read but is the fallback
926 // buffer when the last file is popped off the stack.
927 YY_BUFFER_STATE buffer
=
928 cmDependsFortran_yy_create_buffer(0, 4, this->Scanner
);
929 cmDependsFortran_yy_switch_to_buffer(buffer
, this->Scanner
);
932 //----------------------------------------------------------------------------
933 cmDependsFortranParser_s::~cmDependsFortranParser_s()
935 cmDependsFortran_yylex_destroy(this->Scanner
);
938 //----------------------------------------------------------------------------
939 bool cmDependsFortranParser_FilePush(cmDependsFortranParser
* parser
,
942 // Open the new file and push it onto the stack. Save the old
943 // buffer with it on the stack.
944 if(FILE* file
= fopen(fname
, "rb"))
946 YY_BUFFER_STATE current
=
947 cmDependsFortranLexer_GetCurrentBuffer(parser
->Scanner
);
948 std::string dir
= cmSystemTools::GetParentDirectory(fname
);
949 cmDependsFortranFile
f(file
, current
, dir
);
950 YY_BUFFER_STATE buffer
=
951 cmDependsFortran_yy_create_buffer(0, 16384, parser
->Scanner
);
952 cmDependsFortran_yy_switch_to_buffer(buffer
, parser
->Scanner
);
953 parser
->FileStack
.push(f
);
962 //----------------------------------------------------------------------------
963 bool cmDependsFortranParser_FilePop(cmDependsFortranParser
* parser
)
965 // Pop one file off the stack and close it. Switch the lexer back
966 // to the next one on the stack.
967 if(parser
->FileStack
.empty())
973 cmDependsFortranFile f
= parser
->FileStack
.top(); parser
->FileStack
.pop();
975 YY_BUFFER_STATE current
=
976 cmDependsFortranLexer_GetCurrentBuffer(parser
->Scanner
);
977 cmDependsFortran_yy_delete_buffer(current
, parser
->Scanner
);
978 cmDependsFortran_yy_switch_to_buffer(f
.Buffer
, parser
->Scanner
);
983 //----------------------------------------------------------------------------
984 int cmDependsFortranParser_Input(cmDependsFortranParser
* parser
,
985 char* buffer
, size_t bufferSize
)
987 // Read from the file on top of the stack. If the stack is empty,
988 // the end of the translation unit has been reached.
989 if(!parser
->FileStack
.empty())
991 FILE* file
= parser
->FileStack
.top().File
;
992 return (int)fread(buffer
, 1, bufferSize
, file
);
997 //----------------------------------------------------------------------------
998 void cmDependsFortranParser_StringStart(cmDependsFortranParser
* parser
)
1000 parser
->TokenString
= "";
1003 //----------------------------------------------------------------------------
1004 const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser
* parser
)
1006 return parser
->TokenString
.c_str();
1009 //----------------------------------------------------------------------------
1010 void cmDependsFortranParser_StringAppend(cmDependsFortranParser
* parser
,
1013 parser
->TokenString
+= c
;
1016 //----------------------------------------------------------------------------
1017 void cmDependsFortranParser_SetInInterface(cmDependsFortranParser
* parser
,
1020 if(parser
->InPPFalseBranch
)
1025 parser
->InInterface
= in
;
1028 //----------------------------------------------------------------------------
1029 bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser
* parser
)
1031 return parser
->InInterface
;
1034 //----------------------------------------------------------------------------
1035 void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser
* parser
,
1038 parser
->OldStartcond
= arg
;
1041 //----------------------------------------------------------------------------
1042 int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser
* parser
)
1044 return parser
->OldStartcond
;
1047 //----------------------------------------------------------------------------
1048 void cmDependsFortranParser_Error(cmDependsFortranParser
*, const char*)
1050 // If there is a parser error just ignore it. The source will not
1051 // compile and the user will edit it. Then dependencies will have
1052 // to be regenerated anyway.
1055 //----------------------------------------------------------------------------
1056 void cmDependsFortranParser_RuleUse(cmDependsFortranParser
* parser
,
1059 if(!parser
->InPPFalseBranch
)
1061 parser
->Info
.Requires
.insert(cmSystemTools::LowerCase(name
) );
1065 //----------------------------------------------------------------------------
1066 void cmDependsFortranParser_RuleInclude(cmDependsFortranParser
* parser
,
1069 if(parser
->InPPFalseBranch
)
1074 // If processing an include statement there must be an open file.
1075 assert(!parser
->FileStack
.empty());
1077 // Get the directory containing the source in which the include
1078 // statement appears. This is always the first search location for
1079 // Fortran include files.
1080 std::string dir
= parser
->FileStack
.top().Directory
;
1082 // Find the included file. If it cannot be found just ignore the
1083 // problem because either the source will not compile or the user
1084 // does not care about depending on this included source.
1085 std::string fullName
;
1086 if(parser
->Self
->FindIncludeFile(dir
.c_str(), name
, fullName
))
1088 // Found the included file. Save it in the set of included files.
1089 parser
->Info
.Includes
.insert(fullName
);
1091 // Parse it immediately to translate the source inline.
1092 cmDependsFortranParser_FilePush(parser
, fullName
.c_str());
1096 //----------------------------------------------------------------------------
1097 void cmDependsFortranParser_RuleModule(cmDependsFortranParser
* parser
,
1100 if(!parser
->InPPFalseBranch
&& !parser
->InInterface
)
1102 parser
->Info
.Provides
.insert(cmSystemTools::LowerCase(name
));
1106 //----------------------------------------------------------------------------
1107 void cmDependsFortranParser_RuleDefine(cmDependsFortranParser
* parser
,
1110 if(!parser
->InPPFalseBranch
)
1112 parser
->PPDefinitions
.insert(macro
);
1116 //----------------------------------------------------------------------------
1117 void cmDependsFortranParser_RuleUndef(cmDependsFortranParser
* parser
,
1120 if(!parser
->InPPFalseBranch
)
1122 std::set
<std::string
>::iterator match
;
1123 match
= parser
->PPDefinitions
.find(macro
);
1124 if(match
!= parser
->PPDefinitions
.end())
1126 parser
->PPDefinitions
.erase(match
);
1131 //----------------------------------------------------------------------------
1132 void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser
* parser
,
1135 // A new PP branch has been opened
1136 parser
->SkipToEnd
.push(false);
1138 if (parser
->InPPFalseBranch
)
1140 parser
->InPPFalseBranch
++;
1142 else if(parser
->PPDefinitions
.find(macro
) == parser
->PPDefinitions
.end())
1144 parser
->InPPFalseBranch
=1;
1148 parser
->SkipToEnd
.top() = true;
1152 //----------------------------------------------------------------------------
1153 void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser
* parser
,
1156 // A new PP branch has been opened
1157 parser
->SkipToEnd
.push(false);
1159 if (parser
->InPPFalseBranch
)
1161 parser
->InPPFalseBranch
++;
1163 else if(parser
->PPDefinitions
.find(macro
) != parser
->PPDefinitions
.end())
1165 parser
->InPPFalseBranch
= 1;
1169 // ignore other branches
1170 parser
->SkipToEnd
.top() = true;
1174 //----------------------------------------------------------------------------
1175 void cmDependsFortranParser_RuleIf(cmDependsFortranParser
* parser
)
1177 /* Note: The current parser is _not_ able to get statements like
1181 * #if defined(MYSYMBOL)
1182 * #if defined(MYSYMBOL) && ...
1183 * right. The same for #elif. Thus in
1194 * _all_ N+1 branches are considered. If you got something like this
1195 * #if defined(MYSYMBOL)
1196 * #if !defined(MYSYMBOL)
1203 // A new PP branch has been opened
1204 // Never skip! See note above.
1205 parser
->SkipToEnd
.push(false);
1208 //----------------------------------------------------------------------------
1209 void cmDependsFortranParser_RuleElif(cmDependsFortranParser
* parser
)
1211 /* Note: There are parser limitations. See the note at
1212 * cmDependsFortranParser_RuleIf(..)
1215 // Allways taken unless an #ifdef or #ifndef-branch has been taken
1216 // already. If the second condition isn't meet already
1217 // (parser->InPPFalseBranch == 0) correct it.
1218 if(!parser
->SkipToEnd
.empty() &&
1219 parser
->SkipToEnd
.top() && !parser
->InPPFalseBranch
)
1221 parser
->InPPFalseBranch
= 1;
1225 //----------------------------------------------------------------------------
1226 void cmDependsFortranParser_RuleElse(cmDependsFortranParser
* parser
)
1228 // if the parent branch is false do nothing!
1229 if(parser
->InPPFalseBranch
> 1)
1234 // parser->InPPFalseBranch is either 0 or 1. We change it denpending on
1235 // parser->SkipToEnd.top()
1236 if(!parser
->SkipToEnd
.empty() &&
1237 parser
->SkipToEnd
.top())
1239 parser
->InPPFalseBranch
= 1;
1243 parser
->InPPFalseBranch
= 0;
1247 //----------------------------------------------------------------------------
1248 void cmDependsFortranParser_RuleEndif(cmDependsFortranParser
* parser
)
1250 if(!parser
->SkipToEnd
.empty())
1252 parser
->SkipToEnd
.pop();
1255 // #endif doesn't know if there was a "#else" in before, so it
1256 // always decreases InPPFalseBranch
1257 if(parser
->InPPFalseBranch
)
1259 parser
->InPPFalseBranch
--;