Browse Source

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 năm trước cách đây
mục cha
commit
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