/src/CMake/Source/cmGeneratorExpression.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 "cmGeneratorExpression.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <cassert> |
7 | | #include <cstddef> |
8 | | #include <memory> |
9 | | #include <stack> |
10 | | #include <utility> |
11 | | |
12 | | #include <cm/string_view> |
13 | | |
14 | | #include "cmsys/RegularExpression.hxx" |
15 | | |
16 | | #include "cmGenExContext.h" |
17 | | #include "cmGenExEvaluation.h" |
18 | | #include "cmGeneratorExpressionDAGChecker.h" |
19 | | #include "cmGeneratorExpressionEvaluator.h" |
20 | | #include "cmGeneratorExpressionLexer.h" |
21 | | #include "cmGeneratorExpressionParser.h" |
22 | | #include "cmGeneratorTarget.h" |
23 | | #include "cmList.h" |
24 | | #include "cmLocalGenerator.h" |
25 | | #include "cmMakefile.h" |
26 | | #include "cmMessageType.h" |
27 | | #include "cmStringAlgorithms.h" |
28 | | #include "cmSystemTools.h" |
29 | | #include "cmake.h" |
30 | | |
31 | | cmGeneratorExpression::cmGeneratorExpression(cmake& cmakeInstance, |
32 | | cmListFileBacktrace backtrace) |
33 | 0 | : CMakeInstance(cmakeInstance) |
34 | 0 | , Backtrace(std::move(backtrace)) |
35 | 0 | { |
36 | 0 | } |
37 | | |
38 | 0 | cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() = default; |
39 | | |
40 | 0 | cmGeneratorExpression::~cmGeneratorExpression() = default; |
41 | | |
42 | | std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse( |
43 | | std::string input) const |
44 | 0 | { |
45 | 0 | return std::unique_ptr<cmCompiledGeneratorExpression>( |
46 | 0 | new cmCompiledGeneratorExpression(this->CMakeInstance, this->Backtrace, |
47 | 0 | std::move(input))); |
48 | 0 | } |
49 | | |
50 | | std::string cmGeneratorExpression::Evaluate( |
51 | | std::string input, cmLocalGenerator const* lg, std::string const& config, |
52 | | cmGeneratorTarget const* headTarget, |
53 | | cmGeneratorExpressionDAGChecker* dagChecker, |
54 | | cmGeneratorTarget const* currentTarget, std::string const& language) |
55 | 0 | { |
56 | 0 | if (Find(input) != std::string::npos) { |
57 | 0 | #ifndef CMAKE_BOOTSTRAP |
58 | 0 | auto profilingRAII = lg->GetCMakeInstance()->CreateProfilingEntry( |
59 | 0 | "genex_compile_eval", input); |
60 | 0 | #endif |
61 | |
|
62 | 0 | cm::GenEx::Context context(lg, config, language); |
63 | 0 | cmCompiledGeneratorExpression cge(*lg->GetCMakeInstance(), |
64 | 0 | cmListFileBacktrace(), std::move(input)); |
65 | 0 | return cge.Evaluate(context, dagChecker, headTarget, currentTarget); |
66 | 0 | } |
67 | 0 | return input; |
68 | 0 | } |
69 | | |
70 | | std::string const& cmCompiledGeneratorExpression::Evaluate( |
71 | | cmLocalGenerator const* lg, std::string const& config, |
72 | | cmGeneratorTarget const* headTarget) const |
73 | 0 | { |
74 | 0 | cm::GenEx::Context context(lg, config); |
75 | 0 | return this->Evaluate(context, nullptr, headTarget); |
76 | 0 | } |
77 | | |
78 | | std::string const& cmCompiledGeneratorExpression::Evaluate( |
79 | | cm::GenEx::Context const& context, |
80 | | cmGeneratorExpressionDAGChecker* dagChecker, |
81 | | cmGeneratorTarget const* headTarget, |
82 | | cmGeneratorTarget const* currentTarget) const |
83 | 0 | { |
84 | 0 | cm::GenEx::Evaluation eval(context, this->Quiet, headTarget, |
85 | 0 | currentTarget ? currentTarget : headTarget, |
86 | 0 | this->EvaluateForBuildsystem, this->Backtrace); |
87 | |
|
88 | 0 | if (!this->NeedsEvaluation) { |
89 | 0 | return this->Input; |
90 | 0 | } |
91 | | |
92 | 0 | this->Output.clear(); |
93 | |
|
94 | 0 | for (auto const& it : this->Evaluators) { |
95 | 0 | this->Output += it->Evaluate(&eval, dagChecker); |
96 | |
|
97 | 0 | this->SeenTargetProperties.insert(eval.SeenTargetProperties.cbegin(), |
98 | 0 | eval.SeenTargetProperties.cend()); |
99 | 0 | if (eval.HadError) { |
100 | 0 | this->Output.clear(); |
101 | 0 | break; |
102 | 0 | } |
103 | 0 | } |
104 | |
|
105 | 0 | this->MaxLanguageStandard = eval.MaxLanguageStandard; |
106 | |
|
107 | 0 | if (!eval.HadError) { |
108 | 0 | this->HadContextSensitiveCondition = eval.HadContextSensitiveCondition; |
109 | 0 | this->HadHeadSensitiveCondition = eval.HadHeadSensitiveCondition; |
110 | 0 | this->HadLinkLanguageSensitiveCondition = |
111 | 0 | eval.HadLinkLanguageSensitiveCondition; |
112 | 0 | this->SourceSensitiveTargets = eval.SourceSensitiveTargets; |
113 | 0 | } |
114 | |
|
115 | 0 | this->DependTargets = eval.DependTargets; |
116 | 0 | this->AllTargetsSeen = eval.AllTargets; |
117 | 0 | return this->Output; |
118 | 0 | } |
119 | | |
120 | | cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( |
121 | | cmake& cmakeInstance, cmListFileBacktrace backtrace, std::string input) |
122 | 0 | : Backtrace(std::move(backtrace)) |
123 | 0 | , Input(std::move(input)) |
124 | 0 | { |
125 | 0 | #ifndef CMAKE_BOOTSTRAP |
126 | 0 | auto profilingRAII = |
127 | 0 | cmakeInstance.CreateProfilingEntry("genex_compile", this->Input); |
128 | 0 | #endif |
129 | |
|
130 | 0 | cmGeneratorExpressionLexer l; |
131 | 0 | std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input); |
132 | 0 | this->NeedsEvaluation = l.GetSawGeneratorExpression(); |
133 | |
|
134 | 0 | if (this->NeedsEvaluation) { |
135 | 0 | cmGeneratorExpressionParser p(tokens); |
136 | 0 | p.Parse(this->Evaluators); |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | std::string cmGeneratorExpression::StripEmptyListElements( |
141 | | std::string const& input) |
142 | 11.7k | { |
143 | 11.7k | if (input.find(';') == std::string::npos) { |
144 | 7.19k | return input; |
145 | 7.19k | } |
146 | 4.58k | std::string result; |
147 | 4.58k | result.reserve(input.size()); |
148 | | |
149 | 4.58k | char const* c = input.c_str(); |
150 | 4.58k | char const* last = c; |
151 | 4.58k | bool skipSemiColons = true; |
152 | 1.78M | for (; *c; ++c) { |
153 | 1.78M | if (*c == ';') { |
154 | 78.1k | if (skipSemiColons) { |
155 | 10.4k | result.append(last, c - last); |
156 | 10.4k | last = c + 1; |
157 | 10.4k | } |
158 | 78.1k | skipSemiColons = true; |
159 | 1.70M | } else { |
160 | 1.70M | skipSemiColons = false; |
161 | 1.70M | } |
162 | 1.78M | } |
163 | 4.58k | result.append(last); |
164 | | |
165 | 4.58k | if (!result.empty() && *(result.end() - 1) == ';') { |
166 | 881 | result.resize(result.size() - 1); |
167 | 881 | } |
168 | | |
169 | 4.58k | return result; |
170 | 11.7k | } |
171 | | |
172 | | static std::string extractAllGeneratorExpressions( |
173 | | cm::string_view input, |
174 | | std::map<std::string, std::vector<std::string>>* collected) |
175 | 4.71k | { |
176 | 4.71k | std::string result; |
177 | 4.71k | std::string::size_type pos = 0; |
178 | 4.71k | std::string::size_type lastPos = pos; |
179 | 4.71k | std::stack<char const*> starts; // indices of "$<" |
180 | 4.71k | std::stack<char const*> colons; // indices of ":" |
181 | 63.9k | while ((pos = input.find("$<", lastPos)) != std::string::npos) { |
182 | 59.2k | result += input.substr(lastPos, pos - lastPos); |
183 | 59.2k | starts.push(input.data() + pos); |
184 | 59.2k | pos += 2; |
185 | 59.2k | char const* c = input.data() + pos; |
186 | 59.2k | char const* const cStart = c; |
187 | 2.12M | for (; *c; ++c) { |
188 | 2.07M | if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) { |
189 | 784k | starts.push(c); |
190 | 784k | ++c; |
191 | 784k | continue; |
192 | 784k | } |
193 | 1.28M | if (c[0] == ':') { |
194 | 314k | if (colons.size() < starts.size()) { |
195 | 257k | colons.push(c); |
196 | 257k | } |
197 | 974k | } else if (c[0] == '>') { |
198 | 164k | if (!colons.empty() && !starts.empty() && |
199 | 159k | starts.top() < colons.top()) { |
200 | 118k | if (collected) { |
201 | 59.2k | (*collected)[std::string(starts.top() + 2, colons.top())] |
202 | 59.2k | .push_back(std::string(colons.top() + 1, c)); |
203 | 59.2k | } |
204 | 118k | colons.pop(); |
205 | 118k | } |
206 | 164k | if (!starts.empty()) { |
207 | 164k | starts.pop(); |
208 | 164k | } |
209 | 164k | if (starts.empty()) { |
210 | 9.79k | break; |
211 | 9.79k | } |
212 | 164k | } |
213 | 1.28M | } |
214 | 59.2k | std::string::size_type const traversed = (c - cStart) + 1; |
215 | 59.2k | if (!*c) { |
216 | 49.4k | result += cmStrCat("$<", input.substr(pos, traversed)); |
217 | 49.4k | } |
218 | 59.2k | pos += traversed; |
219 | 59.2k | lastPos = pos; |
220 | 59.2k | } |
221 | 4.71k | if (starts.empty()) { |
222 | 2.13k | result += input.substr(lastPos); |
223 | 2.13k | } |
224 | 4.71k | return cmGeneratorExpression::StripEmptyListElements(result); |
225 | 4.71k | } |
226 | | |
227 | | static std::string stripAllGeneratorExpressions(cm::string_view input) |
228 | 2.35k | { |
229 | 2.35k | return extractAllGeneratorExpressions(input, nullptr); |
230 | 2.35k | } |
231 | | |
232 | | static void prefixItems(std::string const& content, std::string& result, |
233 | | cm::string_view prefix) |
234 | 0 | { |
235 | 0 | std::vector<std::string> entries; |
236 | 0 | cmGeneratorExpression::Split(content, entries); |
237 | 0 | char const* sep = ""; |
238 | 0 | for (std::string const& e : entries) { |
239 | 0 | result += sep; |
240 | 0 | sep = ";"; |
241 | 0 | if (!cmSystemTools::FileIsFullPath(e) && |
242 | 0 | cmGeneratorExpression::Find(e) != 0) { |
243 | 0 | result += prefix; |
244 | 0 | } |
245 | 0 | result += e; |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | | static std::string stripExportInterface( |
250 | | cm::string_view input, cmGeneratorExpression::PreprocessContext context, |
251 | | cm::string_view importPrefix) |
252 | 4.71k | { |
253 | 4.71k | std::string result; |
254 | | |
255 | 4.71k | int nestingLevel = 0; |
256 | 4.71k | std::string::size_type pos = 0; |
257 | 4.71k | std::string::size_type lastPos = pos; |
258 | 17.4k | while (true) { |
259 | 17.4k | std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos); |
260 | 17.4k | std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos); |
261 | 17.4k | std::string::size_type lPos = |
262 | 17.4k | input.find("$<BUILD_LOCAL_INTERFACE:", lastPos); |
263 | | |
264 | 17.4k | pos = std::min({ bPos, iPos, lPos }); |
265 | 17.4k | if (pos == std::string::npos) { |
266 | 4.71k | break; |
267 | 4.71k | } |
268 | | |
269 | 12.7k | result += input.substr(lastPos, pos - lastPos); |
270 | 12.7k | enum class FoundGenex |
271 | 12.7k | { |
272 | 12.7k | BuildInterface, |
273 | 12.7k | InstallInterface, |
274 | 12.7k | BuildLocalInterface, |
275 | 12.7k | } foundGenex = FoundGenex::BuildInterface; |
276 | 12.7k | if (pos == bPos) { |
277 | 6.28k | foundGenex = FoundGenex::BuildInterface; |
278 | 6.28k | pos += cmStrLen("$<BUILD_INTERFACE:"); |
279 | 6.48k | } else if (pos == iPos) { |
280 | 5.08k | foundGenex = FoundGenex::InstallInterface; |
281 | 5.08k | pos += cmStrLen("$<INSTALL_INTERFACE:"); |
282 | 5.08k | } else if (pos == lPos) { |
283 | 1.39k | foundGenex = FoundGenex::BuildLocalInterface; |
284 | 1.39k | pos += cmStrLen("$<BUILD_LOCAL_INTERFACE:"); |
285 | 1.39k | } else { |
286 | 0 | assert(false && "Invalid position found"); |
287 | 0 | } |
288 | 12.7k | nestingLevel = 1; |
289 | 12.7k | char const* c = input.data() + pos; |
290 | 12.7k | char const* const cStart = c; |
291 | 420k | for (; *c; ++c) { |
292 | 415k | if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) { |
293 | 124k | ++nestingLevel; |
294 | 124k | ++c; |
295 | 124k | continue; |
296 | 124k | } |
297 | 290k | if (c[0] == '>') { |
298 | 35.6k | --nestingLevel; |
299 | 35.6k | if (nestingLevel != 0) { |
300 | 27.6k | continue; |
301 | 27.6k | } |
302 | 7.95k | if (context == cmGeneratorExpression::BuildInterface && |
303 | 3.97k | foundGenex == FoundGenex::BuildInterface) { |
304 | 2.31k | result += input.substr(pos, c - cStart); |
305 | 5.64k | } else if (context == cmGeneratorExpression::InstallInterface && |
306 | 3.97k | foundGenex == FoundGenex::InstallInterface) { |
307 | 1.46k | std::string const content = |
308 | 1.46k | static_cast<std::string>(input.substr(pos, c - cStart)); |
309 | 1.46k | if (!importPrefix.empty()) { |
310 | 0 | prefixItems(content, result, importPrefix); |
311 | 1.46k | } else { |
312 | 1.46k | result += content; |
313 | 1.46k | } |
314 | 1.46k | } |
315 | 7.95k | break; |
316 | 35.6k | } |
317 | 290k | } |
318 | 12.7k | std::string::size_type const traversed = (c - cStart) + 1; |
319 | 12.7k | if (!*c) { |
320 | 4.80k | auto remaining = input.substr(pos, traversed); |
321 | 4.80k | switch (foundGenex) { |
322 | 1.66k | case FoundGenex::BuildInterface: |
323 | 1.66k | result = cmStrCat(result, "$<BUILD_INTERFACE:", remaining); |
324 | 1.66k | break; |
325 | 2.15k | case FoundGenex::InstallInterface: |
326 | 2.15k | result = cmStrCat(result, "$<INSTALL_INTERFACE:", remaining); |
327 | 2.15k | break; |
328 | 992 | case FoundGenex::BuildLocalInterface: |
329 | 992 | result = cmStrCat(result, "$<BUILD_LOCAL_INTERFACE:", remaining); |
330 | 992 | break; |
331 | 4.80k | } |
332 | 4.80k | } |
333 | 12.7k | pos += traversed; |
334 | 12.7k | lastPos = pos; |
335 | 12.7k | } |
336 | 4.71k | if (nestingLevel == 0) { |
337 | 4.05k | result += input.substr(lastPos); |
338 | 4.05k | } |
339 | | |
340 | 4.71k | return cmGeneratorExpression::StripEmptyListElements(result); |
341 | 4.71k | } |
342 | | |
343 | | void cmGeneratorExpression::Split(std::string const& input, |
344 | | std::vector<std::string>& output) |
345 | 2.35k | { |
346 | 2.35k | std::string::size_type pos = 0; |
347 | 2.35k | std::string::size_type lastPos = pos; |
348 | 29.7k | while ((pos = input.find("$<", lastPos)) != std::string::npos) { |
349 | 27.3k | std::string part = input.substr(lastPos, pos - lastPos); |
350 | 27.3k | std::string preGenex; |
351 | 27.3k | if (!part.empty()) { |
352 | 18.1k | std::string::size_type startPos = input.rfind(';', pos); |
353 | 18.1k | if (startPos == std::string::npos) { |
354 | 3.79k | preGenex = part; |
355 | 3.79k | part.clear(); |
356 | 14.3k | } else if (startPos != pos - 1 && startPos >= lastPos) { |
357 | 5.74k | part = input.substr(lastPos, startPos - lastPos); |
358 | 5.74k | preGenex = input.substr(startPos + 1, pos - startPos - 1); |
359 | 5.74k | } |
360 | 18.1k | if (!part.empty()) { |
361 | 12.7k | cmExpandList(part, output); |
362 | 12.7k | } |
363 | 18.1k | } |
364 | 27.3k | pos += 2; |
365 | 27.3k | int nestingLevel = 1; |
366 | 27.3k | char const* c = input.c_str() + pos; |
367 | 27.3k | char const* const cStart = c; |
368 | 872k | for (; *c; ++c) { |
369 | 848k | if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) { |
370 | 363k | ++nestingLevel; |
371 | 363k | ++c; |
372 | 363k | continue; |
373 | 363k | } |
374 | 485k | if (c[0] == '>') { |
375 | 45.5k | --nestingLevel; |
376 | 45.5k | if (nestingLevel == 0) { |
377 | 3.46k | break; |
378 | 3.46k | } |
379 | 45.5k | } |
380 | 485k | } |
381 | 256k | for (; *c; ++c) { |
382 | | // Capture the part after the genex and before the next ';' |
383 | 231k | if (c[0] == ';') { |
384 | 2.06k | --c; |
385 | 2.06k | break; |
386 | 2.06k | } |
387 | 231k | } |
388 | 27.3k | std::string::size_type const traversed = (c - cStart) + 1; |
389 | 27.3k | output.push_back(cmStrCat(preGenex, "$<", input.substr(pos, traversed))); |
390 | 27.3k | pos += traversed; |
391 | 27.3k | lastPos = pos; |
392 | 27.3k | } |
393 | 2.35k | if (lastPos < input.size()) { |
394 | 751 | cmExpandList(input.substr(lastPos), output); |
395 | 751 | } |
396 | 2.35k | } |
397 | | |
398 | | std::string cmGeneratorExpression::Preprocess(cm::string_view input, |
399 | | PreprocessContext context, |
400 | | cm::string_view importPrefix) |
401 | 7.06k | { |
402 | 7.06k | if (context == StripAllGeneratorExpressions) { |
403 | 2.35k | return stripAllGeneratorExpressions(input); |
404 | 2.35k | } |
405 | 4.71k | if (context == BuildInterface || context == InstallInterface) { |
406 | 4.71k | return stripExportInterface(input, context, importPrefix); |
407 | 4.71k | } |
408 | | |
409 | 4.71k | assert(false && |
410 | 0 | "cmGeneratorExpression::Preprocess called with invalid args"); |
411 | 0 | return std::string(); |
412 | 4.71k | } |
413 | | |
414 | | std::string cmGeneratorExpression::Collect( |
415 | | std::string const& input, |
416 | | std::map<std::string, std::vector<std::string>>& collected) |
417 | 2.35k | { |
418 | 2.35k | return extractAllGeneratorExpressions(input, &collected); |
419 | 2.35k | } |
420 | | |
421 | | bool cmGeneratorExpression::ForbidGeneratorExpressions( |
422 | | cmGeneratorTarget const* target, std::string const& propertyName, |
423 | | std::string const& propertyValue) |
424 | 0 | { |
425 | 0 | std::map<std::string, std::vector<std::string>> allowList; |
426 | 0 | std::string evaluatedValue; |
427 | 0 | return ForbidGeneratorExpressions(target, propertyName, propertyValue, |
428 | 0 | evaluatedValue, allowList); |
429 | 0 | } |
430 | | |
431 | | bool cmGeneratorExpression::ForbidGeneratorExpressions( |
432 | | cmGeneratorTarget const* target, std::string const& propertyName, |
433 | | std::string const& propertyValue, std::string& evaluatedValue, |
434 | | std::map<std::string, std::vector<std::string>>& allowList) |
435 | 0 | { |
436 | 0 | size_t const initialAllowedGenExps = allowList.size(); |
437 | 0 | evaluatedValue = Collect(propertyValue, allowList); |
438 | 0 | if (evaluatedValue != propertyValue && |
439 | 0 | allowList.size() > initialAllowedGenExps) { |
440 | 0 | target->Makefile->IssueMessage( |
441 | 0 | MessageType::FATAL_ERROR, |
442 | 0 | cmStrCat("Property \"", propertyName, "\" of target \"", |
443 | 0 | target->GetName(), |
444 | 0 | "\" contains a generator expression. This is not allowed.")); |
445 | 0 | return false; |
446 | 0 | } |
447 | | |
448 | | // Check for nested generator expressions (e.g., $<LINK_ONLY:$<...>>). |
449 | 0 | for (auto const& genexp : allowList) { |
450 | 0 | for (auto const& value : genexp.second) { |
451 | 0 | if (value.find("$<") != std::string::npos) { |
452 | 0 | target->Makefile->IssueMessage( |
453 | 0 | MessageType::FATAL_ERROR, |
454 | 0 | cmStrCat("$<", genexp.first, ":...> expression in \"", propertyName, |
455 | 0 | "\" of target \"", target->GetName(), |
456 | 0 | "\" contains a generator expression. This is not " |
457 | 0 | "allowed.")); |
458 | 0 | return false; |
459 | 0 | } |
460 | 0 | } |
461 | 0 | } |
462 | 0 | return true; |
463 | 0 | } |
464 | | |
465 | | cm::string_view::size_type cmGeneratorExpression::Find(cm::string_view input) |
466 | 2.35k | { |
467 | 2.35k | cm::string_view::size_type const openpos = input.find("$<"); |
468 | 2.35k | if (openpos != cm::string_view::npos && |
469 | 1.87k | input.find('>', openpos) != cm::string_view::npos) { |
470 | 1.07k | return openpos; |
471 | 1.07k | } |
472 | 1.28k | return cm::string_view::npos; |
473 | 2.35k | } |
474 | | |
475 | | bool cmGeneratorExpression::IsValidTargetName(std::string const& input) |
476 | 2.35k | { |
477 | | // The ':' is supported to allow use with IMPORTED targets. At least |
478 | | // Qt 4 and 5 IMPORTED targets use ':' as the namespace delimiter. |
479 | 2.35k | static cmsys::RegularExpression targetNameValidator("^[A-Za-z0-9_.:+-]+$"); |
480 | | |
481 | 2.35k | return targetNameValidator.find(input); |
482 | 2.35k | } |
483 | | |
484 | | void cmGeneratorExpression::ReplaceInstallPrefix( |
485 | | std::string& input, std::string const& replacement) |
486 | 0 | { |
487 | 0 | std::string::size_type pos = 0; |
488 | 0 | std::string::size_type lastPos = pos; |
489 | |
|
490 | 0 | while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != |
491 | 0 | std::string::npos) { |
492 | 0 | std::string::size_type endPos = pos + cmStrLen("$<INSTALL_PREFIX>"); |
493 | 0 | input.replace(pos, endPos - pos, replacement); |
494 | 0 | lastPos = endPos; |
495 | 0 | } |
496 | 0 | } |
497 | | |
498 | | void cmCompiledGeneratorExpression::GetMaxLanguageStandard( |
499 | | cmGeneratorTarget const* tgt, std::map<std::string, std::string>& mapping) |
500 | 0 | { |
501 | 0 | auto it = this->MaxLanguageStandard.find(tgt); |
502 | 0 | if (it != this->MaxLanguageStandard.end()) { |
503 | 0 | mapping = it->second; |
504 | 0 | } |
505 | 0 | } |
506 | | |
507 | | std::string const& cmGeneratorExpressionInterpreter::Evaluate( |
508 | | std::string expression, std::string const& property) |
509 | 0 | { |
510 | 0 | this->CompiledGeneratorExpression = |
511 | 0 | this->GeneratorExpression.Parse(std::move(expression)); |
512 | |
|
513 | 0 | cm::GenEx::Context context(this->LocalGenerator, this->Config, |
514 | 0 | this->Language); |
515 | | |
516 | | // Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS |
517 | 0 | cmGeneratorExpressionDAGChecker dagChecker{ |
518 | 0 | this->HeadTarget, |
519 | 0 | property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, |
520 | 0 | nullptr, |
521 | 0 | nullptr, |
522 | 0 | context, |
523 | 0 | }; |
524 | |
|
525 | 0 | return this->CompiledGeneratorExpression->Evaluate(context, &dagChecker, |
526 | 0 | this->HeadTarget); |
527 | 0 | } |