cmVTKMakeInstantiatorCommand.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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 "cmVTKMakeInstantiatorCommand.h"
  14. #include "cmCacheManager.h"
  15. #include "cmGeneratedFileStream.h"
  16. #include "cmSourceFile.h"
  17. bool
  18. cmVTKMakeInstantiatorCommand
  19. ::InitialPass(std::vector<std::string> const& argsIn)
  20. {
  21. if(argsIn.size() < 3)
  22. {
  23. this->SetError("called with incorrect number of arguments");
  24. return false;
  25. }
  26. std::vector<std::string> args;
  27. this->Makefile->ExpandSourceListArguments(argsIn, args, 2);
  28. std::string sourceListValue;
  29. this->ClassName = args[0];
  30. std::vector<cmStdString> inSourceLists;
  31. this->ExportMacro = "-";
  32. bool includesMode = false;
  33. bool oldVersion = true;
  34. // Find the path of the files to be generated.
  35. std::string filePath = this->Makefile->GetCurrentOutputDirectory();
  36. std::string headerPath = filePath;
  37. // Check whether to use the old or new form.
  38. if(this->Makefile->GetDefinition("VTK_USE_INSTANTIATOR_NEW"))
  39. {
  40. oldVersion = false;
  41. }
  42. for(unsigned int i=2;i < args.size();++i)
  43. {
  44. if(args[i] == "HEADER_LOCATION")
  45. {
  46. includesMode = false;
  47. if(++i < args.size())
  48. {
  49. headerPath = args[i];
  50. }
  51. else
  52. {
  53. this->SetError("HEADER_LOCATION option used without value.");
  54. return false;
  55. }
  56. }
  57. else if(args[i] == "EXPORT_MACRO")
  58. {
  59. includesMode = false;
  60. if(++i < args.size())
  61. {
  62. this->ExportMacro = args[i];
  63. }
  64. else
  65. {
  66. this->SetError("EXPORT_MACRO option used without value.");
  67. return false;
  68. }
  69. }
  70. else if(args[i] == "INCLUDES")
  71. {
  72. includesMode = true;
  73. }
  74. // If not an option, it must be another input source list name or
  75. // an include file.
  76. else
  77. {
  78. if(!includesMode)
  79. {
  80. inSourceLists.push_back(args[i]);
  81. }
  82. else
  83. {
  84. this->Includes.push_back(args[i]);
  85. }
  86. }
  87. }
  88. if(this->ExportMacro == "-")
  89. {
  90. this->SetError("No EXPORT_MACRO option given.");
  91. return false;
  92. }
  93. for(std::vector<cmStdString>::const_iterator s = inSourceLists.begin();
  94. s != inSourceLists.end(); ++s)
  95. {
  96. std::string srcName = cmSystemTools::GetFilenameWithoutExtension(*s);
  97. cmSourceFile *sf = this->Makefile->GetSource(s->c_str());
  98. // Wrap-excluded and abstract classes do not have a New() method.
  99. // vtkIndent and vtkTimeStamp are special cases and are not
  100. // vtkObject subclasses.
  101. if(
  102. (!sf || (!sf->GetPropertyAsBool("WRAP_EXCLUDE") &&
  103. !sf->GetPropertyAsBool("ABSTRACT"))) &&
  104. ((srcName != "vtkIndent") && (srcName != "vtkTimeStamp")))
  105. {
  106. this->Classes.push_back(srcName);
  107. }
  108. }
  109. // Generate the header with the class declaration.
  110. {
  111. std::string fileName = this->ClassName + ".h";
  112. std::string fullName = headerPath+"/"+fileName;
  113. // Generate the output file with copy-if-different.
  114. cmGeneratedFileStream fout(fullName.c_str());
  115. fout.SetCopyIfDifferent(true);
  116. // Actually generate the code in the file.
  117. if(!oldVersion)
  118. {
  119. this->GenerateHeaderFile(fout);
  120. }
  121. else
  122. {
  123. this->OldGenerateHeaderFile(fout);
  124. }
  125. }
  126. // Generate the implementation file.
  127. {
  128. std::string fileName = this->ClassName + ".cxx";
  129. std::string fullName = filePath+"/"+fileName;
  130. // Generate the output file with copy-if-different.
  131. {
  132. cmGeneratedFileStream fout(fullName.c_str());
  133. fout.SetCopyIfDifferent(true);
  134. // Actually generate the code in the file.
  135. if(!oldVersion)
  136. {
  137. this->GenerateImplementationFile(fout);
  138. }
  139. else
  140. {
  141. this->OldGenerateImplementationFile(fout);
  142. }
  143. }
  144. // Add the generated source file into the source list.
  145. cmSourceFile file;
  146. file.SetProperty("WRAP_EXCLUDE","1");
  147. file.SetProperty("ABSTRACT","0");
  148. file.SetName(fileName.c_str(), filePath.c_str(),
  149. this->Makefile->GetSourceExtensions(),
  150. this->Makefile->GetHeaderExtensions());
  151. this->Makefile->AddSource(file);
  152. sourceListValue += file.GetSourceName() + ".cxx";
  153. }
  154. if(oldVersion)
  155. {
  156. int groupSize = 10;
  157. size_t numClasses = this->Classes.size();
  158. size_t numFullBlocks = numClasses / groupSize;
  159. size_t lastBlockSize = numClasses % groupSize;
  160. size_t numBlocks = numFullBlocks + ((lastBlockSize>0)? 1:0);
  161. // Generate the files with the ::New() calls to each class. These
  162. // are done in groups to keep the translation unit size smaller.
  163. for(unsigned int block=0; block < numBlocks;++block)
  164. {
  165. std::string fileName = this->OldGenerateCreationFileName(block);
  166. std::string fullName = filePath+"/"+fileName;
  167. // Generate the output file with copy-if-different.
  168. {
  169. cmGeneratedFileStream fout(fullName.c_str());
  170. fout.SetCopyIfDifferent(true);
  171. size_t thisBlockSize =
  172. (block < numFullBlocks)? groupSize:lastBlockSize;
  173. // Actually generate the code in the file.
  174. this->OldGenerateCreationFile(fout,
  175. block*groupSize,
  176. static_cast<int>(thisBlockSize));
  177. }
  178. // Add the generated source file into the source list.
  179. cmSourceFile file;
  180. file.SetProperty("WRAP_EXCLUDE","1");
  181. file.SetProperty("ABSTRACT","0");
  182. file.SetName(fileName.c_str(), filePath.c_str(),
  183. this->Makefile->GetSourceExtensions(),
  184. this->Makefile->GetHeaderExtensions());
  185. this->Makefile->AddSource(file);
  186. sourceListValue += ";";
  187. sourceListValue += file.GetSourceName() + ".cxx";
  188. }
  189. }
  190. this->Makefile->AddDefinition(args[1].c_str(), sourceListValue.c_str());
  191. return true;
  192. }
  193. // Generates the class header file with the definition of the class
  194. // and its initializer class.
  195. void
  196. cmVTKMakeInstantiatorCommand
  197. ::GenerateHeaderFile(std::ostream& os)
  198. {
  199. os <<
  200. "#ifndef __" << this->ClassName.c_str() << "_h\n"
  201. "#define __" << this->ClassName.c_str() << "_h\n"
  202. "\n"
  203. "#include \"vtkInstantiator.h\"\n";
  204. for(unsigned int i=0;i < this->Includes.size();++i)
  205. {
  206. os << "#include \"" << this->Includes[i].c_str() << "\"\n";
  207. }
  208. // Write the instantiator class definition.
  209. os <<
  210. "\n"
  211. "class " << this->ExportMacro.c_str()
  212. << " " << this->ClassName.c_str() << "\n"
  213. "{\n"
  214. "public:\n"
  215. " " << this->ClassName.c_str() << "();\n"
  216. " ~" << this->ClassName.c_str() << "();\n"
  217. "private:\n"
  218. " static void ClassInitialize();\n"
  219. " static void ClassFinalize();\n"
  220. " static unsigned int Count;\n"
  221. "};\n"
  222. "\n";
  223. // Write the initialization instance to make sure the creation
  224. // functions get registered when this generated header is included.
  225. os <<
  226. "static "
  227. << this->ClassName.c_str() << " "
  228. << this->ClassName.c_str() << "Initializer;\n"
  229. "\n"
  230. "#endif\n";
  231. }
  232. // Generates the file with the implementation of the class. All
  233. // methods except the actual object creation functions are generated
  234. // here.
  235. void
  236. cmVTKMakeInstantiatorCommand
  237. ::GenerateImplementationFile(std::ostream& os)
  238. {
  239. // Include the instantiator class header.
  240. os <<
  241. "#include \"" << this->ClassName.c_str() << ".h\"\n"
  242. "\n";
  243. // Write the extern declarations for all the creation functions.
  244. for(unsigned int i=0;i < this->Classes.size();++i)
  245. {
  246. os << "extern vtkObject* vtkInstantiator" <<
  247. this->Classes[i].c_str() << "New();\n";
  248. }
  249. // Write the ClassInitialize method to register all the creation functions.
  250. os <<
  251. "\n"
  252. "void " << this->ClassName.c_str() << "::ClassInitialize()\n"
  253. "{\n";
  254. for(unsigned int i=0;i < this->Classes.size();++i)
  255. {
  256. os << " vtkInstantiator::RegisterInstantiator(\""
  257. << this->Classes[i].c_str() << "\", vtkInstantiator"
  258. << this->Classes[i].c_str() << "New);\n";
  259. }
  260. // Write the ClassFinalize method to unregister all the creation functions.
  261. os <<
  262. "}\n"
  263. "\n"
  264. "void " << this->ClassName.c_str() << "::ClassFinalize()\n"
  265. "{\n";
  266. for(unsigned int i=0;i < this->Classes.size();++i)
  267. {
  268. os << " vtkInstantiator::UnRegisterInstantiator(\""
  269. << this->Classes[i].c_str() << "\", vtkInstantiator"
  270. << this->Classes[i].c_str() << "New);\n";
  271. }
  272. // Write the constructor and destructor of the initializer class to
  273. // call the ClassInitialize and ClassFinalize methods at the right
  274. // time.
  275. os <<
  276. "}\n"
  277. "\n" <<
  278. this->ClassName.c_str() << "::" << this->ClassName.c_str() << "()\n"
  279. "{\n"
  280. " if(++" << this->ClassName.c_str() << "::Count == 1)\n"
  281. " { " << this->ClassName.c_str() << "::ClassInitialize(); }\n"
  282. "}\n"
  283. "\n" <<
  284. this->ClassName.c_str() << "::~" << this->ClassName.c_str() << "()\n"
  285. "{\n"
  286. " if(--" << this->ClassName.c_str() << "::Count == 0)\n"
  287. " { " << this->ClassName.c_str() << "::ClassFinalize(); }\n"
  288. "}\n"
  289. "\n"
  290. "// Number of translation units that include this class's header.\n"
  291. "// Purposely not initialized. Default is static initialization to 0.\n"
  292. "unsigned int " << this->ClassName.c_str() << "::Count;\n";
  293. }
  294. std::string
  295. cmVTKMakeInstantiatorCommand::OldGenerateCreationFileName(unsigned int block)
  296. {
  297. cmOStringStream nameStr;
  298. nameStr << this->ClassName.c_str() << block << ".cxx";
  299. std::string result = nameStr.str();
  300. return result;
  301. }
  302. // Generates a file that includes the headers of the classes it knows
  303. // how to create and provides functions which create the classes with
  304. // the New() method.
  305. void
  306. cmVTKMakeInstantiatorCommand
  307. ::OldGenerateCreationFile(std::ostream& os, unsigned int groupStart,
  308. unsigned int groupSize)
  309. {
  310. // Need to include header of generated class.
  311. os <<
  312. "#include \"" << this->ClassName.c_str() << ".h\"\n"
  313. "\n";
  314. // Include class files.
  315. for(unsigned int i=0;i < groupSize;++i)
  316. {
  317. os << "#include \"" << this->Classes[groupStart+i].c_str() << ".h\"\n";
  318. }
  319. os <<
  320. "\n";
  321. // Write the create function implementations.
  322. for(unsigned int i=0;i < groupSize;++i)
  323. {
  324. os << "vtkObject* " << this->ClassName.c_str() << "::Create_"
  325. << this->Classes[groupStart+i].c_str() << "() { return "
  326. << this->Classes[groupStart+i].c_str() << "::New(); }\n";
  327. }
  328. }
  329. // Generates the class header file with the definition of the class
  330. // and its initializer class.
  331. void
  332. cmVTKMakeInstantiatorCommand
  333. ::OldGenerateHeaderFile(std::ostream& os)
  334. {
  335. os <<
  336. "#ifndef __" << this->ClassName.c_str() << "_h\n"
  337. "#define __" << this->ClassName.c_str() << "_h\n"
  338. "\n"
  339. "#include \"vtkInstantiator.h\"\n";
  340. for(unsigned int i=0;i < this->Includes.size();++i)
  341. {
  342. os << "#include \"" << this->Includes[i].c_str() << "\"\n";
  343. }
  344. os <<
  345. "\n"
  346. "class " << this->ClassName.c_str() << "Initialize;\n"
  347. "\n"
  348. "class " << this->ExportMacro.c_str() << " "
  349. << this->ClassName.c_str() << "\n"
  350. "{\n"
  351. " friend class " << this->ClassName.c_str() << "Initialize;\n"
  352. "\n"
  353. " static void ClassInitialize();\n"
  354. " static void ClassFinalize();\n"
  355. "\n";
  356. for(unsigned int i=0;i < this->Classes.size();++i)
  357. {
  358. os << " static vtkObject* Create_"
  359. << this->Classes[i].c_str() << "();\n";
  360. }
  361. // Write the initializer class to make sure the creation functions
  362. // get registered when this generated header is included.
  363. os <<
  364. "};\n"
  365. "\n"
  366. "class " << this->ExportMacro.c_str() << " "
  367. << this->ClassName.c_str() << "Initialize\n"
  368. "{\n"
  369. "public:\n"
  370. " " << this->ClassName.c_str() << "Initialize();\n"
  371. " ~" << this->ClassName.c_str() << "Initialize();\n"
  372. "private:\n"
  373. " static unsigned int Count;\n"
  374. "};\n"
  375. "\n"
  376. "static " << this->ClassName.c_str() << "Initialize "
  377. << this->ClassName.c_str() << "Initializer;\n"
  378. "\n"
  379. "#endif\n";
  380. }
  381. // Generates the file with the implementation of the class. All
  382. // methods except the actual object creation functions are generated
  383. // here.
  384. void cmVTKMakeInstantiatorCommand
  385. ::OldGenerateImplementationFile(std::ostream& os)
  386. {
  387. // Write the ClassInitialize method to register all the creation functions.
  388. os <<
  389. "#include \"" << this->ClassName.c_str() << ".h\"\n"
  390. "\n"
  391. "void " << this->ClassName.c_str() << "::ClassInitialize()\n"
  392. "{\n";
  393. for(unsigned int i=0;i < this->Classes.size();++i)
  394. {
  395. os << " vtkInstantiator::RegisterInstantiator(\""
  396. << this->Classes[i].c_str() << "\", "
  397. << this->ClassName.c_str() << "::Create_"
  398. << this->Classes[i].c_str() << ");\n";
  399. }
  400. // Write the ClassFinalize method to unregister all the creation functions.
  401. os <<
  402. "}\n"
  403. "\n"
  404. "void " << this->ClassName.c_str() << "::ClassFinalize()\n"
  405. "{\n";
  406. for(unsigned int i=0;i < this->Classes.size();++i)
  407. {
  408. os << " vtkInstantiator::UnRegisterInstantiator(\""
  409. << this->Classes[i].c_str() << "\", "
  410. << this->ClassName.c_str() << "::Create_"
  411. << this->Classes[i].c_str() << ");\n";
  412. }
  413. // Write the constructor and destructor of the initializer class to
  414. // call the ClassInitialize and ClassFinalize methods at the right
  415. // time.
  416. os <<
  417. "}\n"
  418. "\n" <<
  419. this->ClassName.c_str() << "Initialize::" <<
  420. this->ClassName.c_str() << "Initialize()\n"
  421. "{\n"
  422. " if(++" << this->ClassName.c_str() << "Initialize::Count == 1)\n"
  423. " { " << this->ClassName.c_str() << "::ClassInitialize(); }\n"
  424. "}\n"
  425. "\n" <<
  426. this->ClassName.c_str() << "Initialize::~" <<
  427. this->ClassName.c_str() << "Initialize()\n"
  428. "{\n"
  429. " if(--" << this->ClassName.c_str() << "Initialize::Count == 0)\n"
  430. " { " << this->ClassName.c_str() << "::ClassFinalize(); }\n"
  431. "}\n"
  432. "\n"
  433. "// Number of translation units that include this class's header.\n"
  434. "// Purposely not initialized. Default is static initialization to 0.\n"
  435. "unsigned int " << this->ClassName.c_str() << "Initialize::Count;\n";
  436. }