You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

591 lines
20 KiB

  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 "cmDependsFortranParser.h" /* Interface to parser object. */
  18. #include <assert.h>
  19. #include <stack>
  20. // TODO: Test compiler for the case of the mod file. Some always
  21. // use lower case and some always use upper case. I do not know if any
  22. // use the case from the source code.
  23. //----------------------------------------------------------------------------
  24. // Parser methods not included in generated interface.
  25. // Get the current buffer processed by the lexer.
  26. YY_BUFFER_STATE cmDependsFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
  27. // The parser entry point.
  28. int cmDependsFortran_yyparse(yyscan_t);
  29. //----------------------------------------------------------------------------
  30. // Define parser object internal structure.
  31. struct cmDependsFortranFile
  32. {
  33. cmDependsFortranFile(FILE* file, YY_BUFFER_STATE buffer,
  34. const std::string& dir):
  35. File(file), Buffer(buffer), Directory(dir) {}
  36. FILE* File;
  37. YY_BUFFER_STATE Buffer;
  38. std::string Directory;
  39. };
  40. struct cmDependsFortranParser_s
  41. {
  42. cmDependsFortranParser_s(cmDependsFortran* self);
  43. ~cmDependsFortranParser_s();
  44. // Pointer back to the main class.
  45. cmDependsFortran* Self;
  46. // Lexical scanner instance.
  47. yyscan_t Scanner;
  48. // Stack of open files in the translation unit.
  49. std::stack<cmDependsFortranFile> FileStack;
  50. // Buffer for string literals.
  51. std::string TokenString;
  52. // Flag for whether lexer is reading from inside an interface.
  53. bool InInterface;
  54. int OldStartcond;
  55. bool InPPFalseBranch;
  56. std::vector<bool> SkipToEnd;
  57. int StepI;
  58. // Set of provided and required modules.
  59. std::set<cmStdString> Provides;
  60. std::set<cmStdString> Requires;
  61. // Set of files included in the translation unit.
  62. std::set<cmStdString> Includes;
  63. };
  64. //----------------------------------------------------------------------------
  65. cmDependsFortran::cmDependsFortran():
  66. IncludePath(0)
  67. {
  68. }
  69. //----------------------------------------------------------------------------
  70. cmDependsFortran::cmDependsFortran(std::vector<std::string> const& includes):
  71. IncludePath(&includes)
  72. {
  73. }
  74. //----------------------------------------------------------------------------
  75. cmDependsFortran::~cmDependsFortran()
  76. {
  77. }
  78. //----------------------------------------------------------------------------
  79. bool cmDependsFortran::WriteDependencies(const char *src, const char *obj,
  80. std::ostream& makeDepends, std::ostream& internalDepends)
  81. {
  82. // Make sure this is a scanning instance.
  83. if(!src || src[0] == '\0')
  84. {
  85. cmSystemTools::Error("Cannot scan dependencies without an source file.");
  86. return false;
  87. }
  88. if(!obj || obj[0] == '\0')
  89. {
  90. cmSystemTools::Error("Cannot scan dependencies without an object file.");
  91. return false;
  92. }
  93. if(!this->IncludePath)
  94. {
  95. cmSystemTools::Error("Cannot scan dependencies without an include path.");
  96. return false;
  97. }
  98. // Get the directory in which stamp files will be stored.
  99. std::string stamp_dir =
  100. this->LocalGenerator->GetMakefile()->GetCurrentOutputDirectory();
  101. // Create the parser object.
  102. cmDependsFortranParser parser(this);
  103. // Push on the starting file.
  104. cmDependsFortranParser_FilePush(&parser, src);
  105. // Parse the translation unit.
  106. if(cmDependsFortran_yyparse(parser.Scanner) != 0)
  107. {
  108. // Failed to parse the file. Report failure to write dependencies.
  109. return false;
  110. }
  111. // Write the include dependencies to the output stream.
  112. internalDepends << obj << std::endl;
  113. for(std::set<cmStdString>::const_iterator i = parser.Includes.begin();
  114. i != parser.Includes.end(); ++i)
  115. {
  116. makeDepends << obj << ": "
  117. << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
  118. << std::endl;
  119. internalDepends << " " << i->c_str() << std::endl;
  120. }
  121. makeDepends << std::endl;
  122. // Write module requirements to the output stream.
  123. for(std::set<cmStdString>::const_iterator i = parser.Requires.begin();
  124. i != parser.Requires.end(); ++i)
  125. {
  126. // Require only modules not provided in the same source.
  127. if(parser.Provides.find(*i) == parser.Provides.end())
  128. {
  129. // since we require some things add them to our list of requirements
  130. makeDepends << obj << ".requires: " << i->c_str() << ".mod.proxy"
  131. << std::endl;
  132. // create an empty proxy in case no other source provides it
  133. makeDepends << i->c_str() << ".mod.proxy:" << std::endl;
  134. // The object file should depend on timestamped files for the
  135. // modules it uses.
  136. std::string m = cmSystemTools::LowerCase(*i);
  137. makeDepends << obj << ": " << m.c_str() << ".mod.stamp\n";
  138. // Create a dummy timestamp file for the module.
  139. std::string fullPath = stamp_dir;
  140. fullPath += "/";
  141. fullPath += m;
  142. fullPath += ".mod.stamp";
  143. if(!cmSystemTools::FileExists(fullPath.c_str()))
  144. {
  145. std::ofstream dummy(fullPath.c_str());
  146. dummy
  147. << "This is a fake module timestamp file created by CMake because\n"
  148. << " " << src << "\n"
  149. << "requires the module and\n"
  150. << " " << obj << "\n"
  151. << "depends on this timestamp file.\n"
  152. << "\n"
  153. << "If another source in the same directory provides the module\n"
  154. << "this file will be overwritten with a real module timestamp\n"
  155. << "that is updated when the module is rebuilt.\n"
  156. << "\n"
  157. << "If no source in the directory provides the module at least\n"
  158. << "the project will build without failing to find the module\n"
  159. << "timestamp.\n"
  160. << "\n"
  161. << "In the future CMake may be able to locate modules in other\n"
  162. << "directories or outside the project and update this timestamp\n"
  163. << "file as necessary.\n"
  164. ;
  165. }
  166. }
  167. }
  168. // Write provided modules to the output stream.
  169. for(std::set<cmStdString>::const_iterator i = parser.Provides.begin();
  170. i != parser.Provides.end(); ++i)
  171. {
  172. makeDepends << i->c_str() << ".mod.proxy: " << obj
  173. << ".provides" << std::endl;
  174. }
  175. // If any modules are provided then they must be converted to stamp files.
  176. if(!parser.Provides.empty())
  177. {
  178. makeDepends << obj << ".provides.build:\n";
  179. for(std::set<cmStdString>::const_iterator i = parser.Provides.begin();
  180. i != parser.Provides.end(); ++i)
  181. {
  182. // Always use lower case for the mod stamp file name. The
  183. // cmake_copy_f90_mod will call back to this class, which will
  184. // try various cases for the real mod file name.
  185. std::string m = cmSystemTools::LowerCase(*i);
  186. makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod "
  187. << i->c_str() << " " << m.c_str() << ".mod.stamp\n";
  188. }
  189. makeDepends << "\t@touch " << obj << ".provides.build\n";
  190. }
  191. /*
  192. // TODO:
  193. What about .mod files provided in another directory and found with a
  194. -M search path? The stamp file will not be updated, so things might
  195. not rebuild. Possible solutions (not all thought through):
  196. Solution 1: Have all the .o.requires in a directory depend on a
  197. single .outside.requires that searches for .mod files in another
  198. directory of the build tree and uses copy-if-different to produce
  199. the local directory's stamp files. (won't work because the single
  200. rule cannot know about the modules)
  201. Solution 2: When the dependency is detected search the module
  202. include path for a mark file indicating the module is provided. If
  203. not found just write the dummy stamp file. If found, we need a rule
  204. to copy-if-different the module file. When a module is provided,
  205. write this mark file.
  206. Solution 3: Use a set of make rules like this:
  207. # When required:
  208. foo.mod.proxy: foo.mod.default
  209. foo.mod.default:: foo.mod.hack
  210. @echo foo.mod.default2 # Search for and copy-if-different the mod file.
  211. foo.mod.hack:
  212. # When provided:
  213. foo.mod.proxy: foo.o.requires
  214. @rm -f foo.mod.hack foo.mod.default
  215. foo.o.requires: foo.mod.hack
  216. @echo foo.o.requires
  217. foo.mod.hack:
  218. @touch foo.mod.hack
  219. @touch foo.mod.default
  220. Solution 4:
  221. When scanning dependencies and providing a module:
  222. - Create a .mod.provided.
  223. - Add .mod.proxy rule depending on corresponding .o.requires.
  224. When scanning dependencies and requiring a module:
  225. - Search the module path for a .mod.provided or a .mod.
  226. - If a .mod.provided is found depend on the corresponding .mod.stamp
  227. (it is provided by CMake in another directory)
  228. - Else, if a .mod is found depend on it directly
  229. (it is provided in another directory by a non-CMake project)
  230. - Else:
  231. - Add the empty proxy rule (if it is provided locally this will hook it)
  232. - Depend on a local .mod.stamp (it might be provided locally)
  233. - Create the dummy local .mod.stamp (it might not be provided locally)
  234. */
  235. return true;
  236. }
  237. //----------------------------------------------------------------------------
  238. bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
  239. {
  240. // Implements
  241. //
  242. // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
  243. //
  244. // Note that the case of the .mod file depends on the compiler. In
  245. // the future this copy could also account for the fact that some
  246. // compilers include a timestamp in the .mod file so it changes even
  247. // when the interface described in the module does not.
  248. std::string mod = args[2];
  249. std::string stamp = args[3];
  250. std::string mod_upper = cmSystemTools::UpperCase(mod.c_str());
  251. std::string mod_lower = cmSystemTools::LowerCase(mod.c_str());
  252. mod += ".mod";
  253. mod_upper += ".mod";
  254. mod_lower += ".mod";
  255. if(cmSystemTools::FileExists(mod_upper.c_str()))
  256. {
  257. if(!cmSystemTools::CopyFileIfDifferent(mod_upper.c_str(), stamp.c_str()))
  258. {
  259. std::cerr << "Error copying Fortran module from \""
  260. << mod_upper.c_str() << "\" to \"" << stamp.c_str()
  261. << "\".\n";
  262. return false;
  263. }
  264. return true;
  265. }
  266. else if(cmSystemTools::FileExists(mod_lower.c_str()))
  267. {
  268. if(!cmSystemTools::CopyFileIfDifferent(mod_lower.c_str(), stamp.c_str()))
  269. {
  270. std::cerr << "Error copying Fortran module from \""
  271. << mod_lower.c_str() << "\" to \"" << stamp.c_str()
  272. << "\".\n";
  273. return false;
  274. }
  275. return true;
  276. }
  277. std::cerr << "Error copying Fortran module \"" << args[2].c_str()
  278. << "\". Tried \"" << mod_upper.c_str()
  279. << "\" and \"" << mod_lower.c_str() << "\".\n";
  280. return false;
  281. }
  282. //----------------------------------------------------------------------------
  283. bool cmDependsFortran::FindIncludeFile(const char* dir,
  284. const char* includeName,
  285. std::string& fileName)
  286. {
  287. // If the file is a full path, include it directly.
  288. if(cmSystemTools::FileIsFullPath(includeName))
  289. {
  290. fileName = includeName;
  291. return cmSystemTools::FileExists(fileName.c_str());
  292. }
  293. else
  294. {
  295. // Check for the file in the directory containing the including
  296. // file.
  297. std::string fullName = dir;
  298. fullName += "/";
  299. fullName += includeName;
  300. if(cmSystemTools::FileExists(fullName.c_str()))
  301. {
  302. fileName = fullName;
  303. return true;
  304. }
  305. // Search the include path for the file.
  306. for(std::vector<std::string>::const_iterator i =
  307. this->IncludePath->begin(); i != this->IncludePath->end(); ++i)
  308. {
  309. fullName = *i;
  310. fullName += "/";
  311. fullName += includeName;
  312. if(cmSystemTools::FileExists(fullName.c_str()))
  313. {
  314. fileName = fullName;
  315. return true;
  316. }
  317. }
  318. }
  319. return false;
  320. }
  321. //----------------------------------------------------------------------------
  322. cmDependsFortranParser_s::cmDependsFortranParser_s(cmDependsFortran* self):
  323. Self(self)
  324. {
  325. this->InInterface = 0;
  326. // Initialize the lexical scanner.
  327. cmDependsFortran_yylex_init(&this->Scanner);
  328. cmDependsFortran_yyset_extra(this, this->Scanner);
  329. // Create a dummy buffer that is never read but is the fallback
  330. // buffer when the last file is popped off the stack.
  331. YY_BUFFER_STATE buffer =
  332. cmDependsFortran_yy_create_buffer(0, 4, this->Scanner);
  333. cmDependsFortran_yy_switch_to_buffer(buffer, this->Scanner);
  334. }
  335. //----------------------------------------------------------------------------
  336. cmDependsFortranParser_s::~cmDependsFortranParser_s()
  337. {
  338. cmDependsFortran_yylex_destroy(this->Scanner);
  339. }
  340. //----------------------------------------------------------------------------
  341. bool cmDependsFortranParser_FilePush(cmDependsFortranParser* parser,
  342. const char* fname)
  343. {
  344. // Open the new file and push it onto the stack. Save the old
  345. // buffer with it on the stack.
  346. if(FILE* file = fopen(fname, "rb"))
  347. {
  348. YY_BUFFER_STATE current =
  349. cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
  350. std::string dir = cmSystemTools::GetParentDirectory(fname);
  351. cmDependsFortranFile f(file, current, dir);
  352. YY_BUFFER_STATE buffer =
  353. cmDependsFortran_yy_create_buffer(0, 16384, parser->Scanner);
  354. cmDependsFortran_yy_switch_to_buffer(buffer, parser->Scanner);
  355. parser->FileStack.push(f);
  356. return 1;
  357. }
  358. else
  359. {
  360. return 0;
  361. }
  362. }
  363. //----------------------------------------------------------------------------
  364. bool cmDependsFortranParser_FilePop(cmDependsFortranParser* parser)
  365. {
  366. // Pop one file off the stack and close it. Switch the lexer back
  367. // to the next one on the stack.
  368. if(parser->FileStack.empty())
  369. {
  370. return 0;
  371. }
  372. else
  373. {
  374. cmDependsFortranFile f = parser->FileStack.top(); parser->FileStack.pop();
  375. fclose(f.File);
  376. YY_BUFFER_STATE current =
  377. cmDependsFortranLexer_GetCurrentBuffer(parser->Scanner);
  378. cmDependsFortran_yy_delete_buffer(current, parser->Scanner);
  379. cmDependsFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
  380. return 1;
  381. }
  382. }
  383. //----------------------------------------------------------------------------
  384. int cmDependsFortranParser_Input(cmDependsFortranParser* parser,
  385. char* buffer, size_t bufferSize)
  386. {
  387. // Read from the file on top of the stack. If the stack is empty,
  388. // the end of the translation unit has been reached.
  389. if(!parser->FileStack.empty())
  390. {
  391. FILE* file = parser->FileStack.top().File;
  392. return (int)fread(buffer, 1, bufferSize, file);
  393. }
  394. return 0;
  395. }
  396. //----------------------------------------------------------------------------
  397. void cmDependsFortranParser_StringStart(cmDependsFortranParser* parser)
  398. {
  399. parser->TokenString = "";
  400. }
  401. //----------------------------------------------------------------------------
  402. const char* cmDependsFortranParser_StringEnd(cmDependsFortranParser* parser)
  403. {
  404. return parser->TokenString.c_str();
  405. }
  406. //----------------------------------------------------------------------------
  407. void cmDependsFortranParser_StringAppend(cmDependsFortranParser* parser,
  408. char c)
  409. {
  410. parser->TokenString += c;
  411. }
  412. //----------------------------------------------------------------------------
  413. void cmDependsFortranParser_SetInInterface(cmDependsFortranParser* parser,
  414. bool in)
  415. {
  416. parser->InInterface = in;
  417. }
  418. //----------------------------------------------------------------------------
  419. bool cmDependsFortranParser_GetInInterface(cmDependsFortranParser* parser)
  420. {
  421. return parser->InInterface;
  422. }
  423. //----------------------------------------------------------------------------
  424. void cmDependsFortranParser_SetOldStartcond(cmDependsFortranParser* parser,
  425. int arg)
  426. {
  427. parser->OldStartcond = arg;
  428. }
  429. //----------------------------------------------------------------------------
  430. int cmDependsFortranParser_GetOldStartcond(cmDependsFortranParser* parser)
  431. {
  432. return parser->OldStartcond;
  433. }
  434. //----------------------------------------------------------------------------
  435. void cmDependsFortranParser_Error(cmDependsFortranParser*, const char*)
  436. {
  437. // If there is a parser error just ignore it. The source will not
  438. // compile and the user will edit it. Then dependencies will have
  439. // to be regenerated anyway.
  440. }
  441. //----------------------------------------------------------------------------
  442. void cmDependsFortranParser_RuleUse(cmDependsFortranParser* parser,
  443. const char* name)
  444. {
  445. parser->Requires.insert(cmSystemTools::LowerCase(name) );
  446. }
  447. //----------------------------------------------------------------------------
  448. void cmDependsFortranParser_RuleInclude(cmDependsFortranParser* parser,
  449. const char* name)
  450. {
  451. // If processing an include statement there must be an open file.
  452. assert(!parser->FileStack.empty());
  453. // Get the directory containing the source in which the include
  454. // statement appears. This is always the first search location for
  455. // Fortran include files.
  456. std::string dir = parser->FileStack.top().Directory;
  457. // Find the included file. If it cannot be found just ignore the
  458. // problem because either the source will not compile or the user
  459. // does not care about depending on this included source.
  460. std::string fullName;
  461. if(parser->Self->FindIncludeFile(dir.c_str(), name, fullName))
  462. {
  463. // Found the included file. Save it in the set of included files.
  464. parser->Includes.insert(fullName);
  465. // Parse it immediately to translate the source inline.
  466. cmDependsFortranParser_FilePush(parser, fullName.c_str());
  467. }
  468. }
  469. //----------------------------------------------------------------------------
  470. void cmDependsFortranParser_RuleModule(cmDependsFortranParser* parser,
  471. const char* name)
  472. {
  473. if(!parser->InInterface )
  474. {
  475. parser->Provides.insert(cmSystemTools::LowerCase(name));
  476. }
  477. }
  478. //----------------------------------------------------------------------------
  479. void cmDependsFortranParser_RuleDefine(cmDependsFortranParser*, const char*)
  480. {
  481. }
  482. //----------------------------------------------------------------------------
  483. void cmDependsFortranParser_RuleUndef(cmDependsFortranParser*, const char*)
  484. {
  485. }
  486. //----------------------------------------------------------------------------
  487. void cmDependsFortranParser_RuleIfdef(cmDependsFortranParser*, const char*)
  488. {
  489. }
  490. //----------------------------------------------------------------------------
  491. void cmDependsFortranParser_RuleIfndef(cmDependsFortranParser*, const char*)
  492. {
  493. }
  494. //----------------------------------------------------------------------------
  495. void cmDependsFortranParser_RuleIf(cmDependsFortranParser*)
  496. {
  497. }
  498. //----------------------------------------------------------------------------
  499. void cmDependsFortranParser_RuleElif(cmDependsFortranParser*)
  500. {
  501. }
  502. //----------------------------------------------------------------------------
  503. void cmDependsFortranParser_RuleElse(cmDependsFortranParser*)
  504. {
  505. }
  506. //----------------------------------------------------------------------------
  507. void cmDependsFortranParser_RuleEndif(cmDependsFortranParser*)
  508. {
  509. }