ソースを参照

ENH: Add superclass for all commands and handlers. Improve handlers to have initialization code, and start initializing ctest when start is invoked

Andy Cedilnik 20 年 前
コミット
d9dc9b54a6

+ 5 - 0
Source/CTest/cmCTestBuildAndTestHandler.cxx

@@ -31,6 +31,11 @@ cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
   m_BuildNoCMake           = false;
 }
 
+//----------------------------------------------------------------------
+void cmCTestBuildAndTestHandler::Initialize()
+{
+}
+
 //----------------------------------------------------------------------
 const char* cmCTestBuildAndTestHandler::GetOutput()
 {

+ 3 - 0
Source/CTest/cmCTestBuildAndTestHandler.h

@@ -31,6 +31,7 @@ class cmake;
 class cmCTestBuildAndTestHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestBuildAndTestHandler, cmCTestGenericHandler);
 
   /*
    * The main entry point for this class
@@ -49,6 +50,8 @@ public:
   
   cmCTestBuildAndTestHandler();
 
+  virtual void Initialize();
+
 protected:
   ///! Run CMake and build a test and then run it as a single test.
   int RunCMakeAndTest(std::string* output);

+ 58 - 0
Source/CTest/cmCTestBuildHandler.cxx

@@ -186,6 +186,64 @@ cmCTestBuildHandler::cmCTestBuildHandler()
     }
 }
 
+//----------------------------------------------------------------------
+void cmCTestBuildHandler::Initialize()
+{
+  m_StartBuild = "";
+  m_EndBuild = "";
+  m_CustomErrorMatches.clear();
+  m_CustomErrorExceptions.clear();
+  m_CustomWarningMatches.clear();
+  m_CustomWarningExceptions.clear();
+  m_ErrorWarningFileLineRegex.clear();
+
+  m_ErrorMatchRegex.clear();
+  m_ErrorExceptionRegex.clear();
+  m_WarningMatchRegex.clear();
+  m_WarningExceptionRegex.clear();
+  m_BuildProcessingQueue.clear();
+  m_BuildProcessingQueueLocation = m_BuildProcessingQueue.end();
+  m_BuildOutputLogSize = 0;
+  m_CurrentProcessingLine.clear();
+
+  m_SimplifySourceDir = "";
+  m_SimplifyBuildDir = "";
+  m_OutputLineCounter = 0;
+  m_ErrorsAndWarnings.clear();
+  m_LastErrorOrWarning = m_ErrorsAndWarnings.end();
+  m_PostContextCount = 0;
+  m_MaxPreContext = 6;
+  m_MaxPostContext = 6;
+  m_PreContext.clear();
+
+  m_TotalErrors = 0;
+  m_TotalWarnings = 0;
+  m_LastTickChar = 0;
+
+  m_ErrorQuotaReached = false;
+  m_WarningQuotaReached = false;
+
+  m_MaxErrors = 50;
+  m_MaxWarnings = 50;
+
+  int cc;
+  for ( cc = 0; cmCTestWarningErrorFileLine[cc].m_RegularExpressionString; ++ cc )
+    {
+    cmCTestBuildHandler::cmCTestCompileErrorWarningRex r;
+    if ( r.m_RegularExpression.compile(
+        cmCTestWarningErrorFileLine[cc].m_RegularExpressionString) )
+      {
+      r.m_FileIndex = cmCTestWarningErrorFileLine[cc].m_FileIndex;
+      r.m_LineIndex = cmCTestWarningErrorFileLine[cc].m_LineIndex;
+      m_ErrorWarningFileLineRegex.push_back(r);
+      }
+    else
+      {
+      cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem Compiling regular expression: "
+       << cmCTestWarningErrorFileLine[cc].m_RegularExpressionString << std::endl);
+      }
+    }
+}
 
 //----------------------------------------------------------------------
 void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile *mf)

+ 6 - 0
Source/CTest/cmCTestBuildHandler.h

@@ -33,6 +33,7 @@ class cmMakefile;
 class cmCTestBuildHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestBuildHandler, cmCTestGenericHandler);
 
   /*
    * The main entry point for this class
@@ -43,6 +44,11 @@ public:
   
   void PopulateCustomVectors(cmMakefile *mf);
 
+  /**
+   * Initialize handler
+   */
+  virtual void Initialize();
+  
 private:
   //! Run command specialized for make and configure. Returns process status
   // and retVal is return value or exception.

