Browse Source

ENH: ctest now uses CMake global generator to do the build part of build-and-test

Ken Martin 20 years ago
parent
commit
4d30cb309c

+ 84 - 233
Source/cmCTest.cxx

@@ -1733,53 +1733,50 @@ void CMakeStdoutCallback(const char* m, int len, void* s)
   out->append(m, len);
 }
 
-
-int cmCTest::RunCMakeAndTest(std::string* outstring)
-{  
+int cmCTest::RunCMake(std::string* outstring, cmOStringStream &out,
+                      std::string &cmakeOutString, std::string &cwd,
+                      cmake *cm)
+{
   unsigned int k;
-  std::string cmakeOutString;
-  cmSystemTools::SetErrorCallback(CMakeMessageCallback, &cmakeOutString);
-  cmSystemTools::SetStdoutCallback(CMakeStdoutCallback, &cmakeOutString);
-  cmOStringStream out;
-  cmake cm;
-  double timeout = m_TimeOut;
-  // default to the build type of ctest itself
-  if(m_ConfigType.size() == 0)
+  std::vector<std::string> args;
+  args.push_back(m_CMakeSelf);
+  args.push_back(m_SourceDir);
+  if(m_BuildGenerator.size())
     {
-#ifdef  CMAKE_INTDIR
-    m_ConfigType = CMAKE_INTDIR;
-#endif
+    std::string generator = "-G";
+    generator += m_BuildGenerator;
+    args.push_back(generator);
+    }
+  if ( m_ConfigType.size() > 0 )
+    {
+    std::string btype = "-DBUILD_TYPE:STRING=" + m_ConfigType;
+    args.push_back(btype);
     }
 
-  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
-  out << "Internal cmake changing into directory: " << m_BinaryDir << "\n";  
-  if (!cmSystemTools::FileIsDirectory(m_BinaryDir.c_str()))
+  for(k=0; k < m_BuildOptions.size(); ++k)
     {
-    cmSystemTools::MakeDirectory(m_BinaryDir.c_str());
+    args.push_back(m_BuildOptions[k]);
     }
-  cmSystemTools::ChangeDirectory(m_BinaryDir.c_str());
-  if(!m_BuildNoCMake)
+  if (cm->Run(args) != 0)
     {
-    std::vector<std::string> args;
-    args.push_back(m_CMakeSelf);
-    args.push_back(m_SourceDir);
-    if(m_BuildGenerator.size())
-      {
-      std::string generator = "-G";
-      generator += m_BuildGenerator;
-      args.push_back(generator);
-      }
-    if ( m_ConfigType.size() > 0 )
+    out << "Error: cmake execution failed\n";
+    out << cmakeOutString << "\n";
+    // return to the original directory
+    cmSystemTools::ChangeDirectory(cwd.c_str());
+    if(outstring)
       {
-      std::string btype = "-DBUILD_TYPE:STRING=" + m_ConfigType;
-      args.push_back(btype);
+      *outstring = out.str();
       }
-
-    for(k=0; k < m_BuildOptions.size(); ++k)
+    else
       {
-      args.push_back(m_BuildOptions[k]);
+      std::cerr << out.str() << "\n";
       }
-    if (cm.Run(args) != 0)
+    return 1;
+    }
+  // do another config?
+  if(m_BuildTwoConfig)
+    {
+    if (cm->Run(args) != 0)
       {
       out << "Error: cmake execution failed\n";
       out << cmakeOutString << "\n";
@@ -1795,222 +1792,76 @@ int cmCTest::RunCMakeAndTest(std::string* outstring)
         }
       return 1;
       }
-    if(m_BuildTwoConfig)
-      {
-      if (cm.Run(args) != 0)
-        {
-        out << "Error: cmake execution failed\n";
-        out << cmakeOutString << "\n";
-        // return to the original directory
-        cmSystemTools::ChangeDirectory(cwd.c_str());
-        if(outstring)
-          {
-          *outstring = out.str();
-          }
-        else
-          {
-          std::cerr << out.str() << "\n";
-          }
-        return 1;
-        }
-      } 
-    }
+    } 
+  return 0;
+}
 
