Fix issue #2336 - honor the -C arg to ctest. Honor it for all stages of running -D dashboards from the command line and running ctest_configure, ctest_build and ctest_test commands in -S scripts. Also, allow a script to change it by setting the CTEST_CONFIGURATION_TYPE variable: allows for multiple configuration build/test cycles within one script. Add a new signature for the cmake command build_command that accepts CONFIGURATION as one argument. The original build_command signature is still there, but now marked as deprecated in the documentation. Of course... also add CTestConfig tests to verify that -C is honored for -D dashboards and -S scripts.

This commit is contained in:
David Cole 2009-12-04 12:09:01 -05:00
parent af14f1f2c3
commit 0b38bb4c53
21 changed files with 604 additions and 39 deletions

View File

@ -84,10 +84,6 @@ IF(BUILD_TESTING)
ENDIF(EXISTS "${PROJECT_SOURCE_DIR}/DartConfig.cmake") ENDIF(EXISTS "${PROJECT_SOURCE_DIR}/DartConfig.cmake")
SET_IF_NOT_SET (NIGHTLY_START_TIME "00:00:00 EDT") 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 ) FIND_PROGRAM(CVSCOMMAND cvs )
SET(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING SET(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING
"Options passed to the cvs update command.") "Options passed to the cvs update command.")
@ -202,8 +198,17 @@ IF(BUILD_TESTING)
ENDIF(DART_CXX_NAME MATCHES "devenv") ENDIF(DART_CXX_NAME MATCHES "devenv")
SET(BUILDNAME "${BUILD_NAME_SYSTEM_NAME}-${DART_CXX_NAME}") SET(BUILDNAME "${BUILD_NAME_SYSTEM_NAME}-${DART_CXX_NAME}")
ENDIF(NOT BUILDNAME) 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") IF(NOT "${CMAKE_GENERATOR}" MATCHES "Make")
SET(CTEST_USE_LAUNCHERS 0) SET(CTEST_USE_LAUNCHERS 0)

View File

@ -30,6 +30,7 @@ NightlyStartTime: @NIGHTLY_START_TIME@
# Commands for the build/test/submit cycle # Commands for the build/test/submit cycle
ConfigureCommand: "@CMAKE_COMMAND@" "@PROJECT_SOURCE_DIR@" ConfigureCommand: "@CMAKE_COMMAND@" "@PROJECT_SOURCE_DIR@"
MakeCommand: @MAKECOMMAND@ MakeCommand: @MAKECOMMAND@
DefaultCTestConfigurationType: @DEFAULT_CTEST_CONFIGURATION_TYPE@
# CVS options # CVS options
# Default is "-d -P -A" # Default is "-d -P -A"

View File

@ -53,6 +53,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
return 0; return 0;
} }
this->Handler = (cmCTestBuildHandler*)handler; this->Handler = (cmCTestBuildHandler*)handler;
const char* ctestBuildCommand const char* ctestBuildCommand
= this->Makefile->GetDefinition("CTEST_BUILD_COMMAND"); = this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
if ( ctestBuildCommand && *ctestBuildCommand ) 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->Values[ctb_PROJECT_NAME])
? this->Values[ctb_PROJECT_NAME] ? this->Values[ctb_PROJECT_NAME]
: this->Makefile->GetDefinition("CTEST_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 const char* cmakeBuildConfiguration
= (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION]) = (this->Values[ctb_CONFIGURATION] && *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 const char* cmakeBuildAdditionalFlags
= (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS]) = (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
? this->Values[ctb_FLAGS] ? this->Values[ctb_FLAGS]

View File

@ -264,6 +264,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 //clearly it would be nice if this were broken up into a few smaller
//functions and commented... //functions and commented...
@ -300,11 +326,7 @@ int cmCTestBuildHandler::ProcessHandler()
} }
// Determine build command and build directory // Determine build command and build directory
const std::string &makeCommand std::string makeCommand = this->GetMakeCommand();
= this->CTest->GetCTestConfiguration("MakeCommand");
cmCTestLog(this->CTest,
HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand <<
"\n");
if ( makeCommand.size() == 0 ) if ( makeCommand.size() == 0 )
{ {
cmCTestLog(this->CTest, ERROR_MESSAGE, cmCTestLog(this->CTest, ERROR_MESSAGE,
@ -312,6 +334,7 @@ int cmCTestBuildHandler::ProcessHandler()
<< std::endl); << std::endl);
return -1; return -1;
} }
const std::string &buildDirectory const std::string &buildDirectory
= this->CTest->GetCTestConfiguration("BuildDirectory"); = this->CTest->GetCTestConfiguration("BuildDirectory");
if ( buildDirectory.size() == 0 ) if ( buildDirectory.size() == 0 )
@ -519,8 +542,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(std::ostream& os)
static_cast<unsigned int>(this->StartBuildTime) static_cast<unsigned int>(this->StartBuildTime)
<< "</StartBuildTime>\n" << "</StartBuildTime>\n"
<< "<BuildCommand>" << "<BuildCommand>"
<< cmXMLSafe( << cmXMLSafe(this->GetMakeCommand())
this->CTest->GetCTestConfiguration("MakeCommand"))
<< "</BuildCommand>" << std::endl; << "</BuildCommand>" << std::endl;
} }

