cmVTKMakeInstantiatorCommand.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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& 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. cmSystemTools::ExpandListArguments(argsIn, args);
  27. m_ClassName = args[0];
  28. std::string outSourceList = args[1];
  29. std::vector<cmStdString> inSourceLists;
  30. m_ExportMacro = "-";
  31. unsigned int groupSize = 10;
  32. bool includesMode = false;
  33. // Find the path of the files to be generated.
  34. std::string filePath = m_Makefile->GetCurrentOutputDirectory();
  35. std::string headerPath = filePath;
  36. for(unsigned int i=2;i < args.size();++i)
  37. {
  38. if(args[i] == "GROUP_SIZE")
  39. {
  40. includesMode = false;
  41. if(++i < args.size())
  42. {
  43. groupSize = atoi(args[i].c_str());
  44. }
  45. else
  46. {
  47. this->SetError("GROUP_SIZE option used without value.");
  48. return false;
  49. }
  50. }
  51. else if(args[i] == "HEADER_LOCATION")
  52. {
  53. includesMode = false;
  54. if(++i < args.size())
  55. {
  56. headerPath = args[i];
  57. }
  58. else
  59. {
  60. this->SetError("HEADER_LOCATION option used without value.");
  61. return false;
  62. }
  63. }
  64. else if(args[i] == "EXPORT_MACRO")
  65. {
  66. includesMode = false;
  67. if(++i < args.size())
  68. {
  69. m_ExportMacro = args[i];
  70. }
  71. else
  72. {
  73. this->SetError("EXPORT_MACRO option used without value.");
  74. return false;
  75. }
  76. }
  77. else if(args[i] == "INCLUDES")
  78. {
  79. includesMode = true;
  80. }
  81. // If not an option, it must be another input source list name or
  82. // an include file.
  83. else
  84. {
  85. if(!includesMode)
  86. {
  87. inSourceLists.push_back(args[i]);
  88. }
  89. else
  90. {
  91. m_Includes.push_back(args[i]);
  92. }
  93. }
  94. }
  95. if(m_ExportMacro == "-")
  96. {
  97. this->SetError("No EXPORT_MACRO option given.");
  98. return false;
  99. }
  100. for(std::vector<cmStdString>::const_iterator s = inSourceLists.begin();
  101. s != inSourceLists.end(); ++s)
  102. {
  103. // Find the source list specified.
  104. cmMakefile::SourceMap::iterator srcListIter =
  105. m_Makefile->GetSources().find(*s);
  106. if(srcListIter == m_Makefile->GetSources().end())
  107. {
  108. std::string errStr = "No source list named " + *s;
  109. this->SetError(errStr.c_str());
  110. return false;
  111. }
  112. std::vector<cmSourceFile*>& srcList = srcListIter->second;
  113. // Collect the names of the classes.
  114. for(std::vector<cmSourceFile*>::iterator src = srcList.begin();
  115. src != srcList.end();++src)
  116. {
  117. // Wrap-excluded and abstract classes do not have a New() method.
  118. // vtkIndent and vtkTimeStamp are special cases and are not
  119. // vtkObject subclasses.
  120. if(!(*src)->GetWrapExclude() && !(*src)->GetIsAnAbstractClass()
  121. && ((*src)->GetSourceName() != "vtkIndent")
  122. && ((*src)->GetSourceName() != "vtkTimeStamp"))
  123. {
  124. m_Classes.push_back((*src)->GetSourceName());
  125. }
  126. }
  127. }
  128. // Generate the header with the class declaration.
  129. {
  130. std::string fileName = m_ClassName + ".h";
  131. std::string fullName = headerPath+"/"+fileName;
  132. // Generate the output file with copy-if-different.
  133. cmGeneratedFileStream fout(fullName.c_str());
  134. // Actually generate the code in the file.
  135. this->GenerateHeaderFile(fout.GetStream());
  136. }
  137. // Generate the implementation file.
  138. {
  139. std::string fileName = m_ClassName + ".cxx";
  140. std::string fullName = filePath+"/"+fileName;
  141. // Generate the output file with copy-if-different.
  142. {
  143. cmGeneratedFileStream fout(fullName.c_str());
  144. // Actually generate the code in the file.
  145. this->GenerateImplementationFile(fout.GetStream());
  146. }
  147. // Add the generated source file into the source list.
  148. cmSourceFile file;
  149. file.SetWrapExclude(true);
  150. file.SetIsAnAbstractClass(false);
  151. file.SetName(fileName.c_str(), filePath.c_str(),
  152. m_Makefile->GetSourceExtensions(),
  153. m_Makefile->GetHeaderExtensions());
  154. m_Makefile->AddSource(file, outSourceList.c_str());
  155. }
  156. size_t numClasses = m_Classes.size();
  157. size_t numFullBlocks = numClasses / groupSize;
  158. size_t lastBlockSize = numClasses % groupSize;
  159. size_t numBlocks = numFullBlocks + ((lastBlockSize>0)? 1:0);
  160. // Generate the files with the ::New() calls to each class. These
  161. // are done in groups to keep the translation unit size smaller.
  162. for(unsigned int block=0; block < numBlocks;++block)
  163. {
  164. std::string fileName = this->GenerateCreationFileName(block);
  165. std::string fullName = filePath+"/"+fileName;
  166. // Generate the output file with copy-if-different.
  167. {
  168. cmGeneratedFileStream fout(fullName.c_str());
  169. unsigned int thisBlockSize =
  170. (block < numFullBlocks)? groupSize:lastBlockSize;
  171. // Actually generate the code in the file.
  172. this->GenerateCreationFile(fout.GetStream(),
  173. block*groupSize, thisBlockSize);
  174. }
  175. // Add the generated source file into the source list.
  176. cmSourceFile file;
  177. file.SetWrapExclude(true);
  178. file.SetIsAnAbstractClass(false);
  179. file.SetName(fileName.c_str(), filePath.c_str(),
  180. m_Makefile->GetSourceExtensions(),
  181. m_Makefile->GetHeaderExtensions());
  182. m_Makefile->AddSource(file, outSourceList.c_str());
  183. }
  184. return true;
  185. }
  186. std::string
  187. cmVTKMakeInstantiatorCommand::GenerateCreationFileName(unsigned int block)
  188. {
  189. std::strstream nameStr;
  190. nameStr << m_ClassName.c_str() << block << ".cxx" << std::ends;
  191. std::string result = nameStr.str();
  192. nameStr.rdbuf()->freeze(0);
  193. return result;
  194. }
  195. // Generates the class header file with the definition of the class
  196. // and its initializer class.
  197. void
  198. cmVTKMakeInstantiatorCommand
  199. ::GenerateHeaderFile(std::ostream& os)
  200. {
  201. os <<
  202. "#ifndef __" << m_ClassName.c_str() << "_h\n"
  203. "#define __" << m_ClassName.c_str() << "_h\n"
  204. "\n"
  205. "#include \"vtkInstantiator.h\"\n";
  206. for(unsigned int i=0;i < m_Includes.size();++i)
  207. {
  208. os << "#include \"" << m_Includes[i].c_str() << "\"\n";
  209. }
  210. os <<
  211. "\n"
  212. "class " << m_ClassName.c_str() << "Initialize;\n"
  213. "\n"
  214. "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "\n"
  215. "{\n"
  216. " friend class " << m_ClassName.c_str() << "Initialize;\n"
  217. "\n"
  218. " static void ClassInitialize();\n"
  219. " static void ClassFinalize();\n"
  220. "\n";
  221. for(unsigned int i=0;i < m_Classes.size();++i)
  222. {
  223. os << " static vtkObject* Create_" << m_Classes[i].c_str() << "();\n";
  224. }
  225. // Write the initializer class to make sure the creation functions
  226. // get registered when this generated header is included.
  227. os <<
  228. "};\n"
  229. "\n"
  230. "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "Initialize\n"
  231. "{\n"
  232. "public:\n"
  233. " " << m_ClassName.c_str() << "Initialize();\n"
  234. " ~" << m_ClassName.c_str() << "Initialize();\n"
  235. "private:\n"
  236. " static unsigned int Count;\n"
  237. "};\n"
  238. "\n"
  239. "static " << m_ClassName.c_str() << "Initialize " << m_ClassName.c_str() << "Initializer;\n"
  240. "\n"
  241. "#endif\n";
  242. }
  243. // Generates the file with the implementation of the class. All
  244. // methods except the actual object creation functions are generated
  245. // here.
  246. void
  247. cmVTKMakeInstantiatorCommand
  248. ::GenerateImplementationFile(std::ostream& os)
  249. {
  250. // Write the ClassInitialize method to register all the creation functions.
  251. os <<
  252. "#include \"" << m_ClassName.c_str() << ".h\"\n"
  253. "\n"
  254. "void " << m_ClassName.c_str() << "::ClassInitialize()\n"
  255. "{\n";
  256. for(unsigned int i=0;i < m_Classes.size();++i)
  257. {
  258. os << " vtkInstantiator::RegisterInstantiator(\""
  259. << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
  260. << m_Classes[i].c_str() << ");\n";
  261. }
  262. // Write the ClassFinalize method to unregister all the creation functions.
  263. os <<
  264. "}\n"
  265. "\n"
  266. "void " << m_ClassName.c_str() << "::ClassFinalize()\n"
  267. "{\n";
  268. for(unsigned int i=0;i < m_Classes.size();++i)
  269. {
  270. os << " vtkInstantiator::UnRegisterInstantiator(\""
  271. << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
  272. << m_Classes[i].c_str() << ");\n";
  273. }
  274. // Write the constructor and destructor of the initializer class to
  275. // call the ClassInitialize and ClassFinalize methods at the right
  276. // time.
  277. os <<
  278. "}\n"
  279. "\n" <<
  280. m_ClassName.c_str() << "Initialize::" << m_ClassName.c_str() << "Initialize()\n"
  281. "{\n"
  282. " if(++" << m_ClassName.c_str() << "Initialize::Count == 1)\n"
  283. " { " << m_ClassName.c_str() << "::ClassInitialize(); }\n"
  284. "}\n"
  285. "\n" <<
  286. m_ClassName.c_str() << "Initialize::~" << m_ClassName.c_str() << "Initialize()\n"
  287. "{\n"
  288. " if(--" << m_ClassName.c_str() << "Initialize::Count == 0)\n"
  289. " { " << m_ClassName.c_str() << "::ClassFinalize(); }\n"
  290. "}\n"
  291. "\n"
  292. "// Number of translation units that include this class's header.\n"
  293. "// Purposely not initialized. Default is static initialization to 0.\n"
  294. "unsigned int " << m_ClassName.c_str() << "Initialize::Count;\n";
  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. ::GenerateCreationFile(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. }