+ 4 - 0
Source/CTest/cmCTestConfigureHandler.cxx

@@ -28,6 +28,10 @@ cmCTestConfigureHandler::cmCTestConfigureHandler()
 {
 }
 
+//----------------------------------------------------------------------
+void cmCTestConfigureHandler::Initialize()
+{
+}
 
 //----------------------------------------------------------------------
 //clearly it would be nice if this were broken up into a few smaller

+ 3 - 0
Source/CTest/cmCTestConfigureHandler.h

@@ -29,6 +29,7 @@
 class cmCTestConfigureHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestConfigureHandler, cmCTestGenericHandler);
 
   /*
    * The main entry point for this class
@@ -36,6 +37,8 @@ public:
   int ProcessHandler();
   
   cmCTestConfigureHandler();
+
+  void Initialize();
 };
 
 #endif

+ 5 - 1
Source/CTest/cmCTestCoverageHandler.cxx

@@ -34,7 +34,11 @@
 //----------------------------------------------------------------------
 cmCTestCoverageHandler::cmCTestCoverageHandler()
 {
-  m_CTest = 0;
+}
+
+//----------------------------------------------------------------------
+void cmCTestCoverageHandler::Initialize()
+{
 }
 
 //----------------------------------------------------------------------

+ 3 - 0
Source/CTest/cmCTestCoverageHandler.h

@@ -31,6 +31,7 @@ class cmGeneratedFileStream;
 class cmCTestCoverageHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestCoverageHandler, cmCTestGenericHandler);
 
   /*
    * The main entry point for this class
@@ -39,6 +40,8 @@ public:
   
   cmCTestCoverageHandler();
   
+  virtual void Initialize();
+
 private:
   bool ShouldIDoCoverage(const char* file, const char* srcDir,
     const char* binDir);

+ 7 - 2
Source/CTest/cmCTestGenericHandler.h

@@ -19,7 +19,7 @@
 #define cmCTestGenericHandler_h
 
 
-#include "cmStandardIncludes.h"
+#include "cmObject.h"
 
 class cmCTest;
 class cmMakefile;
@@ -29,7 +29,7 @@ class cmCTestCommand;
  * \brief A superclass of all CTest Handlers
  *
  */
-class cmCTestGenericHandler
+class cmCTestGenericHandler : public cmObject
 {
 public:
   /**
@@ -55,6 +55,11 @@ public:
     const std::string& /*currentArg*/, size_t& /*idx*/,
     const std::vector<std::string>& /*allArgs*/) { return 1; }
 
+  /**
+   * Initialize handler
+   */
+  virtual void Initialize() = 0;
+
   /**
    * Set the CTest instance
    */

+ 17 - 0
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -90,6 +90,23 @@ cmCTestMemCheckHandler::cmCTestMemCheckHandler()
   m_MemCheck = true;
 }
 
