cmCTestBuildCommand.cxx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 "cmCTestBuildCommand.h"
  4. #include <sstream>
  5. #include <utility>
  6. #include <cm/memory>
  7. #include <cmext/string_view>
  8. #include "cmArgumentParser.h"
  9. #include "cmCTest.h"
  10. #include "cmCTestBuildHandler.h"
  11. #include "cmCTestGenericHandler.h"
  12. #include "cmCommand.h"
  13. #include "cmExecutionStatus.h"
  14. #include "cmGlobalGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmMessageType.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmSystemTools.h"
  19. #include "cmValue.h"
  20. #include "cmake.h"
  21. std::unique_ptr<cmCommand> cmCTestBuildCommand::Clone()
  22. {
  23. auto ni = cm::make_unique<cmCTestBuildCommand>();
  24. ni->CTest = this->CTest;
  25. return std::unique_ptr<cmCommand>(std::move(ni));
  26. }
  27. bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
  28. cmExecutionStatus& status)
  29. {
  30. static auto const parser =
  31. cmArgumentParser<BuildArguments>{ MakeHandlerParser<BuildArguments>() }
  32. .Bind("NUMBER_ERRORS"_s, &BuildArguments::NumberErrors)
  33. .Bind("NUMBER_WARNINGS"_s, &BuildArguments::NumberWarnings)
  34. .Bind("TARGET"_s, &BuildArguments::Target)
  35. .Bind("CONFIGURATION"_s, &BuildArguments::Configuration)
  36. .Bind("FLAGS"_s, &BuildArguments::Flags)
  37. .Bind("PROJECT_NAME"_s, &BuildArguments::ProjectName)
  38. .Bind("PARALLEL_LEVEL"_s, &BuildArguments::ParallelLevel);
  39. return this->Invoke(parser, args, status, [&](BuildArguments& a) {
  40. return this->ExecuteHandlerCommand(a, status);
  41. });
  42. }
  43. std::unique_ptr<cmCTestGenericHandler> cmCTestBuildCommand::InitializeHandler(
  44. HandlerArguments& arguments, cmExecutionStatus& status) const
  45. {
  46. cmMakefile& mf = status.GetMakefile();
  47. auto const& args = static_cast<BuildArguments&>(arguments);
  48. auto handler = cm::make_unique<cmCTestBuildHandler>(this->CTest);
  49. cmValue ctestBuildCommand = mf.GetDefinition("CTEST_BUILD_COMMAND");
  50. if (cmNonempty(ctestBuildCommand)) {
  51. this->CTest->SetCTestConfiguration("MakeCommand", *ctestBuildCommand,
  52. args.Quiet);
  53. } else {
  54. cmValue cmakeGeneratorName = mf.GetDefinition("CTEST_CMAKE_GENERATOR");
  55. // Build configuration is determined by: CONFIGURATION argument,
  56. // or CTEST_BUILD_CONFIGURATION script variable, or
  57. // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
  58. // line argument... in that order.
  59. //
  60. cmValue ctestBuildConfiguration =
  61. mf.GetDefinition("CTEST_BUILD_CONFIGURATION");
  62. std::string cmakeBuildConfiguration = cmNonempty(args.Configuration)
  63. ? args.Configuration
  64. : cmNonempty(ctestBuildConfiguration) ? *ctestBuildConfiguration
  65. : this->CTest->GetConfigType();
  66. const std::string& cmakeBuildAdditionalFlags = cmNonempty(args.Flags)
  67. ? args.Flags
  68. : mf.GetSafeDefinition("CTEST_BUILD_FLAGS");
  69. const std::string& cmakeBuildTarget = cmNonempty(args.Target)
  70. ? args.Target
  71. : mf.GetSafeDefinition("CTEST_BUILD_TARGET");
  72. if (cmNonempty(cmakeGeneratorName)) {
  73. if (cmakeBuildConfiguration.empty()) {
  74. cmakeBuildConfiguration = "Release";
  75. }
  76. auto globalGenerator =
  77. mf.GetCMakeInstance()->CreateGlobalGenerator(*cmakeGeneratorName);
  78. if (!globalGenerator) {
  79. std::string e = cmStrCat("could not create generator named \"",
  80. *cmakeGeneratorName, '"');
  81. mf.IssueMessage(MessageType::FATAL_ERROR, e);
  82. cmSystemTools::SetFatalErrorOccurred();
  83. return nullptr;
  84. }
  85. if (cmakeBuildConfiguration.empty()) {
  86. cmakeBuildConfiguration = "Debug";
  87. }
  88. std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
  89. std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
  90. cmakeBuildTarget, cmakeBuildConfiguration, args.ParallelLevel,
  91. cmakeBuildAdditionalFlags, mf.IgnoreErrorsCMP0061());
  92. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  93. "SetMakeCommand:" << buildCommand << "\n",
  94. args.Quiet);
  95. this->CTest->SetCTestConfiguration("MakeCommand", buildCommand,
  96. args.Quiet);
  97. } else {
  98. std::ostringstream ostr;
  99. /* clang-format off */
  100. ostr << "has no project to build. If this is a "
  101. "\"built with CMake\" project, verify that CTEST_CMAKE_GENERATOR "
  102. "is set. Otherwise, set CTEST_BUILD_COMMAND to build the project "
  103. "with a custom command line.";
  104. /* clang-format on */
  105. status.SetError(ostr.str());
  106. return nullptr;
  107. }
  108. }
  109. if (cmValue useLaunchers = mf.GetDefinition("CTEST_USE_LAUNCHERS")) {
  110. this->CTest->SetCTestConfiguration("UseLaunchers", *useLaunchers,
  111. args.Quiet);
  112. }
  113. if (cmValue labelsForSubprojects =
  114. mf.GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
  115. this->CTest->SetCTestConfiguration("LabelsForSubprojects",
  116. *labelsForSubprojects, args.Quiet);
  117. }
  118. handler->SetQuiet(args.Quiet);
  119. return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
  120. }
  121. void cmCTestBuildCommand::ProcessAdditionalValues(
  122. cmCTestGenericHandler* generic, HandlerArguments const& arguments,
  123. cmExecutionStatus& status) const
  124. {
  125. cmMakefile& mf = status.GetMakefile();
  126. auto const& args = static_cast<BuildArguments const&>(arguments);
  127. auto const* handler = static_cast<cmCTestBuildHandler*>(generic);
  128. if (!args.NumberErrors.empty()) {
  129. mf.AddDefinition(args.NumberErrors,
  130. std::to_string(handler->GetTotalErrors()));
  131. }
  132. if (!args.NumberWarnings.empty()) {
  133. mf.AddDefinition(args.NumberWarnings,
  134. std::to_string(handler->GetTotalWarnings()));
  135. }
  136. }