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