-  cmSystemTools::SetErrorCallback(0, 0);
-  out << cmakeOutString << "\n";
-  if(m_BuildMakeProgram.size() == 0)
-    {
-    out << "Error: cmake does not have a valid MAKEPROGRAM\n";
-    out << "Did you specify a --build-makeprogram and a --build-generator?\n";
-    if(outstring)
-      {
-      *outstring = out.str();
-      }
-    else
-      {
-      std::cerr << out.str() << "\n";
-      }
-    return 1;
-    }
+int cmCTest::RunCMakeAndTest(std::string* outstring)
+{  
+  unsigned int k;
+  std::string cmakeOutString;
+  cmSystemTools::SetErrorCallback(CMakeMessageCallback, &cmakeOutString);
+  cmSystemTools::SetStdoutCallback(CMakeStdoutCallback, &cmakeOutString);
+  cmOStringStream out;
+  double timeout = m_TimeOut;
   int retVal = 0;
-  std::string makeCommand = cmSystemTools::ConvertToOutputPath(m_BuildMakeProgram.c_str());
-  std::string lowerCaseCommand = cmSystemTools::LowerCase(makeCommand);
-  // if msdev is the make program then do the following
-  // MSDEV 6.0
-  if(lowerCaseCommand.find("msdev") != std::string::npos)
+  
+  // default to the build type of ctest itself
+  if(m_ConfigType.size() == 0)
     {
-    // if there are spaces in the makeCommand, assume a full path
-    // and convert it to a path with no spaces in it as the
-    // RunSingleCommand does not like spaces
-#if defined(_WIN32) && !defined(__CYGWIN__)      
-    if(makeCommand.find(' ') != std::string::npos)
-      {
-      cmSystemTools::GetShortPath(makeCommand.c_str(), makeCommand);
-      }
+#ifdef  CMAKE_INTDIR
+    m_ConfigType = CMAKE_INTDIR;
 #endif
-    makeCommand += " ";
-    makeCommand += m_BuildProject;
-    makeCommand += ".dsw /MAKE \"";
-    if(m_BuildTarget.size())
-      {
-      makeCommand += m_BuildTarget;
-      }
-    else
-      {
-      makeCommand += "ALL_BUILD";
-      }
-    makeCommand += " - ";
-    makeCommand += m_ConfigType;
-    if(m_BuildNoClean)
-      {
-      makeCommand += "\" /BUILD";
-      }
-    else
-      {
-      makeCommand += "\" /REBUILD";
-      }
     }
-  // MSDEV 7.0 .NET
-  else if (lowerCaseCommand.find("devenv") != std::string::npos)
+
+  // make sure the binary dir is there
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+  out << "Internal cmake changing into directory: " << m_BinaryDir << "\n";  
+  if (!cmSystemTools::FileIsDirectory(m_BinaryDir.c_str()))
     {
-#if defined(_WIN32) && !defined(__CYGWIN__)      
-    if(makeCommand.find(' ') != std::string::npos)
-      {
-      cmSystemTools::GetShortPath(makeCommand.c_str(), makeCommand);
-      }
-#endif
-    makeCommand += " ";
-    makeCommand += m_BuildProject;
-    makeCommand += ".sln ";
-    if(m_BuildNoClean)
-      {
-      makeCommand += "/build ";
-      }
-    else
-      {
-      makeCommand += "/rebuild ";
-      }
-    makeCommand += m_ConfigType + " /project ";
-    if(m_BuildTarget.size())
-      {
-      makeCommand += m_BuildTarget;
-      }
-    else
-      {
-      makeCommand += "ALL_BUILD";
-      }
-    }
-  else if (lowerCaseCommand.find("xcode") != std::string::npos)
-    {
-     makeCommand += " -project ";
-     makeCommand += m_BuildProject;
-     makeCommand += ".xcode";
-     makeCommand += " build -target ";
-     if (m_BuildTarget.size())
-       {
-       makeCommand += m_BuildTarget;
-       }
-     else
-       {
-       makeCommand += "ALL_BUILD ";
-       }
-     makeCommand += " -buildstyle Development ";
-    }
-  else if (lowerCaseCommand.find("make") != std::string::npos)
-    {
-    // assume a make sytle program
-    // clean first
-    if(!m_BuildNoClean)
-      {
-      std::string cleanCommand = makeCommand;
-      cleanCommand += " clean";
-      out << "Running make clean command: " << cleanCommand.c_str() << " ...\n";
-      retVal = 0;
-      std::string output;
-      if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), &output, &retVal, 0,
-                                           false, timeout) ||
-        retVal)
-        {
-        out << "Error: " << cleanCommand.c_str() << "  execution failed\n";
-        out << output.c_str() << "\n";
-        // return to the original directory
-        cmSystemTools::ChangeDirectory(cwd.c_str());
-        out << "Return value: " << retVal << std::endl;
-        if(outstring)
-          {
-          *outstring = out.str();
-          }
-        else
-          {
-          std::cerr << out.str() << "\n";
-          }
-        return 1;
-        }
-      out << output;
-      }
+    cmSystemTools::MakeDirectory(m_BinaryDir.c_str());
+    }
+  cmSystemTools::ChangeDirectory(m_BinaryDir.c_str());
 
