cmVTKMakeInstantiatorCommand.cxx 14 KB

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