1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmVTKMakeInstantiatorCommand.cxx,v $
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"
22 cmVTKMakeInstantiatorCommand
23 ::InitialPass(std::vector
<std::string
> const& argsIn
)
27 this->SetError("called with incorrect number of arguments");
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
;
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")
52 groupSize
= atoi(args
[i
].c_str());
56 this->SetError("GROUP_SIZE option used without value.");
60 else if(args
[i
] == "HEADER_LOCATION")
69 this->SetError("HEADER_LOCATION option used without value.");
73 else if(args
[i
] == "EXPORT_MACRO")
78 m_ExportMacro
= args
[i
];
82 this->SetError("EXPORT_MACRO option used without value.");
86 else if(args
[i
] == "INCLUDES")
90 // If not an option, it must be another input source list name or
96 inSourceLists
.push_back(args
[i
]);
100 m_Includes
.push_back(args
[i
]);
105 if(m_ExportMacro
== "-")
107 this->SetError("No EXPORT_MACRO option given.");
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.
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.
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());
205 cmVTKMakeInstantiatorCommand::GenerateCreationFileName(unsigned int block
)
207 cmStringStream nameStr
;
208 nameStr
<< m_ClassName
.c_str() << block
<< ".cxx";
209 std::string result
= nameStr
.str();
213 // Generates the class header file with the definition of the class
214 // and its initializer class.
216 cmVTKMakeInstantiatorCommand
217 ::GenerateHeaderFile(std::ostream
& os
)
220 "#ifndef __" << m_ClassName
.c_str() << "_h\n"
221 "#define __" << m_ClassName
.c_str() << "_h\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";
230 "class " << m_ClassName
.c_str() << "Initialize;\n"
232 "class " << m_ExportMacro
.c_str() << " " << m_ClassName
.c_str() << "\n"
234 " friend class " << m_ClassName
.c_str() << "Initialize;\n"
236 " static void ClassInitialize();\n"
237 " static void ClassFinalize();\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.
250 "class " << m_ExportMacro
.c_str() << " " << m_ClassName
.c_str() << "Initialize\n"
253 " " << m_ClassName
.c_str() << "Initialize();\n"
254 " ~" << m_ClassName
.c_str() << "Initialize();\n"
256 " static unsigned int Count;\n"
259 "static " << m_ClassName
.c_str() << "Initialize " << m_ClassName
.c_str() << "Initializer;\n"
264 // Generates the file with the implementation of the class. All
265 // methods except the actual object creation functions are generated
268 cmVTKMakeInstantiatorCommand
269 ::GenerateImplementationFile(std::ostream
& os
)
271 // Write the ClassInitialize method to register all the creation functions.
273 "#include \"" << m_ClassName
.c_str() << ".h\"\n"
275 "void " << m_ClassName
.c_str() << "::ClassInitialize()\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.
289 "void " << m_ClassName
.c_str() << "::ClassFinalize()\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
305 m_ClassName
.c_str() << "Initialize::" << m_ClassName
.c_str() << "Initialize()\n"
307 " if(++" << m_ClassName
.c_str() << "Initialize::Count == 1)\n"
308 " { " << m_ClassName
.c_str() << "::ClassInitialize(); }\n"
311 m_ClassName
.c_str() << "Initialize::~" << m_ClassName
.c_str() << "Initialize()\n"
313 " if(--" << m_ClassName
.c_str() << "Initialize::Count == 0)\n"
314 " { " << m_ClassName
.c_str() << "::ClassFinalize(); }\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
326 cmVTKMakeInstantiatorCommand
327 ::GenerateCreationFile(std::ostream
& os
, unsigned int groupStart
,
328 unsigned int groupSize
)
330 // Need to include header of generated class.
332 "#include \"" << m_ClassName
.c_str() << ".h\"\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";
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";