-    if(m_BuildTarget.size())
+  // should we cmake?
+  cmake cm;
+  cm.SetGlobalGenerator(cm.CreateGlobalGenerator(m_BuildGenerator.c_str()));
+    
+  if(!m_BuildNoCMake)
+    {
+    // do the cmake step
+    if (this->RunCMake(outstring,out,cmakeOutString,cwd,&cm))
       {
-      makeCommand +=  " ";
-      makeCommand += m_BuildTarget;
+      return 1;
       }
     }
 
-  // command line make program
-
-  out << "Running make command: " << makeCommand.c_str() << "\n";
-  retVal = 0;
+  // do the build
   std::string output;
-  if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), &output, &retVal, 0, false, timeout))
+  retVal = cm.GetGlobalGenerator()->Build(
+    m_SourceDir.c_str(), m_BinaryDir.c_str(),
+    m_BuildProject.c_str(), m_BuildTarget.c_str(),
+    &output, m_BuildMakeProgram.c_str(),
+    m_ConfigType.c_str(),!m_BuildNoClean);
+  
+  out << output;
+  if(outstring)
     {
-    out << "Error: " << makeCommand.c_str() <<  "  execution failed\n";
-    out << output.c_str() << "\n";
-    // return to the original directory
-    cmSystemTools::ChangeDirectory(cwd.c_str());
-    out << "Return value: " << retVal << std::endl;
-    if(outstring)
-      {
-      *outstring = out.str();
-      }
-    else
-      {
-      std::cerr << out.str() << "\n";
-      }
-    return 1;
+    *outstring =  out.str();
     }
-  if ( retVal )
+  
+  // if the build failed then return
+  if (retVal)
     {
-    if(outstring)
-      {
-      *outstring = out.str();
-      *outstring += "Building of project failed\n";
-      *outstring += output;
-      *outstring += "\n";
-      }
-    else
-      {
-      std::cerr << "Building of project failed\n";
-      std::cerr << out.str() << output << "\n";
-      }
-    // return to the original directory
-    cmSystemTools::ChangeDirectory(cwd.c_str());
     return 1;
     }
-  out << output;
-
-  if(m_TestCommand.size() == 0)
+    
+  // if not test was specified then we are done
+  if (!m_TestCommand.size())
     {
-    if(outstring)
-      {
-      *outstring = out.str();
-      }
-    else
-      {
-      std::cout << out.str() << "\n";
-      }
-    return retVal;
+    return 0;
     }
-
+  
   // now run the compiled test if we can find it
   std::vector<std::string> attempted;
   std::vector<std::string> failed;

+ 5 - 0
Source/cmCTest.h

@@ -23,6 +23,7 @@
 #include "cmListFileCache.h"
 #include <time.h>
 