+//----------------------------------------------------------------------
+void cmCTestMemCheckHandler::Initialize()
+{
+  this->Superclass::Initialize();
+  m_MemoryTester = "";
+  m_MemoryTesterOptionsParsed.clear();
+  m_MemoryTesterOptions = "";
+  m_MemoryTesterStyle = UNKNOWN;
+  m_MemoryTesterOutputFile = "";
+  int cc;
+  for ( cc = 0; cc < NO_MEMORY_FAULT; cc ++ )
+    {
+    m_MemoryTesterGlobalResults[cc] = 0;
+    }
+
+}
+
 //----------------------------------------------------------------------
 int cmCTestMemCheckHandler::PreProcessHandler()
 {

+ 3 - 0
Source/CTest/cmCTestMemCheckHandler.h

@@ -31,10 +31,13 @@ class cmMakefile;
 class cmCTestMemCheckHandler : public cmCTestTestHandler
 {
 public:
+  cmTypeMacro(cmCTestMemCheckHandler, cmCTestTestHandler);
+
   void PopulateCustomVectors(cmMakefile *mf);
   
   cmCTestMemCheckHandler();
 
+  void Initialize();
 protected:
   virtual int PreProcessHandler();
   virtual int PostProcessHandler();

+ 43 - 0
Source/CTest/cmCTestScriptHandler.cxx

@@ -97,6 +97,49 @@ cmCTestScriptHandler::cmCTestScriptHandler()
   m_ContinuousDuration = -1;
 }
 
+//----------------------------------------------------------------------
+void cmCTestScriptHandler::Initialize()
+{
+  m_Backup = false;
+  m_EmptyBinDir = false;
+  m_EmptyBinDirOnce = false;
+  
+  m_SourceDir = "";
+  m_BinaryDir = "";
+  m_BackupSourceDir = "";
+  m_BackupBinaryDir = "";
+  m_CTestRoot = "";
+  m_CVSCheckOut = "";
+  m_CTestCmd = "";
+  m_CVSCmd = "";
+  m_CTestEnv = "";
+  m_InitCache = "";
+  m_CMakeCmd = "";
+  m_CMOutFile = "";
+  m_ExtraUpdates.clear();
+
+  m_MinimumInterval = 20*60;
+  m_ContinuousDuration = -1;
+
+  // what time in seconds did this script start running
+  m_ScriptStartTime = 0;
+  
+  m_Makefile = 0;
+  if (m_LocalGenerator)
+    {
+    delete m_LocalGenerator;
+    }
+  m_LocalGenerator = 0;
+  if (m_GlobalGenerator)
+    {
+    delete m_GlobalGenerator;
+    }
+  m_GlobalGenerator = 0;
+  if (m_CMake)
+    {
+    delete m_CMake;
+    }
+}
 
 //----------------------------------------------------------------------
 cmCTestScriptHandler::~cmCTestScriptHandler()

+ 2 - 0
Source/CTest/cmCTestScriptHandler.h

@@ -66,6 +66,7 @@ class cmCTestCommand;
 class cmCTestScriptHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestScriptHandler, cmCTestGenericHandler);
 
   /**
    * Add a script to run
@@ -97,6 +98,7 @@ public:
   cmCTestScriptHandler();
   ~cmCTestScriptHandler();
   
+  void Initialize();
 private:
   // reads in a script
   int ReadInScript(const std::string& total_script_arg);

+ 1 - 0
Source/CTest/cmCTestStartCommand.cxx

@@ -64,6 +64,7 @@ bool cmCTestStartCommand::InitialPass(
     this->SetError("binary directory not specified. Specify binary directory as an argument or set CTEST_BINARY_DIRECTORY");
     return false;
     }
+  m_CTest->EmptyCTestConfiguration();
   m_CTest->SetCTestConfiguration("SourceDirectory", src_dir);
   m_CTest->SetCTestConfiguration("BuildDirectory", bld_dir); 
 

+ 11 - 0
Source/CTest/cmCTestSubmitHandler.cxx

@@ -67,6 +67,17 @@ cmCTestSubmitHandler::cmCTestSubmitHandler() : m_HTTPProxy(), m_FTPProxy()
   m_FTPProxyType = 0;
 }
 
+//----------------------------------------------------------------------------
+void cmCTestSubmitHandler::Initialize()
+{
+  m_HTTPProxy = "";
+  m_HTTPProxyType = 0;
+  m_HTTPProxyAuth = "";
+  m_FTPProxy = "";
+  m_FTPProxyType = 0;
+  m_LogFile = 0;
+}
+
 //----------------------------------------------------------------------------
 bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix, 
   const std::vector<cmStdString>& files,

+ 3 - 0
Source/CTest/cmCTestSubmitHandler.h

@@ -28,6 +28,8 @@
 class cmCTestSubmitHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestSubmitHandler, cmCTestGenericHandler);
+
   cmCTestSubmitHandler();
   ~cmCTestSubmitHandler() { m_LogFile = 0; }
 
@@ -36,6 +38,7 @@ public:
    */
   int ProcessHandler();
 
+  void Initialize();
   
 private:
   void SetLogFile(std::ostream* ost) { m_LogFile = ost; }

+ 29 - 0
Source/CTest/cmCTestTestHandler.cxx

@@ -293,6 +293,35 @@ cmCTestTestHandler::cmCTestTestHandler()
   m_MemCheck = false;
 }
 