View File

@ -46,7 +46,10 @@ public:
int GetTotalErrors() { return this->TotalErrors;} int GetTotalErrors() { return this->TotalErrors;}
int GetTotalWarnings() { return this->TotalWarnings;} int GetTotalWarnings() { return this->TotalWarnings;}
private: private:
std::string GetMakeCommand();
//! Run command specialized for make and configure. Returns process status //! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception. // and retVal is return value or exception.
int RunMakeCommand(const char* command, int RunMakeCommand(const char* command,

View File

@ -11,6 +11,7 @@
============================================================================*/ ============================================================================*/
#include "cmCTestConfigureCommand.h" #include "cmCTestConfigureCommand.h"
#include "cmGlobalGenerator.h"
#include "cmCTest.h" #include "cmCTest.h"
#include "cmCTestGenericHandler.h" #include "cmCTestGenericHandler.h"
@ -66,6 +67,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
const char* ctestConfigureCommand const char* ctestConfigureCommand
= this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND"); = this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
if ( ctestConfigureCommand && *ctestConfigureCommand ) if ( ctestConfigureCommand && *ctestConfigureCommand )
{ {
this->CTest->SetCTestConfiguration("ConfigureCommand", this->CTest->SetCTestConfiguration("ConfigureCommand",
@ -86,6 +88,19 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
"variable"); "variable");
return 0; 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 = "\""; std::string cmakeConfigureCommand = "\"";
cmakeConfigureCommand += this->CTest->GetCMakeExecutable(); cmakeConfigureCommand += this->CTest->GetCMakeExecutable();
cmakeConfigureCommand += "\""; cmakeConfigureCommand += "\"";
@ -95,9 +110,23 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
for (it= options.begin(); it!=options.end(); ++it) for (it= options.begin(); it!=options.end(); ++it)
{ {
option = *it; option = *it;
cmakeConfigureCommand += " \""; cmakeConfigureCommand += " \"";
cmakeConfigureCommand += option; cmakeConfigureCommand += option;
cmakeConfigureCommand += "\""; 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"; cmakeConfigureCommand += " \"-G";
@ -113,9 +142,9 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
} }
else else
{ {
this->SetError("Configure command is not specified. If this is a CMake " this->SetError("Configure command is not specified. If this is a "
"project, specify CTEST_CMAKE_GENERATOR, or if this is not CMake " "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
"project, specify CTEST_CONFIGURE_COMMAND."); "set CTEST_CONFIGURE_COMMAND.");
return 0; return 0;
} }
} }

View File

@ -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;); cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
cmCTestGenericHandler* handler = this->InitializeHandler(); cmCTestGenericHandler* handler = this->InitializeHandler();
if ( !handler ) if ( !handler )

View File

@ -33,6 +33,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
{ {
const char* ctestTimeout = const char* ctestTimeout =
this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT"); this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
double timeout = this->CTest->GetTimeOut(); double timeout = this->CTest->GetTimeOut();
if ( ctestTimeout ) if ( ctestTimeout )
{ {
@ -104,4 +105,3 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
{ {
return this->CTest->GetInitializedHandler("test"); return this->CTest->GetInitializedHandler("test");
} }

View File

@ -14,25 +14,135 @@
#include "cmLocalGenerator.h" #include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h" #include "cmGlobalGenerator.h"
// cmBuildCommand //----------------------------------------------------------------------
bool cmBuildCommand bool cmBuildCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
{ {
if(args.size() < 2 ) // Support the legacy signature of the command:
//
if(2 == args.size())
{ {
this->SetError("called with incorrect number of arguments"); 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; 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 less than two arguments");
return false;
}
const char* define = args[0].c_str(); const char* define = args[0].c_str();
const char* cacheValue const char* cacheValue
= this->Makefile->GetDefinition(define); = this->Makefile->GetDefinition(define);
std::string makeprogram = args[1]; std::string makeprogram = args[1];
std::string configType = "Release"; std::string configType = "Release";
const char* cfg = getenv("CMAKE_CONFIG_TYPE"); const char* cfg = getenv("CMAKE_CONFIG_TYPE");
if ( cfg ) if ( cfg )
{ {
configType = cfg; configType = cfg;
} }
std::string makecommand = this->Makefile->GetLocalGenerator() std::string makecommand = this->Makefile->GetLocalGenerator()
->GetGlobalGenerator()->GenerateBuildCommand ->GetGlobalGenerator()->GenerateBuildCommand
(makeprogram.c_str(), this->Makefile->GetProjectName(), 0, (makeprogram.c_str(), this->Makefile->GetProjectName(), 0,
@ -49,4 +159,3 @@ bool cmBuildCommand
cmCacheManager::STRING); cmCacheManager::STRING);
return true; return true;
} }

View File

@ -37,6 +37,16 @@ public:
virtual bool InitialPass(std::vector<std::string> const& args, virtual bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus &status); 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. * The name of the command as specified in CMakeList.txt.
*/ */
@ -47,7 +57,7 @@ public:
*/ */
virtual const char* GetTerseDocumentation() virtual const char* GetTerseDocumentation()
{ {
return "Get the command line that will build this project."; return "Get the command line to build this project.";
} }
/** /**
@ -56,17 +66,32 @@ public:
virtual const char* GetFullDocumentation() virtual const char* GetFullDocumentation()
{ {
return return
" build_command(<variable> <makecommand>)\n" " build_command(<variable>\n"
"Sets the given <variable> to a string containing the command that " " [CONFIGURATION <config>]\n"
"will build this project from the root of the build tree using the " " [PROJECT_NAME <projname>]\n"
"build tool given by <makecommand>. <makecommand> should be msdev, " " [TARGET <target>])\n"
"nmake, make or one of the end user build tools. " "Sets the given <variable> to a string containing the command line "
"This is useful for configuring testing systems."; "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); cmTypeMacro(cmBuildCommand, cmCommand);
}; };
#endif #endif

View File

@ -258,6 +258,10 @@ public:
/** Supported systems creates a GUID for the given name */ /** Supported systems creates a GUID for the given name */
virtual void CreateGUID(const char*) {} 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: protected:
typedef std::vector<cmLocalGenerator*> GeneratorVector; typedef std::vector<cmLocalGenerator*> GeneratorVector;
// for a project collect all its targets by following depend // for a project collect all its targets by following depend

View File

@ -65,6 +65,11 @@ public:
/** Get the top-level registry key for this VS version. */ /** Get the top-level registry key for this VS version. */
std::string GetRegistryBase(); 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: protected:
void FixUtilityDepends(); void FixUtilityDepends();

View File

@ -3302,3 +3302,18 @@ cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
plist += ".dir/Info.plist"; plist += ".dir/Info.plist";
return 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;
}

View File

@ -80,6 +80,11 @@ public:
std::vector<std::string>& std::vector<std::string>&
dirs); dirs);
void SetCurrentLocalGenerator(cmLocalGenerator*); 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: private:
cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget, cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget,
cmSourceGroup* sg); cmSourceGroup* sg);

View File

@ -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}'")

View File

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

View File

@ -1194,6 +1194,50 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
PASS_REGULAR_EXPRESSION "Could not find executable" PASS_REGULAR_EXPRESSION "Could not find executable"
FAIL_REGULAR_EXPRESSION "SegFault") 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( CONFIGURE_FILE(
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in" "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
"${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake" "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"

View File

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

View File

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

View File

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

View File

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