+class cmake;
 class cmMakefile;
 class cmCTestGenericHandler;
 class cmGeneratedFileStream;
@@ -279,6 +280,10 @@ private:
 
   ///! Run CMake and build a test and then run it as a single test.
   int RunCMakeAndTest(std::string* output);
+  int RunCMake(std::string* outstring, cmOStringStream &out, 
+               std::string &cmakeOutString,
+               std::string &cwd, cmake *cm);
+  
   ///! Find the running cmake
   void FindRunningCMake(const char* arg0);
 

+ 73 - 19
Source/cmGlobalGenerator.cxx

@@ -637,11 +637,11 @@ void cmGlobalGenerator::LocalGenerate()
   delete lg;
 }
 
-int cmGlobalGenerator::TryCompile(const char *, const char *bindir, 
-                                  const char *, const char *target,
-                                  std::string *output, cmMakefile*)
+int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir, 
+                                  const char *projectName, 
+                                  const char *target,
+                                  std::string *output, cmMakefile *mf)
 {
-  // now build the test
   std::string makeCommand = 
     m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
   if(makeCommand.size() == 0)
@@ -650,6 +650,41 @@ int cmGlobalGenerator::TryCompile(const char *, const char *bindir,
       "Generator cannot find the appropriate make command.");
     return 1;
     }
+
+  std::string newTarget;
+  if (target && strlen(target))
+    {
+    newTarget += target;
+#if 0
+#if defined(_WIN32) || defined(__CYGWIN__)
+    std::string tmp = target;
+    // if the target does not already end in . something 
+    // then assume .exe
+    if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
+      {
+      newTarget += ".exe";
+      }
+#endif // WIN32
+#endif
+    }
+  const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+  return this->Build(srcdir,bindir,projectName,
+                     newTarget.c_str(),
+                     output,makeCommand.c_str(),config,false);
+}
+  
+int cmGlobalGenerator::Build(
+  const char *, const char *bindir, 
+  const char *, const char *target,
+  std::string *output, 
+  const char *makeCommandCSTR,
+  const char *config,
+  bool clean)
+{
+  *output += "\nTesting TryCompileWithoutMakefile\n";
+  
+  // now build the test
+  std::string makeCommand = makeCommandCSTR;
   makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
 
   /**
@@ -664,39 +699,58 @@ int cmGlobalGenerator::TryCompile(const char *, const char *bindir,
     {
     makeCommand += " /NOLOGO ";
     }
+
+  int retVal;
+  int timeout = cmGlobalGenerator::s_TryCompileTimeout;
+  bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
+  cmSystemTools::SetRunCommandHideConsole(true);
+
+  // should we do a clean first?
+  if (clean)
+    {
+    std::string cleanCommand = makeCommand + " clean";
+    if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), output, 
+                                         &retVal, 0, false, timeout))
+      {
+      cmSystemTools::SetRunCommandHideConsole(hideconsole);
+      cmSystemTools::Error("Generator: execution of make clean failed.");
+      if (output)
+        {
+        *output += "\nGenerator: execution of make clean failed.\n";
+        }
+      
+      // return to the original directory
+      cmSystemTools::ChangeDirectory(cwd.c_str());
+      return 1;
+      }
+    }
   
   // now build
-  if (target)
+  if (target && strlen(target))
     {
     makeCommand += " ";
     makeCommand += target;
-#if defined(_WIN32) || defined(__CYGWIN__)
-    std::string tmp = target;
-    // if the target does not already end in . something 
-    // then assume .exe
-    if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
-      {
-      makeCommand += ".exe";
-      }
-#endif // WIN32
     }
   else
     {
     makeCommand += " all";
     }
-  int retVal;
-  int timeout = cmGlobalGenerator::s_TryCompileTimeout;
-  bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
-  cmSystemTools::SetRunCommandHideConsole(true);
+
   if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, 
-      &retVal, 0, false, timeout))
+                                       &retVal, 0, false, timeout))
     {
     cmSystemTools::SetRunCommandHideConsole(hideconsole);
     cmSystemTools::Error("Generator: execution of make failed.");
+    if (output)
+      {
+      *output += "\nGenerator: execution of make failed.\n";
+      }
+    
     // return to the original directory
     cmSystemTools::ChangeDirectory(cwd.c_str());
     return 1;
     }
+
   cmSystemTools::SetRunCommandHideConsole(hideconsole);
   
   // The SGI MipsPro 7.3 compiler does not return an error code when

+ 13 - 0
Source/cmGlobalGenerator.h

@@ -93,6 +93,19 @@ public:
                          const char *projectName, const char *targetName,
                          std::string *output, cmMakefile* mf);
 
+  
+  /**
+   * Build a file given the following information. This is a more direct call
+   * that is used by both CTest and TryCompile. If target name is NULL or
+   * empty then all is assumed. clean indicates if a "make clean" should be
+   * done first.
+   */
+  virtual int Build(const char *srcdir, const char *bindir,
+                    const char *projectName, const char *targetName,
+                    std::string *output, 
+                    const char *makeProgram, const char *config,
+                    bool clean);
+
   ///! Set the CMake instance
   void SetCMakeInstance(cmake *cm) {
     this->m_CMakeInstance = cm; };

+ 21 - 12
Source/cmGlobalVisualStudio6Generator.cxx

@@ -67,21 +67,23 @@ void cmGlobalVisualStudio6Generator::GenerateConfigurations(cmMakefile* mf)
     }
 }
 
