484 lines
14 KiB
C++
484 lines
14 KiB
C++
/*=========================================================================
|
|
|
|
Program: CMake - Cross-Platform Makefile Generator
|
|
Module: $RCSfile$
|
|
Language: C++
|
|
Date: $Date$
|
|
Version: $Revision$
|
|
|
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notices for more information.
|
|
|
|
=========================================================================*/
|
|
#include "cmVTKMakeInstantiatorCommand.h"
|
|
|
|
#include "cmCacheManager.h"
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmSourceFile.h"
|
|
|
|
bool
|
|
cmVTKMakeInstantiatorCommand
|
|
::InitialPass(std::vector<std::string> const& argsIn)
|
|
{
|
|
if(argsIn.size() < 3)
|
|
{
|
|
this->SetError("called with incorrect number of arguments");
|
|
return false;
|
|
}
|
|
std::vector<std::string> args;
|
|
this->Makefile->ExpandSourceListArguments(argsIn, args, 2);
|
|
std::string sourceListValue;
|
|
|
|
this->ClassName = args[0];
|
|
|
|
std::vector<cmStdString> inSourceLists;
|
|
this->ExportMacro = "-";
|
|
bool includesMode = false;
|
|
bool oldVersion = true;
|
|
|
|
// Find the path of the files to be generated.
|
|
std::string filePath = this->Makefile->GetCurrentOutputDirectory();
|
|
std::string headerPath = filePath;
|
|
|
|
// Check whether to use the old or new form.
|
|
if(this->Makefile->GetDefinition("VTK_USE_INSTANTIATOR_NEW"))
|
|
{
|
|
oldVersion = false;
|
|
}
|
|
|
|
for(unsigned int i=2;i < args.size();++i)
|
|
{
|
|
if(args[i] == "HEADER_LOCATION")
|
|
{
|
|
includesMode = false;
|
|
if(++i < args.size())
|
|
{
|
|
headerPath = args[i];
|
|
}
|
|
else
|
|
{
|
|
this->SetError("HEADER_LOCATION option used without value.");
|
|
return false;
|
|
}
|
|
}
|
|
else if(args[i] == "EXPORT_MACRO")
|
|
{
|
|
includesMode = false;
|
|
if(++i < args.size())
|
|
{
|
|
this->ExportMacro = args[i];
|
|
}
|
|
else
|
|
{
|
|
this->SetError("EXPORT_MACRO option used without value.");
|
|
return false;
|
|
}
|
|
}
|
|
else if(args[i] == "INCLUDES")
|
|
{
|
|
includesMode = true;
|
|
}
|
|
// If not an option, it must be another input source list name or
|
|
// an include file.
|
|
else
|
|
{
|
|
if(!includesMode)
|
|
{
|
|
inSourceLists.push_back(args[i]);
|
|
}
|
|
else
|
|
{
|
|
this->Includes.push_back(args[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(this->ExportMacro == "-")
|
|
{
|
|
this->SetError("No EXPORT_MACRO option given.");
|
|
return false;
|
|
}
|
|
|
|
for(std::vector<cmStdString>::const_iterator s = inSourceLists.begin();
|
|
s != inSourceLists.end(); ++s)
|
|
{
|
|
std::string srcName = cmSystemTools::GetFilenameWithoutExtension(*s);
|
|
cmSourceFile *sf = this->Makefile->GetSource(s->c_str());
|
|
|
|
// Wrap-excluded and abstract classes do not have a New() method.
|
|
// vtkIndent and vtkTimeStamp are special cases and are not
|
|
// vtkObject subclasses.
|
|
if(
|
|
(!sf || (!sf->GetPropertyAsBool("WRAP_EXCLUDE") &&
|
|
!sf->GetPropertyAsBool("ABSTRACT"))) &&
|
|
((srcName != "vtkIndent") && (srcName != "vtkTimeStamp")))
|
|
{
|
|
this->Classes.push_back(srcName);
|
|
}
|
|
}
|
|
|
|
// Generate the header with the class declaration.
|
|
{
|
|
std::string fileName = this->ClassName + ".h";
|
|
std::string fullName = headerPath+"/"+fileName;
|
|
|
|
// Generate the output file with copy-if-different.
|
|
cmGeneratedFileStream fout(fullName.c_str());
|
|
fout.SetCopyIfDifferent(true);
|
|
|
|
// Actually generate the code in the file.
|
|
if(!oldVersion)
|
|
{
|
|
this->GenerateHeaderFile(fout);
|
|
}
|
|
else
|
|
{
|
|
this->OldGenerateHeaderFile(fout);
|
|
}
|
|
}
|
|
|
|
// Generate the implementation file.
|
|
{
|
|
std::string fileName = this->ClassName + ".cxx";
|
|
std::string fullName = filePath+"/"+fileName;
|
|
|
|
// Generate the output file with copy-if-different.
|
|
{
|
|
cmGeneratedFileStream fout(fullName.c_str());
|
|
fout.SetCopyIfDifferent(true);
|
|
|
|
// Actually generate the code in the file.
|
|
if(!oldVersion)
|
|
{
|
|
this->GenerateImplementationFile(fout);
|
|
}
|
|
else
|
|
{
|
|
this->OldGenerateImplementationFile(fout);
|
|
}
|
|
}
|
|
|
|
// Add the generated source file into the source list.
|
|
cmSourceFile file;
|
|
file.SetProperty("WRAP_EXCLUDE","1");
|
|
file.SetProperty("ABSTRACT","0");
|
|
file.SetName(fileName.c_str(), filePath.c_str(),
|
|
this->Makefile->GetSourceExtensions(),
|
|
this->Makefile->GetHeaderExtensions());
|
|
this->Makefile->AddSource(file);
|
|
sourceListValue += file.GetSourceName() + ".cxx";
|
|
}
|
|
|
|
if(oldVersion)
|
|
{
|
|
int groupSize = 10;
|
|
size_t numClasses = this->Classes.size();
|
|
size_t numFullBlocks = numClasses / groupSize;
|
|
size_t lastBlockSize = numClasses % groupSize;
|
|
size_t numBlocks = numFullBlocks + ((lastBlockSize>0)? 1:0);
|
|
|
|
// Generate the files with the ::New() calls to each class. These
|
|
// are done in groups to keep the translation unit size smaller.
|
|
for(unsigned int block=0; block < numBlocks;++block)
|
|
{
|
|
std::string fileName = this->OldGenerateCreationFileName(block);
|
|
std::string fullName = filePath+"/"+fileName;
|
|
|
|
// Generate the output file with copy-if-different.
|
|
{
|
|
cmGeneratedFileStream fout(fullName.c_str());
|
|
fout.SetCopyIfDifferent(true);
|
|
|
|
size_t thisBlockSize =
|
|
(block < numFullBlocks)? groupSize:lastBlockSize;
|
|
|
|
// Actually generate the code in the file.
|
|
this->OldGenerateCreationFile(fout,
|
|
block*groupSize,
|
|
static_cast<int>(thisBlockSize));
|
|
}
|
|
|
|
// Add the generated source file into the source list.
|
|
cmSourceFile file;
|
|
file.SetProperty("WRAP_EXCLUDE","1");
|
|
file.SetProperty("ABSTRACT","0");
|
|
file.SetName(fileName.c_str(), filePath.c_str(),
|
|
this->Makefile->GetSourceExtensions(),
|
|
this->Makefile->GetHeaderExtensions());
|
|
this->Makefile->AddSource(file);
|
|
sourceListValue += ";";
|
|
sourceListValue += file.GetSourceName() + ".cxx";
|
|
}
|
|
}
|
|
|
|
this->Makefile->AddDefinition(args[1].c_str(), sourceListValue.c_str());
|
|
return true;
|
|
}
|
|
|
|
// Generates the class header file with the definition of the class
|
|
// and its initializer class.
|
|
void
|
|
cmVTKMakeInstantiatorCommand
|
|
::GenerateHeaderFile(std::ostream& os)
|
|
{
|
|
os <<
|
|
"#ifndef __" << this->ClassName.c_str() << "_h\n"
|
|
"#define __" << this->ClassName.c_str() << "_h\n"
|
|
"\n"
|
|
"#include \"vtkInstantiator.h\"\n";
|
|
for(unsigned int i=0;i < this->Includes.size();++i)
|
|
{
|
|
os << "#include \"" << this->Includes[i].c_str() << "\"\n";
|
|
}
|
|
|
|
// Write the instantiator class definition.
|
|
os <<
|
|
"\n"
|
|
"class " << this->ExportMacro.c_str() << " " << this->ClassName.c_str() << "\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" " << this->ClassName.c_str() << "();\n"
|
|
" ~" << this->ClassName.c_str() << "();\n"
|
|
"private:\n"
|
|
" static void ClassInitialize();\n"
|
|
" static void ClassFinalize();\n"
|
|
" static unsigned int Count;\n"
|
|
"};\n"
|
|
"\n";
|
|
|
|
// Write the initialization instance to make sure the creation
|
|
// functions get registered when this generated header is included.
|
|
os <<
|
|
"static "
|
|
<< this->ClassName.c_str() << " "
|
|
<< this->ClassName.c_str() << "Initializer;\n"
|
|
"\n"
|
|
"#endif\n";
|
|
}
|
|
|
|
// Generates the file with the implementation of the class. All
|
|
// methods except the actual object creation functions are generated
|
|
// here.
|
|
void
|
|
cmVTKMakeInstantiatorCommand
|
|
::GenerateImplementationFile(std::ostream& os)
|
|
{
|
|
// Include the instantiator class header.
|
|
os <<
|
|
"#include \"" << this->ClassName.c_str() << ".h\"\n"
|
|
"\n";
|
|
|
|
// Write the extern declarations for all the creation functions.
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << "extern vtkObject* vtkInstantiator" <<
|
|
this->Classes[i].c_str() << "New();\n";
|
|
}
|
|
|
|
// Write the ClassInitialize method to register all the creation functions.
|
|
os <<
|
|
"\n"
|
|
"void " << this->ClassName.c_str() << "::ClassInitialize()\n"
|
|
"{\n";
|
|
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << " vtkInstantiator::RegisterInstantiator(\""
|
|
<< this->Classes[i].c_str() << "\", vtkInstantiator"
|
|
<< this->Classes[i].c_str() << "New);\n";
|
|
}
|
|
|
|
// Write the ClassFinalize method to unregister all the creation functions.
|
|
os <<
|
|
"}\n"
|
|
"\n"
|
|
"void " << this->ClassName.c_str() << "::ClassFinalize()\n"
|
|
"{\n";
|
|
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << " vtkInstantiator::UnRegisterInstantiator(\""
|
|
<< this->Classes[i].c_str() << "\", vtkInstantiator"
|
|
<< this->Classes[i].c_str() << "New);\n";
|
|
}
|
|
|
|
// Write the constructor and destructor of the initializer class to
|
|
// call the ClassInitialize and ClassFinalize methods at the right
|
|
// time.
|
|
os <<
|
|
"}\n"
|
|
"\n" <<
|
|
this->ClassName.c_str() << "::" << this->ClassName.c_str() << "()\n"
|
|
"{\n"
|
|
" if(++" << this->ClassName.c_str() << "::Count == 1)\n"
|
|
" { " << this->ClassName.c_str() << "::ClassInitialize(); }\n"
|
|
"}\n"
|
|
"\n" <<
|
|
this->ClassName.c_str() << "::~" << this->ClassName.c_str() << "()\n"
|
|
"{\n"
|
|
" if(--" << this->ClassName.c_str() << "::Count == 0)\n"
|
|
" { " << this->ClassName.c_str() << "::ClassFinalize(); }\n"
|
|
"}\n"
|
|
"\n"
|
|
"// Number of translation units that include this class's header.\n"
|
|
"// Purposely not initialized. Default is static initialization to 0.\n"
|
|
"unsigned int " << this->ClassName.c_str() << "::Count;\n";
|
|
}
|
|
|
|
std::string
|
|
cmVTKMakeInstantiatorCommand::OldGenerateCreationFileName(unsigned int block)
|
|
{
|
|
cmOStringStream nameStr;
|
|
nameStr << this->ClassName.c_str() << block << ".cxx";
|
|
std::string result = nameStr.str();
|
|
return result;
|
|
}
|
|
|
|
// Generates a file that includes the headers of the classes it knows
|
|
// how to create and provides functions which create the classes with
|
|
// the New() method.
|
|
void
|
|
cmVTKMakeInstantiatorCommand
|
|
::OldGenerateCreationFile(std::ostream& os, unsigned int groupStart,
|
|
unsigned int groupSize)
|
|
{
|
|
// Need to include header of generated class.
|
|
os <<
|
|
"#include \"" << this->ClassName.c_str() << ".h\"\n"
|
|
"\n";
|
|
|
|
// Include class files.
|
|
for(unsigned int i=0;i < groupSize;++i)
|
|
{
|
|
os << "#include \"" << this->Classes[groupStart+i].c_str() << ".h\"\n";
|
|
}
|
|
|
|
os <<
|
|
"\n";
|
|
|
|
// Write the create function implementations.
|
|
for(unsigned int i=0;i < groupSize;++i)
|
|
{
|
|
os << "vtkObject* " << this->ClassName.c_str() << "::Create_"
|
|
<< this->Classes[groupStart+i].c_str() << "() { return "
|
|
<< this->Classes[groupStart+i].c_str() << "::New(); }\n";
|
|
}
|
|
}
|
|
|
|
// Generates the class header file with the definition of the class
|
|
// and its initializer class.
|
|
void
|
|
cmVTKMakeInstantiatorCommand
|
|
::OldGenerateHeaderFile(std::ostream& os)
|
|
{
|
|
os <<
|
|
"#ifndef __" << this->ClassName.c_str() << "_h\n"
|
|
"#define __" << this->ClassName.c_str() << "_h\n"
|
|
"\n"
|
|
"#include \"vtkInstantiator.h\"\n";
|
|
for(unsigned int i=0;i < this->Includes.size();++i)
|
|
{
|
|
os << "#include \"" << this->Includes[i].c_str() << "\"\n";
|
|
}
|
|
os <<
|
|
"\n"
|
|
"class " << this->ClassName.c_str() << "Initialize;\n"
|
|
"\n"
|
|
"class " << this->ExportMacro.c_str() << " " << this->ClassName.c_str() << "\n"
|
|
"{\n"
|
|
" friend class " << this->ClassName.c_str() << "Initialize;\n"
|
|
"\n"
|
|
" static void ClassInitialize();\n"
|
|
" static void ClassFinalize();\n"
|
|
"\n";
|
|
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << " static vtkObject* Create_" << this->Classes[i].c_str() << "();\n";
|
|
}
|
|
|
|
// Write the initializer class to make sure the creation functions
|
|
// get registered when this generated header is included.
|
|
os <<
|
|
"};\n"
|
|
"\n"
|
|
"class " << this->ExportMacro.c_str() << " "
|
|
<< this->ClassName.c_str() << "Initialize\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" " << this->ClassName.c_str() << "Initialize();\n"
|
|
" ~" << this->ClassName.c_str() << "Initialize();\n"
|
|
"private:\n"
|
|
" static unsigned int Count;\n"
|
|
"};\n"
|
|
"\n"
|
|
"static " << this->ClassName.c_str() << "Initialize "
|
|
<< this->ClassName.c_str() << "Initializer;\n"
|
|
"\n"
|
|
"#endif\n";
|
|
}
|
|
|
|
// Generates the file with the implementation of the class. All
|
|
// methods except the actual object creation functions are generated
|
|
// here.
|
|
void
|
|
cmVTKMakeInstantiatorCommand
|
|
::OldGenerateImplementationFile(std::ostream& os)
|
|
{
|
|
// Write the ClassInitialize method to register all the creation functions.
|
|
os <<
|
|
"#include \"" << this->ClassName.c_str() << ".h\"\n"
|
|
"\n"
|
|
"void " << this->ClassName.c_str() << "::ClassInitialize()\n"
|
|
"{\n";
|
|
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << " vtkInstantiator::RegisterInstantiator(\""
|
|
<< this->Classes[i].c_str() << "\", " << this->ClassName.c_str() << "::Create_"
|
|
<< this->Classes[i].c_str() << ");\n";
|
|
}
|
|
|
|
// Write the ClassFinalize method to unregister all the creation functions.
|
|
os <<
|
|
"}\n"
|
|
"\n"
|
|
"void " << this->ClassName.c_str() << "::ClassFinalize()\n"
|
|
"{\n";
|
|
|
|
for(unsigned int i=0;i < this->Classes.size();++i)
|
|
{
|
|
os << " vtkInstantiator::UnRegisterInstantiator(\""
|
|
<< this->Classes[i].c_str() << "\", " << this->ClassName.c_str() << "::Create_"
|
|
<< this->Classes[i].c_str() << ");\n";
|
|
}
|
|
|
|
// Write the constructor and destructor of the initializer class to
|
|
// call the ClassInitialize and ClassFinalize methods at the right
|
|
// time.
|
|
os <<
|
|
"}\n"
|
|
"\n" <<
|
|
this->ClassName.c_str() << "Initialize::" <<
|
|
this->ClassName.c_str() << "Initialize()\n"
|
|
"{\n"
|
|
" if(++" << this->ClassName.c_str() << "Initialize::Count == 1)\n"
|
|
" { " << this->ClassName.c_str() << "::ClassInitialize(); }\n"
|
|
"}\n"
|
|
"\n" <<
|
|
this->ClassName.c_str() << "Initialize::~" <<
|
|
this->ClassName.c_str() << "Initialize()\n"
|
|
"{\n"
|
|
" if(--" << this->ClassName.c_str() << "Initialize::Count == 0)\n"
|
|
" { " << this->ClassName.c_str() << "::ClassFinalize(); }\n"
|
|
"}\n"
|
|
"\n"
|
|
"// Number of translation units that include this class's header.\n"
|
|
"// Purposely not initialized. Default is static initialization to 0.\n"
|
|
"unsigned int " << this->ClassName.c_str() << "Initialize::Count;\n";
|
|
}
|