+//----------------------------------------------------------------------
+void cmCTestTestHandler::Initialize()
+{
+  m_ElapsedTestingTime = -1;
+
+  m_TestResults.clear();
+
+  m_CustomTestsIgnore.clear();
+  m_StartTest = "";
+  m_EndTest = "";
+
+  m_CustomPreTest.clear();
+  m_CustomPostTest.clear();
+  m_CustomMaximumPassedTestOutputSize = 1 * 1024;
+  m_CustomMaximumFailedTestOutputSize = 300 * 1024;
+
+  m_TestsToRun.clear();
+
+  m_UseIncludeRegExp = false;
+  m_UseExcludeRegExp = false;
+  m_UseExcludeRegExpFirst = false;
+  m_IncludeRegExp = "";
+  m_ExcludeRegExp = "";
+
+  TestsToRunString = "";
+  m_UseUnion = false;
+  m_TestList.clear();
+}
+
 //----------------------------------------------------------------------
 void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
 {

+ 3 - 0
Source/CTest/cmCTestTestHandler.h

@@ -31,6 +31,7 @@ class cmMakefile;
 class cmCTestTestHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler);
 
   /**
    * The main entry point for this class
@@ -81,6 +82,8 @@ public:
     int         m_TestCount;
   };
 
+  void Initialize();
+
 protected:
   struct cmCTestTestProperties
   {

+ 1 - 0
Source/CTest/cmCTestUpdateCommand.cxx

@@ -66,6 +66,7 @@ bool cmCTestUpdateCommand::InitialPass(
       }
     }
 
+  m_CTest->SetCTestConfigurationFromCMakeVariable(m_Makefile, "UpdateCommand", "CTEST_UPDATE_COMMAND");
   m_CTest->SetCTestConfigurationFromCMakeVariable(m_Makefile, "CVSCommand", "CTEST_CVS_COMMAND");
   m_CTest->SetCTestConfigurationFromCMakeVariable(m_Makefile, "SVNCommand", "CTEST_SVN_COMMAND");
 

+ 51 - 4
Source/CTest/cmCTestUpdateHandler.cxx

@@ -38,6 +38,23 @@
 #include <math.h>
 #include <float.h>
 
+//----------------------------------------------------------------------
+static const char* cmCTestUpdateHandlerUpdateStrings[] =
+{
+  "Unknown",
+  "CVS",
+  "SVN"
+};
+
+static const char* cmCTestUpdateHandlerUpdateToString(int type)
+{
+  if ( type < cmCTestUpdateHandler::e_UNKNOWN || type >= cmCTestUpdateHandler::e_LAST )
+    {
+    return cmCTestUpdateHandlerUpdateStrings[cmCTestUpdateHandler::e_UNKNOWN];
+    }
+  return cmCTestUpdateHandlerUpdateStrings[type];
+}
+
 //----------------------------------------------------------------------
 //**********************************************************************
 class cmCTestUpdateHandlerSVNXMLParser : public cmXMLParser
@@ -156,14 +173,20 @@ private:
 //----------------------------------------------------------------------
 cmCTestUpdateHandler::cmCTestUpdateHandler()
 {
-  m_CTest = 0;
+}
+
+//----------------------------------------------------------------------
+void cmCTestUpdateHandler::Initialize()
+{
 }
 
 //----------------------------------------------------------------------
 int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
 {
+  cmCTestLog(m_CTest, DEBUG, "Determine update type from command: " << cmd << " and type: " << type << std::endl);
   if ( type && *type )
     {
+    cmCTestLog(m_CTest, DEBUG, "Type specified: " << type << std::endl);
     std::string stype = cmSystemTools::LowerCase(type);
     if ( stype.find("cvs") != std::string::npos )
       {
@@ -176,6 +199,7 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
     }
   else
     {
+    cmCTestLog(m_CTest, DEBUG, "Type not specified, check command: " << cmd << std::endl);
     std::string stype = cmSystemTools::LowerCase(cmd);
     if ( stype.find("cvs") != std::string::npos )
       {
@@ -186,7 +210,20 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
       return cmCTestUpdateHandler::e_SVN;
       }
     }
-  return cmCTestUpdateHandler::e_CVS;
+  std::string sourceDirectory = this->GetOption("SourceDirectory");
+  cmCTestLog(m_CTest, DEBUG, "Check directory: " << sourceDirectory.c_str() << std::endl);
+  sourceDirectory += "/.svn";
+  if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
+    {
+    return cmCTestUpdateHandler::e_SVN;
+    }
+  sourceDirectory = this->GetOption("SourceDirectory");
+  sourceDirectory += "/CVS";
+  if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
+    {
+    return cmCTestUpdateHandler::e_CVS;
+    }
+  return cmCTestUpdateHandler::e_UNKNOWN;
 }
 
 //----------------------------------------------------------------------
@@ -285,6 +322,8 @@ int cmCTestUpdateHandler::ProcessHandler()
     updateType = this->DetermineType(updateCommand.c_str(), m_CTest->GetCTestConfiguration("UpdateType").c_str());
     }
 
+  cmCTestLog(m_CTest, HANDLER_OUTPUT, "   Use " << cmCTestUpdateHandlerUpdateToString(updateType) << " repository type" << std::endl;);
+
   // And update options
   std::string updateOptions = m_CTest->GetCTestConfiguration("UpdateOptions");
   if ( updateOptions.empty() )
@@ -434,6 +473,7 @@ int cmCTestUpdateHandler::ProcessHandler()
           &retVal, sourceDirectory, 0 /*m_TimeOut*/);
         ofs << "  Output: " << partialOutput.c_str() << std::endl;
         ofs << "  Errors: " << errors.c_str() << std::endl;
