Преглед на файлове

ENH: Adding VTK_MAKE_INSTANTIATOR command. This command will be used by VTK kits to register their classes with vtkInstantiator.

Brad King преди 24 години
родител
ревизия
fa53ab0807
променени са 3 файла, в които са добавени 462 реда и са изтрити 2 реда
  1. 2 2
      Source/cmCommands.cxx
  2. 343 0
      Source/cmVTKMakeInstantiatorCommand.cxx
  3. 117 0
      Source/cmVTKMakeInstantiatorCommand.h

+ 2 - 2
Source/cmCommands.cxx

@@ -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);
 }
-
-

+ 343 - 0
Source/cmVTKMakeInstantiatorCommand.cxx

@@ -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";
+    }
+}

+ 117 - 0
Source/cmVTKMakeInstantiatorCommand.h

@@ -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