/src/CMake/Source/cmCustomCommandGenerator.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmCustomCommandGenerator.h" |
4 | | |
5 | | #include <cstddef> |
6 | | #include <memory> |
7 | | #include <utility> |
8 | | |
9 | | #include <cm/optional> |
10 | | #include <cm/string_view> |
11 | | #include <cmext/algorithm> |
12 | | #include <cmext/string_view> |
13 | | |
14 | | #include "cmCryptoHash.h" |
15 | | #include "cmCustomCommand.h" |
16 | | #include "cmCustomCommandLines.h" |
17 | | #include "cmGeneratorExpression.h" |
18 | | #include "cmGeneratorTarget.h" |
19 | | #include "cmGlobalGenerator.h" |
20 | | #include "cmList.h" |
21 | | #include "cmLocalGenerator.h" |
22 | | #include "cmMakefile.h" |
23 | | #include "cmStateTypes.h" |
24 | | #include "cmStringAlgorithms.h" |
25 | | #include "cmSystemTools.h" |
26 | | #include "cmTransformDepfile.h" |
27 | | #include "cmValue.h" |
28 | | |
29 | | namespace { |
30 | | std::string EvaluateSplitConfigGenex( |
31 | | cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg, |
32 | | bool useOutputConfig, std::string const& outputConfig, |
33 | | std::string const& commandConfig, cmGeneratorTarget const* target, |
34 | | std::set<BT<std::pair<std::string, bool>>>* utils = nullptr) |
35 | 0 | { |
36 | 0 | std::string result; |
37 | |
|
38 | 0 | while (!input.empty()) { |
39 | | // Copy non-genex content directly to the result. |
40 | 0 | std::string::size_type pos = input.find("$<"); |
41 | 0 | result += input.substr(0, pos); |
42 | 0 | if (pos == std::string::npos) { |
43 | 0 | break; |
44 | 0 | } |
45 | 0 | input = input.substr(pos); |
46 | | |
47 | | // Find the balanced end of this regex. |
48 | 0 | size_t nestingLevel = 1; |
49 | 0 | for (pos = 2; pos < input.size(); ++pos) { |
50 | 0 | cm::string_view cur = input.substr(pos); |
51 | 0 | if (cmHasLiteralPrefix(cur, "$<")) { |
52 | 0 | ++nestingLevel; |
53 | 0 | ++pos; |
54 | 0 | continue; |
55 | 0 | } |
56 | 0 | if (cmHasPrefix(cur, '>')) { |
57 | 0 | --nestingLevel; |
58 | 0 | if (nestingLevel == 0) { |
59 | 0 | ++pos; |
60 | 0 | break; |
61 | 0 | } |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | // Split this genex from following input. |
66 | 0 | cm::string_view genex = input.substr(0, pos); |
67 | 0 | input = input.substr(pos); |
68 | | |
69 | | // Convert an outer COMMAND_CONFIG or OUTPUT_CONFIG to the matching config. |
70 | 0 | std::string const* config = |
71 | 0 | useOutputConfig ? &outputConfig : &commandConfig; |
72 | 0 | if (nestingLevel == 0) { |
73 | 0 | static cm::string_view const COMMAND_CONFIG = "$<COMMAND_CONFIG:"_s; |
74 | 0 | static cm::string_view const OUTPUT_CONFIG = "$<OUTPUT_CONFIG:"_s; |
75 | 0 | if (cmHasPrefix(genex, COMMAND_CONFIG)) { |
76 | 0 | genex.remove_prefix(COMMAND_CONFIG.size()); |
77 | 0 | genex.remove_suffix(1); |
78 | 0 | useOutputConfig = false; |
79 | 0 | config = &commandConfig; |
80 | 0 | } else if (cmHasPrefix(genex, OUTPUT_CONFIG)) { |
81 | 0 | genex.remove_prefix(OUTPUT_CONFIG.size()); |
82 | 0 | genex.remove_suffix(1); |
83 | 0 | useOutputConfig = true; |
84 | 0 | config = &outputConfig; |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | // Evaluate this genex in the selected configuration. |
89 | 0 | std::unique_ptr<cmCompiledGeneratorExpression> cge = |
90 | 0 | ge.Parse(std::string(genex)); |
91 | 0 | result += cge->Evaluate(lg, *config, target); |
92 | | |
93 | | // Record targets referenced by the genex. |
94 | 0 | if (utils) { |
95 | | // Use a cross-dependency if we referenced the command config. |
96 | 0 | bool const cross = !useOutputConfig; |
97 | 0 | for (cmGeneratorTarget* gt : cge->GetTargets()) { |
98 | 0 | utils->emplace(BT<std::pair<std::string, bool>>( |
99 | 0 | { gt->GetName(), cross }, cge->GetBacktrace())); |
100 | 0 | } |
101 | 0 | } |
102 | 0 | } |
103 | |
|
104 | 0 | return result; |
105 | 0 | } |
106 | | |
107 | | std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths, |
108 | | cmGeneratorExpression const& ge, |
109 | | cmLocalGenerator* lg, |
110 | | std::string const& outputConfig, |
111 | | std::string const& commandConfig) |
112 | 0 | { |
113 | 0 | std::vector<std::string> depends; |
114 | 0 | for (std::string const& p : paths) { |
115 | 0 | std::string const& ep = |
116 | 0 | EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true, |
117 | 0 | /*outputConfig=*/outputConfig, |
118 | 0 | /*commandConfig=*/commandConfig, |
119 | 0 | /*target=*/nullptr); |
120 | 0 | cm::append(depends, cmList{ ep }); |
121 | 0 | } |
122 | 0 | for (std::string& p : depends) { |
123 | 0 | if (cmSystemTools::FileIsFullPath(p)) { |
124 | 0 | p = cmSystemTools::CollapseFullPath(p); |
125 | 0 | } else { |
126 | 0 | cmSystemTools::ConvertToUnixSlashes(p); |
127 | 0 | } |
128 | 0 | } |
129 | 0 | return depends; |
130 | 0 | } |
131 | | |
132 | | std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths, |
133 | | cmGeneratorExpression const& ge, |
134 | | cmLocalGenerator* lg, |
135 | | std::string const& config) |
136 | 0 | { |
137 | 0 | std::vector<std::string> outputs; |
138 | 0 | for (std::string const& p : paths) { |
139 | 0 | std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p); |
140 | 0 | cm::append(outputs, lg->ExpandCustomCommandOutputPaths(*cge, config)); |
141 | 0 | } |
142 | 0 | return outputs; |
143 | 0 | } |
144 | | |
145 | | std::string EvaluateDepfile(std::string const& path, |
146 | | cmGeneratorExpression const& ge, |
147 | | cmLocalGenerator* lg, std::string const& config) |
148 | 0 | { |
149 | 0 | std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path); |
150 | 0 | return cge->Evaluate(lg, config); |
151 | 0 | } |
152 | | |
153 | | std::string EvaluateComment(char const* comment, |
154 | | cmGeneratorExpression const& ge, |
155 | | cmLocalGenerator* lg, std::string const& config) |
156 | 0 | { |
157 | 0 | std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(comment); |
158 | 0 | return cge->Evaluate(lg, config); |
159 | 0 | } |
160 | | } |
161 | | |
162 | | cmCustomCommandGenerator::cmCustomCommandGenerator( |
163 | | cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg, |
164 | | bool transformDepfile, cm::optional<std::string> crossConfig, |
165 | | std::function<std::string(std::string const&, std::string const&)> |
166 | | computeInternalDepfile) |
167 | 0 | : CC(&cc) |
168 | 0 | , OutputConfig(crossConfig ? *crossConfig : config) |
169 | 0 | , CommandConfig(std::move(config)) |
170 | 0 | , Target(cc.GetTarget()) |
171 | 0 | , LG(lg) |
172 | 0 | , OldStyle(cc.GetEscapeOldStyle()) |
173 | 0 | , MakeVars(cc.GetEscapeAllowMakeVars()) |
174 | 0 | , EmulatorsWithArguments(cc.GetCommandLines().size()) |
175 | 0 | , ComputeInternalDepfile(std::move(computeInternalDepfile)) |
176 | 0 | { |
177 | |
|
178 | 0 | cmGeneratorExpression ge(*lg->GetCMakeInstance(), cc.GetBacktrace()); |
179 | 0 | cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse( |
180 | 0 | this->Target) }; |
181 | |
|
182 | 0 | bool const distinctConfigs = this->OutputConfig != this->CommandConfig; |
183 | |
|
184 | 0 | cmCustomCommandLines const& cmdlines = this->CC->GetCommandLines(); |
185 | 0 | for (cmCustomCommandLine const& cmdline : cmdlines) { |
186 | 0 | cmCustomCommandLine argv; |
187 | | // For the command itself, we default to the COMMAND_CONFIG. |
188 | 0 | bool useOutputConfig = false; |
189 | 0 | for (std::string const& clarg : cmdline) { |
190 | 0 | std::string parsed_arg = EvaluateSplitConfigGenex( |
191 | 0 | clarg, ge, this->LG, useOutputConfig, this->OutputConfig, |
192 | 0 | this->CommandConfig, target, &this->Utilities); |
193 | 0 | if (this->CC->GetCommandExpandLists()) { |
194 | 0 | cm::append(argv, cmList{ parsed_arg }); |
195 | 0 | } else { |
196 | 0 | argv.push_back(std::move(parsed_arg)); |
197 | 0 | } |
198 | |
|
199 | 0 | if (distinctConfigs) { |
200 | | // For remaining arguments, we default to the OUTPUT_CONFIG. |
201 | 0 | useOutputConfig = true; |
202 | 0 | } |
203 | 0 | } |
204 | |
|
205 | 0 | if (!argv.empty()) { |
206 | | // If the command references an executable target by name, |
207 | | // collect the target to add a target-level dependency on it. |
208 | 0 | cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front()); |
209 | 0 | if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) { |
210 | | // GetArgv0Location uses the command config, so use a cross-dependency. |
211 | 0 | bool const cross = true; |
212 | 0 | this->Utilities.emplace(BT<std::pair<std::string, bool>>( |
213 | 0 | { gt->GetName(), cross }, cc.GetBacktrace())); |
214 | 0 | } |
215 | 0 | } else { |
216 | | // Later code assumes at least one entry exists, but expanding |
217 | | // lists on an empty command may have left this empty. |
218 | | // FIXME: Should we define behavior for removing empty commands? |
219 | 0 | argv.emplace_back(); |
220 | 0 | } |
221 | |
|
222 | 0 | this->CommandLines.push_back(std::move(argv)); |
223 | 0 | } |
224 | |
|
225 | 0 | if (transformDepfile && !this->CommandLines.empty() && |
226 | 0 | !cc.GetDepfile().empty() && |
227 | 0 | this->LG->GetGlobalGenerator()->DepfileFormat()) { |
228 | 0 | cmCustomCommandLine argv; |
229 | 0 | argv.push_back(cmSystemTools::GetCMakeCommand()); |
230 | 0 | argv.emplace_back("-E"); |
231 | 0 | argv.emplace_back("cmake_transform_depfile"); |
232 | 0 | argv.push_back(this->LG->GetGlobalGenerator()->GetName()); |
233 | 0 | switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { |
234 | 0 | case cmDepfileFormat::GccDepfile: |
235 | 0 | argv.emplace_back("gccdepfile"); |
236 | 0 | break; |
237 | 0 | case cmDepfileFormat::MakeDepfile: |
238 | 0 | argv.emplace_back("makedepfile"); |
239 | 0 | break; |
240 | 0 | case cmDepfileFormat::MSBuildAdditionalInputs: |
241 | 0 | argv.emplace_back("MSBuildAdditionalInputs"); |
242 | 0 | break; |
243 | 0 | } |
244 | 0 | argv.push_back(this->LG->GetSourceDirectory()); |
245 | 0 | argv.push_back(this->LG->GetCurrentSourceDirectory()); |
246 | 0 | argv.push_back(this->LG->GetBinaryDirectory()); |
247 | 0 | argv.push_back(this->LG->GetCurrentBinaryDirectory()); |
248 | 0 | argv.push_back(this->GetFullDepfile()); |
249 | 0 | argv.push_back(this->GetInternalDepfile()); |
250 | |
|
251 | 0 | this->CommandLines.push_back(std::move(argv)); |
252 | 0 | } |
253 | | |
254 | 0 | this->Outputs = |
255 | 0 | EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->OutputConfig); |
256 | 0 | this->Byproducts = |
257 | 0 | EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->OutputConfig); |
258 | 0 | this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG, |
259 | 0 | this->OutputConfig, this->CommandConfig); |
260 | |
|
261 | 0 | std::string const& workingdirectory = this->CC->GetWorkingDirectory(); |
262 | 0 | if (!workingdirectory.empty()) { |
263 | 0 | this->WorkingDirectory = EvaluateSplitConfigGenex( |
264 | 0 | workingdirectory, ge, this->LG, true, this->OutputConfig, |
265 | 0 | this->CommandConfig, target); |
266 | | // Convert working directory to a full path. |
267 | 0 | if (!this->WorkingDirectory.empty()) { |
268 | 0 | std::string const& build_dir = this->LG->GetCurrentBinaryDirectory(); |
269 | 0 | this->WorkingDirectory = |
270 | 0 | cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir); |
271 | 0 | } |
272 | 0 | } |
273 | |
|
274 | 0 | this->FillEmulatorsWithArguments(); |
275 | 0 | } |
276 | | |
277 | | unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const |
278 | 0 | { |
279 | 0 | return static_cast<unsigned int>(this->CommandLines.size()); |
280 | 0 | } |
281 | | |
282 | | void cmCustomCommandGenerator::FillEmulatorsWithArguments() |
283 | 0 | { |
284 | 0 | if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) { |
285 | 0 | return; |
286 | 0 | } |
287 | 0 | cmGeneratorExpression ge(*this->LG->GetCMakeInstance(), |
288 | 0 | this->CC->GetBacktrace()); |
289 | |
|
290 | 0 | for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) { |
291 | | // If the command is the plain name of an executable target, |
292 | | // launch it with its emulator. |
293 | 0 | std::string const& argv0 = this->CommandLines[c][0]; |
294 | 0 | cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); |
295 | 0 | if (target && target->GetType() == cmStateEnums::EXECUTABLE && |
296 | 0 | !target->IsImported()) { |
297 | |
|
298 | 0 | cmValue emulator_property = |
299 | 0 | target->GetProperty("CROSSCOMPILING_EMULATOR"); |
300 | 0 | if (!emulator_property) { |
301 | 0 | continue; |
302 | 0 | } |
303 | | |
304 | | // Plain target names are replaced by GetArgv0Location with the |
305 | | // path to the executable artifact in the command config, so |
306 | | // evaluate the launcher's location in the command config too. |
307 | 0 | std::string const emulator = |
308 | 0 | ge.Parse(*emulator_property)->Evaluate(this->LG, this->CommandConfig); |
309 | 0 | cmExpandList(emulator, this->EmulatorsWithArguments[c]); |
310 | 0 | } |
311 | 0 | } |
312 | 0 | } |
313 | | |
314 | | std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator( |
315 | | unsigned int c) const |
316 | 0 | { |
317 | 0 | if (c >= this->EmulatorsWithArguments.size()) { |
318 | 0 | return std::vector<std::string>(); |
319 | 0 | } |
320 | 0 | return this->EmulatorsWithArguments[c]; |
321 | 0 | } |
322 | | |
323 | | char const* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const |
324 | 0 | { |
325 | | // If the command is the plain name of an executable target, we replace it |
326 | | // with the path to the executable artifact in the command config. |
327 | 0 | std::string const& argv0 = this->CommandLines[c][0]; |
328 | 0 | cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); |
329 | 0 | if (target && target->GetType() == cmStateEnums::EXECUTABLE && |
330 | 0 | (target->IsImported() || |
331 | 0 | target->GetProperty("CROSSCOMPILING_EMULATOR") || |
332 | 0 | !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) { |
333 | 0 | return target->GetLocation(this->CommandConfig).c_str(); |
334 | 0 | } |
335 | 0 | return nullptr; |
336 | 0 | } |
337 | | |
338 | | bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const |
339 | 0 | { |
340 | 0 | for (cmCustomCommandLine const& ccl : this->CommandLines) { |
341 | 0 | for (std::string const& cl : ccl) { |
342 | 0 | if (!cl.empty()) { |
343 | 0 | return false; |
344 | 0 | } |
345 | 0 | } |
346 | 0 | } |
347 | 0 | return true; |
348 | 0 | } |
349 | | |
350 | | std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const |
351 | 0 | { |
352 | 0 | std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c); |
353 | 0 | if (!emulator.empty()) { |
354 | 0 | return emulator[0]; |
355 | 0 | } |
356 | 0 | if (char const* location = this->GetArgv0Location(c)) { |
357 | 0 | return std::string(location); |
358 | 0 | } |
359 | | |
360 | 0 | return this->CommandLines[c][0]; |
361 | 0 | } |
362 | | |
363 | | static std::string escapeForShellOldStyle(std::string const& str) |
364 | 0 | { |
365 | 0 | std::string result; |
366 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
367 | | // if there are spaces |
368 | | std::string temp = str; |
369 | | if (temp.find(" ") != std::string::npos && |
370 | | temp.find("\"") == std::string::npos) { |
371 | | result = cmStrCat('"', str, '"'); |
372 | | return result; |
373 | | } |
374 | | return str; |
375 | | #else |
376 | 0 | for (char const* ch = str.c_str(); *ch != '\0'; ++ch) { |
377 | 0 | if (*ch == ' ') { |
378 | 0 | result += '\\'; |
379 | 0 | } |
380 | 0 | result += *ch; |
381 | 0 | } |
382 | 0 | return result; |
383 | 0 | #endif |
384 | 0 | } |
385 | | |
386 | | void cmCustomCommandGenerator::AppendArguments(unsigned int c, |
387 | | std::string& cmd) const |
388 | 0 | { |
389 | 0 | unsigned int offset = 1; |
390 | 0 | std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c); |
391 | 0 | if (!emulator.empty()) { |
392 | 0 | for (unsigned j = 1; j < emulator.size(); ++j) { |
393 | 0 | cmd += " "; |
394 | 0 | if (this->OldStyle) { |
395 | 0 | cmd += escapeForShellOldStyle(emulator[j]); |
396 | 0 | } else { |
397 | 0 | cmd += |
398 | 0 | this->LG->EscapeForShell(emulator[j], this->MakeVars, false, false, |
399 | 0 | this->MakeVars && this->LG->IsNinjaMulti()); |
400 | 0 | } |
401 | 0 | } |
402 | |
|
403 | 0 | offset = 0; |
404 | 0 | } |
405 | |
|
406 | 0 | cmCustomCommandLine const& commandLine = this->CommandLines[c]; |
407 | 0 | for (unsigned int j = offset; j < commandLine.size(); ++j) { |
408 | 0 | std::string arg; |
409 | 0 | if (char const* location = j == 0 ? this->GetArgv0Location(c) : nullptr) { |
410 | | // GetCommand returned the emulator instead of the argv0 location, |
411 | | // so transform the latter now. |
412 | 0 | arg = location; |
413 | 0 | } else { |
414 | 0 | arg = commandLine[j]; |
415 | 0 | } |
416 | 0 | cmd += " "; |
417 | 0 | if (this->OldStyle) { |
418 | 0 | cmd += escapeForShellOldStyle(arg); |
419 | 0 | } else { |
420 | 0 | cmd += |
421 | 0 | this->LG->EscapeForShell(arg, this->MakeVars, false, false, |
422 | 0 | this->MakeVars && this->LG->IsNinjaMulti()); |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | | |
427 | | std::string cmCustomCommandGenerator::GetDepfile() const |
428 | 0 | { |
429 | 0 | auto const& depfile = this->CC->GetDepfile(); |
430 | 0 | if (depfile.empty()) { |
431 | 0 | return ""; |
432 | 0 | } |
433 | | |
434 | 0 | cmGeneratorExpression ge(*this->LG->GetCMakeInstance(), |
435 | 0 | this->CC->GetBacktrace()); |
436 | 0 | return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig); |
437 | 0 | } |
438 | | |
439 | | std::string cmCustomCommandGenerator::GetFullDepfile() const |
440 | 0 | { |
441 | 0 | std::string depfile = this->GetDepfile(); |
442 | 0 | if (depfile.empty()) { |
443 | 0 | return ""; |
444 | 0 | } |
445 | | |
446 | 0 | if (!cmSystemTools::FileIsFullPath(depfile)) { |
447 | 0 | depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile); |
448 | 0 | } |
449 | 0 | return cmSystemTools::CollapseFullPath(depfile); |
450 | 0 | } |
451 | | |
452 | | std::string cmCustomCommandGenerator::GetInternalDepfileName( |
453 | | std::string const& /*config*/, std::string const& depfile) const |
454 | 0 | { |
455 | 0 | cmCryptoHash hash(cmCryptoHash::AlgoSHA256); |
456 | 0 | std::string extension; |
457 | 0 | switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { |
458 | 0 | case cmDepfileFormat::GccDepfile: |
459 | 0 | case cmDepfileFormat::MakeDepfile: |
460 | 0 | extension = ".d"; |
461 | 0 | break; |
462 | 0 | case cmDepfileFormat::MSBuildAdditionalInputs: |
463 | 0 | extension = ".AdditionalInputs"; |
464 | 0 | break; |
465 | 0 | } |
466 | 0 | return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/", |
467 | 0 | hash.HashString(depfile), extension); |
468 | 0 | } |
469 | | |
470 | | std::string cmCustomCommandGenerator::GetInternalDepfile() const |
471 | 0 | { |
472 | 0 | std::string depfile = this->GetFullDepfile(); |
473 | 0 | if (depfile.empty()) { |
474 | 0 | return ""; |
475 | 0 | } |
476 | | |
477 | 0 | if (this->ComputeInternalDepfile) { |
478 | 0 | return this->ComputeInternalDepfile(this->OutputConfig, depfile); |
479 | 0 | } |
480 | 0 | return this->GetInternalDepfileName(this->OutputConfig, depfile); |
481 | 0 | } |
482 | | |
483 | | cm::optional<std::string> cmCustomCommandGenerator::GetComment() const |
484 | 0 | { |
485 | 0 | char const* comment = this->CC->GetComment(); |
486 | 0 | if (!comment) { |
487 | 0 | return cm::nullopt; |
488 | 0 | } |
489 | 0 | if (!*comment) { |
490 | 0 | return std::string(); |
491 | 0 | } |
492 | | |
493 | 0 | cmGeneratorExpression ge(*this->LG->GetCMakeInstance(), |
494 | 0 | this->CC->GetBacktrace()); |
495 | 0 | return EvaluateComment(comment, ge, this->LG, this->OutputConfig); |
496 | 0 | } |
497 | | |
498 | | std::string cmCustomCommandGenerator::GetWorkingDirectory() const |
499 | 0 | { |
500 | 0 | return this->WorkingDirectory; |
501 | 0 | } |
502 | | |
503 | | std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const |
504 | 0 | { |
505 | 0 | return this->Outputs; |
506 | 0 | } |
507 | | |
508 | | std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const |
509 | 0 | { |
510 | 0 | return this->Byproducts; |
511 | 0 | } |
512 | | |
513 | | std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const |
514 | 0 | { |
515 | 0 | return this->Depends; |
516 | 0 | } |
517 | | |
518 | | std::set<BT<std::pair<std::string, bool>>> const& |
519 | | cmCustomCommandGenerator::GetUtilities() const |
520 | 0 | { |
521 | 0 | return this->Utilities; |
522 | 0 | } |