+        goutput = partialOutput;
         command = updateCommand + " status";
         ofs << "* Status repository: " << std::endl;
         ofs << "  Command: " << command.c_str() << std::endl;
@@ -443,6 +483,7 @@ int cmCTestUpdateHandler::ProcessHandler()
         ofs << "  Errors: " << errors.c_str() << std::endl;
         goutput += partialOutput;
         res = res && res1;
+        ofs << "  Total output of update: " << goutput.c_str() << std::endl;
         }
       }
     if ( ofs )
@@ -467,7 +508,9 @@ int cmCTestUpdateHandler::ProcessHandler()
     << m_CTest->GetTestModelString() << "</BuildStamp>" << std::endl;
   os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n"
     << "\t<UpdateCommand>" << m_CTest->MakeXMLSafe(command)
-    << "</UpdateCommand>\n";
+    << "</UpdateCommand>\n"
+    << "\t<UpdateType>" << m_CTest->MakeXMLSafe(cmCTestUpdateHandlerUpdateToString(updateType))
+    << "</UpdateType>\n";
 
   // Even though it failed, we may have some useful information. Try to continue...
   std::vector<cmStdString> lines;
@@ -503,7 +546,11 @@ int cmCTestUpdateHandler::ProcessHandler()
         }
       }
     }
-  if ( updateType == cmCTestUpdateHandler::e_SVN )
+  if ( svn_latest_revision <= 0 )
+    {
+    cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem determining the current revision of the repository from output:" << std::endl << goutput.c_str() << std::endl);
+    }
+  else if ( updateType == cmCTestUpdateHandler::e_SVN )
     {
     cmCTestLog(m_CTest, HANDLER_OUTPUT, "   Current revision of repository is: " << svn_latest_revision << std::endl);
     }

+ 9 - 1
Source/CTest/cmCTestUpdateHandler.h

@@ -33,6 +33,7 @@
 class cmCTestUpdateHandler : public cmCTestGenericHandler
 {
 public:
+  cmTypeMacro(cmCTestUpdateHandler, cmCTestGenericHandler);
 
   /*
    * The main entry point for this class
@@ -42,9 +43,16 @@ public:
   cmCTestUpdateHandler();
 
   enum {
+    e_UNKNOWN = 0,
     e_CVS,
-    e_SVN
+    e_SVN,
+    e_LAST
   };
+
+  /**
+   * Initialize handler
+   */
+  virtual void Initialize();
   
 private:
   // Some structures needed for update

+ 6 - 0
Source/cmCTest.cxx

@@ -1799,6 +1799,12 @@ std::string cmCTest::GetCTestConfiguration(const char *name)
   return m_CTestConfiguration[name];
 }
 
