cmDependsFortran.cxx 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmDependsFortran.h"
  14. #include "cmSystemTools.h"
  15. #include "cmLocalGenerator.h"
  16. #include "cmMakefile.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmDependsFortranParser.h" /* Interface to parser object. */
  19. #include <assert.h>
  20. #include <stack>
  21. // TODO: Test compiler for the case of the mod file. Some always
  22. // use lower case and some always use upper case. I do not know if any
  23. // use the case from the source code.
  24. //----------------------------------------------------------------------------
  25. // Information about a single source file.
  26. class cmDependsFortranSourceInfo
  27. {
  28. public:
  29. // The name of the soruce file.
  30. std::string Source;
  31. // Set of provided and required modules.
  32. std::set<cmStdString> Provides;
  33. std::set<cmStdString> Requires;
  34. // Set of files included in the translation unit.
  35. std::set<cmStdString> Includes;
  36. };
  37. //----------------------------------------------------------------------------
  38. // Parser methods not included in generated interface.
  39. // Get the current buffer processed by the lexer.
  40. YY_BUFFER_STATE cmDependsFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
  41. // The parser entry point.
  42. int cmDependsFortran_yyparse(yyscan_t);
  43. //----------------------------------------------------------------------------
  44. // Define parser object internal structure.
  45. struct cmDependsFortranFile
  46. {
  47. cmDependsFortranFile(FILE* file, YY_BUFFER_STATE buffer,
  48. const std::string& dir):
  49. File(file), Buffer(buffer), Directory(dir) {}
  50. FILE* File;
  51. YY_BUFFER_STATE Buffer;
  52. std::string Directory;
  53. };
  54. struct cmDependsFortranParser_s
  55. {
  56. cmDependsFortranParser_s(cmDependsFortran* self,
  57. std::set<std::string>& ppDefines,
  58. cmDependsFortranSourceInfo& info);
  59. ~cmDependsFortranParser_s();
  60. // Pointer back to the main class.
  61. cmDependsFortran* Self;
  62. // Lexical scanner instance.
  63. yyscan_t Scanner;
  64. // Stack of open files in the translation unit.
  65. std::stack<cmDependsFortranFile> FileStack;
  66. // Buffer for string literals.
  67. std::string TokenString;
  68. // Flag for whether lexer is reading from inside an interface.
  69. bool InInterface;
  70. int OldStartcond;
  71. std::set<std::string> PPDefinitions;
  72. size_t InPPFalseBranch;
  73. std::stack<bool> SkipToEnd;
  74. // Information about the parsed source.
  75. cmDependsFortranSourceInfo& Info;
  76. };
  77. //----------------------------------------------------------------------------
  78. class cmDependsFortranInternals
  79. {
  80. public:
  81. // The set of modules provided by this target.
  82. std::set<cmStdString> TargetProvides;
  83. // Map modules required by this target to locations.
  84. typedef std::map<cmStdString, cmStdString> TargetRequiresMap;
  85. TargetRequiresMap TargetRequires;
  86. // Information about each object file.
  87. typedef std::map<cmStdString, cmDependsFortranSourceInfo> ObjectInfoMap;
  88. ObjectInfoMap ObjectInfo;
  89. cmDependsFortranSourceInfo& CreateObjectInfo(const char* obj,
  90. const char* src)
  91. {
  92. std::map<cmStdString, cmDependsFortranSourceInfo>::iterator i =
  93. this->ObjectInfo.find(obj);
  94. if(i == this->ObjectInfo.end())
  95. {
  96. std::map<cmStdString, cmDependsFortranSourceInfo>::value_type
  97. entry(obj, cmDependsFortranSourceInfo());
  98. i = this->ObjectInfo.insert(entry).first;
  99. i->second.Source = src;
  100. }
  101. return i->second;
  102. }
  103. };
  104. //----------------------------------------------------------------------------
  105. cmDependsFortran::cmDependsFortran():
  106. IncludePath(0), PPDefinitions(0), Internal(0)
  107. {
  108. }
  109. //----------------------------------------------------------------------------
  110. cmDependsFortran
  111. ::cmDependsFortran(std::vector<std::string> const& includes,
  112. std::vector<std::string> const& definitions):
  113. IncludePath(&includes),
  114. Internal(new cmDependsFortranInternals)
  115. {
  116. // translate i.e. FOO=BAR to FOO and add it to the list of defined
  117. // preprocessor symbols
  118. for(std::vector<std::string>::const_iterator
  119. it = definitions.begin(); it != definitions.end(); ++it)
  120. {
  121. std::string def = *it;
  122. std::string::size_type assignment = def.find("=");
  123. if(assignment != std::string::npos)
  124. {
  125. def = it->substr(0, assignment);
  126. }
  127. this->PPDefinitions.push_back(def);
  128. }
  129. }
  130. //----------------------------------------------------------------------------
  131. cmDependsFortran::~cmDependsFortran()
  132. {
  133. delete this->Internal;
  134. }
  135. //----------------------------------------------------------------------------
  136. bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
  137. std::ostream&, std::ostream&)
  138. {
  139. // Make sure this is a scanning instance.
  140. if(!src || src[0] == '\0')
  141. {
  142. cmSystemTools::Error("Cannot scan dependencies without an source file.");
  143. return false;
  144. }
  145. if(!obj || obj[0] == '\0')
  146. {
  147. cmSystemTools::Error("Cannot scan dependencies without an object file.");
  148. return false;
  149. }
  150. if(!this->IncludePath)
  151. {
  152. cmSystemTools::Error("Cannot scan dependencies without an include path.");
  153. return false;
  154. }
  155. // Get the information object for this source.
  156. cmDependsFortranSourceInfo& info =
  157. this->Internal->CreateObjectInfo(obj, src);
  158. // Make a copy of the macros defined via ADD_DEFINITIONS
  159. std::set<std::string> ppDefines(this->PPDefinitions.begin(),
  160. this->PPDefinitions.end());
  161. // Create the parser object. The constructor takes ppMacro and info per
  162. // reference, so we may look into the resulting objects later.
  163. cmDependsFortranParser parser(this, ppDefines, info);
  164. // Push on the starting file.
  165. cmDependsFortranParser_FilePush(&parser, src);
  166. // Parse the translation unit.
  167. if(cmDependsFortran_yyparse(parser.Scanner) != 0)
  168. {
  169. // Failed to parse the file. Report failure to write dependencies.
  170. return false;
  171. }
  172. return true;
  173. }
  174. //----------------------------------------------------------------------------
  175. bool cmDependsFortran::Finalize(std::ostream& makeDepends,
  176. std::ostream& internalDepends)
  177. {
  178. // Prepare the module search process.
  179. this->LocateModules();
  180. // Get the directory in which stamp files will be stored.
  181. const char* stamp_dir = this->TargetDirectory.c_str();
  182. // Get the directory in which module files will be created.
  183. const char* mod_dir;
  184. cmMakefile* mf = this->LocalGenerator->GetMakefile();
  185. if(const char* target_mod_dir =
  186. mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
  187. {
  188. mod_dir = target_mod_dir;
  189. }
  190. else
  191. {
  192. mod_dir =
  193. this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
  194. }
  195. // Actually write dependencies to the streams.
  196. typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
  197. ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
  198. for(ObjectInfoMap::const_iterator i = objInfo.begin();
  199. i != objInfo.end(); ++i)
  200. {
  201. if(!this->WriteDependenciesReal(i->first.c_str(), i->second,
  202. mod_dir, stamp_dir,
  203. makeDepends, internalDepends))
  204. {
  205. return false;
  206. }
  207. }
  208. // Store the list of modules provided by this target.
  209. std::string fiName = this->TargetDirectory;
  210. fiName += "/fortran.internal";
  211. cmGeneratedFileStream fiStream(fiName.c_str());
  212. fiStream << "# The fortran modules provided by this target.\n";
  213. fiStream << "provides\n";
  214. std::set<cmStdString> const& provides = this->Internal->TargetProvides;
  215. for(std::set<cmStdString>::const_iterator i = provides.begin();
  216. i != provides.end(); ++i)
  217. {
  218. fiStream << " " << *i << "\n";
  219. }
  220. // Create a script to clean the modules.
  221. if(!provides.empty())
  222. {
  223. std::string fcName = this->TargetDirectory;
  224. fcName += "/cmake_clean_Fortran.cmake";
  225. cmGeneratedFileStream fcStream(fcName.c_str());
  226. fcStream << "# Remove fortran modules provided by this target.\n";
  227. fcStream << "FILE(REMOVE";
  228. for(std::set<cmStdString>::const_iterator i = provides.begin();
  229. i != provides.end(); ++i)
  230. {
  231. std::string mod_upper = mod_dir;
  232. mod_upper += "/";
  233. mod_upper += cmSystemTools::UpperCase(*i);
  234. mod_upper += ".mod";
  235. std::string mod_lower = mod_dir;
  236. mod_lower += "/";
  237. mod_lower += *i;
  238. mod_lower += ".mod";
  239. std::string stamp = stamp_dir;
  240. stamp += "/";
  241. stamp += *i;
  242. stamp += ".mod.stamp";
  243. fcStream << "\n";
  244. fcStream << " \"" <<
  245. this->LocalGenerator->Convert(mod_lower.c_str(),
  246. cmLocalGenerator::START_OUTPUT)
  247. << "\"\n";
  248. fcStream << " \"" <<
  249. this->LocalGenerator->Convert(mod_upper.c_str(),
  250. cmLocalGenerator::START_OUTPUT)
  251. << "\"\n";
  252. fcStream << " \"" <<
  253. this->LocalGenerator->Convert(stamp.c_str(),
  254. cmLocalGenerator::START_OUTPUT)
  255. << "\"\n";
  256. }
  257. fcStream << " )\n";
  258. }
  259. return true;
  260. }
  261. //----------------------------------------------------------------------------
  262. void cmDependsFortran::LocateModules()
  263. {
  264. // Collect the set of modules provided and required by all sources.
  265. typedef cmDependsFortranInternals::ObjectInfoMap ObjectInfoMap;
  266. ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
  267. for(ObjectInfoMap::const_iterator infoI = objInfo.begin();
  268. infoI != objInfo.end(); ++infoI)
  269. {
  270. cmDependsFortranSourceInfo const& info = infoI->second;
  271. for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
  272. i != info.Provides.end(); ++i)
  273. {
  274. // Include this module in the set provided by this target.
  275. this->Internal->TargetProvides.insert(*i);
  276. }
  277. for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
  278. i != info.Requires.end(); ++i)
  279. {
  280. // Include this module in the set required by this target.
  281. this->Internal->TargetRequires[*i] = "";
  282. }
  283. }
  284. // Short-circuit for simple targets.
  285. if(this->Internal->TargetRequires.empty())
  286. {
  287. return;
  288. }
  289. // Match modules provided by this target to those it requires.
  290. this->MatchLocalModules();
  291. // Load information about other targets.
  292. cmMakefile* mf = this->LocalGenerator->GetMakefile();
  293. std::vector<std::string> infoFiles;
  294. if(const char* infoFilesValue =
  295. mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES"))
  296. {
  297. cmSystemTools::ExpandListArgument(infoFilesValue, infoFiles);
  298. }
  299. for(std::vector<std::string>::const_iterator i = infoFiles.begin();
  300. i != infoFiles.end(); ++i)
  301. {
  302. std::string targetDir = cmSystemTools::GetFilenamePath(*i);
  303. std::string fname = targetDir + "/fortran.internal";
  304. std::ifstream fin(fname.c_str());
  305. if(fin)
  306. {
  307. this->MatchRemoteModules(fin, targetDir.c_str());
  308. }
  309. }
  310. }
  311. //----------------------------------------------------------------------------
  312. void cmDependsFortran::MatchLocalModules()
  313. {
  314. const char* stampDir = this->TargetDirectory.c_str();
  315. std::set<cmStdString> const& provides = this->Internal->TargetProvides;
  316. for(std::set<cmStdString>::const_iterator i = provides.begin();
  317. i != provides.end(); ++i)
  318. {
  319. this->ConsiderModule(i->c_str(), stampDir);
  320. }
  321. }
  322. //----------------------------------------------------------------------------
  323. void cmDependsFortran::MatchRemoteModules(std::istream& fin,
  324. const char* stampDir)
  325. {
  326. std::string line;
  327. bool doing_provides = false;
  328. while(cmSystemTools::GetLineFromStream(fin, line))
  329. {
  330. // Ignore comments and empty lines.
  331. if(line.empty() || line[0] == '#' || line[0] == '\r')
  332. {
  333. continue;
  334. }
  335. if(line[0] == ' ')
  336. {
  337. if(doing_provides)
  338. {
  339. this->ConsiderModule(line.c_str()+1, stampDir);
  340. }
  341. }
  342. else if(line == "provides")
  343. {
  344. doing_provides = true;
  345. }
  346. else
  347. {
  348. doing_provides = false;
  349. }
  350. }
  351. }
  352. //----------------------------------------------------------------------------
  353. void cmDependsFortran::ConsiderModule(const char* name,
  354. const char* stampDir)
  355. {
  356. // Locate each required module.
  357. typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
  358. TargetRequiresMap::iterator required =
  359. this->Internal->TargetRequires.find(name);
  360. if(required != this->Internal->TargetRequires.end() &&
  361. required->second.empty())
  362. {
  363. // The module is provided by a CMake target. It will have a stamp file.
  364. std::string stampFile = stampDir;
  365. stampFile += "/";
  366. stampFile += name;
  367. stampFile += ".mod.stamp";
  368. required->second = stampFile;
  369. }
  370. }
  371. //----------------------------------------------------------------------------
  372. bool
  373. cmDependsFortran
  374. ::WriteDependenciesReal(const char *obj,
  375. cmDependsFortranSourceInfo const& info,
  376. const char* mod_dir, const char* stamp_dir,
  377. std::ostream& makeDepends,
  378. std::ostream& internalDepends)
  379. {
  380. typedef cmDependsFortranInternals::TargetRequiresMap TargetRequiresMap;
  381. // Get the source file for this object.
  382. const char* src = info.Source.c_str();
  383. // Write the include dependencies to the output stream.
  384. internalDepends << obj << std::endl;
  385. internalDepends << " " << src << std::endl;
  386. for(std::set<cmStdString>::const_iterator i = info.Includes.begin();
  387. i != info.Includes.end(); ++i)
  388. {
  389. makeDepends << obj << ": "
  390. << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
  391. << std::endl;
  392. internalDepends << " " << i->c_str() << std::endl;
  393. }
  394. makeDepends << std::endl;
  395. // Write module requirements to the output stream.
  396. for(std::set<cmStdString>::const_iterator i = info.Requires.begin();
  397. i != info.Requires.end(); ++i)
  398. {
  399. // Require only modules not provided in the same source.
  400. if(info.Provides.find(*i) != info.Provides.end())
  401. {
  402. continue;
  403. }
  404. // If the module is provided in this target special handling is
  405. // needed.
  406. if(this->Internal->TargetProvides.find(*i) !=
  407. this->Internal->TargetProvides.end())
  408. {
  409. // The module is provided by a different source in the same
  410. // target. Add the proxy dependency to make sure the other
  411. // source builds first.
  412. std::string proxy = stamp_dir;
  413. proxy += "/";
  414. proxy += *i;
  415. proxy += ".mod.proxy";
  416. proxy = this->LocalGenerator->Convert(proxy.c_str(),
  417. cmLocalGenerator::HOME_OUTPUT,
  418. cmLocalGenerator::MAKEFILE);
  419. // since we require some things add them to our list of requirements
  420. makeDepends << obj << ".requires: " << proxy << std::endl;
  421. }
  422. // The object file should depend on timestamped files for the
  423. // modules it uses.
  424. TargetRequiresMap::const_iterator required =
  425. this->Internal->TargetRequires.find(*i);
  426. if(required == this->Internal->TargetRequires.end()) { abort(); }
  427. if(!required->second.empty())
  428. {
  429. // This module is known. Depend on its timestamp file.
  430. std::string stampFile =
  431. this->LocalGenerator->Convert(required->second.c_str(),
  432. cmLocalGenerator::HOME_OUTPUT,
  433. cmLocalGenerator::SHELL);
  434. makeDepends << obj << ": " << stampFile << "\n";
  435. }
  436. else
  437. {
  438. // This module is not known to CMake. Try to locate it where
  439. // the compiler will and depend on that.
  440. std::string module;
  441. if(this->FindModule(*i, module))
  442. {
  443. module =
  444. this->LocalGenerator->Convert(module.c_str(),
  445. cmLocalGenerator::HOME_OUTPUT,
  446. cmLocalGenerator::SHELL);
  447. makeDepends << obj << ": " << module << "\n";
  448. }
  449. }
  450. }
  451. // Write provided modules to the output stream.
  452. for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
  453. i != info.Provides.end(); ++i)
  454. {
  455. std::string proxy = stamp_dir;
  456. proxy += "/";
  457. proxy += *i;
  458. proxy += ".mod.proxy";
  459. proxy = this->LocalGenerator->Convert(proxy.c_str(),
  460. cmLocalGenerator::HOME_OUTPUT,
  461. cmLocalGenerator::MAKEFILE);
  462. makeDepends << proxy << ": " << obj << ".provides" << std::endl;
  463. }
  464. // If any modules are provided then they must be converted to stamp files.
  465. if(!info.Provides.empty())
  466. {
  467. // Create a target to copy the module after the object file
  468. // changes.
  469. makeDepends << obj << ".provides.build:\n";
  470. for(std::set<cmStdString>::const_iterator i = info.Provides.begin();
  471. i != info.Provides.end(); ++i)
  472. {
  473. // Include this module in the set provided by this target.
  474. this->Internal->TargetProvides.insert(*i);
  475. // Always use lower case for the mod stamp file name. The
  476. // cmake_copy_f90_mod will call back to this class, which will
  477. // try various cases for the real mod file name.
  478. std::string m = cmSystemTools::LowerCase(*i);
  479. std::string modFile = mod_dir;
  480. modFile += "/";
  481. modFile += *i;
  482. modFile =
  483. this->LocalGenerator->Convert(modFile.c_str(),
  484. cmLocalGenerator::HOME_OUTPUT,
  485. cmLocalGenerator::SHELL);
  486. std::string stampFile = stamp_dir;
  487. stampFile += "/";
  488. stampFile += m;
  489. stampFile += ".mod.stamp";
  490. stampFile =
  491. this->LocalGenerator->Convert(stampFile.c_str(),
  492. cmLocalGenerator::HOME_OUTPUT,
  493. cmLocalGenerator::SHELL);
  494. makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod "
  495. << modFile << " " << stampFile;
  496. cmMakefile* mf = this->LocalGenerator->GetMakefile();
  497. const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
  498. if(cid && *cid)
  499. {
  500. makeDepends << " " << cid;
  501. }
  502. makeDepends << "\n";
  503. }
  504. // After copying the modules update the timestamp file so that
  505. // copying will not be done again until the source rebuilds.
  506. makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj
  507. << ".provides.build\n";
  508. // Make sure the module timestamp rule is evaluated by the time
  509. // the target finishes building.
  510. std::string driver = this->TargetDirectory;
  511. driver += "/build";
  512. driver = this->LocalGenerator->Convert(driver.c_str(),
  513. cmLocalGenerator::HOME_OUTPUT,
  514. cmLocalGenerator::MAKEFILE);
  515. makeDepends << driver << ": " << obj << ".provides.build\n";
  516. }
  517. return true;
  518. }
  519. //----------------------------------------------------------------------------
  520. bool cmDependsFortran::FindModule(std::string const& name,
  521. std::string& module)
  522. {
  523. // Construct possible names for the module file.
  524. std::string mod_upper = cmSystemTools::UpperCase(name);
  525. std::string mod_lower = name;
  526. mod_upper += ".mod";
  527. mod_lower += ".mod";
  528. // Search the include path for the module.
  529. std::string fullName;
  530. for(std::vector<std::string>::const_iterator i =
  531. this->IncludePath->begin(); i != this->IncludePath->end(); ++i)
  532. {
  533. // Try the lower-case name.
  534. fullName = *i;
  535. fullName += "/";
  536. fullName += mod_lower;
  537. if(cmSystemTools::FileExists(fullName.c_str(), true))
  538. {
  539. module = fullName;
  540. return true;
  541. }
  542. // Try the upper-case name.
  543. fullName = *i;
  544. fullName += "/";
  545. fullName += mod_upper;
  546. if(cmSystemTools::FileExists(fullName.c_str(), true))
  547. {
  548. module = fullName;
  549. return true;
  550. }
  551. }
  552. return false;
  553. }
  554. //----------------------------------------------------------------------------
  555. bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
  556. {
  557. // Implements
  558. //
  559. // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
  560. // [compiler-id]
  561. //
  562. // Note that the case of the .mod file depends on the compiler. In
  563. // the future this copy could also account for the fact that some
  564. // compilers include a timestamp in the .mod file so it changes even
  565. // when the interface described in the module does not.
  566. std::string mod = args[2];
  567. std::string stamp = args[3];
  568. std::string compilerId;
  569. if(args.size() >= 5)
  570. {
  571. compilerId = args[4];
  572. }
  573. std::string mod_dir = cmSystemTools::GetFilenamePath(mod);
  574. if(!mod_dir.empty()) { mod_dir += "/"; }
  575. std::string mod_upper = mod_dir;
  576. mod_upper += cmSystemTools::UpperCase(cmSystemTools::GetFilenameName(mod));
  577. std::string mod_lower = mod_dir;
  578. mod_lower += cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(mod));
  579. mod += ".mod";
  580. mod_upper += ".mod";
  581. mod_lower += ".mod";
  582. if(cmSystemTools::FileExists(mod_upper.c_str(), true))
  583. {
  584. if(cmDependsFortran::ModulesDiffer(mod_upper.c_str(), stamp.c_str(),
  585. compilerId.c_str()))
  586. {
  587. if(!cmSystemTools::CopyFileAlways(mod_upper.c_str(), stamp.c_str()))
  588. {
  589. std::cerr << "Error copying Fortran module from \""
  590. << mod_upper.c_str() << "\" to \"" << stamp.c_str()
  591. << "\".\n";
  592. return false;
  593. }
  594. }
  595. return true;
  596. }
  597. else if(cmSystemTools::FileExists(mod_lower.c_str(), true))
  598. {
  599. if(cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(),
  600. compilerId.c_str()))
  601. {
  602. if(!cmSystemTools::CopyFileAlways(mod_lower.c_str(), stamp.c_str()))
  603. {
  604. std::cerr << "Error copying Fortran module from \""
  605. << mod_lower.c_str() << "\" to \"" << stamp.c_str()
  606. << "\".\n";
  607. return false;
  608. }
  609. }
  610. return true;
  611. }
  612. std::cerr << "Error copying Fortran module \"" << args[2].c_str()
  613. << "\". Tried \"" << mod_upper.c_str()
  614. << "\" and \"" << mod_lower.c_str() << "\".\n";
  615. return false;
  616. }
  617. //----------------------------------------------------------------------------
  618. // Helper function to look for a short sequence in a stream. If this
  619. // is later used for longer sequences it should be re-written using an
  620. // efficient string search algorithm such as Boyer-Moore.
  621. static
  622. bool cmDependsFortranStreamContainsSequence(std::ifstream& ifs,
  623. const char* seq, int len)
  624. {
  625. assert(len > 0);
  626. int cur = 0;
  627. while(cur < len)
  628. {
  629. // Get the next character.
  630. int token = ifs.get();
  631. if(!ifs)
  632. {
  633. return false;
  634. }
  635. // Check the character.
  636. if(token == static_cast<int>(seq[cur]))
  637. {
  638. ++cur;
  639. }
  640. else
  641. {
  642. // Assume the sequence has no repeating subsequence.
  643. cur = 0;
  644. }
  645. }
  646. // The entire sequence was matched.
  647. return true;
  648. }
  649. //----------------------------------------------------------------------------
  650. // Helper function to compare the remaining content in two streams.
  651. static bool cmDependsFortranStreamsDiffer(std::ifstream& ifs1,
  652. std::ifstream& ifs2)
  653. {
  654. // Compare the remaining content.
  655. for(;;)
  656. {
  657. int ifs1_c = ifs1.get();
  658. int ifs2_c = ifs2.get();
  659. if(!ifs1 && !ifs2)
  660. {
  661. // We have reached the end of both streams simultaneously.
  662. // The streams are identical.
  663. return false;
  664. }
  665. if(!ifs1 || !ifs2 || ifs1_c != ifs2_c)
  666. {
  667. // We have reached the end of one stream before the other or
  668. // found differing content. The streams are different.
  669. break;
  670. }
  671. }
  672. return true;
  673. }
  674. //----------------------------------------------------------------------------
  675. bool cmDependsFortran::ModulesDiffer(const char* modFile,
  676. const char* stampFile,
  677. const char* compilerId)
  678. {
  679. /*
  680. gnu:
  681. A mod file is an ascii file.
  682. <bar.mod>
  683. FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
  684. If you edit this, you'll get what you deserve.
  685. ...
  686. </bar.mod>
  687. As you can see the first line contains the date.
  688. intel:
  689. A mod file is a binary file.
  690. However, looking into both generated bar.mod files with a hex editor
  691. shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
  692. which is located some bytes in front of the absoulte path to the source
  693. file.
  694. sun:
  695. A mod file is a binary file. Compiling twice produces identical modules.
  696. others:
  697. TODO ...
  698. */
  699. /* Compilers which do _not_ produce different mod content when the same
  700. * source is compiled twice
  701. * -SunPro
  702. */
  703. if(strcmp(compilerId, "SunPro") == 0)
  704. {
  705. return cmSystemTools::FilesDiffer(modFile, stampFile);
  706. }
  707. #if defined(_WIN32) || defined(__CYGWIN__)
  708. std::ifstream finModFile(modFile, std::ios::in | std::ios::binary);
  709. std::ifstream finStampFile(stampFile, std::ios::in | std::ios::binary);
  710. #else
  711. std::ifstream finModFile(modFile, std::ios::in);
  712. std::ifstream finStampFile(stampFile, std::ios::in);
  713. #endif
  714. if(!finModFile || !finStampFile)
  715. {
  716. // At least one of the files does not exist. The modules differ.
  717. return true;
  718. }
  719. /* Compilers which _do_ produce different mod content when the same
  720. * source is compiled twice
  721. * -GNU
  722. * -Intel
  723. *
  724. * Eat the stream content until all recompile only realated changes
  725. * are left bedind.
  726. */
  727. if (strcmp(compilerId, "GNU") == 0 )
  728. {
  729. const char seq[1] = {'\n'};
  730. const int seqlen = 1;
  731. if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
  732. {
  733. // The module is of unexpected format. Assume it is different.
  734. std::cerr << compilerId << " fortran module " << modFile
  735. << " has unexpected format." << std::endl;
  736. return true;
  737. }
  738. if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
  739. {
  740. // The stamp must differ if the sequence is not contained.
  741. return true;
  742. }
  743. }
  744. else if(strcmp(compilerId, "Intel") == 0)
  745. {
  746. const char seq[2] = {'\n', '\0'};
  747. const int seqlen = 2;
  748. if(!cmDependsFortranStreamContainsSequence(finModFile, seq, seqlen))
  749. {
  750. // The module is of unexpected format. Assume it is different.
  751. std::cerr << compilerId << " fortran module " << modFile
  752. << " has unexpected format." << std::endl;
  753. return true;
  754. }
  755. if(!cmDependsFortranStreamContainsSequence(finStampFile, seq, seqlen))
  756. {
  757. // The stamp must differ if the sequence is not contained.
  758. return true;
  759. }
  760. }
  761. // Compare the remainng content. If no compiler id matched above,
  762. // including the case none was given, this will compare the whole
  763. // content.
  764. if(!cmDependsFortranStreamsDiffer(finModFile, finStampFile))
  765. {
  766. return false;
  767. }
  768. // The modules are different.
  769. return true;
  770. }
  771. //----------------------------------------------------------------------------
  772. bool cmDependsFortran::FindIncludeFile(const char* dir,
  773. const char* includeName,
  774. std::string& fileName)
  775. {
  776. // If the file is a full path, include it directly.
  777. if(cmSystemTools::FileIsFullPath(includeName))
  778. {
  779. fileName = includeName;
  780. return cmSystemTools::FileExists(fileName.c_str(), true);
  781. }
  782. else
  783. {
  784. // Check for the file in the directory containing the including
  785. // file.
  786. std::string fullName = dir;
  787. fullName += "/";
  788. fullName += includeName;
  789. if(cmSystemTools::FileExists(fullName.c_str(), true))
  790. {
  791. fileName = fullName;
  792. return true;
  793. }
  794. // Search the include path for the file.
  795. for(std::vector<std::string>::const_iterator i =
  796. this->IncludePath->begin(); i != this->IncludePath->end(); ++i)
  797. {
  798. fullName = *i;
  799. fullName += "/";
  800. fullName += includeName;
  801. if(cmSystemTools::FileExists(fullName.c_str(), true))
  802. {
  803. fileName = fullName;
  804. return true;
  805. }
  806. }
  807. }
  808. return false;
  809. }
  810. //----------------------------------------------------------------------------
  811. cmDependsFortranParser_s
  812. ::cmDependsFortranParser_s(cmDependsFortran* self,
  813. std::set<std::string>& ppDefines,
  814. cmDependsFortranSourceInfo& info):
  815. Self(self), PPDefinitions(ppDefines), Info(info)
  816. {
  817. this->InInterface = 0;
  818. this->InPPFalseBranch = 0;
  819. // Initialize the lexical scanner.
  820. cmDependsFortran_yylex_init(&this->Scanner);
  821. cmDependsFortran_yyset_extra(this, this->Scanner);
  822. // Create a dummy buffer that is never read but is the fallback
  823. // buffer when the last file is popped off the stack.
  824. YY_BUFFER_STATE buffer =
  825. cmDependsFortran_yy_create_buffer(0, 4, this->Scanner);
  826. cmDependsFortran_yy_switch_to_buffer(buffer, this->Scanner);
  827. }
  828. //----------------------------------------------------------------------------
  829. cmDependsFortranParser_s::~cmDependsFortranParser_s()
  830. {
  831. cmDependsFortran_yylex_destroy(this->Scanner);
  832. }
  833. //----------------------------------------------------------------------------
  834. bool cmDependsFortranParser_FilePush(cmDependsFortranParser* parser,
  835. const char* fname)
  836. {
  837. // Open the new file and push it onto the stack. Save the old
  838. // buffer with it on the stack.
  839. if(FILE* file = fopen(fname, "rb"))
  840. {
  841. YY_BUFFER_STATE current =
  842. cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
  843. std::string dir = cmSystemTools::GetParentDirectory(fname);
  844. cmDependsFortranFile f(file, current, dir);
  845. YY_BUFFER_STATE buffer =
  846. cmDependsFortran_yy_create_buffer(0, 16384, parser->Scanner);
  847. cmDependsFortran_yy_switch_to_buffer(buffer, parser->Scanner);
  848. parser->FileStack.push(f);
  849. return 1;
  850. }
  851. else
  852. {
  853. return 0;
  854. }
  855. }
  856. //----------------------------------------------------------------------------
  857. bool cmDependsFortranParser_FilePop(cmDependsFortranParser* parser)
  858. {
  859. // Pop one file off the stack and close it. Switch the lexer back
  860. // to the next one on the stack.
  861. if(parser->FileStack.empty())
  862. {
  863. return 0;
  864. }
  865. else
  866. {
  867. cmDependsFortranFile f = parser->FileStack.top(); parser->FileStack.pop();
  868. fclose(f.File);
  869. YY_BUFFER_STATE current =
  870. cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
  871. cmDependsFortran_yy_delete_buffer(current, parser->Scanner);
  872. cmDependsFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
  873. return 1;
  874. }
  875. }
  876. //----------------------------------------------------------------------------
  877. int cmDependsFortranParser_Input(cmDependsFortranParser* parser,
  878. char* buffer, size_t bufferSize)
  879. {
  880. // Read from the file on top of the stack. If the stack is empty,
  881. // the end of the translation unit has been reached.
  882. if(!parser->FileStack.empty())
  883. {
  884. FILE* file = parser->FileStack.top().File;
  885. return (int)fread(buffer, 1, bufferSize, file);
  886. }
  887. return 0;
  888. }
  889. //----------------------------------------------------------------------------
  890. void cmDependsFortranParser_StringStart(cmDependsFortranParser* parser)
  891. {
  892. parser->TokenString = "";
  893. }
  894. //----------------------------------------------------------------------------
  895. const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser* parser)
  896. {
  897. return parser->TokenString.c_str();
  898. }
  899. //----------------------------------------------------------------------------
  900. void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
  901. char c)
  902. {
  903. parser->TokenString += c;
  904. }
  905. //----------------------------------------------------------------------------
  906. void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
  907. bool in)
  908. {
  909. if(parser->InPPFalseBranch)
  910. {
  911. return;
  912. }
  913. parser->InInterface = in;
  914. }
  915. //----------------------------------------------------------------------------
  916. bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
  917. {
  918. return parser->InInterface;
  919. }
  920. //----------------------------------------------------------------------------
  921. void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
  922. int arg)
  923. {
  924. parser->OldStartcond = arg;
  925. }
  926. //----------------------------------------------------------------------------
  927. int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser* parser)
  928. {
  929. return parser->OldStartcond;
  930. }
  931. //----------------------------------------------------------------------------
  932. void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
  933. {
  934. // If there is a parser error just ignore it. The source will not
  935. // compile and the user will edit it. Then dependencies will have
  936. // to be regenerated anyway.
  937. }
  938. //----------------------------------------------------------------------------
  939. void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
  940. const char* name)
  941. {
  942. if(!parser->InPPFalseBranch)
  943. {
  944. parser->Info.Requires.insert(cmSystemTools::LowerCase(name) );
  945. }
  946. }
  947. //----------------------------------------------------------------------------
  948. void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
  949. const char* name)
  950. {
  951. if(parser->InPPFalseBranch)
  952. {
  953. return;
  954. }
  955. // If processing an include statement there must be an open file.
  956. assert(!parser->FileStack.empty());
  957. // Get the directory containing the source in which the include
  958. // statement appears. This is always the first search location for
  959. // Fortran include files.
  960. std::string dir = parser->FileStack.top().Directory;
  961. // Find the included file. If it cannot be found just ignore the
  962. // problem because either the source will not compile or the user
  963. // does not care about depending on this included source.
  964. std::string fullName;
  965. if(parser->Self->FindIncludeFile(dir.c_str(), name, fullName))
  966. {
  967. // Found the included file. Save it in the set of included files.
  968. parser->Info.Includes.insert(fullName);
  969. // Parse it immediately to translate the source inline.
  970. cmDependsFortranParser_FilePush(parser, fullName.c_str());
  971. }
  972. }
  973. //----------------------------------------------------------------------------
  974. void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
  975. const char* name)
  976. {
  977. if(!parser->InPPFalseBranch && !parser->InInterface)
  978. {
  979. parser->Info.Provides.insert(cmSystemTools::LowerCase(name));
  980. }
  981. }
  982. //----------------------------------------------------------------------------
  983. void cmDependsFortranParser_RuleDefine(cmDependsFortranParser* parser,
  984. const char* macro)
  985. {
  986. if(!parser->InPPFalseBranch)
  987. {
  988. parser->PPDefinitions.insert(macro);
  989. }
  990. }
  991. //----------------------------------------------------------------------------
  992. void cmDependsFortranParser_RuleUndef(cmDependsFortranParser* parser,
  993. const char* macro)
  994. {
  995. if(!parser->InPPFalseBranch)
  996. {
  997. std::set<std::string>::iterator match;
  998. match = parser->PPDefinitions.find(macro);
  999. if(match != parser->PPDefinitions.end())
  1000. {
  1001. parser->PPDefinitions.erase(match);
  1002. }
  1003. }
  1004. }
  1005. //----------------------------------------------------------------------------
  1006. void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser* parser,
  1007. const char* macro)
  1008. {
  1009. // A new PP branch has been opened
  1010. parser->SkipToEnd.push(false);
  1011. if (parser->InPPFalseBranch)
  1012. {
  1013. parser->InPPFalseBranch++;
  1014. }
  1015. else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end())
  1016. {
  1017. parser->InPPFalseBranch=1;
  1018. }
  1019. else
  1020. {
  1021. parser->SkipToEnd.top() = true;
  1022. }
  1023. }
  1024. //----------------------------------------------------------------------------
  1025. void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser* parser,
  1026. const char* macro)
  1027. {
  1028. // A new PP branch has been opened
  1029. parser->SkipToEnd.push(false);
  1030. if (parser->InPPFalseBranch)
  1031. {
  1032. parser->InPPFalseBranch++;
  1033. }
  1034. else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end())
  1035. {
  1036. parser->InPPFalseBranch = 1;
  1037. }
  1038. else
  1039. {
  1040. // ignore other branches
  1041. parser->SkipToEnd.top() = true;
  1042. }
  1043. }
  1044. //----------------------------------------------------------------------------
  1045. void cmDependsFortranParser_RuleIf(cmDependsFortranParser* parser)
  1046. {
  1047. /* Note: The current parser is _not_ able to get statements like
  1048. * #if 0
  1049. * #if 1
  1050. * #if MYSMBOL
  1051. * #if defined(MYSYMBOL)
  1052. * #if defined(MYSYMBOL) && ...
  1053. * right. The same for #elif. Thus in
  1054. * #if SYMBOL_1
  1055. * ..
  1056. * #elif SYMBOL_2
  1057. * ...
  1058. * ...
  1059. * #elif SYMBOL_N
  1060. * ..
  1061. * #else
  1062. * ..
  1063. * #endif
  1064. * _all_ N+1 branches are considered. If you got something like this
  1065. * #if defined(MYSYMBOL)
  1066. * #if !defined(MYSYMBOL)
  1067. * use
  1068. * #ifdef MYSYMBOL
  1069. * #ifndef MYSYMBOL
  1070. * instead.
  1071. */
  1072. // A new PP branch has been opened
  1073. // Never skip! See note above.
  1074. parser->SkipToEnd.push(false);
  1075. }
  1076. //----------------------------------------------------------------------------
  1077. void cmDependsFortranParser_RuleElif(cmDependsFortranParser* parser)
  1078. {
  1079. /* Note: There are parser limitations. See the note at
  1080. * cmDependsFortranParser_RuleIf(..)
  1081. */
  1082. // Allways taken unless an #ifdef or #ifndef-branch has been taken
  1083. // already. If the second condition isn't meet already
  1084. // (parser->InPPFalseBranch == 0) correct it.
  1085. if(parser->SkipToEnd.top() && !parser->InPPFalseBranch)
  1086. {
  1087. parser->InPPFalseBranch = 1;
  1088. }
  1089. }
  1090. //----------------------------------------------------------------------------
  1091. void cmDependsFortranParser_RuleElse(cmDependsFortranParser* parser)
  1092. {
  1093. // if the parent branch is false do nothing!
  1094. if(parser->InPPFalseBranch > 1)
  1095. {
  1096. return;
  1097. }
  1098. // parser->InPPFalseBranch is either 0 or 1. We change it denpending on
  1099. // parser->SkipToEnd.top()
  1100. if(parser->SkipToEnd.top())
  1101. {
  1102. parser->InPPFalseBranch = 1;
  1103. }
  1104. else
  1105. {
  1106. parser->InPPFalseBranch = 0;
  1107. }
  1108. }
  1109. //----------------------------------------------------------------------------
  1110. void cmDependsFortranParser_RuleEndif(cmDependsFortranParser* parser)
  1111. {
  1112. if(!parser->SkipToEnd.empty())
  1113. {
  1114. parser->SkipToEnd.pop();
  1115. }
  1116. // #endif doesn't know if there was a "#else" in before, so it
  1117. // always decreases InPPFalseBranch
  1118. if(parser->InPPFalseBranch)
  1119. {
  1120. parser->InPPFalseBranch--;
  1121. }
  1122. }