cmCTestBuildCommand.cxx 5.6 KB

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