cmVTKMakeInstantiatorCommand.cxx 11 KB

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