FIX: stupid pb fixed (close to being medieval'ed by The Ken)
[cmake.git] / Source / cmVTKMakeInstantiatorCommand.cxx
blobc6ee949e36032cfa0f88cc9aec559632740d6544
1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmVTKMakeInstantiatorCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2002-06-27 19:57:09 $
7 Version: $Revision: 1.12 $
9 Copyright (c) 2002 Insight Consortium. All rights reserved.
10 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmVTKMakeInstantiatorCommand.h"
18 #include "cmCacheManager.h"
19 #include "cmGeneratedFileStream.h"
21 bool
22 cmVTKMakeInstantiatorCommand
23 ::InitialPass(std::vector<std::string> const& argsIn)
25 if(argsIn.size() < 3)
27 this->SetError("called with incorrect number of arguments");
28 return false;
30 std::vector<std::string> args;
31 m_Makefile->ExpandSourceListArguments(argsIn, args, 2);
32 std::string sourceListValue;
34 m_ClassName = args[0];
36 std::vector<cmStdString> inSourceLists;
37 m_ExportMacro = "-";
38 unsigned int groupSize = 10;
39 bool includesMode = false;
41 // Find the path of the files to be generated.
42 std::string filePath = m_Makefile->GetCurrentOutputDirectory();
43 std::string headerPath = filePath;
45 for(unsigned int i=2;i < args.size();++i)
47 if(args[i] == "GROUP_SIZE")
49 includesMode = false;
50 if(++i < args.size())
52 groupSize = atoi(args[i].c_str());
54 else
56 this->SetError("GROUP_SIZE option used without value.");
57 return false;
60 else if(args[i] == "HEADER_LOCATION")
62 includesMode = false;
63 if(++i < args.size())
65 headerPath = args[i];
67 else
69 this->SetError("HEADER_LOCATION option used without value.");
70 return false;
73 else if(args[i] == "EXPORT_MACRO")
75 includesMode = false;
76 if(++i < args.size())
78 m_ExportMacro = args[i];
80 else
82 this->SetError("EXPORT_MACRO option used without value.");
83 return false;
86 else if(args[i] == "INCLUDES")
88 includesMode = true;
90 // If not an option, it must be another input source list name or
91 // an include file.
92 else
94 if(!includesMode)
96 inSourceLists.push_back(args[i]);
98 else
100 m_Includes.push_back(args[i]);
105 if(m_ExportMacro == "-")
107 this->SetError("No EXPORT_MACRO option given.");
108 return false;
111 for(std::vector<cmStdString>::const_iterator s = inSourceLists.begin();
112 s != inSourceLists.end(); ++s)
114 std::string srcName = cmSystemTools::GetFilenameWithoutExtension(*s);
115 cmSourceFile *sf = m_Makefile->GetSource(s->c_str());
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.
121 (!sf || (!sf->GetWrapExclude() && !sf->GetIsAnAbstractClass())) &&
122 ((srcName != "vtkIndent") && (srcName != "vtkTimeStamp")))
124 m_Classes.push_back(srcName);
128 // Generate the header with the class declaration.
130 std::string fileName = m_ClassName + ".h";
131 std::string fullName = headerPath+"/"+fileName;
133 // Generate the output file with copy-if-different.
134 cmGeneratedFileStream fout(fullName.c_str());
136 // Actually generate the code in the file.
137 this->GenerateHeaderFile(fout.GetStream());
140 // Generate the implementation file.
142 std::string fileName = m_ClassName + ".cxx";
143 std::string fullName = filePath+"/"+fileName;
145 // Generate the output file with copy-if-different.
147 cmGeneratedFileStream fout(fullName.c_str());
149 // Actually generate the code in the file.
150 this->GenerateImplementationFile(fout.GetStream());
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);
161 sourceListValue += file.GetSourceName() + ".cxx";
164 size_t numClasses = m_Classes.size();
165 size_t numFullBlocks = numClasses / groupSize;
166 size_t lastBlockSize = numClasses % groupSize;
167 size_t numBlocks = numFullBlocks + ((lastBlockSize>0)? 1:0);
169 // Generate the files with the ::New() calls to each class. These
170 // are done in groups to keep the translation unit size smaller.
171 for(unsigned int block=0; block < numBlocks;++block)
173 std::string fileName = this->GenerateCreationFileName(block);
174 std::string fullName = filePath+"/"+fileName;
176 // Generate the output file with copy-if-different.
178 cmGeneratedFileStream fout(fullName.c_str());
180 unsigned int thisBlockSize =
181 (block < numFullBlocks)? groupSize:lastBlockSize;
183 // Actually generate the code in the file.
184 this->GenerateCreationFile(fout.GetStream(),
185 block*groupSize, thisBlockSize);
188 // Add the generated source file into the source list.
189 cmSourceFile file;
190 file.SetWrapExclude(true);
191 file.SetIsAnAbstractClass(false);
192 file.SetName(fileName.c_str(), filePath.c_str(),
193 m_Makefile->GetSourceExtensions(),
194 m_Makefile->GetHeaderExtensions());
195 m_Makefile->AddSource(file);
196 sourceListValue += ";";
197 sourceListValue += file.GetSourceName() + ".cxx";
200 m_Makefile->AddDefinition(args[1].c_str(), sourceListValue.c_str());
201 return true;
204 std::string
205 cmVTKMakeInstantiatorCommand::GenerateCreationFileName(unsigned int block)
207 cmStringStream nameStr;
208 nameStr << m_ClassName.c_str() << block << ".cxx";
209 std::string result = nameStr.str();
210 return result;
213 // Generates the class header file with the definition of the class
214 // and its initializer class.
215 void
216 cmVTKMakeInstantiatorCommand
217 ::GenerateHeaderFile(std::ostream& os)
219 os <<
220 "#ifndef __" << m_ClassName.c_str() << "_h\n"
221 "#define __" << m_ClassName.c_str() << "_h\n"
222 "\n"
223 "#include \"vtkInstantiator.h\"\n";
224 for(unsigned int i=0;i < m_Includes.size();++i)
226 os << "#include \"" << m_Includes[i].c_str() << "\"\n";
228 os <<
229 "\n"
230 "class " << m_ClassName.c_str() << "Initialize;\n"
231 "\n"
232 "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "\n"
233 "{\n"
234 " friend class " << m_ClassName.c_str() << "Initialize;\n"
235 "\n"
236 " static void ClassInitialize();\n"
237 " static void ClassFinalize();\n"
238 "\n";
240 for(unsigned int i=0;i < m_Classes.size();++i)
242 os << " static vtkObject* Create_" << m_Classes[i].c_str() << "();\n";
245 // Write the initializer class to make sure the creation functions
246 // get registered when this generated header is included.
247 os <<
248 "};\n"
249 "\n"
250 "class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "Initialize\n"
251 "{\n"
252 "public:\n"
253 " " << m_ClassName.c_str() << "Initialize();\n"
254 " ~" << m_ClassName.c_str() << "Initialize();\n"
255 "private:\n"
256 " static unsigned int Count;\n"
257 "};\n"
258 "\n"
259 "static " << m_ClassName.c_str() << "Initialize " << m_ClassName.c_str() << "Initializer;\n"
260 "\n"
261 "#endif\n";
264 // Generates the file with the implementation of the class. All
265 // methods except the actual object creation functions are generated
266 // here.
267 void
268 cmVTKMakeInstantiatorCommand
269 ::GenerateImplementationFile(std::ostream& os)
271 // Write the ClassInitialize method to register all the creation functions.
272 os <<
273 "#include \"" << m_ClassName.c_str() << ".h\"\n"
274 "\n"
275 "void " << m_ClassName.c_str() << "::ClassInitialize()\n"
276 "{\n";
278 for(unsigned int i=0;i < m_Classes.size();++i)
280 os << " vtkInstantiator::RegisterInstantiator(\""
281 << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
282 << m_Classes[i].c_str() << ");\n";
285 // Write the ClassFinalize method to unregister all the creation functions.
286 os <<
287 "}\n"
288 "\n"
289 "void " << m_ClassName.c_str() << "::ClassFinalize()\n"
290 "{\n";
292 for(unsigned int i=0;i < m_Classes.size();++i)
294 os << " vtkInstantiator::UnRegisterInstantiator(\""
295 << m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
296 << m_Classes[i].c_str() << ");\n";
299 // Write the constructor and destructor of the initializer class to
300 // call the ClassInitialize and ClassFinalize methods at the right
301 // time.
302 os <<
303 "}\n"
304 "\n" <<
305 m_ClassName.c_str() << "Initialize::" << m_ClassName.c_str() << "Initialize()\n"
306 "{\n"
307 " if(++" << m_ClassName.c_str() << "Initialize::Count == 1)\n"
308 " { " << m_ClassName.c_str() << "::ClassInitialize(); }\n"
309 "}\n"
310 "\n" <<
311 m_ClassName.c_str() << "Initialize::~" << m_ClassName.c_str() << "Initialize()\n"
312 "{\n"
313 " if(--" << m_ClassName.c_str() << "Initialize::Count == 0)\n"
314 " { " << m_ClassName.c_str() << "::ClassFinalize(); }\n"
315 "}\n"
316 "\n"
317 "// Number of translation units that include this class's header.\n"
318 "// Purposely not initialized. Default is static initialization to 0.\n"
319 "unsigned int " << m_ClassName.c_str() << "Initialize::Count;\n";
322 // Generates a file that includes the headers of the classes it knows
323 // how to create and provides functions which create the classes with
324 // the New() method.
325 void
326 cmVTKMakeInstantiatorCommand
327 ::GenerateCreationFile(std::ostream& os, unsigned int groupStart,
328 unsigned int groupSize)
330 // Need to include header of generated class.
331 os <<
332 "#include \"" << m_ClassName.c_str() << ".h\"\n"
333 "\n";
335 // Include class files.
336 for(unsigned int i=0;i < groupSize;++i)
338 os << "#include \"" << m_Classes[groupStart+i].c_str() << ".h\"\n";
341 os <<
342 "\n";
344 // Write the create function implementations.
345 for(unsigned int i=0;i < groupSize;++i)
347 os << "vtkObject* " << m_ClassName.c_str() << "::Create_"
348 << m_Classes[groupStart+i].c_str() << "() { return "
349 << m_Classes[groupStart+i].c_str() << "::New(); }\n";