-int cmGlobalVisualStudio6Generator::TryCompile(const char *, 
-                                               const char *bindir, 
-                                               const char *projectName,
-                                               const char *targetName,
-                                               std::string *output,
-                                               cmMakefile* mf)
+int cmGlobalVisualStudio6Generator::Build(
+  const char *, 
+  const char *bindir, 
+  const char *projectName,
+  const char *targetName,
+  std::string *output,
+  const char *makeCommandCSTR,
+  const char *config,
+  bool clean)
 {
   // now build the test
-  std::string makeCommand = 
-    m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
   std::vector<std::string> mp;
   mp.push_back("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\6.0\\Setup;VsCommonDir]/MSDev98/Bin");
   cmSystemTools::ExpandRegistryValues(mp[0]);
-  std::string originalCommand = makeCommand;
-  makeCommand = cmSystemTools::FindProgram(makeCommand.c_str(), mp);
+  std::string originalCommand = makeCommandCSTR;
+  std::string makeCommand = 
+    cmSystemTools::FindProgram(makeCommandCSTR, mp);
   if(makeCommand.size() == 0)
     {
     std::string e = "Generator cannot find Visual Studio 6 msdev program \"";
@@ -119,7 +121,7 @@ int cmGlobalVisualStudio6Generator::TryCompile(const char *,
     makeCommand += "ALL_BUILD";
     }
   makeCommand += " - ";
-  if(const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"))
+  if(config)
     {
     makeCommand += config;
     }
@@ -127,7 +129,14 @@ int cmGlobalVisualStudio6Generator::TryCompile(const char *,
     {
     makeCommand += "Debug";
     }
-  makeCommand += "\"";
+  if(clean)
+    {
+    makeCommand += "\" /REBUILD";
+    }
+  else
+    {
+    makeCommand += "\" /BUILD";
+    }
   int retVal;
   int timeout = cmGlobalGenerator::s_TryCompileTimeout;
   if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, 

+ 8 - 4
Source/cmGlobalVisualStudio6Generator.h

@@ -47,14 +47,18 @@ public:
    * Try to determine system infomation such as shared library
    * extension, pthreads, byte order etc.  
    */
-  virtual void EnableLanguage(std::vector<std::string>const& languages, cmMakefile *);
+  virtual void EnableLanguage(std::vector<std::string>const& languages, 
+                              cmMakefile *);
+
   /**
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    */
-  virtual int TryCompile(const char *srcdir, const char *bindir,
-                         const char *projectName, const char *targetName,
-                         std::string *output, cmMakefile* mf);
+  virtual int Build(const char *srcdir, const char *bindir,
+                    const char *projectName, const char *targetName,
+                    std::string *output, 
+                    const char *makeProgram,
+                    const char *config, bool clean);
 
   /**
    * Generate the all required files for building this project/tree. This

+ 24 - 17
Source/cmGlobalVisualStudio7Generator.cxx

@@ -43,23 +43,19 @@ void cmGlobalVisualStudio7Generator::EnableLanguage(std::vector<std::string>cons
   this->cmGlobalGenerator::EnableLanguage(lang, mf);
 }
 
-int cmGlobalVisualStudio7Generator::TryCompile(const char *, 
-                                               const char *bindir, 
-                                               const char *projectName,
-                                               const char *targetName,
-                                               std::string *output,
-                                               cmMakefile* mf)
+int cmGlobalVisualStudio7Generator::Build(
+  const char *, 
+  const char *bindir, 
+  const char *projectName,
+  const char *targetName,
+  std::string *output,
+  const char *makeCommandCSTR,
+  const char *config,
+  bool clean)
 {
   // now build the test
   std::string makeCommand = 
-    m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
-  if(makeCommand.size() == 0)
-    {
-    cmSystemTools::Error(
-      "Generator cannot find the appropriate make command.");
-    return 1;
-    }
-  makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
+    cmSystemTools::ConvertToOutputPath(makeCommandCSTR);
   std::string lowerCaseCommand = makeCommand;
   cmSystemTools::LowerCase(lowerCaseCommand);
 
@@ -80,8 +76,17 @@ int cmGlobalVisualStudio7Generator::TryCompile(const char *,
 #endif
   makeCommand += " ";
   makeCommand += projectName;
-  makeCommand += ".sln /build ";
-  if(const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"))
+  makeCommand += ".sln ";
+  if(clean)
+    {
+    makeCommand += "/rebuild ";
+    }
+  else
+    {
+    makeCommand += "/build ";
+    }
+
+  if(config && strlen(config))
     {
     makeCommand += config;
     }
@@ -90,7 +95,8 @@ int cmGlobalVisualStudio7Generator::TryCompile(const char *,
     makeCommand += "Debug";
     }
   makeCommand += " /project ";
-  if (targetName)
+
+  if (targetName && strlen(targetName))
     {
     makeCommand += targetName;
     }
@@ -109,6 +115,7 @@ int cmGlobalVisualStudio7Generator::TryCompile(const char *,
     cmSystemTools::ChangeDirectory(cwd.c_str());
     return 1;
     }
+  *output += makeCommand;
   cmSystemTools::ChangeDirectory(cwd.c_str());
   return retVal;
 }

+ 5 - 3
Source/cmGlobalVisualStudio7Generator.h

@@ -53,9 +53,11 @@ public:
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    */
-  virtual int TryCompile(const char *srcdir, const char *bindir,
-                         const char *projectName, const char *targetName,
-                         std::string *output, cmMakefile* mf);
+  virtual int Build(const char *srcdir, const char *bindir,
+                    const char *projectName, const char *targetName,
+                    std::string *output, 
+                    const char *makeProgram,
+                    const char *config, bool clean);
 
   /**
    * Generate the all required files for building this project/tree. This

+ 12 - 10
Source/cmGlobalXCodeGenerator.cxx

@@ -76,23 +76,25 @@ void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
 }
 
 //----------------------------------------------------------------------------
-int cmGlobalXCodeGenerator::TryCompile(const char *, 
-                                       const char * bindir, 
-                                       const char * projectName,
-                                       const char * targetName,
-                                       std::string * output,
-                                       cmMakefile*)
+int cmGlobalXCodeGenerator::Build(
+  const char *, 
+  const char *bindir, 
+  const char *projectName,
+  const char *targetName,
+  std::string *output,
+  const char *makeCommandCSTR,
+  const char *,
+  bool )
 {
   // now build the test
-  std::string makeCommand = 
-    m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
-  if(makeCommand.size() == 0)
+  if(makeCommandCSTR == 0 || !strlen(makeCommandCSTR))
     {
     cmSystemTools::Error(
       "Generator cannot find the appropriate make command.");
     return 1;
     }
-  makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
+  std::string makeCommand = 
+    cmSystemTools::ConvertToOutputPath(makeCommandCSTR);
   std::string lowerCaseCommand = makeCommand;
   cmSystemTools::LowerCase(lowerCaseCommand);
 

+ 5 - 3
Source/cmGlobalXCodeGenerator.h

@@ -55,9 +55,11 @@ public:
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    */
-  virtual int TryCompile(const char *srcdir, const char *bindir,
-                         const char *projectName, const char *targetName,
-                         std::string *output, cmMakefile* mf);
+  virtual int Build(const char *srcdir, const char *bindir,
+                    const char *projectName, const char *targetName,
+                    std::string *output, 
+                    const char *makeProgram,
+                    const char *config, bool clean);
 
   /**
    * Generate the all required files for building this project/tree. This

+ 25 - 12
Source/ctest.cxx

@@ -100,18 +100,25 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
    "When both -R and -I are specified by default the intersection of "
    "tests are run. By specifying -U the union of tests is run instead."},
   {"--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1.",
-   "This option causes ctest to run tests in either an interactive mode or a non-interactive mode. "
-   "On Windows this means that in non-interactive mode, all system debug pop up windows are blocked. "
-   "In dashboard mode (Experimental, Nightly, Continuous), the default is non-interactive.  "
-   "When just running tests not for a dashboard the default is to allow popups and interactive "
+
+   "This option causes ctest to run tests in either an interactive mode or "
+   "a non-interactive mode. On Windows this means that in non-interactive "
+   "mode, all system debug pop up windows are blocked. In dashboard mode "
+   "(Experimental, Nightly, Continuous), the default is non-interactive.  "
+   "When just running tests not for a dashboard the default is to allow "
+   "popups and interactive "
    "debugging."},
-  {"--build-and-test", "Build and run a test.",
-   "This option allows a test to be compiled and then run. "
-   "CMake is run on the source tree and then based on the generator the build is run. "
-   "The arguments to this command line are the source and binary directories. "
-   "Other options that affect this mode are --build-target --build-nocmake, --build-run-dir, "
-   "--build-two-config, --build-exe-dir, --build-generator, --build-project," 
-   "--build-makeprogram "
+  {"--build-and-test", "Configure, build and run a test.",
+   "This option tells ctest to configure (i.e. run cmake on), build, and or "
+   "execute a test. The configure and test steps are optional. The arguments "
+   "to this command line are the source and binary directories. By default "
+   "this will run CMake on the Source/Bin directories specified unless "
+   "--build-nocmake is specified. Both --build-makeprogram and "
+   "--build-generator MUST be provided to use --built-and-test. If "
+   "--test-command is specified then that will be run after the build is "
+   "complete. Other options that affect this mode are --build-target "
+   "--build-nocmake, --build-run-dir, "
+   "--build-two-config, --build-exe-dir, --build-project," 
    "--build-noclean, --build-options"},
   {"--build-target", "Specify a specific target to build.", 
    "This option goes with the --build-and-test option, if left out the all target is built." },
@@ -126,6 +133,7 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
   {"--build-makeprogram", "Specify the make program to use.", "" },
   {"--build-noclean", "Skip the make clean step.", "" },
   {"--build-options", "Add extra options to the build step.", "" },
+  {"--test-command", "The test to run with the --build-and-test option.", "" },
   {"--tomorrow-tag", "Nightly or experimental starts with next day tag.", 
    "This is useful if the build will not finish in one day." },
   {0,0,0}
@@ -191,7 +199,12 @@ int main (int argc, char *argv[])
     args.push_back(argv[i]);
     }
   // run ctest
-  int res = inst.Run(args);
+  std::string output;
+  int res = inst.Run(args,&output);
+  if (res)
+    {
+    std::cout << output;
+    }
   cmListFileCache::ClearCache();
 
   return res;