ENH: Adding VTK_MAKE_INSTANTIATOR command. This command will be used by VTK kits to register their classes with vtkInstantiator.
This commit is contained in:
parent
1b6ca3eba0
commit
fa53ab0807
|
@ -64,6 +64,7 @@
|
|||
#include "cmQTWrapUICommand.cxx"
|
||||
#include "cmWrapExcludeFilesCommand.cxx"
|
||||
#include "cmAddCustomCommandCommand.cxx"
|
||||
#include "cmVTKMakeInstantiatorCommand.cxx"
|
||||
|
||||
void GetPredefinedCommands(std::list<cmCommand*>& commands)
|
||||
{
|
||||
|
@ -128,6 +129,5 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands)
|
|||
commands.push_back(new cmQTWrapUICommand);
|
||||
commands.push_back(new cmWrapExcludeFilesCommand);
|
||||
commands.push_back(new cmAddCustomCommandCommand);
|
||||
commands.push_back(new cmVTKMakeInstantiatorCommand);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
/*=========================================================================
|
||||
|
||||
Program: Insight Segmentation & Registration Toolkit
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2001 Insight Consortium
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* The name of the Insight Consortium, nor the names of any consortium members,
|
||||
nor of any contributors, may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
* Modified source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=========================================================================*/
|
||||
#include "cmVTKMakeInstantiatorCommand.h"
|
||||
#include "cmCacheManager.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
|
||||
bool
|
||||
cmVTKMakeInstantiatorCommand
|
||||
::InitialPass(std::vector<std::string> const& args)
|
||||
{
|
||||
if(args.size() < 3)
|
||||
{
|
||||
this->SetError("called with incorrect number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string libName = args[0];
|
||||
std::string srcListName = args[1];
|
||||
m_ExportMacro = args[2];
|
||||
unsigned int groupSize = 10;
|
||||
|
||||
// Find the path of the files to be generated.
|
||||
std::string filePath = m_Makefile->GetCurrentOutputDirectory();
|
||||
std::string headerPath = filePath;
|
||||
|
||||
if(args.size() > 3)
|
||||
{
|
||||
for(unsigned int i=3;i < args.size();++i)
|
||||
{
|
||||
if(args[i] == "GROUP_SIZE")
|
||||
{
|
||||
if(++i < args.size())
|
||||
{
|
||||
groupSize = atoi(args[i].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->SetError("GROUP_SIZE option used without value.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(args[i] == "HEADER_LOCATION")
|
||||
{
|
||||
if(++i < args.size())
|
||||
{
|
||||
headerPath = args[i];
|
||||
m_Makefile->ExpandVariablesInString(headerPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->SetError("HEADER_LOCATION option used without value.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Makefile->ExpandVariablesInString(srcListName);
|
||||
|
||||
// Find the source list specified.
|
||||
cmMakefile::SourceMap::iterator srcListIter =
|
||||
m_Makefile->GetSources().find(srcListName);
|
||||
|
||||
if(srcListIter == m_Makefile->GetSources().end())
|
||||
{
|
||||
std::string errStr = "No source list named " + srcListName;
|
||||
this->SetError(errStr.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ClassName = libName+"Instantiator";
|
||||
|
||||
std::vector<cmSourceFile>& srcList = srcListIter->second;
|
||||
|
||||
// Collect the names of the classes.
|
||||
for(std::vector<cmSourceFile>::iterator src = srcList.begin();
|
||||
src != srcList.end();++src)
|
||||
{
|
||||
// Wrap-excluded and abstract classes do not have a New() method.
|
||||
// vtkIndent and vtkTimeStamp are special cases and are not
|
||||
// vtkObject subclasses.
|
||||
if(!src->GetWrapExclude() && !src->GetIsAnAbstractClass()
|
||||
&& (src->GetSourceName() != "vtkIndent")
|
||||
&& (src->GetSourceName() != "vtkTimeStamp"))
|
||||
{
|
||||
m_Classes.push_back(src->GetSourceName());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the header with the class declaration.
|
||||
{
|
||||
std::string fileName = m_ClassName + ".h";
|
||||
std::string fullName = headerPath+"/"+fileName;
|
||||
|
||||
// Generate the output file with copy-if-different.
|
||||
cmGeneratedFileStream fout(fullName.c_str());
|
||||
|
||||
// Actually generate the code in the file.
|
||||
this->GenerateHeaderFile(fout.GetStream());
|
||||
}
|
||||
|
||||
// Generate the implementation file.
|
||||
{
|
||||
std::string fileName = m_ClassName + ".cxx";
|
||||
std::string fullName = filePath+"/"+fileName;
|
||||
|
||||
// Generate the output file with copy-if-different.
|
||||
{
|
||||
cmGeneratedFileStream fout(fullName.c_str());
|
||||
|
||||
// Actually generate the code in the file.
|
||||
this->GenerateImplementationFile(fout.GetStream());
|
||||
}
|
||||
|
||||
// Add the generated source file into the source list.
|
||||
cmSourceFile file;
|
||||
file.SetWrapExclude(true);
|
||||
file.SetIsAnAbstractClass(false);
|
||||
file.SetName(fileName.c_str(), filePath.c_str(),
|
||||
m_Makefile->GetSourceExtensions(),
|
||||
m_Makefile->GetHeaderExtensions());
|
||||
m_Makefile->AddSource(file, srcListName.c_str());
|
||||
}
|
||||
|
||||
unsigned int numClasses = m_Classes.size();
|
||||
unsigned int numFullBlocks = numClasses / groupSize;
|
||||
unsigned int lastBlockSize = numClasses % groupSize;
|
||||
unsigned int 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->GenerateCreationFileName(block);
|
||||
std::string fullName = filePath+"/"+fileName;
|
||||
|
||||
// Generate the output file with copy-if-different.
|
||||
{
|
||||
cmGeneratedFileStream fout(fullName.c_str());
|
||||
|
||||
unsigned int thisBlockSize =
|
||||
(block < numFullBlocks)? groupSize:lastBlockSize;
|
||||
|
||||
// Actually generate the code in the file.
|
||||
this->GenerateCreationFile(fout.GetStream(),
|
||||
block*groupSize, thisBlockSize);
|
||||
}
|
||||
|
||||
// Add the generated source file into the source list.
|
||||
cmSourceFile file;
|
||||
file.SetWrapExclude(true);
|
||||
file.SetIsAnAbstractClass(false);
|
||||
file.SetName(fileName.c_str(), filePath.c_str(),
|
||||
m_Makefile->GetSourceExtensions(),
|
||||
m_Makefile->GetHeaderExtensions());
|
||||
m_Makefile->AddSource(file, srcListName.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
cmVTKMakeInstantiatorCommand::GenerateCreationFileName(unsigned int block)
|
||||
{
|
||||
std::ostrstream nameStr;
|
||||
nameStr << m_ClassName.c_str() << block << ".cxx" << std::ends;
|
||||
std::string result = nameStr.str();
|
||||
nameStr.rdbuf()->freeze(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Generates the class header file with the definition of the class
|
||||
// and its initializer class.
|
||||
void
|
||||
cmVTKMakeInstantiatorCommand
|
||||
::GenerateHeaderFile(std::ostream& os)
|
||||
{
|
||||
os <<
|
||||
"#ifndef __" << m_ClassName.c_str() << "_h\n"
|
||||
"#define __" << m_ClassName.c_str() << "_h\n"
|
||||
"\n"
|
||||
"#include \"vtkInstantiator.h\"\n"
|
||||
"\n"
|
||||
"class " << m_ClassName.c_str() << "Initialize;\n"
|
||||
"\n"
|
||||
"class " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "\n"
|
||||
"{\n"
|
||||
" friend class " << m_ClassName.c_str() << "Initialize;\n"
|
||||
"\n"
|
||||
" static void ClassInitialize();\n"
|
||||
" static void ClassFinalize();\n"
|
||||
"\n";
|
||||
|
||||
for(unsigned int i=0;i < m_Classes.size();++i)
|
||||
{
|
||||
os << " static vtkObject* Create_" << m_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 " << m_ExportMacro.c_str() << " " << m_ClassName.c_str() << "Initialize\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" " << m_ClassName.c_str() << "Initialize();\n"
|
||||
" ~" << m_ClassName.c_str() << "Initialize();\n"
|
||||
"private:\n"
|
||||
" static unsigned int Count;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"static " << m_ClassName.c_str() << "Initialize " << m_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)
|
||||
{
|
||||
// Write the ClassInitialize method to register all the creation functions.
|
||||
os <<
|
||||
"#include \"" << m_ClassName.c_str() << ".h\"\n"
|
||||
"\n"
|
||||
"void " << m_ClassName.c_str() << "::ClassInitialize()\n"
|
||||
"{\n";
|
||||
|
||||
for(unsigned int i=0;i < m_Classes.size();++i)
|
||||
{
|
||||
os << " vtkInstantiator::RegisterInstantiator(\""
|
||||
<< m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
|
||||
<< m_Classes[i].c_str() << ");\n";
|
||||
}
|
||||
|
||||
// Write the ClassFinalize method to unregister all the creation functions.
|
||||
os <<
|
||||
"}\n"
|
||||
"\n"
|
||||
"void " << m_ClassName.c_str() << "::ClassFinalize()\n"
|
||||
"{\n";
|
||||
|
||||
for(unsigned int i=0;i < m_Classes.size();++i)
|
||||
{
|
||||
os << " vtkInstantiator::UnRegisterInstantiator(\""
|
||||
<< m_Classes[i].c_str() << "\", " << m_ClassName.c_str() << "::Create_"
|
||||
<< m_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" <<
|
||||
m_ClassName.c_str() << "Initialize::" << m_ClassName.c_str() << "Initialize()\n"
|
||||
"{\n"
|
||||
" if(++" << m_ClassName.c_str() << "Initialize::Count == 1)\n"
|
||||
" { " << m_ClassName.c_str() << "::ClassInitialize(); }\n"
|
||||
"}\n"
|
||||
"\n" <<
|
||||
m_ClassName.c_str() << "Initialize::~" << m_ClassName.c_str() << "Initialize()\n"
|
||||
"{\n"
|
||||
" if(--" << m_ClassName.c_str() << "Initialize::Count == 0)\n"
|
||||
" { " << m_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 " << m_ClassName.c_str() << "Initialize::Count;\n";
|
||||
}
|
||||
|
||||
// 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
|
||||
::GenerateCreationFile(std::ostream& os, unsigned int groupStart,
|
||||
unsigned int groupSize)
|
||||
{
|
||||
// Need to include header of generated class.
|
||||
os <<
|
||||
"#include \"" << m_ClassName.c_str() << ".h\"\n"
|
||||
"\n";
|
||||
|
||||
// Include class files.
|
||||
for(unsigned int i=0;i < groupSize;++i)
|
||||
{
|
||||
os << "#include \"" << m_Classes[groupStart+i].c_str() << ".h\"\n";
|
||||
}
|
||||
|
||||
os <<
|
||||
"\n";
|
||||
|
||||
// Write the create function implementations.
|
||||
for(unsigned int i=0;i < groupSize;++i)
|
||||
{
|
||||
os << "vtkObject* " << m_ClassName.c_str() << "::Create_"
|
||||
<< m_Classes[groupStart+i].c_str() << "() { return "
|
||||
<< m_Classes[groupStart+i].c_str() << "::New(); }\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*=========================================================================
|
||||
|
||||
Program: Insight Segmentation & Registration Toolkit
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2001 Insight Consortium
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* The name of the Insight Consortium, nor the names of any consortium members,
|
||||
nor of any contributors, may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
* Modified source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=========================================================================*/
|
||||
#ifndef cmVTKMakeInstantiatorCommand_h
|
||||
#define cmVTKMakeInstantiatorCommand_h
|
||||
|
||||
#include "cmStandardIncludes.h"
|
||||
#include "cmCommand.h"
|
||||
|
||||
/** \class cmVTKMakeInstantiatorCommand
|
||||
* cmVTKMakeInstantiatorCommand implements the VTK_MAKE_INSTANTIATOR
|
||||
* command. This generates a source file to add to a VTK library that
|
||||
* registers instance creation functions with vtkInstantiator for every
|
||||
* class in that library.
|
||||
*/
|
||||
class cmVTKMakeInstantiatorCommand : public cmCommand
|
||||
{
|
||||
public:
|
||||
/** This is a virtual constructor for the command. */
|
||||
virtual cmCommand* Clone()
|
||||
{ return new cmVTKMakeInstantiatorCommand; }
|
||||
|
||||
/**
|
||||
* This is called when the command is first encountered in
|
||||
* the CMakeLists.txt file.
|
||||
*/
|
||||
virtual bool InitialPass(std::vector<std::string> const& args);
|
||||
|
||||
/** The name of the command as specified in CMakeList.txt. */
|
||||
virtual const char* GetName() { return "VTK_MAKE_INSTANTIATOR"; }
|
||||
|
||||
/** Succinct documentation. */
|
||||
virtual const char* GetTerseDocumentation()
|
||||
{
|
||||
return "Setup a library's classes to be created by vtkInstantiator";
|
||||
}
|
||||
|
||||
/** More documentation. */
|
||||
virtual const char* GetFullDocumentation()
|
||||
{
|
||||
return
|
||||
"VTK_MAKE_INSTANTIATOR(libName srcList exportMacro\n"
|
||||
" [HEADER_LOCATION dir] [GROUP_SIZE groupSize])\n"
|
||||
"Generates a new class for the given library to allow its other\n"
|
||||
"classes to be created by vtkInstantiator. Functions to create\n"
|
||||
"classes listed in srcList are registered with vtkInstantiator, and\n"
|
||||
"the new class containing this code is added to the srcList for\n"
|
||||
"inclusion in the library. The libName argument is used to generate\n"
|
||||
"the filename and name of the class used to register the functions\n"
|
||||
"when the library is loaded. The exportMacro is the name of the\n"
|
||||
"DLL export macro to use in the class definition\n"
|
||||
"(ex. VTK_COMMON_EXPORT).\n"
|
||||
"The HEADER_LOCATION option must be followed by a path. It specifies\n"
|
||||
"the directory in which to place the generated class's header file.\n"
|
||||
"The generated class implementation files always go in the build\n"
|
||||
"directory corresponding to the CMakeLists.txt file containing\n"
|
||||
"the command. This is the default location for the header.\n"
|
||||
"The GROUP_SIZE option must be followed by a positive integer.\n"
|
||||
"As an implementation detail, the registered creation functions may\n"
|
||||
"be split up into multiple files. The groupSize option specifies\n"
|
||||
"the number of classes per file. Its default is 10.";
|
||||
}
|
||||
|
||||
cmTypeMacro(cmVTKMakeInstantiatorCommand, cmCommand);
|
||||
|
||||
protected:
|
||||
std::string m_ClassName;
|
||||
std::string m_ExportMacro;
|
||||
std::vector<cmStdString> m_Classes;
|
||||
|
||||
std::string GenerateCreationFileName(unsigned int group);
|
||||
|
||||
void GenerateHeaderFile(std::ostream&);
|
||||
void GenerateImplementationFile(std::ostream&);
|
||||
void GenerateCreationFile(std::ostream&, unsigned int groupStart,
|
||||
unsigned int groupSize);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue