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