+//----------------------------------------------------------------------
+void cmCTest::EmptyCTestConfiguration()
+{
+  m_CTestConfiguration.clear();
+}
+
 //----------------------------------------------------------------------
 void cmCTest::SetCTestConfiguration(const char *name, const char* value)
 {

+ 1 - 0
Source/cmCTest.h

@@ -114,6 +114,7 @@ public:
   static std::string CleanString(const std::string& str);
   std::string GetCTestConfiguration(const char *name);
   void SetCTestConfiguration(const char *name, const char* value);
+  void EmptyCTestConfiguration();
   
   /**
    * constructor and destructor

+ 4 - 45
Source/cmCommand.h

@@ -17,6 +17,7 @@
 #ifndef cmCommand_h
 #define cmCommand_h
 
+#include "cmObject.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 
@@ -30,9 +31,11 @@
  * to support such features as enable/disable, inheritance, 
  * documentation, and construction.
  */
-class cmCommand
+class cmCommand : public cmObject
 {
 public:
+  cmTypeMacro(cmCommand, cmObject);
+
   /**
    * Construct the command. By default it is enabled with no makefile.
    */
@@ -103,11 +106,6 @@ public:
    */
   virtual const char* GetName() = 0;
 
-  /**
-   * The class name of the command.
-   */
-  virtual const char* GetNameOfClass() = 0;
-
   /**
    * Succinct documentation.
    */
@@ -155,19 +153,6 @@ public:
       return m_Error.c_str();
     }
 
-  /**
-   * Returns true if this class is the given class, or a subclass of it.
-   */
-  static bool IsTypeOf(const char *type)
-    { return !strcmp("cmCommand", type); }
-  
-  /**
-   * Returns true if this object is an instance of the given class or
-   * a subclass of it.
-   */
-  virtual bool IsA(const char *type)
-    { return cmCommand::IsTypeOf(type); }
-
   /**
    * Set the error message
    */
@@ -186,30 +171,4 @@ private:
   std::string m_Error;
 };
 
-// All subclasses of cmCommand should invoke this macro.
-#define cmTypeMacro(thisClass,superclass) \
-virtual const char* GetNameOfClass() { return #thisClass; } \
-typedef superclass Superclass; \
-static bool IsTypeOf(const char *type) \
-{ \
-  if ( !strcmp(#thisClass,type) ) \
-    { \
-    return true; \
-    } \
-  return Superclass::IsTypeOf(type); \
-} \
-virtual bool IsA(const char *type) \
-{ \
-  return thisClass::IsTypeOf(type); \
-} \
-static thisClass* SafeDownCast(cmCommand *c) \
-{ \
-  if ( c && c->IsA(#thisClass) ) \
-    { \
-    return (thisClass *)c; \
-    } \
-  return 0;\
-}
-
-
 #endif

+ 56 - 0
Source/cmObject.h

@@ -0,0 +1,56 @@
+/*=========================================================================
+
+  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.
+
+=========================================================================*/
+#ifndef cmObject_h
+#define cmObject_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmObject
+ * \brief Superclass for all commands and other classes in CMake.
+ *
+ * cmObject is the base class for all classes in CMake. It defines some methods
+ * such as GetNameOfClass, IsA, SafeDownCast.
+ */
+class cmObject
+{
+public:
+  /**
+   * Need virtual destructor to destroy real command type.
+   */
+  virtual ~cmObject() {}
+  
+  /**
+   * The class name of the command.
+   */
+  virtual const char* GetNameOfClass() = 0;
+
+  /**
+   * Returns true if this class is the given class, or a subclass of it.
+   */
+  static bool IsTypeOf(const char *type)
+    { return !strcmp("cmObject", type); }
+  
+  /**
+   * Returns true if this object is an instance of the given class or
+   * a subclass of it.
+   */
+  virtual bool IsA(const char *type)
+    { return cmObject::IsTypeOf(type); }
+};
+
+#endif
+

+ 27 - 0
Source/cmStandardIncludes.h

@@ -323,4 +323,31 @@ public:
 # pragma reset woff 1375 /* base class destructor not virtual */
 #endif
 
+// All subclasses of cmCommand or cmCTestGenericHandler should invoke this macro.
+#define cmTypeMacro(thisClass,superclass) \
+virtual const char* GetNameOfClass() { return #thisClass; } \
+typedef superclass Superclass; \
+static bool IsTypeOf(const char *type) \
+{ \
+  if ( !strcmp(#thisClass,type) ) \
+    { \
+    return true; \
+    } \
+  return Superclass::IsTypeOf(type); \
+} \
+virtual bool IsA(const char *type) \
+{ \
+  return thisClass::IsTypeOf(type); \
+} \
+static thisClass* SafeDownCast(cmObject *c) \
+{ \
+  if ( c && c->IsA(#thisClass) ) \
+    { \
+    return (thisClass *)c; \
+    } \
+  return 0;\
+}
+
+
+
 #endif