cmDependsFortran.cxx 39 KB

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