cmVTKMakeInstantiatorCommand.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*=========================================================================
  2. Program: Insight Segmentation & Registration Toolkit
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Insight Consortium. All rights reserved.
  8. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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& args)
  19. {
  20. if(args.size() < 3)
  21. {
  22. this->SetError("called with incorrect number of arguments");
  23. return false;
  24. }
  25. m_ClassName = args[0];
  26. std::string outSourceList = args[1];
  27. std::vector<cmStdString> inSourceLists;
  28. m_ExportMacro = "-";
  29. unsigned int groupSize = 10;
  30. bool includesMode = false;
  31. // Find the path of the files to be generated.
  32. std::string filePath = m_Makefile->GetCurrentOutputDirectory();
  33. std::string headerPath = filePath;
  34. for(unsigned int i=2;i < args.size();++i)
  35. {
  36. if(args[i] == "GROUP_SIZE")
  37. {
  38. includesMode = false;
  39. if(++i < args.size())
  40. {
  41. groupSize = atoi(args[i].c_str());
  42. }
  43. else
  44. {
  45. this->SetError("GROUP_SIZE option used without value.");
  46. return false;
  47. }
  48. }
  49. else if(args[i] == "HEADER_LOCATION")
  50. {
  51. includesMode = false;
  52. if(++i < args.size())
  53. {
  54. headerPath = args[i];
  55. }
  56. else
  57. {
  58. this->SetError("HEADER_LOCATION option used without value.");
  59. return false;
  60. }
  61. }
  62. else if(args[i] == "EXPORT_MACRO")
  63. {
  64. includesMode = false;
  65. if(++i < args.size())
  66. {
  67. m_ExportMacro = args[i];
  68. }
  69. else
  70. {
  71. this->SetError("EXPORT_MACRO option used without value.");
  72. return false;
  73. }
  74. }
  75. else if(args[i] == "INCLUDES")
  76. {
  77. includesMode = true;
  78. }
  79. // If not an option, it must be another input source list name or
  80. // an include file.
  81. else
  82. {
  83. if(!includesMode)
  84. {
  85. inSourceLists.push_back(args[i]);
  86. }
  87. else
  88. {
  89. m_Includes.push_back(args[i]);
  90. }
  91. }
  92. }
  93. if(m_ExportMacro == "-")
  94. {
  95. this->SetError("No EXPORT_MACRO option given.");
  96. return false;
  97. }
  98. for(std::vector<cmStdString>::const_iterator s = inSourceLists.begin();
  99. s != inSourceLists.end(); ++s)
  100. {
  101. // Find the source list specified.
  102. cmMakefile::SourceMap::iterator srcListIter =
  103. m_Makefile->GetSources().find(*s);
  104. if(srcListIter == m_Makefile->GetSources().end())
  105. {
  106. std::string errStr = "No source list named " + *s;
  107. this->SetError(errStr.c_str());
  108. return false;
  109. }
  110. std::vector<cmSourceFile>& srcList = srcListIter->second;
  111. // Collect the names of the classes.
  112. for(std::vector<cmSourceFile>::iterator src = srcList.begin();
  113. src != srcList.end();++src)
  114. {
  115. // Wrap-excluded and abstract classes do not have a New() method.
  116. // vtkIndent and vtkTimeStamp are special cases and are not
  117. // vtkObject subclasses.
  118. if(!src->GetWrapExclude() && !src->GetIsAnAbstractClass()
  119. && (src->GetSourceName() != "vtkIndent")
  120. && (src->GetSourceName() != "vtkTimeStamp"))
  121. {
  122. m_Classes.push_back(src->GetSourceName());
  123. }
  124. }
  125. }
  126. // Generate the header with the class declaration.
  127. {
  128. std::string fileName = m_ClassName + ".h";
  129. std::string fullName = headerPath+"/"+fileName;
  130. // Generate the output file with copy-if-different.
  131. cmGeneratedFileStream fout(fullName.c_str());
  132. // Actually generate the code in the file.
  133. this->GenerateHeaderFile(fout.GetStream());
  134. }
  135. // Generate the implementation file.
  136. {
  137. std::string fileName = m_ClassName + ".cxx";
  138. std::string fullName = filePath+"/"+fileName;
  139. // Generate the output file with copy-if-different.
  140. {
  141. cmGeneratedFileStream fout(fullName.c_str());
  142. // Actually generate the code in the file.
  143. this->GenerateImplementationFile(fout.GetStream());
  144. }
  145. // Add the generated source file into the source list.
  146. cmSourceFile file;
  147. file.SetWrapExclude(true);
  148. file.SetIsAnAbstractClass(false);
  149. file.SetName(fileName.c_str(), filePath.c_str(),
  150. m_Makefile->GetSourceExtensions(),
  151. m_Makefile->GetHeaderExtensions());
  152. m_Makefile->AddSource(file, outSourceList.c_str());
  153. }
  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->GenerateCreationFileName(block);
  163. std::string fullName = filePath+"/"+fileName;
  164. // Generate the output file with copy-if-different.
  165. {
  166. cmGeneratedFileStream fout(fullName.c_str());
  167. unsigned int thisBlockSize =
  168. (block < numFullBlocks)? groupSize:lastBlockSize;
  169. // Actually generate the code in the file.
  170. this->GenerateCreationFile(fout.GetStream(),
  171. block*groupSize, thisBlockSize);
  172. }
  173. // Add the generated source file into the source list.
  174. cmSourceFile file;
  175. file.SetWrapExclude(true);
  176. file.SetIsAnAbstractClass(false);
  177. file.SetName(fileName.c_str(), filePath.c_str(),
  178. m_Makefile->GetSourceExtensions(),
  179. m_Makefile->GetHeaderExtensions());
  180. m_Makefile->AddSource(file, outSourceList.c_str());
  181. }
  182. return true;
  183. }
  184. std::string
  185. cmVTKMakeInstantiatorCommand::GenerateCreationFileName(unsigned int block)
  186. {
  187. std::strstream nameStr;
  188. nameStr << m_ClassName.c_str() << block << ".cxx" << std::ends;
  189. std::string result = nameStr.str();
  190. nameStr.rdbuf()->freeze(0);
  191. return result;
  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 __" << m_ClassName.c_str() << "_h\n"
  201. "#define __" << m_ClassName.c_str() << "_h\n"
  202. "\n"
  203. "#include \"vtkInstantiator.h\"\n";
  204. for(unsigned int i=0;i < m_Includes.size();++i)
  205. {
  206. os << "#include \"" << m_Includes[i].c_str() << "\"\n";
  207. }
  208. os <<
  209. "\n"
  210. "class " << m_ClassName.c_str() << "Initialize;\n"
  211. "\n"
  212. "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "\n"
  213. "{\n"
  214. " friend class " << m_ClassName.c_str() << "Initialize;\n"
  215. "\n"
  216. " static void ClassInitialize();\n"
  217. " static void ClassFinalize();\n"
  218. "\n";
  219. for(unsigned int i=0;i < m_Classes.size();++i)
  220. {
  221. os << " static vtkObject* Create_" << m_Classes[i].c_str() << "();\n";
  222. }
  223. // Write the initializer class to make sure the creation functions
  224. // get registered when this generated header is included.
  225. os <<
  226. "};\n"
  227. "\n"
  228. "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "Initialize\n"
  229. "{\n"
  230. "public:\n"
  231. " " << m_ClassName.c_str() << "Initialize();\n"
  232. " ~" << m_ClassName.c_str() << "Initialize();\n"
  233. "private:\n"
  234. " static unsigned int Count;\n"
  235. "};\n"
  236. "\n"
  237. "static " << m_ClassName.c_str() << "Initialize " << m_ClassName.c_str() << "Initializer;\n"
  238. "\n"
  239. "#endif\n";
  240. }
  241. // Generates the file with the implementation of the class. All
  242. // methods except the actual object creation functions are generated
  243. // here.
  244. void
  245. cmVTKMakeInstantiatorCommand
  246. ::GenerateImplementationFile(std::ostream& os)
  247. {
  248. // Write the ClassInitialize method to register all the creation functions.
  249. os <<
  250. "#include \"" << m_ClassName.c_str() << ".h\"\n"
  251. "\n"
  252. "void " << m_ClassName.c_str() << "::ClassInitialize()\n"
  253. "{\n";
  254. for(unsigned int i=0;i < m_Classes.size();++i)
  255. {
  256. os << " vtkInstantiator::RegisterInstantiator(\""
  257. << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
  258. << m_Classes[i].c_str() << ");\n";
  259. }
  260. // Write the ClassFinalize method to unregister all the creation functions.
  261. os <<
  262. "}\n"
  263. "\n"
  264. "void " << m_ClassName.c_str() << "::ClassFinalize()\n"
  265. "{\n";
  266. for(unsigned int i=0;i < m_Classes.size();++i)
  267. {
  268. os << " vtkInstantiator::UnRegisterInstantiator(\""
  269. << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
  270. << m_Classes[i].c_str() << ");\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. m_ClassName.c_str() << "Initialize::" << m_ClassName.c_str() << "Initialize()\n"
  279. "{\n"
  280. " if(++" << m_ClassName.c_str() << "Initialize::Count == 1)\n"
  281. " { " << m_ClassName.c_str() << "::ClassInitialize(); }\n"
  282. "}\n"
  283. "\n" <<
  284. m_ClassName.c_str() << "Initialize::~" << m_ClassName.c_str() << "Initialize()\n"
  285. "{\n"
  286. " if(--" << m_ClassName.c_str() << "Initialize::Count == 0)\n"
  287. " { " << m_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 " << m_ClassName.c_str() << "Initialize::Count;\n";
  293. }
  294. // Generates a file that includes the headers of the classes it knows
  295. // how to create and provides functions which create the classes with
  296. // the New() method.
  297. void
  298. cmVTKMakeInstantiatorCommand
  299. ::GenerateCreationFile(std::ostream& os, unsigned int groupStart,
  300. unsigned int groupSize)
  301. {
  302. // Need to include header of generated class.
  303. os <<
  304. "#include \"" << m_ClassName.c_str() << ".h\"\n"
  305. "\n";
  306. // Include class files.
  307. for(unsigned int i=0;i < groupSize;++i)
  308. {
  309. os << "#include \"" << m_Classes[groupStart+i].c_str() << ".h\"\n";
  310. }
  311. os <<
  312. "\n";
  313. // Write the create function implementations.
  314. for(unsigned int i=0;i < groupSize;++i)
  315. {
  316. os << "vtkObject* " << m_ClassName.c_str() << "::Create_"
  317. << m_Classes[groupStart+i].c_str() << "() { return "
  318. << m_Classes[groupStart+i].c_str() << "::New(); }\n";
  319. }
  320. }