summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/CTest.cmake17
-rw-r--r--Modules/DartConfiguration.tcl.in1
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx16
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx36
-rw-r--r--Source/CTest/cmCTestBuildHandler.h3
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx35
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx11
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx2
-rw-r--r--Source/cmBuildCommand.cxx115
-rw-r--r--Source/cmBuildCommand.h49
-rw-r--r--Source/cmGlobalGenerator.h4
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h5
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx15
-rw-r--r--Source/cmGlobalXCodeGenerator.h5
-rw-r--r--Tests/CMakeCommands/build_command/CMakeLists.txt58
-rw-r--r--Tests/CMakeCommands/build_command/RunCMake.cmake86
-rw-r--r--Tests/CMakeLists.txt52
-rw-r--r--Tests/CTestConfig/CMakeLists.txt47
-rw-r--r--Tests/CTestConfig/CTestConfig.cxx20
-rw-r--r--Tests/CTestConfig/dashboard.cmake.in43
-rw-r--r--Tests/CTestConfig/script.cmake.in21
21 files changed, 603 insertions, 38 deletions
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index aaa6040..fb430a7 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -84,10 +84,6 @@ IF(BUILD_TESTING)
ENDIF(EXISTS "${PROJECT_SOURCE_DIR}/DartConfig.cmake")
SET_IF_NOT_SET (NIGHTLY_START_TIME "00:00:00 EDT")
- # make program just needs to use CMAKE_MAKE_PROGRAM which is required
- # to be defined by cmake
- SET(MAKEPROGRAM ${CMAKE_MAKE_PROGRAM})
-
FIND_PROGRAM(CVSCOMMAND cvs )
SET(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING
"Options passed to the cvs update command.")
@@ -202,8 +198,17 @@ IF(BUILD_TESTING)
ENDIF(DART_CXX_NAME MATCHES "devenv")
SET(BUILDNAME "${BUILD_NAME_SYSTEM_NAME}-${DART_CXX_NAME}")
ENDIF(NOT BUILDNAME)
- # set the build command
- BUILD_COMMAND(MAKECOMMAND ${MAKEPROGRAM} )
+
+ # the build command
+ BUILD_COMMAND(MAKECOMMAND CONFIGURATION "\${CTEST_CONFIGURATION_TYPE}")
+ SET(MAKECOMMAND ${MAKECOMMAND} CACHE STRING "Command to build the project")
+
+ # the default build configuration the ctest build handler will use
+ # if there is no -C arg given to ctest:
+ SET(DEFAULT_CTEST_CONFIGURATION_TYPE "$ENV{CMAKE_CONFIG_TYPE}")
+ IF(DEFAULT_CTEST_CONFIGURATION_TYPE STREQUAL "")
+ SET(DEFAULT_CTEST_CONFIGURATION_TYPE "Release")
+ ENDIF(DEFAULT_CTEST_CONFIGURATION_TYPE STREQUAL "")
IF(NOT "${CMAKE_GENERATOR}" MATCHES "Make")
SET(CTEST_USE_LAUNCHERS 0)
diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in
index 2eea45c..00e8af6 100644
--- a/Modules/DartConfiguration.tcl.in
+++ b/Modules/DartConfiguration.tcl.in
@@ -30,6 +30,7 @@ NightlyStartTime: @NIGHTLY_START_TIME@
# Commands for the build/test/submit cycle
ConfigureCommand: "@CMAKE_COMMAND@" "@PROJECT_SOURCE_DIR@"
MakeCommand: @MAKECOMMAND@
+DefaultCTestConfigurationType: @DEFAULT_CTEST_CONFIGURATION_TYPE@
# CVS options
# Default is "-d -P -A"
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index af21e0d..7a4d877 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -53,6 +53,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
return 0;
}
this->Handler = (cmCTestBuildHandler*)handler;
+
const char* ctestBuildCommand
= this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
if ( ctestBuildCommand && *ctestBuildCommand )
@@ -67,10 +68,21 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
= (this->Values[ctb_PROJECT_NAME] && *this->Values[ctb_PROJECT_NAME])
? this->Values[ctb_PROJECT_NAME]
: this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
+
+ // Build configuration is determined by: CONFIGURATION argument,
+ // or CTEST_BUILD_CONFIGURATION script variable, or
+ // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
+ // line argument... in that order.
+ //
+ const char* ctestBuildConfiguration
+ = this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
const char* cmakeBuildConfiguration
= (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION])
? this->Values[ctb_CONFIGURATION]
- : this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
+ : ((ctestBuildConfiguration && *ctestBuildConfiguration)
+ ? ctestBuildConfiguration
+ : this->CTest->GetConfigType().c_str());
+
const char* cmakeBuildAdditionalFlags
= (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
? this->Values[ctb_FLAGS]
@@ -117,7 +129,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
}
cmakeBuildConfiguration = config;
}
-
+
std::string buildCommand
= this->GlobalGenerator->
GenerateBuildCommand(cmakeMakeProgram,
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 0095bbc..a125459 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -265,6 +265,32 @@ void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile *mf)
}
//----------------------------------------------------------------------
+std::string cmCTestBuildHandler::GetMakeCommand()
+{
+ std::string makeCommand
+ = this->CTest->GetCTestConfiguration("MakeCommand");
+ cmCTestLog(this->CTest,
+ HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand <<
+ "\n");
+
+ std::string configType = this->CTest->GetConfigType();
+ if (configType == "")
+ {
+ configType
+ = this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType");
+ }
+ if (configType == "")
+ {
+ configType = "Release";
+ }
+
+ cmSystemTools::ReplaceString(makeCommand,
+ "${CTEST_CONFIGURATION_TYPE}", configType.c_str());
+
+ return makeCommand;
+}
+
+//----------------------------------------------------------------------
//clearly it would be nice if this were broken up into a few smaller
//functions and commented...
int cmCTestBuildHandler::ProcessHandler()
@@ -300,11 +326,7 @@ int cmCTestBuildHandler::ProcessHandler()
}
// Determine build command and build directory
- const std::string &makeCommand
- = this->CTest->GetCTestConfiguration("MakeCommand");
- cmCTestLog(this->CTest,
- HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand <<
- "\n");
+ std::string makeCommand = this->GetMakeCommand();
if ( makeCommand.size() == 0 )
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -312,6 +334,7 @@ int cmCTestBuildHandler::ProcessHandler()
<< std::endl);
return -1;
}
+
const std::string &buildDirectory
= this->CTest->GetCTestConfiguration("BuildDirectory");
if ( buildDirectory.size() == 0 )
@@ -519,8 +542,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(std::ostream& os)
static_cast<unsigned int>(this->StartBuildTime)
<< "</StartBuildTime>\n"
<< "<BuildCommand>"
- << cmXMLSafe(
- this->CTest->GetCTestConfiguration("MakeCommand"))
+ << cmXMLSafe(this->GetMakeCommand())
<< "</BuildCommand>" << std::endl;
}
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index 7ee50be..439efd6 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -46,7 +46,10 @@ public:
int GetTotalErrors() { return this->TotalErrors;}
int GetTotalWarnings() { return this->TotalWarnings;}
+
private:
+ std::string GetMakeCommand();
+
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
int RunMakeCommand(const char* command,
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index 00d9ec5..1ad4e24 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -11,6 +11,7 @@
============================================================================*/
#include "cmCTestConfigureCommand.h"
+#include "cmGlobalGenerator.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
@@ -66,6 +67,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
const char* ctestConfigureCommand
= this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
+
if ( ctestConfigureCommand && *ctestConfigureCommand )
{
this->CTest->SetCTestConfiguration("ConfigureCommand",
@@ -86,6 +88,19 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
"variable");
return 0;
}
+
+ bool multiConfig = false;
+ bool cmakeBuildTypeInOptions = false;
+
+ cmGlobalGenerator *gg =
+ this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+ cmakeGeneratorName);
+ if(gg)
+ {
+ multiConfig = gg->IsMultiConfig();
+ delete gg;
+ }
+
std::string cmakeConfigureCommand = "\"";
cmakeConfigureCommand += this->CTest->GetCMakeExecutable();
cmakeConfigureCommand += "\"";
@@ -95,9 +110,23 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
for (it= options.begin(); it!=options.end(); ++it)
{
option = *it;
+
cmakeConfigureCommand += " \"";
cmakeConfigureCommand += option;
cmakeConfigureCommand += "\"";
+
+ if ((0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
+ (0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING=")))
+ {
+ cmakeBuildTypeInOptions = true;
+ }
+ }
+
+ if (!multiConfig && !cmakeBuildTypeInOptions)
+ {
+ cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING=";
+ cmakeConfigureCommand += this->CTest->GetConfigType();
+ cmakeConfigureCommand += "\"";
}
cmakeConfigureCommand += " \"-G";
@@ -113,9 +142,9 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
}
else
{
- this->SetError("Configure command is not specified. If this is a CMake "
- "project, specify CTEST_CMAKE_GENERATOR, or if this is not CMake "
- "project, specify CTEST_CONFIGURE_COMMAND.");
+ this->SetError("Configure command is not specified. If this is a "
+ "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
+ "set CTEST_CONFIGURE_COMMAND.");
return 0;
}
}
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 1c9f080..1957e04 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -59,6 +59,17 @@ bool cmCTestHandlerCommand
}
}
+ // Set the config type of this ctest to the current value of the
+ // CTEST_CONFIGURATION_TYPE script variable if it is defined.
+ // The current script value trumps the -C argument on the command
+ // line.
+ const char* ctestConfigType =
+ this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
+ if (ctestConfigType)
+ {
+ this->CTest->SetConfigType(ctestConfigType);
+ }
+
cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
cmCTestGenericHandler* handler = this->InitializeHandler();
if ( !handler )
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 23cc20e..b0adf22 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -33,6 +33,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
{
const char* ctestTimeout =
this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
+
double timeout = this->CTest->GetTimeOut();
if ( ctestTimeout )
{
@@ -104,4 +105,3 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
{
return this->CTest->GetInitializedHandler("test");
}
-
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
index b9ce561..3722ab6 100644
--- a/Source/cmBuildCommand.cxx
+++ b/Source/cmBuildCommand.cxx
@@ -14,25 +14,135 @@
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
-// cmBuildCommand
+//----------------------------------------------------------------------
bool cmBuildCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
{
+ // Support the legacy signature of the command:
+ //
+ if(2 == args.size())
+ {
+ return this->TwoArgsSignature(args);
+ }
+
+ return this->MainSignature(args);
+}
+
+//----------------------------------------------------------------------
+bool cmBuildCommand
+::MainSignature(std::vector<std::string> const& args)
+{
+ if(args.size() < 1)
+ {
+ this->SetError("requires at least one argument naming a CMake variable");
+ return false;
+ }
+
+ // The cmake variable in which to store the result.
+ const char* variable = args[0].c_str();
+
+ // Parse remaining arguments.
+ const char* configuration = 0;
+ const char* project_name = 0;
+ const char* target = 0;
+ enum Doing { DoingNone, DoingConfiguration, DoingProjectName, DoingTarget };
+ Doing doing = DoingNone;
+ for(unsigned int i=1; i < args.size(); ++i)
+ {
+ if(args[i] == "CONFIGURATION")
+ {
+ doing = DoingConfiguration;
+ }
+ else if(args[i] == "PROJECT_NAME")
+ {
+ doing = DoingProjectName;
+ }
+ else if(args[i] == "TARGET")
+ {
+ doing = DoingTarget;
+ }
+ else if(doing == DoingConfiguration)
+ {
+ doing = DoingNone;
+ configuration = args[i].c_str();
+ }
+ else if(doing == DoingProjectName)
+ {
+ doing = DoingNone;
+ project_name = args[i].c_str();
+ }
+ else if(doing == DoingTarget)
+ {
+ doing = DoingNone;
+ target = args[i].c_str();
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "unknown argument \"" << args[i] << "\"";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
+
+ const char* makeprogram
+ = this->Makefile->GetDefinition("CMAKE_MAKE_PROGRAM");
+
+ // If null/empty CONFIGURATION argument, GenerateBuildCommand uses 'Debug'
+ // in the currently implemented multi-configuration global generators...
+ // so we put this code here to end up with the same default configuration
+ // as the original 2-arg build_command signature:
+ //
+ if(!configuration || !*configuration)
+ {
+ configuration = getenv("CMAKE_CONFIG_TYPE");
+ }
+ if(!configuration || !*configuration)
+ {
+ configuration = "Release";
+ }
+
+ // If null/empty PROJECT_NAME argument, use the Makefile's project name:
+ //
+ if(!project_name || !*project_name)
+ {
+ project_name = this->Makefile->GetProjectName();
+ }
+
+ // If null/empty TARGET argument, GenerateBuildCommand omits any mention
+ // of a target name on the build command line...
+ //
+ std::string makecommand = this->Makefile->GetLocalGenerator()
+ ->GetGlobalGenerator()->GenerateBuildCommand
+ (makeprogram, project_name, 0, target, configuration, true, false);
+
+ this->Makefile->AddDefinition(variable, makecommand.c_str());
+
+ return true;
+}
+
+//----------------------------------------------------------------------
+bool cmBuildCommand
+::TwoArgsSignature(std::vector<std::string> const& args)
+{
if(args.size() < 2 )
{
- this->SetError("called with incorrect number of arguments");
+ this->SetError("called with less than two arguments");
return false;
}
+
const char* define = args[0].c_str();
const char* cacheValue
= this->Makefile->GetDefinition(define);
std::string makeprogram = args[1];
+
std::string configType = "Release";
const char* cfg = getenv("CMAKE_CONFIG_TYPE");
if ( cfg )
{
configType = cfg;
}
+
std::string makecommand = this->Makefile->GetLocalGenerator()
->GetGlobalGenerator()->GenerateBuildCommand
(makeprogram.c_str(), this->Makefile->GetProjectName(), 0,
@@ -49,4 +159,3 @@ bool cmBuildCommand
cmCacheManager::STRING);
return true;
}
-
diff --git a/Source/cmBuildCommand.h b/Source/cmBuildCommand.h
index 9d494e7..703ff88 100644
--- a/Source/cmBuildCommand.h
+++ b/Source/cmBuildCommand.h
@@ -38,35 +38,60 @@ public:
cmExecutionStatus &status);
/**
+ * The primary command signature with optional, KEYWORD-based args.
+ */
+ virtual bool MainSignature(std::vector<std::string> const& args);
+
+ /**
+ * Legacy "exactly 2 args required" signature.
+ */
+ virtual bool TwoArgsSignature(std::vector<std::string> const& args);
+
+ /**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() {return "build_command";}
-
+
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
- return "Get the command line that will build this project.";
+ return "Get the command line to build this project.";
}
-
+
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
- " build_command(<variable> <makecommand>)\n"
- "Sets the given <variable> to a string containing the command that "
- "will build this project from the root of the build tree using the "
- "build tool given by <makecommand>. <makecommand> should be msdev, "
- "nmake, make or one of the end user build tools. "
- "This is useful for configuring testing systems.";
+ " build_command(<variable>\n"
+ " [CONFIGURATION <config>]\n"
+ " [PROJECT_NAME <projname>]\n"
+ " [TARGET <target>])\n"
+ "Sets the given <variable> to a string containing the command line "
+ "for building one configuration of a target in a project using the "
+ "build tool appropriate for the current CMAKE_GENERATOR.\n"
+ "If CONFIGURATION is omitted, CMake chooses a reasonable default "
+ "value for multi-configuration generators. CONFIGURATION is "
+ "ignored for single-configuration generators.\n"
+ "If PROJECT_NAME is omitted, the resulting command line will build "
+ "the top level PROJECT in the current build tree.\n"
+ "If TARGET is omitted, the resulting command line will build "
+ "everything, effectively using build target 'all' or 'ALL_BUILD'.\n"
+ " build_command(<cachevariable> <makecommand>)\n"
+ "This second signature is deprecated, but still available for "
+ "backwards compatibility. Use the first signature instead.\n"
+ "Sets the given <cachevariable> to a string containing the command "
+ "to build this project from the root of the build tree using "
+ "the build tool given by <makecommand>. <makecommand> should be "
+ "the full path to msdev, devenv, nmake, make or one of the end "
+ "user build tools."
+ ;
}
-
+
cmTypeMacro(cmBuildCommand, cmCommand);
};
-
-
#endif
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index c9d0790..b7b4324 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -258,6 +258,10 @@ public:
/** Supported systems creates a GUID for the given name */
virtual void CreateGUID(const char*) {}
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() { return false; }
+
protected:
typedef std::vector<cmLocalGenerator*> GeneratorVector;
// for a project collect all its targets by following depend
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 0c7cf7f..b0be087 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -65,6 +65,11 @@ public:
/** Get the top-level registry key for this VS version. */
std::string GetRegistryBase();
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() { return true; }
+
protected:
void FixUtilityDepends();
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index a409e5f..05c6848 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3302,3 +3302,18 @@ cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
plist += ".dir/Info.plist";
return plist;
}
+
+//----------------------------------------------------------------------------
+// Return true if the generated build tree may contain multiple builds.
+// i.e. "Can I build Debug and Release in the same tree?"
+bool cmGlobalXCodeGenerator::IsMultiConfig()
+{
+ // Old Xcode 1.5 is single config:
+ if(this->XcodeVersion == 15)
+ {
+ return false;
+ }
+
+ // Newer Xcode versions are multi config:
+ return true;
+}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 02ac1b5..b4de805 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -80,6 +80,11 @@ public:
std::vector<std::string>&
dirs);
void SetCurrentLocalGenerator(cmLocalGenerator*);
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig();
+
private:
cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget,
cmSourceGroup* sg);
diff --git a/Tests/CMakeCommands/build_command/CMakeLists.txt b/Tests/CMakeCommands/build_command/CMakeLists.txt
new file mode 100644
index 0000000..990ac90
--- /dev/null
+++ b/Tests/CMakeCommands/build_command/CMakeLists.txt
@@ -0,0 +1,58 @@
+# This CMakeLists file is *sometimes expected* to result in a configure error.
+#
+# expect this to succeed:
+# ../bin/Release/cmake -G Xcode
+# ../../CMake/Tests/CMakeCommands/build_command
+#
+# expect this to fail:
+# ../bin/Release/cmake -DTEST_ERROR_CONDITIONS:BOOL=ON -G Xcode
+# ../../CMake/Tests/CMakeCommands/build_command
+#
+# This project exists merely to test the CMake command 'build_command'...
+# ...even purposefully calling it with known-bad argument lists to cover
+# error handling code.
+#
+cmake_minimum_required(VERSION 2.8)
+project(test_build_command)
+
+set(cmd "initial")
+
+message("CTEST_FULL_OUTPUT")
+message("0. begin")
+
+if(TEST_ERROR_CONDITIONS)
+ # Test with no arguments (an error):
+ build_command()
+ message("1. cmd='${cmd}'")
+
+ # Test with unknown arguments (also an error):
+ build_command(cmd BOGUS STUFF)
+ message("2. cmd='${cmd}'")
+
+ build_command(cmd STUFF BOGUS)
+ message("3. cmd='${cmd}'")
+else()
+ message("(skipping cases 1, 2 and 3 because TEST_ERROR_CONDITIONS is OFF)")
+endif()
+
+# Test the one arg signature with none of the optional KEYWORD arguments:
+build_command(cmd)
+message("4. cmd='${cmd}'")
+
+# Test the two-arg legacy signature:
+build_command(legacy_cmd ${CMAKE_BUILD_TOOL})
+message("5. legacy_cmd='${legacy_cmd}'")
+message(" CMAKE_BUILD_TOOL='${CMAKE_BUILD_TOOL}'")
+
+# Test the optional KEYWORDs:
+build_command(cmd CONFIGURATION hoohaaConfig)
+message("6. cmd='${cmd}'")
+
+build_command(cmd PROJECT_NAME hoohaaProject)
+message("7. cmd='${cmd}'")
+
+build_command(cmd TARGET hoohaaTarget)
+message("8. cmd='${cmd}'")
+
+set(cmd "final")
+message("9. cmd='${cmd}'")
diff --git a/Tests/CMakeCommands/build_command/RunCMake.cmake b/Tests/CMakeCommands/build_command/RunCMake.cmake
new file mode 100644
index 0000000..55d9359
--- /dev/null
+++ b/Tests/CMakeCommands/build_command/RunCMake.cmake
@@ -0,0 +1,86 @@
+if(NOT DEFINED CMake_SOURCE_DIR)
+ message(FATAL_ERROR "CMake_SOURCE_DIR not defined")
+endif()
+
+if(NOT DEFINED dir)
+ message(FATAL_ERROR "dir not defined")
+endif()
+
+if(NOT DEFINED gen)
+ message(FATAL_ERROR "gen not defined")
+endif()
+
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+
+# Run cmake:
+#
+function(run_cmake build_dir extra_args expected_result expected_output expected_error)
+ message(STATUS "run_cmake build_dir='${build_dir}' extra_args='${extra_args}'")
+
+ # Ensure build_dir exists:
+ #
+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${build_dir})
+
+ # Run cmake:
+ #
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ ${extra_args}
+ -G ${gen} ${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ WORKING_DIRECTORY ${build_dir}
+ )
+
+ message(STATUS "result='${result}'")
+ message(STATUS "stdout='${stdout}'")
+ message(STATUS "stderr='${stderr}'")
+ message(STATUS "")
+
+ # Verify result and output match expectations:
+ #
+ if("0" STREQUAL "${expected_result}")
+ if(NOT "${result}" STREQUAL "0")
+ message(FATAL_ERROR
+ "error: result='${result}' is non-zero and different than expected_result='${expected_result}'")
+ endif()
+ else()
+ if("${result}" STREQUAL "0")
+ message(FATAL_ERROR
+ "error: result='${result}' is zero and different than expected_result='${expected_result}'")
+ endif()
+ endif()
+
+ foreach(e ${expected_output})
+ if(NOT stdout MATCHES "${e}")
+ message(FATAL_ERROR
+ "error: stdout does not match expected_output item e='${e}'")
+ else()
+ message(STATUS "info: stdout matches '${e}'")
+ endif()
+ endforeach()
+
+ foreach(e ${expected_error})
+ if(NOT stderr MATCHES "${e}")
+ message(FATAL_ERROR
+ "error: stderr does not match expected_error item e='${e}'")
+ else()
+ message(STATUS "info: stderr matches '${e}'")
+ endif()
+ endforeach()
+
+ message(STATUS "result, stdout and stderr match all expectations: test passes")
+ message(STATUS "")
+endfunction()
+
+
+# Expect this case to succeed:
+run_cmake("${dir}/b1" "" 0
+ "Build files have been written to:"
+ "skipping cases 1, 2 and 3 because TEST_ERROR_CONDITIONS is OFF")
+
+
+# Expect this one to fail:
+run_cmake("${dir}/b2" "-DTEST_ERROR_CONDITIONS:BOOL=ON" 1
+ "Configuring incomplete, errors occurred!"
+ "build_command requires at least one argument naming a CMake variable;build_command unknown argument ")
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index a9b584b..fe8caeb 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1181,7 +1181,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
)
SET_TESTS_PROPERTIES(CTestTestNoBuild PROPERTIES
FAIL_REGULAR_EXPRESSION "Error" WILL_FAIL true)
-
+
CONFIGURE_FILE(
"${CMake_SOURCE_DIR}/Tests/CTestTestFailure/testNoExe.cmake.in"
"${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoExe.cmake"
@@ -1194,6 +1194,50 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
PASS_REGULAR_EXPRESSION "Could not find executable"
FAIL_REGULAR_EXPRESSION "SegFault")
+
+ # Use macro, not function so that build can still be driven by CMake 2.4.
+ # After 2.6 is required, this could be a function without the extra 'set'
+ # calls.
+ #
+ macro(add_config_tests cfg)
+ set(cfg "${cfg}")
+ set(base "${CMake_BINARY_DIR}/Tests/CTestConfig")
+
+ # Test -S script with a -C config arg to ctest:
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestConfig/script.cmake.in"
+ "${base}/${cfg}-script.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestConfig.Script.${cfg} ${CMAKE_CTEST_COMMAND}
+ -C ${cfg}
+ -S "${base}/${cfg}-script.cmake" -VV
+ --output-log "${base}/${cfg}-script.log"
+ )
+
+ # Test -D dashboard with a -C config arg to ctest.
+ # (Actual commands inside a cmake -P script because we need to be able to set
+ # the working directory reliably...)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestConfig/dashboard.cmake.in"
+ "${base}/${cfg}-dashboard.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestConfig.Dashboard.${cfg} ${CMAKE_CMAKE_COMMAND}
+ -P "${base}/${cfg}-dashboard.cmake" -VV
+ )
+ endmacro()
+
+ add_config_tests(Debug)
+ add_config_tests(MinSizeRel)
+ add_config_tests(Release)
+ add_config_tests(RelWithDebInfo)
+
+ add_test(CMakeCommands.build_command ${CMAKE_CMAKE_COMMAND}
+ -DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}
+ -Ddir=${CMake_BINARY_DIR}/Tests/CMakeCommands/build_command
+ -Dgen=${CMAKE_TEST_GENERATOR}
+ -P "${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command/RunCMake.cmake"
+ )
+
CONFIGURE_FILE(
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
"${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"
@@ -1256,11 +1300,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
-S "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/test.cmake" -V
--output-log "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/testOutput.log"
)
-
+
ADD_TEST(CTestTestShowOnly ${CMAKE_CTEST_COMMAND} -N)
-
+
ADD_TEST(CTestBatchTest ${CMAKE_CTEST_COMMAND} -B)
-
+
# Use macro, not function so that build can still be driven by CMake 2.4.
# After 2.6 is required, this could be a function without the extra 'set'
# calls.
diff --git a/Tests/CTestConfig/CMakeLists.txt b/Tests/CTestConfig/CMakeLists.txt
new file mode 100644
index 0000000..f46d89a
--- /dev/null
+++ b/Tests/CTestConfig/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 2.8)
+project(CTestConfig)
+
+include(CTest)
+
+
+# We expect this configure to occur through a 'ctest -D Experimental' or a
+# 'ctest -S script.cmake' call.
+#
+# In either case, we expect CMAKE_BUILD_TYPE to be defined for single-configuration
+# build trees and not defined for multi-configuration build trees.
+#
+if(CMAKE_CONFIGURATION_TYPES)
+ # multi-configuration: expect not defined, error if defined
+ if(DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "")
+ message(FATAL_ERROR "CMAKE_CONFIGURATION_TYPES='${CMAKE_CONFIGURATION_TYPES}' CMAKE_BUILD_TYPE='${CMAKE_BUILD_TYPE}' is defined and non-empty (but should not be for a multi-configuration generator)")
+ endif()
+else()
+ # single-configuration: expect defined, error if not defined
+ if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
+ message(FATAL_ERROR "CMAKE_BUILD_TYPE is not defined or is empty (but should be defined and non-empty for a single-configuration generator)")
+ endif()
+endif()
+
+
+if(DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "")
+ add_definitions(-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}")
+endif()
+
+add_executable(ctc CTestConfig.cxx)
+
+
+foreach(cfg ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
+ add_test(NAME ctc-${cfg} CONFIGURATIONS ${cfg} COMMAND ctc --config $<CONFIGURATION>)
+
+ if(CMAKE_CONFIGURATION_TYPES)
+ set_property(TEST ctc-${cfg}
+ PROPERTY PASS_REGULAR_EXPRESSION "CMAKE_INTDIR is ${cfg}")
+ set_property(TEST ctc-${cfg}
+ PROPERTY FAIL_REGULAR_EXPRESSION "CMAKE_BUILD_TYPE is")
+ else()
+ set_property(TEST ctc-${cfg}
+ PROPERTY PASS_REGULAR_EXPRESSION "CMAKE_BUILD_TYPE is ${cfg}")
+ set_property(TEST ctc-${cfg}
+ PROPERTY FAIL_REGULAR_EXPRESSION "CMAKE_INTDIR is")
+ endif()
+endforeach()
diff --git a/Tests/CTestConfig/CTestConfig.cxx b/Tests/CTestConfig/CTestConfig.cxx
new file mode 100644
index 0000000..49c5324
--- /dev/null
+++ b/Tests/CTestConfig/CTestConfig.cxx
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ int i = 0;
+ for (; i<argc; ++i)
+ {
+ fprintf(stdout, "%s\n", argv[i]);
+ }
+
+#ifdef CMAKE_BUILD_TYPE
+ fprintf(stdout, "CMAKE_BUILD_TYPE is %s\n", CMAKE_BUILD_TYPE);
+#endif
+
+#ifdef CMAKE_INTDIR
+ fprintf(stdout, "CMAKE_INTDIR is %s\n", CMAKE_INTDIR);
+#endif
+
+ return 0;
+}
diff --git a/Tests/CTestConfig/dashboard.cmake.in b/Tests/CTestConfig/dashboard.cmake.in
new file mode 100644
index 0000000..c7ac210
--- /dev/null
+++ b/Tests/CTestConfig/dashboard.cmake.in
@@ -0,0 +1,43 @@
+set(CMAKE_CONFIGURATION_TYPES "@CMAKE_CONFIGURATION_TYPES@")
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestConfig")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestConfig/@cfg@-dashboard")
+
+file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+
+get_filename_component(dir "${CMAKE_COMMAND}" PATH)
+set(CMAKE_CTEST_COMMAND "${dir}/ctest")
+
+message("CMAKE_COMMAND='${CMAKE_COMMAND}'")
+message("CMAKE_CTEST_COMMAND='${CMAKE_CTEST_COMMAND}'")
+
+set(arg "")
+if(NOT CMAKE_CONFIGURATION_TYPES)
+ set(arg "-DCMAKE_BUILD_TYPE:STRING=@cfg@")
+endif()
+
+message("cmake initial configure")
+execute_process(COMMAND ${CMAKE_COMMAND}
+ ${arg} -G "@CMAKE_TEST_GENERATOR@" ${CTEST_SOURCE_DIRECTORY}
+ WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
+ RESULT_VARIABLE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "error calling cmake: rv='${rv}'")
+endif()
+
+
+function(call_ctest arg)
+ message("call_ctest ${arg}")
+ execute_process(COMMAND ${CMAKE_CTEST_COMMAND}
+ -C "@cfg@" -D ${arg} -VV
+ WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
+ RESULT_VARIABLE rv)
+ if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "error calling ctest: rv='${rv}'")
+ endif()
+endfunction()
+
+
+call_ctest(ExperimentalStart)
+call_ctest(ExperimentalConfigure)
+call_ctest(ExperimentalBuild)
+call_ctest(ExperimentalTest)
diff --git a/Tests/CTestConfig/script.cmake.in b/Tests/CTestConfig/script.cmake.in
new file mode 100644
index 0000000..5ceb7c3
--- /dev/null
+++ b/Tests/CTestConfig/script.cmake.in
@@ -0,0 +1,21 @@
+set(CTEST_CMAKE_GENERATOR "@CMAKE_TEST_GENERATOR@")
+set(CTEST_PROJECT_NAME "CTestConfig")
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestConfig")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestConfig/@cfg@-script")
+
+ctest_start(Experimental)
+
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_configure ***")
+endif()
+
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_build ***")
+endif()
+
+ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_test ***")
+endif()