cmCTestConfigureCommand.cxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmCTestConfigureCommand.h"
  4. #include <cstring>
  5. #include <sstream>
  6. #include <utility>
  7. #include <vector>
  8. #include <cm/memory>
  9. #include <cmext/string_view>
  10. #include "cmArgumentParser.h"
  11. #include "cmCTest.h"
  12. #include "cmCTestConfigureHandler.h"
  13. #include "cmCTestGenericHandler.h"
  14. #include "cmCommand.h"
  15. #include "cmExecutionStatus.h"
  16. #include "cmGlobalGenerator.h"
  17. #include "cmList.h"
  18. #include "cmMakefile.h"
  19. #include "cmStringAlgorithms.h"
  20. #include "cmSystemTools.h"
  21. #include "cmValue.h"
  22. #include "cmake.h"
  23. std::unique_ptr<cmCommand> cmCTestConfigureCommand::Clone()
  24. {
  25. auto ni = cm::make_unique<cmCTestConfigureCommand>();
  26. ni->CTest = this->CTest;
  27. return std::unique_ptr<cmCommand>(std::move(ni));
  28. }
  29. std::unique_ptr<cmCTestGenericHandler>
  30. cmCTestConfigureCommand::InitializeHandler(HandlerArguments& arguments,
  31. cmExecutionStatus& status) const
  32. {
  33. cmMakefile& mf = status.GetMakefile();
  34. auto const& args = static_cast<ConfigureArguments&>(arguments);
  35. cmList options;
  36. if (!args.Options.empty()) {
  37. options.assign(args.Options);
  38. }
  39. if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {
  40. status.SetError(
  41. "Build directory not specified. Either use BUILD "
  42. "argument to CTEST_CONFIGURE command or set CTEST_BINARY_DIRECTORY "
  43. "variable");
  44. return nullptr;
  45. }
  46. cmValue ctestConfigureCommand = mf.GetDefinition("CTEST_CONFIGURE_COMMAND");
  47. if (cmNonempty(ctestConfigureCommand)) {
  48. this->CTest->SetCTestConfiguration("ConfigureCommand",
  49. *ctestConfigureCommand, args.Quiet);
  50. } else {
  51. cmValue cmakeGeneratorName = mf.GetDefinition("CTEST_CMAKE_GENERATOR");
  52. if (cmNonempty(cmakeGeneratorName)) {
  53. const std::string& source_dir =
  54. this->CTest->GetCTestConfiguration("SourceDirectory");
  55. if (source_dir.empty()) {
  56. status.SetError(
  57. "Source directory not specified. Either use SOURCE "
  58. "argument to CTEST_CONFIGURE command or set CTEST_SOURCE_DIRECTORY "
  59. "variable");
  60. return nullptr;
  61. }
  62. const std::string cmakelists_file = source_dir + "/CMakeLists.txt";
  63. if (!cmSystemTools::FileExists(cmakelists_file)) {
  64. std::ostringstream e;
  65. e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]";
  66. status.SetError(e.str());
  67. return nullptr;
  68. }
  69. bool multiConfig = false;
  70. bool cmakeBuildTypeInOptions = false;
  71. auto gg =
  72. mf.GetCMakeInstance()->CreateGlobalGenerator(*cmakeGeneratorName);
  73. if (gg) {
  74. multiConfig = gg->IsMultiConfig();
  75. gg.reset();
  76. }
  77. std::string cmakeConfigureCommand =
  78. cmStrCat('"', cmSystemTools::GetCMakeCommand(), '"');
  79. for (std::string const& option : options) {
  80. cmakeConfigureCommand += " \"";
  81. cmakeConfigureCommand += option;
  82. cmakeConfigureCommand += "\"";
  83. if ((nullptr != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
  84. (nullptr != strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING="))) {
  85. cmakeBuildTypeInOptions = true;
  86. }
  87. }
  88. if (!multiConfig && !cmakeBuildTypeInOptions &&
  89. !this->CTest->GetConfigType().empty()) {
  90. cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING=";
  91. cmakeConfigureCommand += this->CTest->GetConfigType();
  92. cmakeConfigureCommand += "\"";
  93. }
  94. if (mf.IsOn("CTEST_USE_LAUNCHERS")) {
  95. cmakeConfigureCommand += " \"-DCTEST_USE_LAUNCHERS:BOOL=TRUE\"";
  96. }
  97. cmakeConfigureCommand += " \"-G";
  98. cmakeConfigureCommand += *cmakeGeneratorName;
  99. cmakeConfigureCommand += "\"";
  100. cmValue cmakeGeneratorPlatform =
  101. mf.GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
  102. if (cmNonempty(cmakeGeneratorPlatform)) {
  103. cmakeConfigureCommand += " \"-A";
  104. cmakeConfigureCommand += *cmakeGeneratorPlatform;
  105. cmakeConfigureCommand += "\"";
  106. }
  107. cmValue cmakeGeneratorToolset =
  108. mf.GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
  109. if (cmNonempty(cmakeGeneratorToolset)) {
  110. cmakeConfigureCommand += " \"-T";
  111. cmakeConfigureCommand += *cmakeGeneratorToolset;
  112. cmakeConfigureCommand += "\"";
  113. }
  114. cmakeConfigureCommand += " \"-S";
  115. cmakeConfigureCommand += source_dir;
  116. cmakeConfigureCommand += "\"";
  117. cmakeConfigureCommand += " \"-B";
  118. cmakeConfigureCommand +=
  119. this->CTest->GetCTestConfiguration("BuildDirectory");
  120. cmakeConfigureCommand += "\"";
  121. this->CTest->SetCTestConfiguration("ConfigureCommand",
  122. cmakeConfigureCommand, args.Quiet);
  123. } else {
  124. status.SetError(
  125. "Configure command is not specified. If this is a "
  126. "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
  127. "set CTEST_CONFIGURE_COMMAND.");
  128. return nullptr;
  129. }
  130. }
  131. if (cmValue labelsForSubprojects =
  132. mf.GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
  133. this->CTest->SetCTestConfiguration("LabelsForSubprojects",
  134. *labelsForSubprojects, args.Quiet);
  135. }
  136. auto handler = cm::make_unique<cmCTestConfigureHandler>(this->CTest);
  137. handler->SetQuiet(args.Quiet);
  138. return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
  139. }
  140. bool cmCTestConfigureCommand::InitialPass(std::vector<std::string> const& args,
  141. cmExecutionStatus& status)
  142. {
  143. using Args = ConfigureArguments;
  144. static auto const parser =
  145. cmArgumentParser<Args>{ MakeHandlerParser<Args>() } //
  146. .Bind("OPTIONS"_s, &ConfigureArguments::Options);
  147. return this->Invoke(parser, args, status, [&](ConfigureArguments& a) {
  148. return this->ExecuteHandlerCommand(a, status);
  149. });
  150. }