Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorExpressionNode.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 "cmGeneratorExpressionNode.h"
4
5
#include <algorithm>
6
#include <cassert>
7
#include <cerrno>
8
#include <cstdlib>
9
#include <cstring>
10
#include <exception>
11
#include <functional>
12
#include <map>
13
#include <memory>
14
#include <set>
15
#include <stdexcept>
16
#include <unordered_map>
17
#include <utility>
18
19
#include <cm/iterator>
20
#include <cm/optional>
21
#include <cm/string_view>
22
#include <cmext/algorithm>
23
#include <cmext/string_view>
24
25
#include "cmsys/RegularExpression.hxx"
26
#include "cmsys/String.h"
27
28
#include "cmCMakePath.h"
29
#include "cmCMakeString.hxx"
30
#include "cmComputeLinkInformation.h"
31
#include "cmDirectoryPropertyHelper.h"
32
#include "cmGenExContext.h"
33
#include "cmGenExEvaluation.h"
34
#include "cmGeneratorExpression.h"
35
#include "cmGeneratorExpressionDAGChecker.h"
36
#include "cmGeneratorExpressionEvaluator.h"
37
#include "cmGeneratorFileSet.h"
38
#include "cmGeneratorRule.h"
39
#include "cmGeneratorTarget.h"
40
#include "cmGlobalGenerator.h"
41
#include "cmLinkItem.h"
42
#include "cmList.h"
43
#include "cmListFileCache.h"
44
#include "cmLocalGenerator.h"
45
#include "cmMakefile.h"
46
#include "cmMessageType.h"
47
#include "cmOutputConverter.h"
48
#include "cmPolicies.h"
49
#include "cmRange.h"
50
#include "cmRule.h"
51
#include "cmSourceFile.h"
52
#include "cmStandardLevelResolver.h"
53
#include "cmState.h"
54
#include "cmStateSnapshot.h"
55
#include "cmStateTypes.h"
56
#include "cmStringAlgorithms.h"
57
#include "cmSystemTools.h"
58
#include "cmTarget.h"
59
#include "cmTargetTypes.h"
60
#include "cmUnreachable.h"
61
#include "cmValue.h"
62
#include "cmake.h"
63
64
namespace {
65
66
bool IsValidPropertyName(std::string const& propertyName)
67
13.8k
{
68
13.8k
  static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_:]+$");
69
70
13.8k
  return propertyNameValidator.find(propertyName);
71
13.8k
}
72
bool IsValidPropertyName(cm::GenEx::Evaluation* eval,
73
                         GeneratorExpressionContent const* content,
74
                         std::string const& propertyName)
75
13.7k
{
76
13.7k
  if (!IsValidPropertyName(propertyName)) {
77
180
    reportError(eval, content->GetOriginalExpression(),
78
180
                "Property name not supported.");
79
180
    return false;
80
180
  }
81
13.6k
  return true;
82
13.7k
}
83
84
bool HasKnownObjectFileLocation(cm::GenEx::Evaluation* eval,
85
                                GeneratorExpressionContent const* content,
86
                                std::string const& genex,
87
                                cmGeneratorTarget const* target)
88
602
{
89
602
  std::string reason;
90
602
  if (!eval->EvaluateForBuildsystem &&
91
13
      !target->Target->HasKnownObjectFileLocation(&reason)) {
92
0
    reportError(
93
0
      eval, content->GetOriginalExpression(),
94
0
      cmStrCat("The evaluation of the ", genex,
95
0
               " generator expression is only suitable for consumption by "
96
0
               "CMake (limited",
97
0
               reason, ").  It is not suitable for writing out elsewhere."));
98
0
    return false;
99
0
  }
100
602
  return true;
101
602
}
102
103
} // namespace
104
105
std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
106
  std::string const& prop, cm::GenEx::Evaluation* eval,
107
  cmGeneratorTarget const* headTarget,
108
  cmGeneratorExpressionDAGChecker* dagChecker,
109
  cmGeneratorTarget const* currentTarget)
110
8.98k
{
111
8.98k
  cmGeneratorExpression ge(*eval->Context.LG->GetCMakeInstance(),
112
8.98k
                           eval->Backtrace);
113
8.98k
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
114
8.98k
  cge->SetEvaluateForBuildsystem(eval->EvaluateForBuildsystem);
115
8.98k
  cge->SetQuiet(eval->Quiet);
116
8.98k
  std::string result =
117
8.98k
    cge->Evaluate(eval->Context, dagChecker, headTarget, currentTarget);
118
8.98k
  if (cge->GetHadContextSensitiveCondition()) {
119
379
    eval->HadContextSensitiveCondition = true;
120
379
  }
121
8.98k
  if (cge->GetHadHeadSensitiveCondition()) {
122
94
    eval->HadHeadSensitiveCondition = true;
123
94
  }
124
8.98k
  if (cge->GetHadLinkLanguageSensitiveCondition()) {
125
0
    eval->HadLinkLanguageSensitiveCondition = true;
126
0
  }
127
8.98k
  return result;
128
8.98k
}
129
130
// Re-evaluate the unevaluated <body> subtree of a binding operation with the
131
// given operands bound (accessible as $<_0>, $<_1>, ...).  A fresh Evaluation
132
// is built from a copied, mutated Context so that nested binding operations
133
// can shadow the operands and restore them on exit.
134
static std::string EvaluateBodyWithBoundOperands(
135
  cmGeneratorExpressionEvaluatorVector const& bodyExpr,
136
  std::vector<std::string> operands, cm::GenEx::Evaluation* eval,
137
  cmGeneratorExpressionDAGChecker* dagChecker)
138
0
{
139
0
  cm::GenEx::Context elemContext = eval->Context; // copy
140
0
  elemContext.SetBoundOperands(std::move(operands));
141
0
  cm::GenEx::Evaluation elemEval(
142
0
    elemContext, eval->Quiet, eval->HeadTarget, eval->CurrentTarget,
143
0
    eval->EvaluateForBuildsystem, eval->Backtrace);
144
145
0
  std::string result;
146
0
  for (auto const& pExprEval : bodyExpr) {
147
0
    result += pExprEval->Evaluate(&elemEval, dagChecker);
148
0
    if (elemEval.HadError) {
149
0
      eval->HadError = true;
150
0
      return std::string{};
151
0
    }
152
0
  }
153
0
  eval->HadContextSensitiveCondition |= elemEval.HadContextSensitiveCondition;
154
0
  eval->HadHeadSensitiveCondition |= elemEval.HadHeadSensitiveCondition;
155
0
  eval->HadLinkLanguageSensitiveCondition |=
156
0
    elemEval.HadLinkLanguageSensitiveCondition;
157
0
  eval->DependTargets.insert(elemEval.DependTargets.begin(),
158
0
                             elemEval.DependTargets.end());
159
0
  eval->AllTargets.insert(elemEval.AllTargets.begin(),
160
0
                          elemEval.AllTargets.end());
161
0
  eval->SeenTargetProperties.insert(elemEval.SeenTargetProperties.begin(),
162
0
                                    elemEval.SeenTargetProperties.end());
163
0
  eval->SourceSensitiveTargets.insert(elemEval.SourceSensitiveTargets.begin(),
164
0
                                      elemEval.SourceSensitiveTargets.end());
165
0
  for (auto const& entry : elemEval.MaxLanguageStandard) {
166
0
    eval->MaxLanguageStandard[entry.first].insert(entry.second.begin(),
167
0
                                                  entry.second.end());
168
0
  }
169
0
  return result;
170
0
}
171
172
static std::string EvaluateBodyWithBoundOperand(
173
  cmGeneratorExpressionEvaluatorVector const& bodyExpr,
174
  std::string const& operand, cm::GenEx::Evaluation* eval,
175
  cmGeneratorExpressionDAGChecker* dagChecker)
176
0
{
177
0
  return EvaluateBodyWithBoundOperands(bodyExpr, { operand }, eval,
178
0
                                       dagChecker);
179
0
}
180
181
// Evaluate `predicateBody` once per element of `list`, binding `$<_0>` to the
182
// element (reusing EvaluateBodyWithBoundOperand).  Each result must be exactly
183
// "0" or "1".  Returns the per-element boolean mask, or cm::nullopt after
184
// reporting an error (non-boolean result, or a failure inside the body).
185
static cm::optional<std::vector<bool>> EvaluatePredicateMask(
186
  cmGeneratorExpressionEvaluatorVector const& predicateBody,
187
  cmList const& list, cm::string_view subCommand, cm::GenEx::Evaluation* eval,
188
  GeneratorExpressionContent const* content,
189
  cmGeneratorExpressionDAGChecker* dagChecker)
190
0
{
191
0
  cm::optional<std::vector<bool>> result;
192
0
  std::vector<bool> mask;
193
0
  mask.reserve(list.size());
194
0
  for (auto const& element : list) {
195
0
    std::string r =
196
0
      EvaluateBodyWithBoundOperand(predicateBody, element, eval, dagChecker);
197
0
    if (eval->HadError) {
198
0
      return result;
199
0
    }
200
0
    if (r == "1") {
201
0
      mask.push_back(true);
202
0
    } else if (r == "0") {
203
0
      mask.push_back(false);
204
0
    } else {
205
0
      reportError(
206
0
        eval, content->GetOriginalExpression(),
207
0
        cmStrCat("sub-command ", subCommand,
208
0
                 ", PREDICATE body must evaluate to \"0\" or \"1\", but "
209
0
                 "evaluated to \"",
210
0
                 r, "\"."));
211
0
      return result;
212
0
    }
213
0
  }
214
0
  result = std::move(mask);
215
0
  return result;
216
0
}
217
218
static const struct ZeroNode : public cmGeneratorExpressionNode
219
{
220
20
  ZeroNode() {} // NOLINT(modernize-use-equals-default)
221
222
3.36k
  bool GeneratesContent() const override { return false; }
223
224
3.36k
  bool AcceptsArbitraryContentParameter() const override { return true; }
225
226
  std::string Evaluate(
227
    std::vector<std::string> const& /*parameters*/,
228
    cm::GenEx::Evaluation* /*eval*/,
229
    GeneratorExpressionContent const* /*content*/,
230
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
231
0
  {
232
0
    return std::string();
233
0
  }
234
} zeroNode;
235
236
static const struct OneNode : public cmGeneratorExpressionNode
237
{
238
30
  OneNode() {} // NOLINT(modernize-use-equals-default)
239
240
1.99k
  bool AcceptsArbitraryContentParameter() const override { return true; }
241
242
  std::string Evaluate(
243
    std::vector<std::string> const& parameters,
244
    cm::GenEx::Evaluation* /*eval*/,
245
    GeneratorExpressionContent const* /*content*/,
246
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
247
1.98k
  {
248
1.98k
    return parameters.front();
249
1.98k
  }
250
} oneNode;
251
252
struct BoundOperandNode : public cmGeneratorExpressionNode
253
{
254
  explicit BoundOperandNode(std::size_t index)
255
20
    : Index(index)
256
20
  {
257
20
  }
258
259
0
  int NumExpectedParameters() const override { return 0; }
260
261
  std::string Evaluate(
262
    std::vector<std::string> const& /*parameters*/,
263
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
264
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
265
0
  {
266
0
    if (!eval->Context.HasBoundOperand(this->Index)) {
267
0
      std::size_t const count = eval->Context.BoundOperandCount();
268
0
      if (count == 0) {
269
0
        reportError(eval, content->GetOriginalExpression(),
270
0
                    cmStrCat("$<_", this->Index,
271
0
                             "> may only be used inside the body of a binding "
272
0
                             "operation."));
273
0
      } else {
274
0
        reportError(
275
0
          eval, content->GetOriginalExpression(),
276
0
          cmStrCat(
277
0
            "$<_", this->Index,
278
0
            "> is out of range for the current binding operation, which "
279
0
            "binds only ",
280
0
            count, " operand(s) (maximum $<_", count - 1, ">)."));
281
0
      }
282
0
      return std::string();
283
0
    }
284
0
    return eval->Context.GetBoundOperand(this->Index);
285
0
  }
286
287
  std::size_t Index;
288
};
289
static BoundOperandNode const boundOperandNode0{ 0 };
290
static BoundOperandNode const boundOperandNode1{ 1 };
291
292
static const struct OneNode buildInterfaceNode;
293
294
static const struct ZeroNode installInterfaceNode;
295
296
static const struct OneNode buildLocalInterfaceNode;
297
298
struct BooleanOpNode : public cmGeneratorExpressionNode
299
{
300
  BooleanOpNode(char const* op_, char const* successVal_,
301
                char const* failureVal_)
302
20
    : op(op_)
303
20
    , successVal(successVal_)
304
20
    , failureVal(failureVal_)
305
20
  {
306
20
  }
307
308
109
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
309
310
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
311
                                   std::string& def_value) const override
312
975
  {
313
975
    if (!parameters.empty() && parameters.back() == failureVal) {
314
30
      def_value = failureVal;
315
30
      return false;
316
30
    }
317
945
    return true;
318
975
  }
319
320
  std::string Evaluate(std::vector<std::string> const& parameters,
321
                       cm::GenEx::Evaluation* eval,
322
                       GeneratorExpressionContent const* content,
323
                       cmGeneratorExpressionDAGChecker*) const override
324
75
  {
325
81
    for (std::string const& param : parameters) {
326
81
      if (param == this->failureVal) {
327
7
        return this->failureVal;
328
7
      }
329
74
      if (param != this->successVal) {
330
64
        reportError(eval, content->GetOriginalExpression(),
331
64
                    cmStrCat("Parameters to $<", this->op,
332
64
                             "> must resolve to either '0' or '1'."));
333
64
        return std::string();
334
64
      }
335
74
    }
336
4
    return this->successVal;
337
75
  }
338
339
  char const *const op, *const successVal, *const failureVal;
340
};
341
342
static BooleanOpNode const andNode("AND", "1", "0"), orNode("OR", "0", "1");
343
344
static const struct NotNode : public cmGeneratorExpressionNode
345
{
346
10
  NotNode() {} // NOLINT(modernize-use-equals-default)
347
348
  std::string Evaluate(
349
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
350
    GeneratorExpressionContent const* content,
351
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
352
32
  {
353
32
    if (parameters.front() != "0" && parameters.front() != "1") {
354
23
      reportError(
355
23
        eval, content->GetOriginalExpression(),
356
23
        "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
357
23
      return std::string();
358
23
    }
359
9
    return parameters.front() == "0" ? "1" : "0";
360
32
  }
361
} notNode;
362
363
static const struct BoolNode : public cmGeneratorExpressionNode
364
{
365
10
  BoolNode() {} // NOLINT(modernize-use-equals-default)
366
367
224
  int NumExpectedParameters() const override { return 1; }
368
369
  std::string Evaluate(
370
    std::vector<std::string> const& parameters,
371
    cm::GenEx::Evaluation* /*eval*/,
372
    GeneratorExpressionContent const* /*content*/,
373
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
374
205
  {
375
205
    return !cmIsOff(parameters.front()) ? "1" : "0";
376
205
  }
377
} boolNode;
378
379
static const struct ArgsNode : public cmGeneratorExpressionNode
380
{
381
10
  ArgsNode() {} // NOLINT(modernize-use-equals-default)
382
383
11
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
384
385
  std::string Evaluate(std::vector<std::string> const& parameters,
386
                       cm::GenEx::Evaluation*,
387
                       GeneratorExpressionContent const*,
388
                       cmGeneratorExpressionDAGChecker*) const override
389
11
  {
390
11
    if (parameters.empty()) {
391
11
      return std::string{};
392
11
    }
393
0
    if (parameters.size() == 1 && parameters[0].empty()) {
394
0
      return parameters.front();
395
0
    }
396
397
0
    cmList args{ parameters.begin(), parameters.end(),
398
0
                 cmList::ExpandElements::Yes, cmList::EmptyElements::Yes };
399
0
    return cmStrCat("<ARGS>", args.join(","_s), "</ARGS>");
400
0
  }
401
} argsNode;
402
403
static const struct IfNode : public cmGeneratorExpressionNode
404
{
405
10
  IfNode() {} // NOLINT(modernize-use-equals-default)
406
407
120
  int NumExpectedParameters() const override { return 3; }
408
409
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
410
                                   std::string&) const override
411
366
  {
412
366
    return (parameters.empty() ||
413
246
            parameters[0] != cmStrCat(parameters.size() - 1, ""));
414
366
  }
415
416
  std::string Evaluate(std::vector<std::string> const& parameters,
417
                       cm::GenEx::Evaluation* eval,
418
                       GeneratorExpressionContent const* content,
419
                       cmGeneratorExpressionDAGChecker*) const override
420
31
  {
421
31
    if (parameters[0] != "1" && parameters[0] != "0") {
422
11
      reportError(eval, content->GetOriginalExpression(),
423
11
                  "First parameter to $<IF> must resolve to exactly one '0' "
424
11
                  "or '1' value.");
425
11
      return std::string();
426
11
    }
427
20
    return parameters[0] == "1" ? parameters[1] : parameters[2];
428
31
  }
429
} ifNode;
430
431
static const struct StrEqualNode : public cmGeneratorExpressionNode
432
{
433
10
  StrEqualNode() {} // NOLINT(modernize-use-equals-default)
434
435
106
  int NumExpectedParameters() const override { return 2; }
436
437
  std::string Evaluate(
438
    std::vector<std::string> const& parameters,
439
    cm::GenEx::Evaluation* /*eval*/,
440
    GeneratorExpressionContent const* /*content*/,
441
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
442
97
  {
443
97
    return cm::CMakeString{ parameters.front() }.Compare(
444
97
             cm::CMakeString::CompOperator::EQUAL, parameters[1])
445
97
      ? "1"
446
97
      : "0";
447
97
  }
448
} strEqualNode;
449
static const struct StrLessNode : public cmGeneratorExpressionNode
450
{
451
10
  StrLessNode() {} // NOLINT(modernize-use-equals-default)
452
453
174
  int NumExpectedParameters() const override { return 2; }
454
455
  std::string Evaluate(
456
    std::vector<std::string> const& parameters,
457
    cm::GenEx::Evaluation* /*eval*/,
458
    GeneratorExpressionContent const* /*content*/,
459
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
460
145
  {
461
145
    return cm::CMakeString{ parameters.front() }.Compare(
462
145
             cm::CMakeString::CompOperator::LESS, parameters[1])
463
145
      ? "1"
464
145
      : "0";
465
145
  }
466
} strLessNode;
467
static const struct StrLessEqualNode : public cmGeneratorExpressionNode
468
{
469
10
  StrLessEqualNode() {} // NOLINT(modernize-use-equals-default)
470
471
0
  int NumExpectedParameters() const override { return 2; }
472
473
  std::string Evaluate(
474
    std::vector<std::string> const& parameters,
475
    cm::GenEx::Evaluation* /*eval*/,
476
    GeneratorExpressionContent const* /*content*/,
477
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
478
0
  {
479
0
    return cm::CMakeString{ parameters.front() }.Compare(
480
0
             cm::CMakeString::CompOperator::LESS_EQUAL, parameters[1])
481
0
      ? "1"
482
0
      : "0";
483
0
  }
484
} strLessEqualNode;
485
static const struct StrGreaterNode : public cmGeneratorExpressionNode
486
{
487
10
  StrGreaterNode() {} // NOLINT(modernize-use-equals-default)
488
489
2
  int NumExpectedParameters() const override { return 2; }
490
491
  std::string Evaluate(
492
    std::vector<std::string> const& parameters,
493
    cm::GenEx::Evaluation* /*eval*/,
494
    GeneratorExpressionContent const* /*content*/,
495
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
496
0
  {
497
0
    return cm::CMakeString{ parameters.front() }.Compare(
498
0
             cm::CMakeString::CompOperator::GREATER, parameters[1])
499
0
      ? "1"
500
0
      : "0";
501
0
  }
502
} strGreaterNode;
503
static const struct StrGreaterEqualNode : public cmGeneratorExpressionNode
504
{
505
10
  StrGreaterEqualNode() {} // NOLINT(modernize-use-equals-default)
506
507
39
  int NumExpectedParameters() const override { return 2; }
508
509
  std::string Evaluate(
510
    std::vector<std::string> const& parameters,
511
    cm::GenEx::Evaluation* /*eval*/,
512
    GeneratorExpressionContent const* /*content*/,
513
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
514
25
  {
515
25
    return cm::CMakeString{ parameters.front() }.Compare(
516
25
             cm::CMakeString::CompOperator::GREATER_EQUAL, parameters[1])
517
25
      ? "1"
518
25
      : "0";
519
25
  }
520
} strGreaterEqualNode;
521
522
static const struct EqualNode : public cmGeneratorExpressionNode
523
{
524
10
  EqualNode() {} // NOLINT(modernize-use-equals-default)
525
526
33
  int NumExpectedParameters() const override { return 2; }
527
528
  std::string Evaluate(
529
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
530
    GeneratorExpressionContent const* content,
531
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
532
24
  {
533
24
    long numbers[2];
534
24
    for (int i = 0; i < 2; ++i) {
535
24
      if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
536
24
        reportError(eval, content->GetOriginalExpression(),
537
24
                    cmStrCat("$<EQUAL> parameter ", parameters[i],
538
24
                             " is not a valid integer."));
539
24
        return {};
540
24
      }
541
24
    }
542
0
    return numbers[0] == numbers[1] ? "1" : "0";
543
24
  }
544
545
  static bool ParameterToLong(char const* param, long* outResult)
546
24
  {
547
24
    char const isNegative = param[0] == '-';
548
549
24
    int base = 0;
550
24
    if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
551
1
      base = 2;
552
1
      param += 2;
553
23
    } else if (cmHasLiteralPrefix(param, "-0b") ||
554
23
               cmHasLiteralPrefix(param, "-0B") ||
555
23
               cmHasLiteralPrefix(param, "+0b") ||
556
23
               cmHasLiteralPrefix(param, "+0B")) {
557
0
      base = 2;
558
0
      param += 3;
559
0
    }
560
561
24
    char* pEnd;
562
24
    long result = strtol(param, &pEnd, base);
563
24
    if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
564
24
      return false;
565
24
    }
566
0
    if (isNegative && result > 0) {
567
0
      result *= -1;
568
0
    }
569
0
    *outResult = result;
570
0
    return true;
571
24
  }
572
} equalNode;
573
574
static const struct InListNode : public cmGeneratorExpressionNode
575
{
576
10
  InListNode() {} // NOLINT(modernize-use-equals-default)
577
578
90
  int NumExpectedParameters() const override { return 2; }
579
580
  std::string Evaluate(
581
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
582
    GeneratorExpressionContent const* /*content*/,
583
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
584
72
  {
585
72
    cmList values;
586
72
    cmList checkValues;
587
72
    bool check = false;
588
72
    cmLocalGenerator const* const lg = eval->Context.LG;
589
72
    switch (lg->GetPolicyStatus(cmPolicies::CMP0085)) {
590
0
      case cmPolicies::WARN:
591
0
        if (parameters.front().empty()) {
592
0
          check = true;
593
0
          checkValues.assign(parameters[1], cmList::EmptyElements::Yes);
594
0
        }
595
0
        CM_FALLTHROUGH;
596
0
      case cmPolicies::OLD:
597
0
        values.assign(parameters[1]);
598
0
        if (check && values != checkValues) {
599
0
          lg->IssuePolicyWarning(
600
0
            cmPolicies::CMP0085, {},
601
0
            cmStrCat("Search Item:\n  \""_s, parameters.front(),
602
0
                     "\"\nList:\n  \""_s, parameters[1], "\"\n"_s),
603
0
            eval->Backtrace);
604
0
          return "0";
605
0
        }
606
0
        if (values.empty()) {
607
0
          return "0";
608
0
        }
609
0
        break;
610
72
      case cmPolicies::NEW:
611
72
        values.assign(parameters[1], cmList::EmptyElements::Yes);
612
72
        break;
613
72
    }
614
615
72
    return values.find(parameters.front()) != cmList::npos ? "1" : "0";
616
72
  }
617
} inListNode;
618
619
static const struct FilterNode : public cmGeneratorExpressionNode
620
{
621
10
  FilterNode() {} // NOLINT(modernize-use-equals-default)
622
623
20
  int NumExpectedParameters() const override { return 3; }
624
625
  std::string Evaluate(
626
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
627
    GeneratorExpressionContent const* content,
628
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
629
6
  {
630
6
    if (parameters.size() != 3) {
631
0
      reportError(eval, content->GetOriginalExpression(),
632
0
                  "$<FILTER:...> expression requires three parameters");
633
0
      return {};
634
0
    }
635
636
6
    if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
637
6
      reportError(
638
6
        eval, content->GetOriginalExpression(),
639
6
        "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
640
6
      return {};
641
6
    }
642
643
0
    try {
644
0
      return cmList{ parameters.front(), cmList::EmptyElements::Yes }
645
0
        .filter(parameters[2],
646
0
                parameters[1] == "EXCLUDE" ? cmList::FilterMode::EXCLUDE
647
0
                                           : cmList::FilterMode::INCLUDE)
648
0
        .to_string();
649
0
    } catch (std::invalid_argument&) {
650
0
      reportError(eval, content->GetOriginalExpression(),
651
0
                  "$<FILTER:...> failed to compile regex");
652
0
      return {};
653
0
    }
654
0
  }
655
} filterNode;
656
657
static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
658
{
659
10
  RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
660
661
606
  int NumExpectedParameters() const override { return 1; }
662
663
  std::string Evaluate(
664
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
665
    GeneratorExpressionContent const* content,
666
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
667
593
  {
668
593
    if (parameters.size() != 1) {
669
0
      reportError(
670
0
        eval, content->GetOriginalExpression(),
671
0
        "$<REMOVE_DUPLICATES:...> expression requires one parameter");
672
0
    }
673
674
593
    return cmList{ parameters.front(), cmList::EmptyElements::Yes }
675
593
      .remove_duplicates()
676
593
      .to_string();
677
593
  }
678
679
} removeDuplicatesNode;
680
681
static const struct TargetExistsNode : public cmGeneratorExpressionNode
682
{
683
10
  TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
684
685
48
  int NumExpectedParameters() const override { return 1; }
686
687
  std::string Evaluate(
688
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
689
    GeneratorExpressionContent const* content,
690
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
691
46
  {
692
46
    if (parameters.size() != 1) {
693
0
      reportError(eval, content->GetOriginalExpression(),
694
0
                  "$<TARGET_EXISTS:...> expression requires one parameter");
695
0
      return std::string();
696
0
    }
697
698
46
    std::string const& targetName = parameters.front();
699
46
    if (targetName.empty() ||
700
43
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
701
15
      reportError(eval, content->GetOriginalExpression(),
702
15
                  "$<TARGET_EXISTS:tgt> expression requires a non-empty "
703
15
                  "valid target name.");
704
15
      return std::string();
705
15
    }
706
707
31
    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName) ? "1"
708
31
                                                                        : "0";
709
46
  }
710
} targetExistsNode;
711
712
static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
713
{
714
10
  TargetNameIfExistsNode() {} // NOLINT(modernize-use-equals-default)
715
716
148
  int NumExpectedParameters() const override { return 1; }
717
718
  std::string Evaluate(
719
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
720
    GeneratorExpressionContent const* content,
721
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
722
148
  {
723
148
    if (parameters.size() != 1) {
724
0
      reportError(eval, content->GetOriginalExpression(),
725
0
                  "$<TARGET_NAME_IF_EXISTS:...> expression requires one "
726
0
                  "parameter");
727
0
      return std::string();
728
0
    }
729
730
148
    std::string const& targetName = parameters.front();
731
148
    if (targetName.empty() ||
732
145
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
733
9
      reportError(eval, content->GetOriginalExpression(),
734
9
                  "$<TARGET_NAME_IF_EXISTS:tgt> expression requires a "
735
9
                  "non-empty valid target name.");
736
9
      return std::string();
737
9
    }
738
739
139
    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName)
740
139
      ? targetName
741
139
      : std::string();
742
148
  }
743
} targetNameIfExistsNode;
744
745
struct GenexEvaluator : public cmGeneratorExpressionNode
746
{
747
20
  GenexEvaluator() {} // NOLINT(modernize-use-equals-default)
748
749
protected:
750
  std::string EvaluateExpression(
751
    std::string const& genexOperator, std::string const& expression,
752
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
753
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const
754
1.09k
  {
755
1.09k
    if (eval->HeadTarget) {
756
1.07k
      cmGeneratorExpressionDAGChecker dagChecker{
757
1.07k
        eval->HeadTarget, cmStrCat(genexOperator, ':', expression),
758
1.07k
        content,          dagCheckerParent,
759
1.07k
        eval->Context,    eval->Backtrace,
760
1.07k
      };
761
1.07k
      switch (dagChecker.Check()) {
762
0
        case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
763
0
        case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
764
0
          dagChecker.ReportError(eval, content->GetOriginalExpression());
765
0
          return std::string();
766
0
        }
767
173
        case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
768
1.07k
        case cmGeneratorExpressionDAGChecker::DAG:
769
1.07k
          break;
770
1.07k
      }
771
772
1.07k
      return this->EvaluateDependentExpression(
773
1.07k
        expression, eval, eval->HeadTarget, &dagChecker, eval->CurrentTarget);
774
1.07k
    }
775
776
24
    return this->EvaluateDependentExpression(
777
24
      expression, eval, eval->HeadTarget, dagCheckerParent,
778
24
      eval->CurrentTarget);
779
1.09k
  }
780
};
781
782
static const struct TargetGenexEvalNode : public GenexEvaluator
783
{
784
10
  TargetGenexEvalNode() {} // NOLINT(modernize-use-equals-default)
785
786
342
  int NumExpectedParameters() const override { return 2; }
787
788
342
  bool AcceptsArbitraryContentParameter() const override { return true; }
789
790
  std::string Evaluate(
791
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
792
    GeneratorExpressionContent const* content,
793
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
794
316
  {
795
316
    std::string const& targetName = parameters.front();
796
316
    if (targetName.empty() ||
797
313
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
798
14
      reportError(eval, content->GetOriginalExpression(),
799
14
                  "$<TARGET_GENEX_EVAL:tgt, ...> expression requires a "
800
14
                  "non-empty valid target name.");
801
14
      return std::string();
802
14
    }
803
804
302
    auto const* target =
805
302
      eval->Context.LG->FindGeneratorTargetToUse(targetName);
806
302
    if (!target) {
807
6
      reportError(eval, content->GetOriginalExpression(),
808
6
                  cmStrCat("$<TARGET_GENEX_EVAL:tgt, ...> target \"",
809
6
                           targetName, "\" not found."));
810
6
      return std::string();
811
6
    }
812
813
296
    std::string const& expression = parameters[1];
814
296
    if (expression.empty()) {
815
71
      return expression;
816
71
    }
817
818
    // Replace the surrounding context with the named target.
819
225
    cm::GenEx::Evaluation targetEval(eval->Context, eval->Quiet, target,
820
225
                                     target, eval->EvaluateForBuildsystem,
821
225
                                     eval->Backtrace);
822
823
225
    return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
824
225
                                    &targetEval, content, dagCheckerParent);
825
296
  }
826
} targetGenexEvalNode;
827
828
static const struct GenexEvalNode : public GenexEvaluator
829
{
830
10
  GenexEvalNode() {} // NOLINT(modernize-use-equals-default)
831
832
903
  int NumExpectedParameters() const override { return 1; }
833
834
903
  bool AcceptsArbitraryContentParameter() const override { return true; }
835
836
  std::string Evaluate(
837
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
838
    GeneratorExpressionContent const* content,
839
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
840
895
  {
841
895
    std::string const& expression = parameters[0];
842
895
    if (expression.empty()) {
843
23
      return expression;
844
23
    }
845
846
872
    return this->EvaluateExpression("GENEX_EVAL", expression, eval, content,
847
872
                                    dagCheckerParent);
848
895
  }
849
} genexEvalNode;
850
851
static const struct LowerCaseNode : public cmGeneratorExpressionNode
852
{
853
10
  LowerCaseNode() {} // NOLINT(modernize-use-equals-default)
854
855
90
  bool AcceptsArbitraryContentParameter() const override { return true; }
856
857
  std::string Evaluate(
858
    std::vector<std::string> const& parameters,
859
    cm::GenEx::Evaluation* /*eval*/,
860
    GeneratorExpressionContent const* /*content*/,
861
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
862
90
  {
863
90
    return cmSystemTools::LowerCase(parameters.front());
864
90
  }
865
} lowerCaseNode;
866
867
static const struct UpperCaseNode : public cmGeneratorExpressionNode
868
{
869
10
  UpperCaseNode() {} // NOLINT(modernize-use-equals-default)
870
871
363
  bool AcceptsArbitraryContentParameter() const override { return true; }
872
873
  std::string Evaluate(
874
    std::vector<std::string> const& parameters,
875
    cm::GenEx::Evaluation* /*eval*/,
876
    GeneratorExpressionContent const* /*content*/,
877
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
878
308
  {
879
308
    return cmSystemTools::UpperCase(parameters.front());
880
308
  }
881
} upperCaseNode;
882
883
namespace {
884
template <typename Container>
885
class Range : public cmRange<typename Container::const_iterator>
886
{
887
private:
888
  using Base = cmRange<typename Container::const_iterator>;
889
890
public:
891
  using const_iterator = typename Container::const_iterator;
892
  using value_type = typename Container::value_type;
893
  using size_type = typename Container::size_type;
894
  using difference_type = typename Container::difference_type;
895
  using const_reference = typename Container::const_reference;
896
897
  Range(Container const& container)
898
1.33k
    : Base(container.begin(), container.end())
899
1.33k
  {
900
1.33k
  }
901
902
  const_reference operator[](size_type pos) const
903
340
  {
904
340
    return *(this->begin() + pos);
905
340
  }
906
907
1.52k
  const_reference front() const { return *this->begin(); }
908
0
  const_reference back() const { return *std::prev(this->end()); }
909
910
  Range& advance(difference_type amount) &
911
1.39k
  {
912
1.39k
    Base::advance(amount);
913
1.39k
    return *this;
914
1.39k
  }
915
  Range advance(difference_type amount) &&
916
1.33k
  {
917
1.33k
    Base::advance(amount);
918
1.33k
    return std::move(*this);
919
1.33k
  }
920
};
921
922
using Arguments = Range<std::vector<std::string>>;
923
924
bool CheckGenExParameters(cm::GenEx::Evaluation* eval,
925
                          GeneratorExpressionContent const* cnt,
926
                          cm::string_view genex, cm::string_view option,
927
                          std::size_t count, int required = 1,
928
                          bool exactly = true)
929
1.33k
{
930
1.33k
  if (static_cast<int>(count) < required ||
931
1.31k
      (exactly && static_cast<int>(count) > required)) {
932
21
    std::string nbParameters;
933
21
    switch (required) {
934
3
      case 1:
935
3
        nbParameters = "one parameter";
936
3
        break;
937
11
      case 2:
938
11
        nbParameters = "two parameters";
939
11
        break;
940
7
      case 3:
941
7
        nbParameters = "three parameters";
942
7
        break;
943
0
      case 4:
944
0
        nbParameters = "four parameters";
945
0
        break;
946
0
      default:
947
0
        nbParameters = cmStrCat(required, " parameters");
948
21
    }
949
21
    reportError(eval, cnt->GetOriginalExpression(),
950
21
                cmStrCat("$<", genex, ':', option, "> expression requires ",
951
21
                         (exactly ? "exactly" : "at least"), ' ', nbParameters,
952
21
                         '.'));
953
21
    return false;
954
21
  }
955
1.31k
  return true;
956
1.33k
};
957
958
template <typename IndexType>
959
bool GetNumericArgument(std::string const& arg, IndexType& value)
960
0
{
961
0
  try {
962
0
    std::size_t pos;
963
964
0
    if (sizeof(IndexType) == sizeof(long)) {
965
0
      value = std::stol(arg, &pos);
966
0
    } else {
967
0
      value = std::stoll(arg, &pos);
968
0
    }
969
970
0
    if (pos != arg.length()) {
971
      // this is not a number
972
0
      return false;
973
0
    }
974
0
  } catch (std::invalid_argument const&) {
975
0
    return false;
976
0
  }
977
978
0
  return true;
979
0
}
980
981
template <typename IndexType>
982
bool GetNumericArguments(
983
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt,
984
  Arguments args, std::vector<IndexType>& indexes,
985
  cmList::ExpandElements expandElements = cmList::ExpandElements::No)
986
0
{
987
0
  using IndexRange = cmRange<Arguments::const_iterator>;
988
0
  IndexRange arguments(args.begin(), args.end());
989
0
  cmList list;
990
0
  if (expandElements == cmList::ExpandElements::Yes) {
991
0
    list = cmList{ args.begin(), args.end(), expandElements };
992
0
    arguments = IndexRange{ list.begin(), list.end() };
993
0
  }
994
995
0
  for (auto const& value : arguments) {
996
0
    IndexType index;
997
0
    if (!GetNumericArgument(value, index)) {
998
0
      reportError(eval, cnt->GetOriginalExpression(),
999
0
                  cmStrCat("index: \"", value, "\" is not a valid index"));
1000
0
      return false;
1001
0
    }
1002
0
    indexes.push_back(index);
1003
0
  }
1004
0
  return true;
1005
0
}
1006
1007
// CMP0223: an empty path used to be a prefix of every path.
1008
bool IsPrefixCMP0223(cmCMakePath const& prefix, cm::GenEx::Evaluation* eval)
1009
0
{
1010
0
  if (!prefix.IsEmpty()) {
1011
0
    return false;
1012
0
  }
1013
0
  cmLocalGenerator const* const lg = eval->Context.LG;
1014
0
  switch (lg->GetPolicyStatus(cmPolicies::CMP0223)) {
1015
0
    case cmPolicies::WARN:
1016
0
      lg->IssuePolicyWarning(cmPolicies::CMP0223, {}, {}, eval->Backtrace);
1017
0
      CM_FALLTHROUGH;
1018
0
    case cmPolicies::OLD:
1019
0
      return true;
1020
0
    case cmPolicies::NEW:
1021
0
      break;
1022
0
  }
1023
0
  return false;
1024
0
}
1025
1026
bool CheckPathParametersEx(cm::GenEx::Evaluation* eval,
1027
                           GeneratorExpressionContent const* cnt,
1028
                           cm::string_view option, std::size_t count,
1029
                           int required = 1, bool exactly = true)
1030
53
{
1031
53
  return CheckGenExParameters(eval, cnt, "PATH"_s, option, count, required,
1032
53
                              exactly);
1033
53
}
1034
bool CheckPathParameters(cm::GenEx::Evaluation* eval,
1035
                         GeneratorExpressionContent const* cnt,
1036
                         cm::string_view option, Arguments args,
1037
                         int required = 1)
1038
53
{
1039
53
  return CheckPathParametersEx(eval, cnt, option, args.size(), required);
1040
53
};
1041
1042
std::string ToString(bool isTrue)
1043
0
{
1044
0
  return isTrue ? "1" : "0";
1045
0
};
1046
}
1047
1048
static const struct PathNode : public cmGeneratorExpressionNode
1049
{
1050
10
  PathNode() {} // NOLINT(modernize-use-equals-default)
1051
1052
125
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
1053
1054
125
  bool AcceptsArbitraryContentParameter() const override { return true; }
1055
1056
  std::string Evaluate(
1057
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
1058
    GeneratorExpressionContent const* content,
1059
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1060
104
  {
1061
104
    static auto processList =
1062
104
      [](std::string const& arg,
1063
104
         std::function<void(std::string&)> transform) -> std::string {
1064
47
      cmList list{ arg };
1065
47
      std::for_each(list.begin(), list.end(), std::move(transform));
1066
47
      return list.to_string();
1067
47
    };
1068
1069
104
    static std::unordered_map<
1070
104
      cm::string_view,
1071
104
      std::function<std::string(cm::GenEx::Evaluation*,
1072
104
                                GeneratorExpressionContent const*,
1073
104
                                Arguments&)>>
1074
104
      pathCommands{
1075
104
        { "GET_ROOT_NAME"_s,
1076
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1077
104
             Arguments& args) -> std::string {
1078
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_NAME"_s, args) &&
1079
0
                !args.front().empty()) {
1080
0
              return processList(args.front(), [](std::string& value) {
1081
0
                value = cmCMakePath{ value }.GetRootName().String();
1082
0
              });
1083
0
            }
1084
0
            return std::string{};
1085
0
          } },
1086
104
        { "GET_ROOT_DIRECTORY"_s,
1087
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1088
104
             Arguments& args) -> std::string {
1089
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_DIRECTORY"_s, args) &&
1090
0
                !args.front().empty()) {
1091
0
              return processList(args.front(), [](std::string& value) {
1092
0
                value = cmCMakePath{ value }.GetRootDirectory().String();
1093
0
              });
1094
0
            }
1095
0
            return std::string{};
1096
0
          } },
1097
104
        { "GET_ROOT_PATH"_s,
1098
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1099
104
             Arguments& args) -> std::string {
1100
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_PATH"_s, args) &&
1101
0
                !args.front().empty()) {
1102
0
              return processList(args.front(), [](std::string& value) {
1103
0
                value = cmCMakePath{ value }.GetRootPath().String();
1104
0
              });
1105
0
            }
1106
0
            return std::string{};
1107
0
          } },
1108
104
        { "GET_FILENAME"_s,
1109
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1110
104
             Arguments& args) -> std::string {
1111
12
            if (CheckPathParameters(ev, cnt, "GET_FILENAME"_s, args) &&
1112
9
                !args.front().empty()) {
1113
9
              return processList(args.front(), [](std::string& value) {
1114
9
                value = cmCMakePath{ value }.GetFileName().String();
1115
9
              });
1116
9
            }
1117
3
            return std::string{};
1118
12
          } },
1119
104
        { "GET_EXTENSION"_s,
1120
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1121
104
             Arguments& args) -> std::string {
1122
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1123
0
            if (lastOnly) {
1124
0
              args.advance(1);
1125
0
            }
1126
0
            if (CheckPathParametersEx(ev, cnt,
1127
0
                                      lastOnly ? "GET_EXTENSION,LAST_ONLY"_s
1128
0
                                               : "GET_EXTENSION"_s,
1129
0
                                      args.size())) {
1130
0
              if (args.front().empty()) {
1131
0
                return std::string{};
1132
0
              }
1133
0
              if (lastOnly) {
1134
0
                return processList(args.front(), [](std::string& value) {
1135
0
                  value = cmCMakePath{ value }.GetExtension().String();
1136
0
                });
1137
0
              }
1138
0
              return processList(args.front(), [](std::string& value) {
1139
0
                value = cmCMakePath{ value }.GetWideExtension().String();
1140
0
              });
1141
0
            }
1142
0
            return std::string{};
1143
0
          } },
1144
104
        { "GET_STEM"_s,
1145
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1146
104
             Arguments& args) -> std::string {
1147
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1148
0
            if (lastOnly) {
1149
0
              args.advance(1);
1150
0
            }
1151
0
            if (CheckPathParametersEx(
1152
0
                  ev, cnt, lastOnly ? "GET_STEM,LAST_ONLY"_s : "GET_STEM"_s,
1153
0
                  args.size())) {
1154
0
              if (args.front().empty()) {
1155
0
                return std::string{};
1156
0
              }
1157
0
              if (lastOnly) {
1158
0
                return processList(args.front(), [](std::string& value) {
1159
0
                  value = cmCMakePath{ value }.GetStem().String();
1160
0
                });
1161
0
              }
1162
0
              return processList(args.front(), [](std::string& value) {
1163
0
                value = cmCMakePath{ value }.GetNarrowStem().String();
1164
0
              });
1165
0
            }
1166
0
            return std::string{};
1167
0
          } },
1168
104
        { "GET_RELATIVE_PART"_s,
1169
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1170
104
             Arguments& args) -> std::string {
1171
0
            if (CheckPathParameters(ev, cnt, "GET_RELATIVE_PART"_s, args) &&
1172
0
                !args.front().empty()) {
1173
0
              return processList(args.front(), [](std::string& value) {
1174
0
                value = cmCMakePath{ value }.GetRelativePath().String();
1175
0
              });
1176
0
            }
1177
0
            return std::string{};
1178
0
          } },
1179
104
        { "GET_PARENT_PATH"_s,
1180
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1181
104
             Arguments& args) -> std::string {
1182
0
            if (CheckPathParameters(ev, cnt, "GET_PARENT_PATH"_s, args)) {
1183
0
              return processList(args.front(), [](std::string& value) {
1184
0
                value = cmCMakePath{ value }.GetParentPath().String();
1185
0
              });
1186
0
            }
1187
0
            return std::string{};
1188
0
          } },
1189
104
        { "HAS_ROOT_NAME"_s,
1190
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1191
104
             Arguments& args) -> std::string {
1192
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_NAME"_s, args)
1193
0
              ? ToString(cmCMakePath{ args.front() }.HasRootName())
1194
0
              : std::string{ "0" };
1195
0
          } },
1196
104
        { "HAS_ROOT_DIRECTORY"_s,
1197
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1198
104
             Arguments& args) -> std::string {
1199
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_DIRECTORY"_s, args)
1200
0
              ? ToString(cmCMakePath{ args.front() }.HasRootDirectory())
1201
0
              : std::string{ "0" };
1202
0
          } },
1203
104
        { "HAS_ROOT_PATH"_s,
1204
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1205
104
             Arguments& args) -> std::string {
1206
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_PATH"_s, args)
1207
0
              ? ToString(cmCMakePath{ args.front() }.HasRootPath())
1208
0
              : std::string{ "0" };
1209
0
          } },
1210
104
        { "HAS_FILENAME"_s,
1211
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1212
104
             Arguments& args) -> std::string {
1213
0
            return CheckPathParameters(ev, cnt, "HAS_FILENAME"_s, args)
1214
0
              ? ToString(cmCMakePath{ args.front() }.HasFileName())
1215
0
              : std::string{ "0" };
1216
0
          } },
1217
104
        { "HAS_EXTENSION"_s,
1218
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1219
104
             Arguments& args) -> std::string {
1220
0
            return CheckPathParameters(ev, cnt, "HAS_EXTENSION"_s, args) &&
1221
0
                !args.front().empty()
1222
0
              ? ToString(cmCMakePath{ args.front() }.HasExtension())
1223
0
              : std::string{ "0" };
1224
0
          } },
1225
104
        { "HAS_STEM"_s,
1226
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1227
104
             Arguments& args) -> std::string {
1228
0
            return CheckPathParameters(ev, cnt, "HAS_STEM"_s, args)
1229
0
              ? ToString(cmCMakePath{ args.front() }.HasStem())
1230
0
              : std::string{ "0" };
1231
0
          } },
1232
104
        { "HAS_RELATIVE_PART"_s,
1233
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1234
104
             Arguments& args) -> std::string {
1235
0
            return CheckPathParameters(ev, cnt, "HAS_RELATIVE_PART"_s, args)
1236
0
              ? ToString(cmCMakePath{ args.front() }.HasRelativePath())
1237
0
              : std::string{ "0" };
1238
0
          } },
1239
104
        { "HAS_PARENT_PATH"_s,
1240
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1241
104
             Arguments& args) -> std::string {
1242
0
            return CheckPathParameters(ev, cnt, "HAS_PARENT_PATH"_s, args)
1243
0
              ? ToString(cmCMakePath{ args.front() }.HasParentPath())
1244
0
              : std::string{ "0" };
1245
0
          } },
1246
104
        { "IS_ABSOLUTE"_s,
1247
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1248
104
             Arguments& args) -> std::string {
1249
0
            return CheckPathParameters(ev, cnt, "IS_ABSOLUTE"_s, args)
1250
0
              ? ToString(cmCMakePath{ args.front() }.IsAbsolute())
1251
0
              : std::string{ "0" };
1252
0
          } },
1253
104
        { "IS_RELATIVE"_s,
1254
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1255
104
             Arguments& args) -> std::string {
1256
0
            return CheckPathParameters(ev, cnt, "IS_RELATIVE"_s, args)
1257
0
              ? ToString(cmCMakePath{ args.front() }.IsRelative())
1258
0
              : std::string{ "0" };
1259
0
          } },
1260
104
        { "IS_PREFIX"_s,
1261
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1262
104
             Arguments& args) -> std::string {
1263
0
            bool normalize = args.front() == "NORMALIZE"_s;
1264
0
            if (normalize) {
1265
0
              args.advance(1);
1266
0
            }
1267
0
            if (CheckPathParametersEx(
1268
0
                  ev, cnt, normalize ? "IS_PREFIX,NORMALIZE"_s : "IS_PREFIX"_s,
1269
0
                  args.size(), 2)) {
1270
0
              cmCMakePath prefix{ args[0] };
1271
0
              cmCMakePath value{ args[1] };
1272
0
              if (normalize) {
1273
0
                prefix = prefix.Normal();
1274
0
                value = value.Normal();
1275
0
              }
1276
0
              return ToString(prefix.IsPrefix(value) ||
1277
0
                              IsPrefixCMP0223(prefix, ev));
1278
0
            }
1279
0
            return std::string{};
1280
0
          } },
1281
104
        { "CMAKE_PATH"_s,
1282
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1283
104
             Arguments& args) -> std::string {
1284
0
            bool normalize = args.front() == "NORMALIZE"_s;
1285
0
            if (normalize) {
1286
0
              args.advance(1);
1287
0
            }
1288
0
            if (CheckPathParametersEx(ev, cnt,
1289
0
                                      normalize ? "CMAKE_PATH,NORMALIZE"_s
1290
0
                                                : "CMAKE_PATH"_s,
1291
0
                                      args.size(), 1)) {
1292
0
              return processList(
1293
0
                args.front(), [normalize](std::string& value) {
1294
0
                  auto path = cmCMakePath{ value, cmCMakePath::auto_format };
1295
0
                  value = normalize ? path.Normal().GenericString()
1296
0
                                    : path.GenericString();
1297
0
                });
1298
0
            }
1299
0
            return std::string{};
1300
0
          } },
1301
104
        { "NATIVE_PATH"_s,
1302
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1303
104
             Arguments& args) -> std::string {
1304
0
            bool normalize = args.front() == "NORMALIZE"_s;
1305
0
            if (normalize) {
1306
0
              args.advance(1);
1307
0
            }
1308
0
            if (CheckPathParametersEx(ev, cnt,
1309
0
                                      normalize ? "NATIVE_PATH,NORMALIZE"_s
1310
0
                                                : "NATIVE_PATH"_s,
1311
0
                                      args.size(), 1)) {
1312
0
              return processList(
1313
0
                args.front(), [normalize](std::string& value) {
1314
0
                  auto path = cmCMakePath{ value };
1315
0
                  value = normalize ? path.Normal().NativeString()
1316
0
                                    : path.NativeString();
1317
0
                });
1318
0
            }
1319
0
            return std::string{};
1320
0
          } },
1321
104
        { "APPEND"_s,
1322
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1323
104
             Arguments& args) -> std::string {
1324
0
            if (CheckPathParametersEx(ev, cnt, "APPEND"_s, args.size(), 1,
1325
0
                                      false)) {
1326
0
              auto const& list = args.front();
1327
0
              args.advance(1);
1328
1329
0
              return processList(list, [&args](std::string& value) {
1330
0
                cmCMakePath path{ value };
1331
0
                for (auto const& p : args) {
1332
0
                  path /= p;
1333
0
                }
1334
0
                value = path.String();
1335
0
              });
1336
0
            }
1337
0
            return std::string{};
1338
0
          } },
1339
104
        { "REMOVE_FILENAME"_s,
1340
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1341
104
             Arguments& args) -> std::string {
1342
0
            if (CheckPathParameters(ev, cnt, "REMOVE_FILENAME"_s, args) &&
1343
0
                !args.front().empty()) {
1344
0
              return processList(args.front(), [](std::string& value) {
1345
0
                value = cmCMakePath{ value }.RemoveFileName().String();
1346
0
              });
1347
0
            }
1348
0
            return std::string{};
1349
0
          } },
1350
104
        { "REPLACE_FILENAME"_s,
1351
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1352
104
             Arguments& args) -> std::string {
1353
0
            if (CheckPathParameters(ev, cnt, "REPLACE_FILENAME"_s, args, 2)) {
1354
0
              return processList(args.front(), [&args](std::string& value) {
1355
0
                value = cmCMakePath{ value }
1356
0
                          .ReplaceFileName(cmCMakePath{ args[1] })
1357
0
                          .String();
1358
0
              });
1359
0
            }
1360
0
            return std::string{};
1361
0
          } },
1362
104
        { "REMOVE_EXTENSION"_s,
1363
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1364
104
             Arguments& args) -> std::string {
1365
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1366
0
            if (lastOnly) {
1367
0
              args.advance(1);
1368
0
            }
1369
0
            if (CheckPathParametersEx(ev, cnt,
1370
0
                                      lastOnly ? "REMOVE_EXTENSION,LAST_ONLY"_s
1371
0
                                               : "REMOVE_EXTENSION"_s,
1372
0
                                      args.size())) {
1373
0
              if (args.front().empty()) {
1374
0
                return std::string{};
1375
0
              }
1376
0
              if (lastOnly) {
1377
0
                return processList(args.front(), [](std::string& value) {
1378
0
                  value = cmCMakePath{ value }.RemoveExtension().String();
1379
0
                });
1380
0
              }
1381
0
              return processList(args.front(), [](std::string& value) {
1382
0
                value = cmCMakePath{ value }.RemoveWideExtension().String();
1383
0
              });
1384
0
            }
1385
0
            return std::string{};
1386
0
          } },
1387
104
        { "REPLACE_EXTENSION"_s,
1388
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1389
104
             Arguments& args) -> std::string {
1390
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1391
0
            if (lastOnly) {
1392
0
              args.advance(1);
1393
0
            }
1394
0
            if (CheckPathParametersEx(ev, cnt,
1395
0
                                      lastOnly
1396
0
                                        ? "REPLACE_EXTENSION,LAST_ONLY"_s
1397
0
                                        : "REPLACE_EXTENSION"_s,
1398
0
                                      args.size(), 2)) {
1399
0
              if (lastOnly) {
1400
0
                return processList(args.front(), [&args](std::string& value) {
1401
0
                  value = cmCMakePath{ value }
1402
0
                            .ReplaceExtension(cmCMakePath{ args[1] })
1403
0
                            .String();
1404
0
                });
1405
0
              }
1406
0
              return processList(args.front(), [&args](std::string& value) {
1407
0
                value = cmCMakePath{ value }
1408
0
                          .ReplaceWideExtension(cmCMakePath{ args[1] })
1409
0
                          .String();
1410
0
              });
1411
0
            }
1412
0
            return std::string{};
1413
0
          } },
1414
104
        { "NORMAL_PATH"_s,
1415
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1416
104
             Arguments& args) -> std::string {
1417
0
            if (CheckPathParameters(ev, cnt, "NORMAL_PATH"_s, args) &&
1418
0
                !args.front().empty()) {
1419
0
              return processList(args.front(), [](std::string& value) {
1420
0
                value = cmCMakePath{ value }.Normal().String();
1421
0
              });
1422
0
            }
1423
0
            return std::string{};
1424
0
          } },
1425
104
        { "RELATIVE_PATH"_s,
1426
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1427
104
             Arguments& args) -> std::string {
1428
41
            if (CheckPathParameters(ev, cnt, "RELATIVE_PATH"_s, args, 2)) {
1429
38
              return processList(args.front(), [&args](std::string& value) {
1430
38
                value = cmCMakePath{ value }.Relative(args[1]).String();
1431
38
              });
1432
38
            }
1433
3
            return std::string{};
1434
41
          } },
1435
104
        { "ABSOLUTE_PATH"_s,
1436
104
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1437
104
             Arguments& args) -> std::string {
1438
0
            bool normalize = args.front() == "NORMALIZE"_s;
1439
0
            if (normalize) {
1440
0
              args.advance(1);
1441
0
            }
1442
0
            if (CheckPathParametersEx(ev, cnt,
1443
0
                                      normalize ? "ABSOLUTE_PATH,NORMALIZE"_s
1444
0
                                                : "ABSOLUTE_PATH"_s,
1445
0
                                      args.size(), 2)) {
1446
0
              return processList(
1447
0
                args.front(), [&args, normalize](std::string& value) {
1448
0
                  auto path = cmCMakePath{ value }.Absolute(args[1]);
1449
0
                  value = normalize ? path.Normal().String() : path.String();
1450
0
                });
1451
0
            }
1452
0
            return std::string{};
1453
0
          } }
1454
104
      };
1455
1456
104
    if (cm::contains(pathCommands, parameters.front())) {
1457
53
      auto args = Arguments{ parameters }.advance(1);
1458
53
      return pathCommands[parameters.front()](eval, content, args);
1459
53
    }
1460
1461
51
    reportError(eval, content->GetOriginalExpression(),
1462
51
                cmStrCat(parameters.front(), ": invalid option."));
1463
51
    return std::string{};
1464
104
  }
1465
} pathNode;
1466
1467
static const struct PathEqualNode : public cmGeneratorExpressionNode
1468
{
1469
10
  PathEqualNode() {} // NOLINT(modernize-use-equals-default)
1470
1471
15
  int NumExpectedParameters() const override { return 2; }
1472
1473
  std::string Evaluate(
1474
    std::vector<std::string> const& parameters,
1475
    cm::GenEx::Evaluation* /*eval*/,
1476
    GeneratorExpressionContent const* /*content*/,
1477
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1478
12
  {
1479
12
    return cmCMakePath{ parameters[0] } == cmCMakePath{ parameters[1] } ? "1"
1480
12
                                                                        : "0";
1481
12
  }
1482
} pathEqualNode;
1483
1484
namespace {
1485
inline bool CheckStringParametersEx(cm::GenEx::Evaluation* eval,
1486
                                    GeneratorExpressionContent const* cnt,
1487
                                    cm::string_view option, std::size_t count,
1488
                                    int required = 1, bool exactly = true)
1489
178
{
1490
178
  return CheckGenExParameters(eval, cnt, "STRING"_s, option, count, required,
1491
178
                              exactly);
1492
178
}
1493
inline bool CheckStringParameters(cm::GenEx::Evaluation* eval,
1494
                                  GeneratorExpressionContent const* cnt,
1495
                                  cm::string_view option, Arguments args,
1496
                                  int required = 1)
1497
0
{
1498
0
  return CheckStringParametersEx(eval, cnt, option, args.size(), required);
1499
0
};
1500
}
1501
1502
static const struct StringNode : public cmGeneratorExpressionNode
1503
{
1504
10
  StringNode() {} // NOLINT(modernize-use-equals-default)
1505
1506
273
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
1507
1508
273
  bool AcceptsArbitraryContentParameter() const override { return true; }
1509
1510
  std::string Evaluate(
1511
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
1512
    GeneratorExpressionContent const* content,
1513
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1514
260
  {
1515
260
    static std::unordered_map<
1516
260
      cm::string_view,
1517
260
      std::function<std::string(cm::GenEx::Evaluation*,
1518
260
                                GeneratorExpressionContent const*,
1519
260
                                Arguments&)>>
1520
260
      stringCommands{
1521
260
        { "LENGTH"_s,
1522
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1523
260
             Arguments& args) -> std::string {
1524
0
            if (CheckStringParameters(ev, cnt, "LENGTH"_s, args)) {
1525
0
              return std::to_string(cm::CMakeString{ args.front() }.Length());
1526
0
            }
1527
0
            return std::string{};
1528
0
          } },
1529
260
        { "SUBSTRING"_s,
1530
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1531
260
             Arguments& args) -> std::string {
1532
0
            if (CheckStringParameters(ev, cnt, "SUBSTRING"_s, args, 3)) {
1533
0
              cm::CMakeString str{ args.front() };
1534
0
              std::vector<long> indexes;
1535
0
              if (GetNumericArguments(ev, cnt, args.advance(1), indexes)) {
1536
0
                try {
1537
0
                  return str.Substring(indexes.front(), indexes.back());
1538
0
                } catch (std::out_of_range const& e) {
1539
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
1540
0
                  return std::string{};
1541
0
                }
1542
0
              }
1543
0
            }
1544
0
            return std::string{};
1545
0
          } },
1546
260
        { "FIND"_s,
1547
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1548
260
             Arguments& args) -> std::string {
1549
0
            if (CheckStringParametersEx(ev, cnt, "FIND"_s, args.size(), 2,
1550
0
                                        false)) {
1551
0
              if (args.size() > 3) {
1552
0
                reportError(ev, cnt->GetOriginalExpression(),
1553
0
                            "$<STRING:FIND> expression expects at "
1554
0
                            "most three parameters.");
1555
0
                return std::string{};
1556
0
              }
1557
1558
0
              auto const FROM = "FROM:"_s;
1559
1560
0
              cm::CMakeString str{ args.front() };
1561
0
              cm::CMakeString::FindFrom from =
1562
0
                cm::CMakeString::FindFrom::Begin;
1563
0
              cm::string_view substring;
1564
1565
0
              args.advance(1);
1566
0
              if (args.size() == 2) {
1567
0
                cm::CMakeString::FindFrom opt =
1568
0
                  static_cast<cm::CMakeString::FindFrom>(-1);
1569
1570
0
                for (auto const& arg : args) {
1571
0
                  if (cmHasPrefix(arg, FROM)) {
1572
0
                    if (arg != "FROM:BEGIN"_s && arg != "FROM:END"_s) {
1573
0
                      reportError(
1574
0
                        ev, cnt->GetOriginalExpression(),
1575
0
                        cmStrCat("Invalid value for '", FROM,
1576
0
                                 "' option. 'BEGIN' or 'END' expected."));
1577
0
                      return std::string{};
1578
0
                    }
1579
0
                    opt = arg == "FROM:BEGIN"_s
1580
0
                      ? cm::CMakeString::FindFrom::Begin
1581
0
                      : cm::CMakeString::FindFrom::End;
1582
0
                  } else {
1583
0
                    substring = arg;
1584
0
                  }
1585
0
                }
1586
0
                if (opt == static_cast<cm::CMakeString::FindFrom>(-1)) {
1587
0
                  reportError(
1588
0
                    ev, cnt->GetOriginalExpression(),
1589
0
                    cmStrCat("Expected option '", FROM, "' is missing."));
1590
0
                  return std::string{};
1591
0
                }
1592
0
                from = opt;
1593
0
              } else {
1594
0
                substring = args.front();
1595
0
              }
1596
0
              auto pos = str.Find(substring, from);
1597
0
              return pos == cm::CMakeString::npos ? "-1" : std::to_string(pos);
1598
0
            }
1599
0
            return std::string{};
1600
0
          } },
1601
260
        { "MATCH"_s,
1602
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1603
260
             Arguments& args) -> std::string {
1604
0
            if (CheckStringParametersEx(ev, cnt, "MATCH"_s, args.size(), 2,
1605
0
                                        false)) {
1606
0
              if (args.size() > 3) {
1607
0
                reportError(ev, cnt->GetOriginalExpression(),
1608
0
                            "$<STRING:MATCH> expression expects at "
1609
0
                            "most three parameters.");
1610
0
                return std::string{};
1611
0
              }
1612
1613
0
              auto const SEEK = "SEEK:"_s;
1614
1615
0
              cm::CMakeString str{ args.front() };
1616
0
              cm::CMakeString::MatchItems seek =
1617
0
                cm::CMakeString::MatchItems::Once;
1618
0
              auto const* regex = &args[1];
1619
1620
0
              args.advance(1);
1621
0
              if (args.size() == 2) {
1622
0
                cm::CMakeString::MatchItems opt =
1623
0
                  static_cast<cm::CMakeString::MatchItems>(-1);
1624
1625
0
                for (auto const& arg : args) {
1626
0
                  if (cmHasPrefix(arg, SEEK)) {
1627
0
                    if (arg != "SEEK:ONCE"_s && arg != "SEEK:ALL"_s) {
1628
0
                      reportError(
1629
0
                        ev, cnt->GetOriginalExpression(),
1630
0
                        cmStrCat("Invalid value for '", SEEK,
1631
0
                                 "' option. 'ONCE' or 'ALL' expected."));
1632
0
                      return std::string{};
1633
0
                    }
1634
0
                    opt = arg == "SEEK:ONCE"_s
1635
0
                      ? cm::CMakeString::MatchItems::Once
1636
0
                      : cm::CMakeString::MatchItems::All;
1637
0
                  } else {
1638
0
                    regex = &arg;
1639
0
                  }
1640
0
                }
1641
0
                if (opt == static_cast<cm::CMakeString::MatchItems>(-1)) {
1642
0
                  reportError(
1643
0
                    ev, cnt->GetOriginalExpression(),
1644
0
                    cmStrCat("Expected option '", SEEK, "' is missing."));
1645
0
                  return std::string{};
1646
0
                }
1647
0
                seek = opt;
1648
0
              }
1649
1650
0
              try {
1651
0
                return str.Match(*regex, seek).to_string();
1652
0
              } catch (std::invalid_argument const& e) {
1653
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1654
0
                return std::string{};
1655
0
              }
1656
0
            }
1657
0
            return std::string{};
1658
0
          } },
1659
260
        { "JOIN"_s,
1660
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1661
260
             Arguments& args) -> std::string {
1662
0
            if (CheckStringParametersEx(ev, cnt, "JOIN"_s, args.size(), 2,
1663
0
                                        false)) {
1664
0
              auto const& glue = args.front();
1665
0
              return cm::CMakeString{ args.advance(1), glue };
1666
0
            }
1667
0
            return std::string{};
1668
0
          } },
1669
260
        { "ASCII"_s,
1670
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1671
260
             Arguments& args) -> std::string {
1672
0
            if (CheckStringParametersEx(ev, cnt, "ASCII"_s, args.size(), 1,
1673
0
                                        false)) {
1674
0
              try {
1675
0
                return cm::CMakeString{}.FromASCII(args);
1676
0
              } catch (std::invalid_argument const& e) {
1677
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1678
0
                return std::string{};
1679
0
              }
1680
0
            }
1681
0
            return std::string{};
1682
0
          } },
1683
260
        { "TIMESTAMP"_s,
1684
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1685
260
             Arguments& args) -> std::string {
1686
0
            cm::string_view format;
1687
0
            cm::CMakeString::UTC utc = cm::CMakeString::UTC::No;
1688
1689
0
            if (args.size() == 2 && args.front() != "UTC"_s &&
1690
0
                args.back() != "UTC"_s) {
1691
0
              reportError(ev, cnt->GetOriginalExpression(),
1692
0
                          "'UTC' option is expected.");
1693
0
              return std::string{};
1694
0
            }
1695
0
            if (args.size() > 2) {
1696
0
              reportError(ev, cnt->GetOriginalExpression(),
1697
0
                          "$<STRING:TIMESTAMP> expression expects at most two "
1698
0
                          "parameters.");
1699
0
              return std::string{};
1700
0
            }
1701
1702
0
            for (auto const& arg : args) {
1703
0
              if (arg == "UTC"_s) {
1704
0
                utc = cm::CMakeString::UTC::Yes;
1705
0
              } else {
1706
0
                format = arg;
1707
0
              }
1708
0
            }
1709
0
            return cm::CMakeString{}.Timestamp(format, utc);
1710
0
          } },
1711
260
        { "RANDOM"_s,
1712
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1713
260
             Arguments& args) -> std::string {
1714
0
            auto const ALPHABET = "ALPHABET:"_s;
1715
0
            auto const LENGTH = "LENGTH:"_s;
1716
0
            auto const RANDOM_SEED = "RANDOM_SEED:"_s;
1717
1718
0
            if (args.size() > 3) {
1719
0
              reportError(ev, cnt->GetOriginalExpression(),
1720
0
                          "$<STRING:RANDOM> expression expects at most three "
1721
0
                          "parameters.");
1722
0
              return std::string{};
1723
0
            }
1724
1725
0
            cm::string_view alphabet;
1726
0
            std::size_t length = 5;
1727
0
            bool seed_specified = false;
1728
0
            unsigned int seed = 0;
1729
0
            for (auto const& arg : args) {
1730
0
              if (cmHasPrefix(arg, ALPHABET)) {
1731
0
                alphabet = cm::string_view{ arg.c_str() + ALPHABET.length() };
1732
0
                continue;
1733
0
              }
1734
0
              if (cmHasPrefix(arg, LENGTH)) {
1735
0
                try {
1736
0
                  length = std::stoul(arg.substr(LENGTH.size()));
1737
0
                } catch (std::exception const&) {
1738
0
                  reportError(ev, cnt->GetOriginalExpression(),
1739
0
                              cmStrCat(arg, ": invalid numeric value for '",
1740
0
                                       LENGTH, "' option."));
1741
0
                  return std::string{};
1742
0
                }
1743
0
                continue;
1744
0
              }
1745
0
              if (cmHasPrefix(arg, RANDOM_SEED)) {
1746
0
                try {
1747
0
                  seed_specified = true;
1748
0
                  seed = static_cast<unsigned int>(
1749
0
                    std::stoul(arg.substr(RANDOM_SEED.size())));
1750
0
                } catch (std::exception const&) {
1751
0
                  reportError(ev, cnt->GetOriginalExpression(),
1752
0
                              cmStrCat(arg, ": invalid numeric value for '",
1753
0
                                       RANDOM_SEED, "' option."));
1754
0
                  return std::string{};
1755
0
                }
1756
0
                continue;
1757
0
              }
1758
0
              reportError(ev, cnt->GetOriginalExpression(),
1759
0
                          cmStrCat(arg, ": invalid parameter."));
1760
0
              return std::string{};
1761
0
            }
1762
1763
0
            try {
1764
0
              if (seed_specified) {
1765
0
                return cm::CMakeString{}.Random(seed, length, alphabet);
1766
0
              }
1767
0
              return cm::CMakeString{}.Random(length, alphabet);
1768
0
            } catch (std::exception const& e) {
1769
0
              reportError(ev, cnt->GetOriginalExpression(), e.what());
1770
0
              return std::string{};
1771
0
            }
1772
0
          } },
1773
260
        { "UUID"_s,
1774
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1775
260
             Arguments& args) -> std::string {
1776
0
            if (CheckStringParametersEx(ev, cnt, "UUID"_s, args.size(), 2,
1777
0
                                        false)) {
1778
0
              auto const NAMESPACE = "NAMESPACE:"_s;
1779
0
              auto const NAME = "NAME:"_s;
1780
0
              auto const TYPE = "TYPE:"_s;
1781
0
              auto const CASE = "CASE:"_s;
1782
1783
0
              if (args.size() > 4) {
1784
0
                reportError(ev, cnt->GetOriginalExpression(),
1785
0
                            "$<STRING:UUID> expression expects at most four "
1786
0
                            "parameters.");
1787
0
                return std::string{};
1788
0
              }
1789
1790
0
              cm::string_view nameSpace;
1791
0
              cm::string_view name;
1792
0
              cm::CMakeString::UUIDType type =
1793
0
                static_cast<cm::CMakeString::UUIDType>(-1);
1794
0
              cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower;
1795
0
              for (auto const& arg : args) {
1796
0
                if (cmHasPrefix(arg, NAMESPACE)) {
1797
0
                  nameSpace =
1798
0
                    cm::string_view{ arg.c_str() + NAMESPACE.length() };
1799
0
                  if (nameSpace.empty()) {
1800
0
                    reportError(
1801
0
                      ev, cnt->GetOriginalExpression(),
1802
0
                      cmStrCat("Invalid value for '", NAMESPACE, "' option."));
1803
0
                    return std::string{};
1804
0
                  }
1805
0
                  continue;
1806
0
                }
1807
0
                if (cmHasPrefix(arg, NAME)) {
1808
0
                  name = cm::string_view{ arg.c_str() + NAME.length() };
1809
0
                  continue;
1810
0
                }
1811
0
                if (cmHasPrefix(arg, TYPE)) {
1812
0
                  auto value = cm::string_view{ arg.c_str() + TYPE.length() };
1813
0
                  if (value != "MD5"_s && value != "SHA1"_s) {
1814
0
                    reportError(
1815
0
                      ev, cnt->GetOriginalExpression(),
1816
0
                      cmStrCat("Invalid value for '", TYPE,
1817
0
                               "' option. 'MD5' or 'SHA1' expected."));
1818
0
                    return std::string{};
1819
0
                  }
1820
0
                  type = value == "MD5"_s ? cm::CMakeString::UUIDType::MD5
1821
0
                                          : cm::CMakeString::UUIDType::SHA1;
1822
0
                  continue;
1823
0
                }
1824
0
                if (cmHasPrefix(arg, CASE)) {
1825
0
                  auto value = cm::string_view{ arg.c_str() + CASE.length() };
1826
0
                  if (value != "UPPER"_s && value != "LOWER"_s) {
1827
0
                    reportError(
1828
0
                      ev, cnt->GetOriginalExpression(),
1829
0
                      cmStrCat("Invalid value for '", CASE,
1830
0
                               "' option. 'UPPER' or 'LOWER' expected."));
1831
0
                    return std::string{};
1832
0
                  }
1833
0
                  uuidCase = value == "UPPER"_s ? cm::CMakeString::Case::Upper
1834
0
                                                : cm::CMakeString::Case::Lower;
1835
0
                  continue;
1836
0
                }
1837
0
                reportError(ev, cnt->GetOriginalExpression(),
1838
0
                            cmStrCat(arg, ": invalid parameter."));
1839
0
                return std::string{};
1840
0
              }
1841
0
              if (nameSpace.empty()) {
1842
0
                reportError(
1843
0
                  ev, cnt->GetOriginalExpression(),
1844
0
                  cmStrCat("Required option '", NAMESPACE, "' is missing."));
1845
0
                return std::string{};
1846
0
              }
1847
0
              if (type == static_cast<cm::CMakeString::UUIDType>(-1)) {
1848
0
                reportError(
1849
0
                  ev, cnt->GetOriginalExpression(),
1850
0
                  cmStrCat("Required option '", TYPE, "' is missing."));
1851
0
                return std::string{};
1852
0
              }
1853
1854
0
              try {
1855
0
                return cm::CMakeString{}.UUID(nameSpace, name, type, uuidCase);
1856
0
              } catch (std::exception const& e) {
1857
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1858
0
                return std::string{};
1859
0
              }
1860
0
            }
1861
0
            return std::string{};
1862
0
          } },
1863
260
        { "REPLACE"_s,
1864
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1865
260
             Arguments& args) -> std::string {
1866
178
            if (CheckStringParametersEx(ev, cnt, "REPLACE"_s, args.size(), 3,
1867
178
                                        false)) {
1868
171
              if (args.size() > 4) {
1869
13
                reportError(ev, cnt->GetOriginalExpression(),
1870
13
                            "$<STRING:REPLACE> expression expects at "
1871
13
                            "most four parameters.");
1872
13
                return std::string{};
1873
13
              }
1874
1875
158
              cm::CMakeString::Regex isRegex = cm::CMakeString::Regex::No;
1876
158
              if (args.size() == 4) {
1877
7
                cm::string_view type = args.front();
1878
7
                if (type != "STRING"_s && type != "REGEX"_s) {
1879
7
                  reportError(
1880
7
                    ev, cnt->GetOriginalExpression(),
1881
7
                    cmStrCat(
1882
7
                      '\'', type,
1883
7
                      "' is unexpected. 'STRING' or 'REGEX' expected."));
1884
7
                  return std::string{};
1885
7
                }
1886
0
                isRegex = type == "STRING"_s ? cm::CMakeString::Regex::No
1887
0
                                             : cm::CMakeString::Regex::Yes;
1888
0
                args.advance(1);
1889
0
              }
1890
1891
151
              try {
1892
151
                return cm::CMakeString{ args.front() }.Replace(
1893
151
                  args[1], args[2], isRegex);
1894
151
              } catch (std::invalid_argument const& e) {
1895
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1896
0
                return std::string{};
1897
0
              }
1898
151
            }
1899
7
            return std::string{};
1900
178
          } },
1901
260
        { "APPEND"_s,
1902
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1903
260
             Arguments& args) -> std::string {
1904
0
            if (CheckStringParametersEx(ev, cnt, "APPEND"_s, args.size(), 2,
1905
0
                                        false)) {
1906
0
              cm::CMakeString data{ args.front() };
1907
0
              return data.Append(args.advance(1));
1908
0
            }
1909
0
            return std::string{};
1910
0
          } },
1911
260
        { "PREPEND"_s,
1912
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1913
260
             Arguments& args) -> std::string {
1914
0
            if (CheckStringParametersEx(ev, cnt, "PREPEND "_s, args.size(), 2,
1915
0
                                        false)) {
1916
0
              cm::CMakeString data{ args.front() };
1917
0
              return data.Prepend(args.advance(1));
1918
0
            }
1919
0
            return std::string{};
1920
0
          } },
1921
260
        { "TOLOWER"_s,
1922
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1923
260
             Arguments& args) -> std::string {
1924
0
            if (CheckStringParameters(ev, cnt, "TOLOWER"_s, args, 1)) {
1925
0
              return cm::CMakeString{}.ToLower(args.front());
1926
0
            }
1927
0
            return std::string{};
1928
0
          } },
1929
260
        { "TOUPPER"_s,
1930
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1931
260
             Arguments& args) -> std::string {
1932
0
            if (CheckStringParameters(ev, cnt, "TOUPPER"_s, args, 1)) {
1933
0
              return cm::CMakeString{}.ToUpper(args.front());
1934
0
            }
1935
0
            return std::string{};
1936
0
          } },
1937
260
        { "STRIP"_s,
1938
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1939
260
             Arguments& args) -> std::string {
1940
0
            if (CheckStringParameters(ev, cnt, "STRIP"_s, args, 2)) {
1941
0
              if (args.front() != "SPACES"_s) {
1942
0
                reportError(ev, cnt->GetOriginalExpression(),
1943
0
                            cmStrCat('\'', args.front(),
1944
0
                                     "' is unexpected. 'SPACES' expected."));
1945
0
                return std::string{};
1946
0
              }
1947
1948
0
              return cm::CMakeString{ args[1] }.Strip();
1949
0
            }
1950
0
            return std::string{};
1951
0
          } },
1952
260
        { "QUOTE"_s,
1953
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1954
260
             Arguments& args) -> std::string {
1955
0
            if (CheckStringParameters(ev, cnt, "QUOTE"_s, args, 2)) {
1956
0
              if (args.front() != "REGEX"_s) {
1957
0
                reportError(ev, cnt->GetOriginalExpression(),
1958
0
                            cmStrCat('\'', args.front(),
1959
0
                                     "' is unexpected. 'REGEX' expected."));
1960
0
                return std::string{};
1961
0
              }
1962
1963
0
              return cm::CMakeString{ args[1] }.Quote();
1964
0
            }
1965
0
            return std::string{};
1966
0
          } },
1967
260
        { "HEX"_s,
1968
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1969
260
             Arguments& args) -> std::string {
1970
0
            if (CheckStringParameters(ev, cnt, "HEX"_s, args, 1)) {
1971
0
              return cm::CMakeString{ args.front() }.ToHexadecimal();
1972
0
            }
1973
0
            return std::string{};
1974
0
          } },
1975
260
        { "HASH"_s,
1976
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1977
260
             Arguments& args) -> std::string {
1978
0
            if (CheckStringParameters(ev, cnt, "HASH"_s, args, 2)) {
1979
0
              auto const ALGORITHM = "ALGORITHM:"_s;
1980
1981
0
              if (cmHasPrefix(args[1], ALGORITHM)) {
1982
0
                try {
1983
0
                  auto const algo =
1984
0
                    cm::string_view{ args[1].c_str() + ALGORITHM.length() };
1985
0
                  if (algo.empty()) {
1986
0
                    reportError(
1987
0
                      ev, cnt->GetOriginalExpression(),
1988
0
                      cmStrCat("Missing value for '", ALGORITHM, "' option."));
1989
0
                    return std::string{};
1990
0
                  }
1991
0
                  return cm::CMakeString{ args.front() }.Hash(algo);
1992
0
                } catch (std::exception const& e) {
1993
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
1994
0
                  return std::string{};
1995
0
                }
1996
0
              }
1997
0
              reportError(ev, cnt->GetOriginalExpression(),
1998
0
                          cmStrCat(args[1], ": invalid parameter. Option '",
1999
0
                                   ALGORITHM, "' expected."));
2000
0
            }
2001
0
            return std::string{};
2002
0
          } },
2003
260
        { "MAKE_C_IDENTIFIER"_s,
2004
260
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2005
260
             Arguments& args) -> std::string {
2006
0
            if (CheckStringParameters(ev, cnt, "MAKE_C_IDENTIFIER"_s, args,
2007
0
                                      1)) {
2008
0
              return cm::CMakeString{ args.front() }.MakeCIdentifier();
2009
0
            }
2010
0
            return std::string{};
2011
0
          } }
2012
260
      };
2013
2014
260
    if (parameters.front().empty()) {
2015
7
      reportError(eval, content->GetOriginalExpression(),
2016
7
                  "$<STRING> expression requires at least one parameter.");
2017
7
      return std::string{};
2018
7
    }
2019
2020
253
    if (cm::contains(stringCommands, parameters.front())) {
2021
178
      auto args = Arguments{ parameters }.advance(1);
2022
178
      return stringCommands[parameters.front()](eval, content, args);
2023
178
    }
2024
2025
75
    reportError(eval, content->GetOriginalExpression(),
2026
75
                cmStrCat(parameters.front(), ": invalid option."));
2027
75
    return std::string{};
2028
253
  }
2029
} stringNode;
2030
2031
namespace {
2032
inline bool CheckListParametersEx(cm::GenEx::Evaluation* eval,
2033
                                  GeneratorExpressionContent const* cnt,
2034
                                  cm::string_view option, std::size_t count,
2035
                                  int required = 1, bool exactly = true)
2036
1.10k
{
2037
1.10k
  return CheckGenExParameters(eval, cnt, "LIST"_s, option, count, required,
2038
1.10k
                              exactly);
2039
1.10k
}
2040
inline bool CheckListParameters(cm::GenEx::Evaluation* eval,
2041
                                GeneratorExpressionContent const* cnt,
2042
                                cm::string_view option, Arguments args,
2043
                                int required = 1)
2044
0
{
2045
0
  return CheckListParametersEx(eval, cnt, option, args.size(), required);
2046
0
};
2047
2048
inline cmList GetList(std::string const& list)
2049
1.08k
{
2050
1.08k
  return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes };
2051
1.08k
}
2052
2053
struct TransformActionDescriptor
2054
{
2055
  cmList::TransformAction Action;
2056
  int Arity;
2057
};
2058
2059
// Look up a canned TRANSFORM action by name (APPLY is handled separately).
2060
cm::optional<TransformActionDescriptor> FindTransformActionDescriptor(
2061
  std::string const& name)
2062
1.33k
{
2063
1.33k
  static std::unordered_map<cm::string_view, TransformActionDescriptor> const
2064
1.33k
    descriptors{
2065
1.33k
      { "APPEND"_s, { cmList::TransformAction::APPEND, 1 } },
2066
1.33k
      { "PREPEND"_s, { cmList::TransformAction::PREPEND, 1 } },
2067
1.33k
      { "TOUPPER"_s, { cmList::TransformAction::TOUPPER, 0 } },
2068
1.33k
      { "TOLOWER"_s, { cmList::TransformAction::TOLOWER, 0 } },
2069
1.33k
      { "STRIP"_s, { cmList::TransformAction::STRIP, 0 } },
2070
1.33k
      { "REPLACE"_s, { cmList::TransformAction::REPLACE, 2 } },
2071
1.33k
    };
2072
1.33k
  auto it = descriptors.find(name);
2073
1.33k
  if (it == descriptors.end()) {
2074
443
    return cm::nullopt;
2075
443
  }
2076
894
  return it->second;
2077
1.33k
}
2078
2079
// Index in `parameters` at which a TRANSFORM action's selector region begins,
2080
// or nullopt if this is not a TRANSFORM or the action is unknown.  For the
2081
// APPLY action the <body> occupies slot 3, so the selector starts at slot 4.
2082
cm::optional<std::size_t> TransformSelectorStart(
2083
  std::vector<std::string> const& parameters)
2084
9.88k
{
2085
9.88k
  if (parameters.size() < 3 || parameters[0] != "TRANSFORM") {
2086
8.76k
    return cm::nullopt;
2087
8.76k
  }
2088
1.12k
  std::string const& action = parameters[2];
2089
1.12k
  if (action == "APPLY") {
2090
0
    return std::size_t{ 4 };
2091
0
  }
2092
1.12k
  if (auto d = FindTransformActionDescriptor(action)) {
2093
742
    return std::size_t{ 3 } + static_cast<std::size_t>(d->Arity);
2094
742
  }
2095
379
  return cm::nullopt;
2096
1.12k
}
2097
2098
// Handle $<LIST:TRANSFORM,...,PREDICATE,<body>>.  `predIndex` is the index of
2099
// the PREDICATE token in `parameters`; the <body> follows it.  PREDICATE is
2100
// the sole selector: only elements whose predicate is "1" are transformed.
2101
std::string EvaluateTransformPredicate(
2102
  std::vector<std::string> const& parameters, std::size_t predIndex,
2103
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
2104
  cmGeneratorExpressionDAGChecker* dagChecker)
2105
0
{
2106
  // PREDICATE must take exactly one <body> and not be combined with another
2107
  // selector (AT/FOR/REGEX) or trailing tokens.
2108
0
  if (parameters.size() < predIndex + 2) {
2109
0
    reportError(eval, content->GetOriginalExpression(),
2110
0
                "sub-command TRANSFORM, selector PREDICATE expects a <body> "
2111
0
                "argument.");
2112
0
    return std::string();
2113
0
  }
2114
0
  if (parameters.size() > predIndex + 2) {
2115
0
    reportError(eval, content->GetOriginalExpression(),
2116
0
                "sub-command TRANSFORM, selector PREDICATE expects a single "
2117
0
                "<body> argument and cannot be combined with another "
2118
0
                "selector.");
2119
0
    return std::string();
2120
0
  }
2121
2122
0
  cmList list = GetList(parameters[1]);
2123
0
  if (list.empty()) {
2124
0
    return std::string();
2125
0
  }
2126
2127
0
  cmGeneratorExpressionEvaluatorVector const& predicateBody =
2128
0
    content->GetParamChildren()[predIndex + 1];
2129
0
  auto mask = EvaluatePredicateMask(predicateBody, list, "TRANSFORM"_s, eval,
2130
0
                                    content, dagChecker);
2131
0
  if (!mask) {
2132
0
    return std::string();
2133
0
  }
2134
2135
0
  if (parameters[2] == "APPLY") {
2136
0
    cmGeneratorExpressionEvaluatorVector const& applyBody =
2137
0
      content->GetParamChildren()[3];
2138
0
    std::vector<std::string> out;
2139
0
    out.reserve(list.size());
2140
0
    std::size_t i = 0;
2141
0
    for (auto const& element : list) {
2142
0
      if ((*mask)[i]) {
2143
0
        out.push_back(
2144
0
          EvaluateBodyWithBoundOperand(applyBody, element, eval, dagChecker));
2145
0
        if (eval->HadError) {
2146
0
          return std::string();
2147
0
        }
2148
0
      } else {
2149
0
        out.push_back(element);
2150
0
      }
2151
0
      ++i;
2152
0
    }
2153
0
    return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2154
0
                   cmList::EmptyElements::Yes }
2155
0
      .to_string();
2156
0
  }
2157
2158
0
  std::string const& action = parameters[2];
2159
0
  auto descriptor = FindTransformActionDescriptor(action);
2160
0
  if (!descriptor) {
2161
0
    reportError(
2162
0
      eval, content->GetOriginalExpression(),
2163
0
      cmStrCat(" sub-command TRANSFORM, ", action, " invalid action."));
2164
0
    return std::string();
2165
0
  }
2166
2167
  // Action arguments occupy parameters[3 .. predIndex); TransformSelectorStart
2168
  // guarantees there are exactly descriptor->Arity of them.
2169
0
  std::vector<std::string> arguments(parameters.begin() + 3,
2170
0
                                     parameters.begin() + predIndex);
2171
2172
0
  std::vector<cmList::index_type> indices;
2173
0
  for (std::size_t i = 0; i < mask->size(); ++i) {
2174
0
    if ((*mask)[i]) {
2175
0
      indices.push_back(static_cast<cmList::index_type>(i));
2176
0
    }
2177
0
  }
2178
0
  if (indices.empty()) {
2179
    // No element selected: TRANSFORM is a no-op.
2180
0
    return list.to_string();
2181
0
  }
2182
2183
0
  auto selector =
2184
0
    cmList::TransformSelector::New<cmList::TransformSelector::AT>(
2185
0
      std::move(indices));
2186
0
  selector->Makefile = eval->Context.LG->GetMakefile();
2187
0
  try {
2188
0
    return list.transform(descriptor->Action, arguments, std::move(selector))
2189
0
      .to_string();
2190
0
  } catch (cmList::transform_error& e) {
2191
0
    reportError(eval, content->GetOriginalExpression(), e.what());
2192
0
    return std::string();
2193
0
  }
2194
0
}
2195
2196
enum class SortOptionResult
2197
{
2198
  NotRecognized, // `arg` is not a SORT option keyword
2199
  Parsed,        // recognized and applied to `sortConfig`
2200
  Error,         // recognized but malformed or duplicate (already reported)
2201
};
2202
2203
// Parse one $<LIST:SORT> colon-option (COMPARE:/CASE:/ORDER:) into sortConfig.
2204
SortOptionResult ParseSortOption(std::string const& arg,
2205
                                 cmList::SortConfiguration& sortConfig,
2206
                                 cm::GenEx::Evaluation* eval,
2207
                                 GeneratorExpressionContent const* content)
2208
127
{
2209
127
  using SortConfig = cmList::SortConfiguration;
2210
127
  auto const COMPARE = "COMPARE:"_s;
2211
127
  auto const CASE = "CASE:"_s;
2212
127
  auto const ORDER = "ORDER:"_s;
2213
2214
127
  if (cmHasPrefix(arg, COMPARE)) {
2215
0
    if (sortConfig.Compare != SortConfig::CompareMethod::DEFAULT) {
2216
0
      reportError(eval, content->GetOriginalExpression(),
2217
0
                  "sub-command SORT, COMPARE option has been specified "
2218
0
                  "multiple times.");
2219
0
      return SortOptionResult::Error;
2220
0
    }
2221
0
    auto option = cm::string_view{ arg.c_str() + COMPARE.length() };
2222
0
    if (option == "STRING"_s) {
2223
0
      sortConfig.Compare = SortConfig::CompareMethod::STRING;
2224
0
    } else if (option == "FILE_BASENAME"_s) {
2225
0
      sortConfig.Compare = SortConfig::CompareMethod::FILE_BASENAME;
2226
0
    } else if (option == "NATURAL"_s) {
2227
0
      sortConfig.Compare = SortConfig::CompareMethod::NATURAL;
2228
0
    } else {
2229
0
      reportError(eval, content->GetOriginalExpression(),
2230
0
                  cmStrCat("sub-command SORT, an invalid COMPARE option has "
2231
0
                           "been specified: \"",
2232
0
                           option, "\"."));
2233
0
      return SortOptionResult::Error;
2234
0
    }
2235
0
    return SortOptionResult::Parsed;
2236
0
  }
2237
2238
127
  if (cmHasPrefix(arg, CASE)) {
2239
0
    if (sortConfig.Case != SortConfig::CaseSensitivity::DEFAULT) {
2240
0
      reportError(eval, content->GetOriginalExpression(),
2241
0
                  "sub-command SORT, CASE option has been specified multiple "
2242
0
                  "times.");
2243
0
      return SortOptionResult::Error;
2244
0
    }
2245
0
    auto option = cm::string_view{ arg.c_str() + CASE.length() };
2246
0
    if (option == "SENSITIVE"_s) {
2247
0
      sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE;
2248
0
    } else if (option == "INSENSITIVE"_s) {
2249
0
      sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE;
2250
0
    } else {
2251
0
      reportError(eval, content->GetOriginalExpression(),
2252
0
                  cmStrCat("sub-command SORT, an invalid CASE option has been "
2253
0
                           "specified: \"",
2254
0
                           option, "\"."));
2255
0
      return SortOptionResult::Error;
2256
0
    }
2257
0
    return SortOptionResult::Parsed;
2258
0
  }
2259
2260
127
  if (cmHasPrefix(arg, ORDER)) {
2261
94
    if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) {
2262
0
      reportError(eval, content->GetOriginalExpression(),
2263
0
                  "sub-command SORT, ORDER option has been specified multiple "
2264
0
                  "times.");
2265
0
      return SortOptionResult::Error;
2266
0
    }
2267
94
    auto option = cm::string_view{ arg.c_str() + ORDER.length() };
2268
94
    if (option == "ASCENDING"_s) {
2269
0
      sortConfig.Order = SortConfig::OrderMode::ASCENDING;
2270
94
    } else if (option == "DESCENDING"_s) {
2271
78
      sortConfig.Order = SortConfig::OrderMode::DESCENDING;
2272
78
    } else {
2273
16
      reportError(
2274
16
        eval, content->GetOriginalExpression(),
2275
16
        cmStrCat("sub-command SORT, an invalid ORDER option has been "
2276
16
                 "specified: \"",
2277
16
                 option, "\"."));
2278
16
      return SortOptionResult::Error;
2279
16
    }
2280
78
    return SortOptionResult::Parsed;
2281
94
  }
2282
2283
33
  return SortOptionResult::NotRecognized;
2284
127
}
2285
2286
// $<LIST:SORT,...,COMPARATOR,body>: sort with a per-comparison genex body, the
2287
// two elements bound to $<_0> and $<_1>; body must yield "0" or "1".
2288
std::string EvaluateSortComparator(std::vector<std::string> const& parameters,
2289
                                   std::size_t comparatorIndex,
2290
                                   cm::GenEx::Evaluation* eval,
2291
                                   GeneratorExpressionContent const* content,
2292
                                   cmGeneratorExpressionDAGChecker* dagChecker)
2293
0
{
2294
0
  if (comparatorIndex + 1 >= parameters.size()) {
2295
0
    reportError(eval, content->GetOriginalExpression(),
2296
0
                "sub-command SORT, COMPARATOR expects a <body> argument.");
2297
0
    return std::string();
2298
0
  }
2299
0
  cmGeneratorExpressionEvaluatorVector const& bodyExpr =
2300
0
    content->GetParamChildren()[comparatorIndex + 1];
2301
2302
0
  using SortConfig = cmList::SortConfiguration;
2303
0
  SortConfig sortConfig;
2304
0
  sortConfig.Compare = SortConfig::CompareMethod::COMPARATOR;
2305
0
  for (std::size_t i = 2; i < parameters.size(); ++i) {
2306
0
    if (i == comparatorIndex || i == comparatorIndex + 1) {
2307
0
      continue; // COMPARATOR keyword + its (empty) body slot
2308
0
    }
2309
0
    std::string const& arg = parameters[i];
2310
    // COMPARATOR defines the ordering, so reject COMPARE:; CASE:/ORDER: are
2311
    // accepted as in list(SORT ... COMPARATOR) (CASE: folds the body
2312
    // operands).
2313
0
    if (cmHasPrefix(arg, "COMPARE:"_s)) {
2314
0
      reportError(eval, content->GetOriginalExpression(),
2315
0
                  "sub-command SORT, option \"COMPARE\" is incompatible with "
2316
0
                  "\"COMPARATOR\".");
2317
0
      return std::string();
2318
0
    }
2319
0
    switch (ParseSortOption(arg, sortConfig, eval, content)) {
2320
0
      case SortOptionResult::Parsed:
2321
0
        break;
2322
0
      case SortOptionResult::Error:
2323
0
        return std::string();
2324
0
      case SortOptionResult::NotRecognized:
2325
0
        reportError(
2326
0
          eval, content->GetOriginalExpression(),
2327
0
          cmStrCat("sub-command SORT, option \"", arg, "\" is invalid."));
2328
0
        return std::string();
2329
0
    }
2330
0
  }
2331
2332
0
  cmList list = GetList(parameters[1]);
2333
0
  if (list.size() < 2) {
2334
0
    return list.to_string();
2335
0
  }
2336
2337
  // The strict-weak-ordering guard in cmList::sort may call this twice per
2338
  // pair, so the body can be evaluated up to twice per comparison.
2339
0
  auto comparator = [&](std::string const& a, std::string const& b) -> bool {
2340
0
    std::string r =
2341
0
      EvaluateBodyWithBoundOperands(bodyExpr, { a, b }, eval, dagChecker);
2342
0
    if (eval->HadError) {
2343
0
      throw cmList::transform_error(std::string{}); // body already reported
2344
0
    }
2345
0
    if (r == "1") {
2346
0
      return true;
2347
0
    }
2348
0
    if (r == "0") {
2349
0
      return false;
2350
0
    }
2351
0
    throw cmList::transform_error(
2352
0
      cmStrCat("sub-command SORT, COMPARATOR body must evaluate to \"0\" or "
2353
0
               "\"1\", but evaluated to \"",
2354
0
               r, "\"."));
2355
0
  };
2356
2357
0
  try {
2358
0
    list.sort(sortConfig, comparator);
2359
0
  } catch (std::invalid_argument& e) {
2360
0
    if (!eval->HadError) {
2361
0
      reportError(eval, content->GetOriginalExpression(), e.what());
2362
0
    }
2363
0
    return std::string();
2364
0
  }
2365
0
  return list.to_string();
2366
0
}
2367
2368
// Parse the optional trailing selector of a $<LIST:TRANSFORM,...> action
2369
// (AT <i>... / FOR <start> <stop> [<step>] / REGEX <re>) into a
2370
// cmList::TransformSelector.  Returns nullptr (after reporting via `eval`) on
2371
// a malformed selector; empty `tokens` yields a select-all selector.
2372
std::unique_ptr<cmList::TransformSelector> ParseTransformSelector(
2373
  std::vector<std::string> const& tokens, cm::GenEx::Evaluation* eval,
2374
  GeneratorExpressionContent const* content)
2375
152
{
2376
152
  static std::string const REGEX{ "REGEX" };
2377
152
  static std::string const AT{ "AT" };
2378
152
  static std::string const FOR{ "FOR" };
2379
2380
152
  std::unique_ptr<cmList::TransformSelector> selector;
2381
2382
152
  std::size_t i = 0;
2383
152
  while (i < tokens.size()) {
2384
33
    std::string const& tok = tokens[i];
2385
2386
33
    if ((tok == REGEX || tok == AT || tok == FOR) && selector) {
2387
0
      reportError(
2388
0
        eval, content->GetOriginalExpression(),
2389
0
        cmStrCat("sub-command TRANSFORM, selector already specified (",
2390
0
                 selector->GetTag(), ")."));
2391
0
      return nullptr;
2392
0
    }
2393
2394
33
    if (tok == REGEX) {
2395
0
      if (i + 1 >= tokens.size()) {
2396
0
        reportError(eval, content->GetOriginalExpression(),
2397
0
                    "sub-command TRANSFORM, selector REGEX expects "
2398
0
                    "'regular expression' argument.");
2399
0
        return nullptr;
2400
0
      }
2401
0
      selector =
2402
0
        cmList::TransformSelector::New<cmList::TransformSelector::REGEX>(
2403
0
          tokens[i + 1]);
2404
0
      i += 2;
2405
0
      continue;
2406
0
    }
2407
2408
33
    if (tok == AT) {
2409
0
      ++i;
2410
0
      std::vector<cmList::index_type> indexes;
2411
0
      for (; i < tokens.size(); ++i) {
2412
0
        cmList indexList{ tokens[i] };
2413
0
        for (auto const& index : indexList) {
2414
0
          cmList::index_type value;
2415
0
          if (!GetNumericArgument(index, value)) {
2416
0
            reportError(eval, content->GetOriginalExpression(),
2417
0
                        cmStrCat("sub-command TRANSFORM, selector AT: '",
2418
0
                                 index, "': unexpected argument."));
2419
0
            return nullptr;
2420
0
          }
2421
0
          indexes.push_back(value);
2422
0
        }
2423
0
      }
2424
0
      if (indexes.empty()) {
2425
0
        reportError(eval, content->GetOriginalExpression(),
2426
0
                    "sub-command TRANSFORM, selector AT expects at least one "
2427
0
                    "numeric value.");
2428
0
        return nullptr;
2429
0
      }
2430
0
      selector = cmList::TransformSelector::New<cmList::TransformSelector::AT>(
2431
0
        std::move(indexes));
2432
0
      continue;
2433
0
    }
2434
2435
33
    if (tok == FOR) {
2436
0
      if (i + 2 >= tokens.size()) {
2437
0
        reportError(eval, content->GetOriginalExpression(),
2438
0
                    "sub-command TRANSFORM, selector FOR expects, at least, "
2439
0
                    "two arguments.");
2440
0
        return nullptr;
2441
0
      }
2442
0
      cmList::index_type start = 0;
2443
0
      cmList::index_type stop = 0;
2444
0
      cmList::index_type step = 1;
2445
0
      if (!GetNumericArgument(tokens[i + 1], start) ||
2446
0
          !GetNumericArgument(tokens[i + 2], stop)) {
2447
0
        reportError(eval, content->GetOriginalExpression(),
2448
0
                    "sub-command TRANSFORM, selector FOR expects, at least, "
2449
0
                    "two numeric values.");
2450
0
        return nullptr;
2451
0
      }
2452
0
      i += 3;
2453
0
      if (i < tokens.size()) {
2454
0
        if (!GetNumericArgument(tokens[i], step)) {
2455
0
          step = -1;
2456
0
        }
2457
0
        ++i;
2458
0
      }
2459
0
      if (step <= 0) {
2460
0
        reportError(eval, content->GetOriginalExpression(),
2461
0
                    "sub-command TRANSFORM, selector FOR expects positive "
2462
0
                    "numeric value for <step>.");
2463
0
        return nullptr;
2464
0
      }
2465
0
      selector =
2466
0
        cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
2467
0
          { start, stop, step });
2468
0
      continue;
2469
0
    }
2470
2471
33
    std::vector<std::string> const rest(tokens.begin() + i, tokens.end());
2472
33
    reportError(eval, content->GetOriginalExpression(),
2473
33
                cmStrCat("sub-command TRANSFORM, '", cmJoin(rest, ", "),
2474
33
                         "': unexpected argument(s)."));
2475
33
    return nullptr;
2476
33
  }
2477
2478
119
  if (!selector) {
2479
119
    selector = cmList::TransformSelector::New();
2480
119
  }
2481
119
  return selector;
2482
152
}
2483
}
2484
2485
static const struct ListNode : public cmGeneratorExpressionNode
2486
{
2487
10
  ListNode() {} // NOLINT(modernize-use-equals-default)
2488
2489
1.28k
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
2490
2491
1.28k
  bool AcceptsArbitraryContentParameter() const override { return true; }
2492
2493
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
2494
                                   std::string&) const override
2495
9.66k
  {
2496
    // Leave the FILTER PREDICATE <body> (slot 4) unevaluated so $<_0> is never
2497
    // evaluated unbound.
2498
9.66k
    if (parameters.size() == 4 && parameters[0] == "FILTER" &&
2499
0
        parameters[3] == "PREDICATE") {
2500
0
      return false;
2501
0
    }
2502
    // Leave a TRANSFORM PREDICATE selector's <body> unevaluated.  PREDICATE is
2503
    // the selector keyword only when it sits exactly at the selector position
2504
    // (not when it is a literal action argument such as APPEND PREDICATE).
2505
9.66k
    if (auto start = TransformSelectorStart(parameters)) {
2506
590
      if (parameters.size() == *start + 1 &&
2507
34
          parameters.back() == "PREDICATE") {
2508
0
        return false;
2509
0
      }
2510
590
    }
2511
    // Leave the SORT COMPARATOR <body> unevaluated; a bare COMPARATOR token is
2512
    // unambiguous since SORT's other options are colon-style.
2513
9.66k
    if (parameters.size() >= 3 && parameters[0] == "SORT" &&
2514
1.75k
        parameters.back() == "COMPARATOR") {
2515
0
      return false;
2516
0
    }
2517
    // Skip the APPLY <body> (4th parameter) so $<_0> is not evaluated unbound;
2518
    // selector args (5th+) evaluate normally.
2519
9.66k
    return !(parameters.size() == 3 && parameters[0] == "TRANSFORM" &&
2520
211
             parameters[2] == "APPLY");
2521
9.66k
  }
2522
2523
  std::string Evaluate(
2524
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
2525
    GeneratorExpressionContent const* content,
2526
    cmGeneratorExpressionDAGChecker* dagChecker) const override
2527
1.22k
  {
2528
    // TRANSFORM ... PREDICATE <body>: genex-native predicate selector, usable
2529
    // with any action (canned or APPLY).  Handled here (not in the
2530
    // listCommands lambda) because the predicate <body> needs the DAG checker.
2531
1.22k
    if (parameters.size() >= 3 && parameters[0] == "TRANSFORM") {
2532
217
      if (auto start = TransformSelectorStart(parameters)) {
2533
152
        if (*start < parameters.size() && parameters[*start] == "PREDICATE") {
2534
0
          return EvaluateTransformPredicate(parameters, *start, eval, content,
2535
0
                                            dagChecker);
2536
0
        }
2537
152
      }
2538
217
    }
2539
2540
1.22k
    if (parameters.size() >= 3 && parameters[0] == "TRANSFORM" &&
2541
217
        parameters[2] == "APPLY") {
2542
0
      if (parameters.size() < 4) {
2543
0
        reportError(
2544
0
          eval, content->GetOriginalExpression(),
2545
0
          "sub-command TRANSFORM, action APPLY expects a <body> argument.");
2546
0
        return std::string();
2547
0
      }
2548
0
      cmList list = GetList(parameters[1]);
2549
0
      if (list.empty()) {
2550
0
        return std::string{};
2551
0
      }
2552
0
      cmGeneratorExpressionEvaluatorVector const& bodyExpr =
2553
0
        content->GetParamChildren()[3];
2554
0
      std::vector<std::string> const selectorTokens(parameters.begin() + 4,
2555
0
                                                    parameters.end());
2556
0
      std::unique_ptr<cmList::TransformSelector> selector =
2557
0
        ParseTransformSelector(selectorTokens, eval, content);
2558
0
      if (!selector) {
2559
0
        return std::string();
2560
0
      }
2561
      // selector->Makefile is left unset: the REGEX/AT/FOR selectors never
2562
      // consult it, and the only one that does (list()'s PREDICATE) cannot
2563
      // reach here.
2564
0
      std::vector<bool> selected;
2565
0
      try {
2566
0
        selected = list.GetTransformSelection(*selector);
2567
0
      } catch (cmList::transform_error& e) {
2568
0
        reportError(eval, content->GetOriginalExpression(), e.what());
2569
0
        return std::string();
2570
0
      }
2571
2572
0
      std::vector<std::string> out;
2573
0
      out.reserve(list.size());
2574
0
      std::size_t i = 0;
2575
0
      for (auto const& element : list) {
2576
0
        if (i < selected.size() && selected[i]) {
2577
0
          out.push_back(
2578
0
            EvaluateBodyWithBoundOperand(bodyExpr, element, eval, dagChecker));
2579
0
          if (eval->HadError) {
2580
0
            return std::string();
2581
0
          }
2582
0
        } else {
2583
0
          out.push_back(element);
2584
0
        }
2585
0
        ++i;
2586
0
      }
2587
      // Join per-element results with ';'; keep empty elements so a body that
2588
      // yields "" is not dropped.
2589
0
      return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2590
0
                     cmList::EmptyElements::Yes }
2591
0
        .to_string();
2592
0
    }
2593
2594
    // FILTER ... PREDICATE <body>: genex-native predicate filter.
2595
1.22k
    if (parameters.size() >= 4 && parameters[0] == "FILTER" &&
2596
0
        parameters[3] == "PREDICATE") {
2597
0
      if (parameters.size() != 5) {
2598
0
        reportError(eval, content->GetOriginalExpression(),
2599
0
                    "sub-command FILTER, PREDICATE expects a single <body> "
2600
0
                    "argument.");
2601
0
        return std::string();
2602
0
      }
2603
0
      std::string const& op = parameters[2];
2604
0
      if (op != "INCLUDE" && op != "EXCLUDE") {
2605
0
        reportError(
2606
0
          eval, content->GetOriginalExpression(),
2607
0
          cmStrCat("sub-command FILTER does not recognize operator \"", op,
2608
0
                   "\". It must be either INCLUDE or EXCLUDE."));
2609
0
        return std::string();
2610
0
      }
2611
0
      cmList list = GetList(parameters[1]);
2612
0
      if (list.empty()) {
2613
0
        return std::string();
2614
0
      }
2615
0
      cmGeneratorExpressionEvaluatorVector const& predicateBody =
2616
0
        content->GetParamChildren()[4];
2617
0
      auto mask = EvaluatePredicateMask(predicateBody, list, "FILTER"_s, eval,
2618
0
                                        content, dagChecker);
2619
0
      if (!mask) {
2620
0
        return std::string();
2621
0
      }
2622
0
      bool const keepWhenTrue = (op == "INCLUDE");
2623
0
      std::vector<std::string> out;
2624
0
      std::size_t i = 0;
2625
0
      for (auto const& element : list) {
2626
0
        if ((*mask)[i] == keepWhenTrue) {
2627
0
          out.push_back(element);
2628
0
        }
2629
0
        ++i;
2630
0
      }
2631
0
      return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2632
0
                     cmList::EmptyElements::Yes }
2633
0
        .to_string();
2634
0
    }
2635
2636
    // SORT COMPARATOR is handled here, not the listCommands SORT lambda,
2637
    // because the body needs the DAG checker.
2638
1.22k
    if (parameters.size() >= 3 && parameters[0] == "SORT") {
2639
2.01k
      for (std::size_t i = 2; i < parameters.size(); ++i) {
2640
1.88k
        if (parameters[i] == "COMPARATOR") {
2641
0
          return EvaluateSortComparator(parameters, i, eval, content,
2642
0
                                        dagChecker);
2643
0
        }
2644
1.88k
      }
2645
127
    }
2646
2647
1.22k
    static std::unordered_map<
2648
1.22k
      cm::string_view,
2649
1.22k
      std::function<std::string(cm::GenEx::Evaluation*,
2650
1.22k
                                GeneratorExpressionContent const*,
2651
1.22k
                                Arguments&)>>
2652
1.22k
      listCommands{
2653
1.22k
        { "LENGTH"_s,
2654
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2655
1.22k
             Arguments& args) -> std::string {
2656
0
            if (CheckListParameters(ev, cnt, "LENGTH"_s, args)) {
2657
0
              return std::to_string(GetList(args.front()).size());
2658
0
            }
2659
0
            return std::string{};
2660
0
          } },
2661
1.22k
        { "GET"_s,
2662
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2663
1.22k
             Arguments& args) -> std::string {
2664
0
            if (CheckListParametersEx(ev, cnt, "GET"_s, args.size(), 2,
2665
0
                                      false)) {
2666
0
              auto list = GetList(args.front());
2667
0
              if (list.empty()) {
2668
0
                reportError(ev, cnt->GetOriginalExpression(),
2669
0
                            "given empty list");
2670
0
                return std::string{};
2671
0
              }
2672
2673
0
              std::vector<cmList::index_type> indexes;
2674
0
              if (!GetNumericArguments(ev, cnt, args.advance(1), indexes,
2675
0
                                       cmList::ExpandElements::Yes)) {
2676
0
                return std::string{};
2677
0
              }
2678
0
              try {
2679
0
                return list.get_items(indexes.begin(), indexes.end())
2680
0
                  .to_string();
2681
0
              } catch (std::out_of_range& e) {
2682
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2683
0
                return std::string{};
2684
0
              }
2685
0
            }
2686
0
            return std::string{};
2687
0
          } },
2688
1.22k
        { "JOIN"_s,
2689
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2690
1.22k
             Arguments& args) -> std::string {
2691
0
            if (CheckListParameters(ev, cnt, "JOIN"_s, args, 2)) {
2692
0
              return GetList(args.front()).join(args[1]);
2693
0
            }
2694
0
            return std::string{};
2695
0
          } },
2696
1.22k
        { "SUBLIST"_s,
2697
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2698
1.22k
             Arguments& args) -> std::string {
2699
0
            if (CheckListParameters(ev, cnt, "SUBLIST"_s, args, 3)) {
2700
0
              auto list = GetList(args.front());
2701
0
              if (!list.empty()) {
2702
0
                std::vector<cmList::index_type> indexes;
2703
0
                if (!GetNumericArguments(ev, cnt, args.advance(1), indexes)) {
2704
0
                  return std::string{};
2705
0
                }
2706
0
                if (indexes[0] < 0) {
2707
0
                  reportError(ev, cnt->GetOriginalExpression(),
2708
0
                              cmStrCat("begin index: ", indexes[0],
2709
0
                                       " is out of range 0 - ",
2710
0
                                       list.size() - 1));
2711
0
                  return std::string{};
2712
0
                }
2713
0
                if (indexes[1] < -1) {
2714
0
                  reportError(ev, cnt->GetOriginalExpression(),
2715
0
                              cmStrCat("length: ", indexes[1],
2716
0
                                       " should be -1 or greater"));
2717
0
                  return std::string{};
2718
0
                }
2719
0
                try {
2720
0
                  return list
2721
0
                    .sublist(static_cast<cmList::size_type>(indexes[0]),
2722
0
                             static_cast<cmList::size_type>(indexes[1]))
2723
0
                    .to_string();
2724
0
                } catch (std::out_of_range& e) {
2725
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
2726
0
                  return std::string{};
2727
0
                }
2728
0
              }
2729
0
            }
2730
0
            return std::string{};
2731
0
          } },
2732
1.22k
        { "FIND"_s,
2733
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2734
1.22k
             Arguments& args) -> std::string {
2735
0
            if (CheckListParameters(ev, cnt, "FIND"_s, args, 2)) {
2736
0
              auto list = GetList(args.front());
2737
0
              auto index = list.find(args[1]);
2738
0
              return index == cmList::npos ? "-1" : std::to_string(index);
2739
0
            }
2740
0
            return std::string{};
2741
0
          } },
2742
1.22k
        { "APPEND"_s,
2743
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2744
1.22k
             Arguments& args) -> std::string {
2745
11
            if (CheckListParametersEx(ev, cnt, "APPEND"_s, args.size(), 2,
2746
11
                                      false)) {
2747
6
              auto list = args.front();
2748
6
              args.advance(1);
2749
6
              return cmList::append(list, args.begin(), args.end());
2750
6
            }
2751
5
            return std::string{};
2752
11
          } },
2753
1.22k
        { "PREPEND"_s,
2754
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2755
1.22k
             Arguments& args) -> std::string {
2756
0
            if (CheckListParametersEx(ev, cnt, "PREPEND"_s, args.size(), 2,
2757
0
                                      false)) {
2758
0
              auto list = args.front();
2759
0
              args.advance(1);
2760
0
              return cmList::prepend(list, args.begin(), args.end());
2761
0
            }
2762
0
            return std::string{};
2763
0
          } },
2764
1.22k
        { "INSERT"_s,
2765
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2766
1.22k
             Arguments& args) -> std::string {
2767
0
            if (CheckListParametersEx(ev, cnt, "INSERT"_s, args.size(), 3,
2768
0
                                      false)) {
2769
0
              cmList::index_type index;
2770
0
              if (!GetNumericArgument(args[1], index)) {
2771
0
                reportError(
2772
0
                  ev, cnt->GetOriginalExpression(),
2773
0
                  cmStrCat("index: \"", args[1], "\" is not a valid index"));
2774
0
                return std::string{};
2775
0
              }
2776
0
              try {
2777
0
                auto list = GetList(args.front());
2778
0
                args.advance(2);
2779
0
                list.insert_items(index, args.begin(), args.end(),
2780
0
                                  cmList::ExpandElements::No,
2781
0
                                  cmList::EmptyElements::Yes);
2782
0
                return list.to_string();
2783
0
              } catch (std::out_of_range& e) {
2784
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2785
0
                return std::string{};
2786
0
              }
2787
0
            }
2788
0
            return std::string{};
2789
0
          } },
2790
1.22k
        { "POP_BACK"_s,
2791
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2792
1.22k
             Arguments& args) -> std::string {
2793
0
            if (CheckListParameters(ev, cnt, "POP_BACK"_s, args)) {
2794
0
              auto list = GetList(args.front());
2795
0
              if (!list.empty()) {
2796
0
                list.pop_back();
2797
0
                return list.to_string();
2798
0
              }
2799
0
            }
2800
0
            return std::string{};
2801
0
          } },
2802
1.22k
        { "POP_FRONT"_s,
2803
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2804
1.22k
             Arguments& args) -> std::string {
2805
0
            if (CheckListParameters(ev, cnt, "POP_FRONT"_s, args)) {
2806
0
              auto list = GetList(args.front());
2807
0
              if (!list.empty()) {
2808
0
                list.pop_front();
2809
0
                return list.to_string();
2810
0
              }
2811
0
            }
2812
0
            return std::string{};
2813
0
          } },
2814
1.22k
        { "REMOVE_DUPLICATES"_s,
2815
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2816
1.22k
             Arguments& args) -> std::string {
2817
0
            if (CheckListParameters(ev, cnt, "REMOVE_DUPLICATES"_s, args)) {
2818
0
              return GetList(args.front()).remove_duplicates().to_string();
2819
0
            }
2820
0
            return std::string{};
2821
0
          } },
2822
1.22k
        { "REMOVE_ITEM"_s,
2823
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2824
1.22k
             Arguments& args) -> std::string {
2825
0
            if (CheckListParametersEx(ev, cnt, "REMOVE_ITEM"_s, args.size(), 2,
2826
0
                                      false)) {
2827
0
              auto list = GetList(args.front());
2828
0
              args.advance(1);
2829
0
              cmList items{ args.begin(), args.end(),
2830
0
                            cmList::ExpandElements::Yes };
2831
0
              return list.remove_items(items.begin(), items.end()).to_string();
2832
0
            }
2833
0
            return std::string{};
2834
0
          } },
2835
1.22k
        { "REMOVE_AT"_s,
2836
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2837
1.22k
             Arguments& args) -> std::string {
2838
0
            if (CheckListParametersEx(ev, cnt, "REMOVE_AT"_s, args.size(), 2,
2839
0
                                      false)) {
2840
0
              auto list = GetList(args.front());
2841
0
              std::vector<cmList::index_type> indexes;
2842
0
              if (!GetNumericArguments(ev, cnt, args.advance(1), indexes,
2843
0
                                       cmList::ExpandElements::Yes)) {
2844
0
                return std::string{};
2845
0
              }
2846
0
              try {
2847
0
                return list.remove_items(indexes.begin(), indexes.end())
2848
0
                  .to_string();
2849
0
              } catch (std::out_of_range& e) {
2850
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2851
0
                return std::string{};
2852
0
              }
2853
0
            }
2854
0
            return std::string{};
2855
0
          } },
2856
1.22k
        { "FILTER"_s,
2857
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2858
1.22k
             Arguments& args) -> std::string {
2859
            // args = [list, INCLUDE|EXCLUDE, <regex> | REGEX <regex>].
2860
            // (PREDICATE is handled up-front in Evaluate and never reaches
2861
            // here.)
2862
0
            bool const explicitRegex =
2863
0
              args.size() >= 3 && args[2] == "REGEX"_s;
2864
0
            int const required = explicitRegex ? 4 : 3;
2865
0
            if (CheckListParameters(ev, cnt, "FILTER"_s, args, required)) {
2866
0
              auto const& op = args[1];
2867
0
              if (op != "INCLUDE"_s && op != "EXCLUDE"_s) {
2868
0
                reportError(
2869
0
                  ev, cnt->GetOriginalExpression(),
2870
0
                  cmStrCat("sub-command FILTER does not recognize operator \"",
2871
0
                           op, "\". It must be either INCLUDE or EXCLUDE."));
2872
0
                return std::string{};
2873
0
              }
2874
0
              auto const& regex = explicitRegex ? args[3] : args[2];
2875
0
              try {
2876
0
                return GetList(args.front())
2877
0
                  .filter(regex,
2878
0
                          op == "INCLUDE"_s ? cmList::FilterMode::INCLUDE
2879
0
                                            : cmList::FilterMode::EXCLUDE)
2880
0
                  .to_string();
2881
0
              } catch (std::invalid_argument&) {
2882
0
                reportError(
2883
0
                  ev, cnt->GetOriginalExpression(),
2884
0
                  cmStrCat("sub-command FILTER, failed to compile regex \"",
2885
0
                           regex, "\"."));
2886
0
                return std::string{};
2887
0
              }
2888
0
            }
2889
0
            return std::string{};
2890
0
          } },
2891
1.22k
        { "TRANSFORM"_s,
2892
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2893
1.22k
             Arguments& args) -> std::string {
2894
220
            if (CheckListParametersEx(ev, cnt, "TRANSFORM"_s, args.size(), 2,
2895
220
                                      false)) {
2896
217
              auto list = GetList(args.front());
2897
217
              if (!list.empty()) {
2898
216
                std::string const actionName = args.advance(1).front();
2899
216
                auto descriptor = FindTransformActionDescriptor(actionName);
2900
216
                if (!descriptor) {
2901
64
                  reportError(ev, cnt->GetOriginalExpression(),
2902
64
                              cmStrCat(" sub-command TRANSFORM, ", actionName,
2903
64
                                       " invalid action."));
2904
64
                  return std::string{};
2905
64
                }
2906
2907
                // Action arguments
2908
152
                args.advance(1);
2909
152
                if (args.size() < descriptor->Arity) {
2910
0
                  reportError(ev, cnt->GetOriginalExpression(),
2911
0
                              cmStrCat("sub-command TRANSFORM, action ",
2912
0
                                       actionName, " expects ",
2913
0
                                       descriptor->Arity, " argument(s)."));
2914
0
                  return std::string{};
2915
0
                }
2916
152
                std::vector<std::string> arguments;
2917
152
                if (descriptor->Arity > 0) {
2918
152
                  arguments = std::vector<std::string>(
2919
152
                    args.begin(), args.begin() + descriptor->Arity);
2920
152
                  args.advance(descriptor->Arity);
2921
152
                }
2922
2923
152
                std::unique_ptr<cmList::TransformSelector> selector;
2924
2925
152
                try {
2926
152
                  std::vector<std::string> const tokens(args.begin(),
2927
152
                                                        args.end());
2928
152
                  selector = ParseTransformSelector(tokens, ev, cnt);
2929
152
                  if (!selector) {
2930
33
                    return std::string{};
2931
33
                  }
2932
119
                  selector->Makefile = ev->Context.LG->GetMakefile();
2933
2934
119
                  return list
2935
119
                    .transform(descriptor->Action, arguments,
2936
119
                               std::move(selector))
2937
119
                    .to_string();
2938
152
                } catch (cmList::transform_error& e) {
2939
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
2940
0
                  return std::string{};
2941
0
                }
2942
152
              }
2943
217
            }
2944
4
            return std::string{};
2945
220
          } },
2946
1.22k
        { "REVERSE"_s,
2947
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2948
1.22k
             Arguments& args) -> std::string {
2949
0
            if (CheckListParameters(ev, cnt, "REVERSE"_s, args)) {
2950
0
              return GetList(args.front()).reverse().to_string();
2951
0
            }
2952
0
            return std::string{};
2953
0
          } },
2954
1.22k
        { "SORT"_s,
2955
1.22k
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2956
1.22k
             Arguments& args) -> std::string {
2957
872
            if (CheckListParametersEx(ev, cnt, "SORT"_s, args.size(), 1,
2958
872
                                      false)) {
2959
872
              auto list = GetList(args.front());
2960
872
              args.advance(1);
2961
872
              cmList::SortConfiguration sortConfig;
2962
872
              for (auto const& arg : args) {
2963
127
                switch (ParseSortOption(arg, sortConfig, ev, cnt)) {
2964
78
                  case SortOptionResult::Parsed:
2965
78
                    break;
2966
16
                  case SortOptionResult::Error:
2967
16
                    return std::string{};
2968
33
                  case SortOptionResult::NotRecognized:
2969
33
                    reportError(ev, cnt->GetOriginalExpression(),
2970
33
                                cmStrCat("sub-command SORT, option \"", arg,
2971
33
                                         "\" is invalid."));
2972
33
                    return std::string{};
2973
127
                }
2974
127
              }
2975
2976
823
              return list.sort(sortConfig).to_string();
2977
872
            }
2978
0
            return std::string{};
2979
872
          } }
2980
1.22k
      };
2981
2982
1.22k
    if (cm::contains(listCommands, parameters.front())) {
2983
1.10k
      auto args = Arguments{ parameters }.advance(1);
2984
1.10k
      return listCommands[parameters.front()](eval, content, args);
2985
1.10k
    }
2986
2987
121
    reportError(eval, content->GetOriginalExpression(),
2988
121
                cmStrCat(parameters.front(), ": invalid option."));
2989
121
    return std::string{};
2990
1.22k
  }
2991
} listNode;
2992
2993
static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
2994
{
2995
10
  MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
2996
2997
542
  bool AcceptsArbitraryContentParameter() const override { return true; }
2998
2999
  std::string Evaluate(
3000
    std::vector<std::string> const& parameters,
3001
    cm::GenEx::Evaluation* /*eval*/,
3002
    GeneratorExpressionContent const* /*content*/,
3003
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3004
531
  {
3005
531
    return cmSystemTools::MakeCidentifier(parameters.front());
3006
531
  }
3007
} makeCIdentifierNode;
3008
3009
template <char C>
3010
struct CharacterNode : public cmGeneratorExpressionNode
3011
{
3012
40
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)62>::CharacterNode()
Line
Count
Source
3012
10
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)44>::CharacterNode()
Line
Count
Source
3012
10
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)59>::CharacterNode()
Line
Count
Source
3012
10
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)34>::CharacterNode()
Line
Count
Source
3012
10
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
3013
3014
497
  int NumExpectedParameters() const override { return 0; }
CharacterNode<(char)62>::NumExpectedParameters() const
Line
Count
Source
3014
134
  int NumExpectedParameters() const override { return 0; }
CharacterNode<(char)44>::NumExpectedParameters() const
Line
Count
Source
3014
29
  int NumExpectedParameters() const override { return 0; }
CharacterNode<(char)59>::NumExpectedParameters() const
Line
Count
Source
3014
70
  int NumExpectedParameters() const override { return 0; }
CharacterNode<(char)34>::NumExpectedParameters() const
Line
Count
Source
3014
264
  int NumExpectedParameters() const override { return 0; }
3015
3016
  std::string Evaluate(
3017
    std::vector<std::string> const& /*parameters*/,
3018
    cm::GenEx::Evaluation* /*eval*/,
3019
    GeneratorExpressionContent const* /*content*/,
3020
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3021
497
  {
3022
497
    return { C };
3023
497
  }
CharacterNode<(char)62>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3021
134
  {
3022
134
    return { C };
3023
134
  }
CharacterNode<(char)44>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3021
29
  {
3022
29
    return { C };
3023
29
  }
CharacterNode<(char)59>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3021
70
  {
3022
70
    return { C };
3023
70
  }
CharacterNode<(char)34>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3021
264
  {
3022
264
    return { C };
3023
264
  }
3024
};
3025
static CharacterNode<'>'> const angle_rNode;
3026
static CharacterNode<','> const commaNode;
3027
static CharacterNode<';'> const semicolonNode;
3028
static CharacterNode<'"'> const quoteNode;
3029
3030
struct CompilerIdNode : public cmGeneratorExpressionNode
3031
{
3032
  CompilerIdNode(char const* compilerLang)
3033
90
    : CompilerLanguage(compilerLang)
3034
90
  {
3035
90
  }
3036
3037
1.01k
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3038
3039
  std::string Evaluate(
3040
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3041
    GeneratorExpressionContent const* content,
3042
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3043
1.01k
  {
3044
1.01k
    if (!eval->HeadTarget) {
3045
4
      reportError(
3046
4
        eval, content->GetOriginalExpression(),
3047
4
        cmStrCat("$<", this->CompilerLanguage,
3048
4
                 "_COMPILER_ID> may only be used with binary targets.  It may "
3049
4
                 "not be used with add_custom_command or add_custom_target."));
3050
4
      return {};
3051
4
    }
3052
1.00k
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3053
1.00k
                                      this->CompilerLanguage);
3054
1.01k
  }
3055
3056
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3057
                                   cm::GenEx::Evaluation* eval,
3058
                                   GeneratorExpressionContent const* content,
3059
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3060
                                   std::string const& lang) const
3061
1.00k
  {
3062
1.00k
    std::string const& compilerId =
3063
1.00k
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3064
1.00k
        cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
3065
1.00k
    if (parameters.empty()) {
3066
948
      return compilerId;
3067
948
    }
3068
59
    if (compilerId.empty()) {
3069
7
      return parameters.front().empty() ? "1" : "0";
3070
7
    }
3071
52
    static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
3072
3073
56
    for (auto const& param : parameters) {
3074
56
      if (!compilerIdValidator.find(param)) {
3075
16
        reportError(eval, content->GetOriginalExpression(),
3076
16
                    "Expression syntax not recognized.");
3077
16
        return std::string();
3078
16
      }
3079
3080
40
      if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
3081
0
        return "1";
3082
0
      }
3083
40
    }
3084
36
    return "0";
3085
52
  }
3086
3087
  char const* const CompilerLanguage;
3088
};
3089
3090
static CompilerIdNode const cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
3091
  cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"),
3092
  objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"),
3093
  hipCompilerIdNode("HIP"), ispcCompilerIdNode("ISPC"),
3094
  syclCompilerIdNode("SYCL");
3095
3096
struct CompilerVersionNode : public cmGeneratorExpressionNode
3097
{
3098
  CompilerVersionNode(char const* compilerLang)
3099
90
    : CompilerLanguage(compilerLang)
3100
90
  {
3101
90
  }
3102
3103
53
  int NumExpectedParameters() const override { return OneOrZeroParameters; }
3104
3105
  std::string Evaluate(
3106
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3107
    GeneratorExpressionContent const* content,
3108
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3109
53
  {
3110
53
    if (!eval->HeadTarget) {
3111
3
      reportError(eval, content->GetOriginalExpression(),
3112
3
                  cmStrCat("$<", this->CompilerLanguage,
3113
3
                           "_COMPILER_VERSION> may only be used with binary "
3114
3
                           "targets.  It may not be used with "
3115
3
                           "add_custom_command or add_custom_target."));
3116
3
      return {};
3117
3
    }
3118
50
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3119
50
                                      this->CompilerLanguage);
3120
53
  }
3121
3122
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3123
                                   cm::GenEx::Evaluation* eval,
3124
                                   GeneratorExpressionContent const* content,
3125
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3126
                                   std::string const& lang) const
3127
50
  {
3128
50
    std::string const& compilerVersion =
3129
50
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3130
50
        cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
3131
50
    if (parameters.empty()) {
3132
50
      return compilerVersion;
3133
50
    }
3134
3135
0
    static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
3136
0
    if (!compilerIdValidator.find(parameters.front())) {
3137
0
      reportError(eval, content->GetOriginalExpression(),
3138
0
                  "Expression syntax not recognized.");
3139
0
      return {};
3140
0
    }
3141
0
    if (compilerVersion.empty()) {
3142
0
      return parameters.front().empty() ? "1" : "0";
3143
0
    }
3144
3145
0
    return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
3146
0
                                         parameters.front(), compilerVersion)
3147
0
      ? "1"
3148
0
      : "0";
3149
0
  }
3150
3151
  char const* const CompilerLanguage;
3152
};
3153
3154
static CompilerVersionNode const cCompilerVersionNode("C"),
3155
  cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
3156
  objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"),
3157
  fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC"),
3158
  hipCompilerVersionNode("HIP"), syclCompilerVersionNode("SYCL");
3159
3160
struct CompilerFrontendVariantNode : public cmGeneratorExpressionNode
3161
{
3162
  CompilerFrontendVariantNode(char const* compilerLang)
3163
90
    : CompilerLanguage(compilerLang)
3164
90
  {
3165
90
  }
3166
3167
345
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3168
3169
  std::string Evaluate(
3170
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3171
    GeneratorExpressionContent const* content,
3172
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3173
345
  {
3174
345
    if (!eval->HeadTarget) {
3175
3
      reportError(
3176
3
        eval, content->GetOriginalExpression(),
3177
3
        cmStrCat("$<", this->CompilerLanguage,
3178
3
                 "_COMPILER_FRONTEND_VARIANT> may only be used with binary "
3179
3
                 "targets.  It may not be used with add_custom_command or "
3180
3
                 "add_custom_target."));
3181
3
      return {};
3182
3
    }
3183
342
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3184
342
                                      this->CompilerLanguage);
3185
345
  }
3186
3187
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3188
                                   cm::GenEx::Evaluation* eval,
3189
                                   GeneratorExpressionContent const* content,
3190
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3191
                                   std::string const& lang) const
3192
342
  {
3193
342
    std::string const& compilerFrontendVariant =
3194
342
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3195
342
        cmStrCat("CMAKE_", lang, "_COMPILER_FRONTEND_VARIANT"));
3196
342
    if (parameters.empty()) {
3197
342
      return compilerFrontendVariant;
3198
342
    }
3199
0
    if (compilerFrontendVariant.empty()) {
3200
0
      return parameters.front().empty() ? "1" : "0";
3201
0
    }
3202
0
    static cmsys::RegularExpression compilerFrontendVariantValidator(
3203
0
      "^[A-Za-z0-9_]*$");
3204
3205
0
    for (auto const& param : parameters) {
3206
0
      if (!compilerFrontendVariantValidator.find(param)) {
3207
0
        reportError(eval, content->GetOriginalExpression(),
3208
0
                    "Expression syntax not recognized.");
3209
0
        return {};
3210
0
      }
3211
0
      if (strcmp(param.c_str(), compilerFrontendVariant.c_str()) == 0) {
3212
0
        return "1";
3213
0
      }
3214
0
    }
3215
0
    return "0";
3216
0
  }
3217
3218
  char const* const CompilerLanguage;
3219
};
3220
3221
static CompilerFrontendVariantNode const cCompilerFrontendVariantNode("C"),
3222
  cxxCompilerFrontendVariantNode("CXX"),
3223
  cudaCompilerFrontendVariantNode("CUDA"),
3224
  objcCompilerFrontendVariantNode("OBJC"),
3225
  objcxxCompilerFrontendVariantNode("OBJCXX"),
3226
  fortranCompilerFrontendVariantNode("Fortran"),
3227
  hipCompilerFrontendVariantNode("HIP"),
3228
  ispcCompilerFrontendVariantNode("ISPC"),
3229
  syclCompilerFrontendVariantNode("SYCL");
3230
3231
struct PlatformIdNode : public cmGeneratorExpressionNode
3232
{
3233
10
  PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
3234
3235
250
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3236
3237
  std::string Evaluate(
3238
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3239
    GeneratorExpressionContent const* /*content*/,
3240
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3241
248
  {
3242
248
    std::string const& platformId =
3243
248
      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
3244
248
    if (parameters.empty()) {
3245
20
      return platformId;
3246
20
    }
3247
3248
228
    if (platformId.empty()) {
3249
0
      return parameters.front().empty() ? "1" : "0";
3250
0
    }
3251
3252
666
    for (auto const& param : parameters) {
3253
666
      if (param == platformId) {
3254
1
        return "1";
3255
1
      }
3256
666
    }
3257
227
    return "0";
3258
228
  }
3259
};
3260
static struct PlatformIdNode platformIdNode;
3261
3262
template <cmSystemTools::CompareOp Op>
3263
struct VersionNode : public cmGeneratorExpressionNode
3264
{
3265
50
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)4>::VersionNode()
Line
Count
Source
3265
10
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)5>::VersionNode()
Line
Count
Source
3265
10
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)2>::VersionNode()
Line
Count
Source
3265
10
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)3>::VersionNode()
Line
Count
Source
3265
10
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)1>::VersionNode()
Line
Count
Source
3265
10
  VersionNode() {} // NOLINT(modernize-use-equals-default)
3266
3267
181
  int NumExpectedParameters() const override { return 2; }
VersionNode<(cmSystemTools::CompareOp)4>::NumExpectedParameters() const
Line
Count
Source
3267
128
  int NumExpectedParameters() const override { return 2; }
Unexecuted instantiation: VersionNode<(cmSystemTools::CompareOp)5>::NumExpectedParameters() const
VersionNode<(cmSystemTools::CompareOp)2>::NumExpectedParameters() const
Line
Count
Source
3267
23
  int NumExpectedParameters() const override { return 2; }
VersionNode<(cmSystemTools::CompareOp)3>::NumExpectedParameters() const
Line
Count
Source
3267
8
  int NumExpectedParameters() const override { return 2; }
VersionNode<(cmSystemTools::CompareOp)1>::NumExpectedParameters() const
Line
Count
Source
3267
22
  int NumExpectedParameters() const override { return 2; }
3268
3269
  std::string Evaluate(
3270
    std::vector<std::string> const& parameters,
3271
    cm::GenEx::Evaluation* /*eval*/,
3272
    GeneratorExpressionContent const* /*content*/,
3273
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3274
149
  {
3275
149
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3276
149
      ? "1"
3277
149
      : "0";
3278
149
  }
VersionNode<(cmSystemTools::CompareOp)4>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3274
113
  {
3275
113
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3276
113
      ? "1"
3277
113
      : "0";
3278
113
  }
Unexecuted instantiation: VersionNode<(cmSystemTools::CompareOp)5>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
VersionNode<(cmSystemTools::CompareOp)2>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3274
17
  {
3275
17
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3276
17
      ? "1"
3277
17
      : "0";
3278
17
  }
VersionNode<(cmSystemTools::CompareOp)3>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3274
5
  {
3275
5
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3276
5
      ? "1"
3277
5
      : "0";
3278
5
  }
VersionNode<(cmSystemTools::CompareOp)1>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
3274
14
  {
3275
14
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3276
14
      ? "1"
3277
14
      : "0";
3278
14
  }
3279
};
3280
3281
static VersionNode<cmSystemTools::OP_GREATER> const versionGreaterNode;
3282
static VersionNode<cmSystemTools::OP_GREATER_EQUAL> const versionGreaterEqNode;
3283
static VersionNode<cmSystemTools::OP_LESS> const versionLessNode;
3284
static VersionNode<cmSystemTools::OP_LESS_EQUAL> const versionLessEqNode;
3285
static VersionNode<cmSystemTools::OP_EQUAL> const versionEqualNode;
3286
3287
static const struct CompileOnlyNode : public cmGeneratorExpressionNode
3288
{
3289
10
  CompileOnlyNode() {} // NOLINT(modernize-use-equals-default)
3290
3291
  std::string Evaluate(
3292
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3293
    GeneratorExpressionContent const* content,
3294
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3295
744
  {
3296
744
    if (!dagChecker) {
3297
6
      reportError(eval, content->GetOriginalExpression(),
3298
6
                  "$<COMPILE_ONLY:...> may only be used for linking");
3299
6
      return std::string();
3300
6
    }
3301
738
    if (dagChecker->GetTransitivePropertiesOnly()) {
3302
365
      return parameters.front();
3303
365
    }
3304
373
    return std::string{};
3305
738
  }
3306
} compileOnlyNode;
3307
3308
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
3309
{
3310
10
  LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
3311
3312
  std::string Evaluate(
3313
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3314
    GeneratorExpressionContent const* content,
3315
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3316
8.52k
  {
3317
8.52k
    if (!dagChecker) {
3318
6
      reportError(eval, content->GetOriginalExpression(),
3319
6
                  "$<LINK_ONLY:...> may only be used for linking");
3320
6
      return std::string();
3321
6
    }
3322
8.52k
    if (!dagChecker->GetTransitivePropertiesOnlyCMP0131()) {
3323
2.20k
      return parameters.front();
3324
2.20k
    }
3325
6.32k
    return std::string();
3326
8.52k
  }
3327
} linkOnlyNode;
3328
3329
static const struct ConfigurationNode : public cmGeneratorExpressionNode
3330
{
3331
10
  ConfigurationNode() {} // NOLINT(modernize-use-equals-default)
3332
3333
102
  int NumExpectedParameters() const override { return 0; }
3334
3335
  std::string Evaluate(
3336
    std::vector<std::string> const& /*parameters*/,
3337
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* /*content*/,
3338
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3339
632
  {
3340
632
    eval->HadContextSensitiveCondition = true;
3341
632
    return eval->Context.Config;
3342
632
  }
3343
} configurationNode;
3344
3345
static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
3346
{
3347
10
  ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default)
3348
3349
5.11k
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3350
3351
  std::string Evaluate(
3352
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3353
    GeneratorExpressionContent const* content,
3354
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3355
5.10k
  {
3356
5.10k
    if (parameters.empty()) {
3357
530
      return configurationNode.Evaluate(parameters, eval, content, nullptr);
3358
530
    }
3359
3360
4.57k
    eval->HadContextSensitiveCondition = true;
3361
3362
    // First, validate our arguments.
3363
4.57k
    static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
3364
4.57k
    bool firstParam = true;
3365
5.04k
    for (auto const& param : parameters) {
3366
5.04k
      if (!configValidator.find(param)) {
3367
436
        if (firstParam) {
3368
27
          reportError(eval, content->GetOriginalExpression(),
3369
27
                      "Expression syntax not recognized.");
3370
27
          return std::string();
3371
27
        }
3372
        // for backwards compat invalid config names are only errors as
3373
        // the first parameter
3374
409
        eval->Context.LG->GetCMakeInstance()->IssueMessage(
3375
409
          MessageType::WARNING,
3376
409
          cmStrCat("Warning evaluating generator expression:\n"
3377
409
                   "  ",
3378
409
                   content->GetOriginalExpression(),
3379
409
                   "\n"
3380
409
                   "The config name of \"",
3381
409
                   param, "\" is invalid"),
3382
409
          eval->Backtrace);
3383
409
      }
3384
5.01k
      firstParam = false;
3385
5.01k
    }
3386
3387
    // Partially determine the context(s) in which the expression should be
3388
    // evaluated.
3389
    //
3390
    // If CMPxxxx is NEW, the context is exactly one of the imported target's
3391
    // selected configuration, if applicable and if the target was imported
3392
    // from CPS, or the consuming target's configuration otherwise. Here, we
3393
    // determine if we are in that 'otherwise' branch.
3394
    //
3395
    // Longer term, we need a way for non-CPS users to match the selected
3396
    // configuration of the imported target. At that time, CPS should switch
3397
    // to that mechanism and the CPS-specific logic here should be dropped.
3398
    // (We can do that because CPS doesn't use generator expressions directly;
3399
    // rather, CMake generates them on import.)
3400
4.54k
    bool const targetIsImported =
3401
4.54k
      (eval->CurrentTarget && eval->CurrentTarget->IsImported());
3402
4.54k
    bool const useConsumerConfig =
3403
4.54k
      (targetIsImported &&
3404
8
       eval->CurrentTarget->Target->GetOrigin() != cmTarget::Origin::Cps);
3405
3406
4.54k
    if (!targetIsImported || useConsumerConfig) {
3407
      // Does the consuming target's configuration match any of the arguments?
3408
5.00k
      for (auto const& param : parameters) {
3409
5.00k
        if (eval->Context.Config.empty()) {
3410
494
          if (param.empty()) {
3411
3
            return "1";
3412
3
          }
3413
4.51k
        } else if (cmsysString_strcasecmp(param.c_str(),
3414
4.51k
                                          eval->Context.Config.c_str()) == 0) {
3415
972
          return "1";
3416
972
        }
3417
5.00k
      }
3418
4.54k
    }
3419
3420
3.57k
    if (targetIsImported) {
3421
8
      cmValue loc = nullptr;
3422
8
      cmValue imp = nullptr;
3423
8
      std::string suffix;
3424
8
      if (eval->CurrentTarget->Target->GetMappedConfig(eval->Context.Config,
3425
8
                                                       loc, imp, suffix)) {
3426
        // Finish determine the context(s) in which the expression should be
3427
        // evaluated. Note that we use the consumer's policy, so that end users
3428
        // can override the imported target's policy. This may be needed if
3429
        // upstream has changed their policy version without realizing that
3430
        // consumers were depending on the OLD behavior.
3431
8
        bool const oldPolicy = [&] {
3432
8
          if (!useConsumerConfig) {
3433
            // Targets imported from CPS shall use only the selected
3434
            // configuration of the imported target.
3435
0
            return false;
3436
0
          }
3437
8
          cmLocalGenerator const* const lg = eval->Context.LG;
3438
8
          switch (eval->HeadTarget->GetPolicyStatusCMP0199()) {
3439
8
            case cmPolicies::WARN:
3440
8
              if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
3441
8
                    "CMAKE_POLICY_WARNING_CMP0199")) {
3442
0
                lg->IssuePolicyWarning(
3443
0
                  cmPolicies::CMP0199, {},
3444
0
                  cmStrCat("Evaluation of $<CONFIG> for imported target  \""_s,
3445
0
                           eval->CurrentTarget->GetName(), "\", used by \""_s,
3446
0
                           eval->HeadTarget->GetName(),
3447
0
                           "\", may match multiple configurations."_s),
3448
0
                  eval->Backtrace);
3449
0
              }
3450
8
              CM_FALLTHROUGH;
3451
8
            case cmPolicies::OLD:
3452
8
              return true;
3453
0
            case cmPolicies::NEW:
3454
0
              return false;
3455
8
          }
3456
3457
0
          CM_UNREACHABLE;
3458
0
          return false;
3459
8
        }();
3460
3461
8
        if (oldPolicy) {
3462
          // If CMPxxxx is OLD (and we aren't dealing with a target imported
3463
          // form CPS), we already evaluated in the context of the consuming
3464
          // target. Next, for imported targets, we will evaluate based on the
3465
          // mapped configurations.
3466
          //
3467
          // If the target has a MAP_IMPORTED_CONFIG_<CONFIG> property for the
3468
          // consumer's <CONFIG>, we will match *any* config in that list,
3469
          // regardless of whether it's valid or of what GetMappedConfig
3470
          // actually picked. This will result in $<CONFIG> producing '1' for
3471
          // multiple configs, and is almost certainly wrong, but it's what
3472
          // CMake did for a very long time, and... Hyrum's Law.
3473
8
          cmList mappedConfigs;
3474
8
          std::string mapProp =
3475
8
            cmStrCat("MAP_IMPORTED_CONFIG_",
3476
8
                     cmSystemTools::UpperCase(eval->Context.Config));
3477
8
          if (cmValue mapValue = eval->CurrentTarget->GetProperty(mapProp)) {
3478
4
            mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue));
3479
3480
11
            for (auto const& param : parameters) {
3481
11
              if (cm::contains(mappedConfigs,
3482
11
                               cmSystemTools::UpperCase(param))) {
3483
0
                return "1";
3484
0
              }
3485
11
            }
3486
3487
4
            return "0";
3488
4
          }
3489
8
        }
3490
3491
        // Finally, check if we selected (possibly via mapping) a configuration
3492
        // for this imported target, and if we should evaluate the expression
3493
        // in the context of the same.
3494
        //
3495
        // For targets imported from CPS, this is the only context we evaluate
3496
        // the expression.
3497
4
        if (!suffix.empty()) {
3498
2
          for (auto const& param : parameters) {
3499
2
            if (cmStrCat('_', cmSystemTools::UpperCase(param)) == suffix) {
3500
0
              return "1";
3501
0
            }
3502
2
          }
3503
1
        }
3504
4
      }
3505
8
    }
3506
3507
3.56k
    return "0";
3508
3.57k
  }
3509
} configurationTestNode;
3510
3511
static const struct JoinNode : public cmGeneratorExpressionNode
3512
{
3513
10
  JoinNode() {} // NOLINT(modernize-use-equals-default)
3514
3515
77
  int NumExpectedParameters() const override { return 2; }
3516
3517
77
  bool AcceptsArbitraryContentParameter() const override { return true; }
3518
3519
  std::string Evaluate(
3520
    std::vector<std::string> const& parameters,
3521
    cm::GenEx::Evaluation* /*eval*/,
3522
    GeneratorExpressionContent const* /*content*/,
3523
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3524
56
  {
3525
56
    return cmList{ parameters.front() }.join(parameters[1]);
3526
56
  }
3527
} joinNode;
3528
3529
static const struct CompileLanguageNode : public cmGeneratorExpressionNode
3530
{
3531
10
  CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
3532
3533
982
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3534
3535
  std::string Evaluate(
3536
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3537
    GeneratorExpressionContent const* content,
3538
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3539
982
  {
3540
982
    if (eval->Context.Language.empty() &&
3541
629
        (!dagChecker || !dagChecker->EvaluatingCompileExpression())) {
3542
491
      reportError(
3543
491
        eval, content->GetOriginalExpression(),
3544
491
        "$<COMPILE_LANGUAGE:...> may only be used to specify include "
3545
491
        "directories, compile definitions, compile options, compile wrappers, "
3546
491
        "and to evaluate components of the file(GENERATE) command.");
3547
491
      return std::string();
3548
491
    }
3549
3550
491
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3551
491
    std::string genName = gg->GetName();
3552
491
    if (genName.find("Makefiles") == std::string::npos &&
3553
491
        genName.find("Ninja") == std::string::npos &&
3554
491
        genName.find("Visual Studio") == std::string::npos &&
3555
491
        genName.find("Xcode") == std::string::npos &&
3556
491
        genName.find("Watcom WMake") == std::string::npos &&
3557
491
        genName.find("FASTBuild") == std::string::npos &&
3558
491
        genName.find("Green Hills MULTI") == std::string::npos) {
3559
491
      reportError(eval, content->GetOriginalExpression(),
3560
491
                  "$<COMPILE_LANGUAGE:...> not supported for this generator.");
3561
491
      return std::string();
3562
491
    }
3563
0
    if (parameters.empty()) {
3564
0
      return eval->Context.Language;
3565
0
    }
3566
3567
0
    for (auto const& param : parameters) {
3568
0
      if (eval->Context.Language == param) {
3569
0
        return "1";
3570
0
      }
3571
0
    }
3572
0
    return "0";
3573
0
  }
3574
} languageNode;
3575
3576
static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
3577
{
3578
10
  CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
3579
3580
67
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3581
3582
  std::string Evaluate(
3583
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3584
    GeneratorExpressionContent const* content,
3585
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3586
58
  {
3587
58
    if (!eval->HeadTarget ||
3588
55
        (eval->Context.Language.empty() &&
3589
9
         (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) {
3590
      // reportError(eval, content->GetOriginalExpression(), "");
3591
9
      reportError(
3592
9
        eval, content->GetOriginalExpression(),
3593
9
        "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary "
3594
9
        "targets "
3595
9
        "to specify include directories, compile definitions, compile "
3596
9
        "options, and compile wrappers.  It may not be used with the "
3597
9
        "add_custom_command, add_custom_target, or file(GENERATE) commands.");
3598
9
      return std::string();
3599
9
    }
3600
49
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3601
49
    std::string genName = gg->GetName();
3602
49
    if (genName.find("Makefiles") == std::string::npos &&
3603
49
        genName.find("Ninja") == std::string::npos &&
3604
49
        genName.find("FASTBuild") == std::string::npos &&
3605
49
        genName.find("Visual Studio") == std::string::npos &&
3606
49
        genName.find("Xcode") == std::string::npos &&
3607
49
        genName.find("Watcom WMake") == std::string::npos &&
3608
49
        genName.find("Green Hills MULTI") == std::string::npos) {
3609
49
      reportError(
3610
49
        eval, content->GetOriginalExpression(),
3611
49
        "$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
3612
49
      return std::string();
3613
49
    }
3614
3615
0
    std::string const& lang = eval->Context.Language;
3616
0
    if (lang == parameters.front()) {
3617
0
      std::vector<std::string> idParameter((parameters.cbegin() + 1),
3618
0
                                           parameters.cend());
3619
0
      return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
3620
0
        idParameter, eval, content, dagChecker, lang);
3621
0
    }
3622
0
    return "0";
3623
0
  }
3624
} languageAndIdNode;
3625
3626
static const struct LinkLanguageNode : public cmGeneratorExpressionNode
3627
{
3628
10
  LinkLanguageNode() {} // NOLINT(modernize-use-equals-default)
3629
3630
140
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3631
3632
  std::string Evaluate(
3633
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3634
    GeneratorExpressionContent const* content,
3635
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3636
136
  {
3637
136
    if (!eval->HeadTarget || !dagChecker ||
3638
129
        !(dagChecker->EvaluatingLinkExpression() ||
3639
20
          dagChecker->EvaluatingLinkLibraries() ||
3640
15
          dagChecker->EvaluatingLinkerLauncher())) {
3641
15
      reportError(eval, content->GetOriginalExpression(),
3642
15
                  "$<LINK_LANGUAGE:...> may only be used with binary targets "
3643
15
                  "to specify link libraries, link directories, link options, "
3644
15
                  "link depends, and link wrappers.");
3645
15
      return std::string();
3646
15
    }
3647
121
    if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) {
3648
6
      reportError(
3649
6
        eval, content->GetOriginalExpression(),
3650
6
        "$<LINK_LANGUAGE> is not supported in link libraries expression.");
3651
6
      return std::string();
3652
6
    }
3653
3654
115
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3655
115
    std::string genName = gg->GetName();
3656
115
    if (genName.find("Makefiles") == std::string::npos &&
3657
115
        genName.find("Ninja") == std::string::npos &&
3658
115
        genName.find("FASTBuild") == std::string::npos &&
3659
115
        genName.find("Visual Studio") == std::string::npos &&
3660
115
        genName.find("Xcode") == std::string::npos &&
3661
115
        genName.find("Watcom WMake") == std::string::npos &&
3662
115
        genName.find("Green Hills MULTI") == std::string::npos) {
3663
115
      reportError(eval, content->GetOriginalExpression(),
3664
115
                  "$<LINK_LANGUAGE:...> not supported for this generator.");
3665
115
      return std::string();
3666
115
    }
3667
3668
0
    if (dagChecker->EvaluatingLinkLibraries()) {
3669
0
      eval->HadHeadSensitiveCondition = true;
3670
0
      eval->HadLinkLanguageSensitiveCondition = true;
3671
0
    }
3672
3673
0
    if (parameters.empty()) {
3674
0
      return eval->Context.Language;
3675
0
    }
3676
3677
0
    for (auto const& param : parameters) {
3678
0
      if (eval->Context.Language == param) {
3679
0
        return "1";
3680
0
      }
3681
0
    }
3682
0
    return "0";
3683
0
  }
3684
} linkLanguageNode;
3685
3686
namespace {
3687
struct LinkerId
3688
{
3689
  static std::string Evaluate(std::vector<std::string> const& parameters,
3690
                              cm::GenEx::Evaluation* eval,
3691
                              GeneratorExpressionContent const* content,
3692
                              std::string const& lang)
3693
0
  {
3694
0
    std::string const& linkerId =
3695
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3696
0
        cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
3697
0
    if (parameters.empty()) {
3698
0
      return linkerId;
3699
0
    }
3700
0
    if (linkerId.empty()) {
3701
0
      return parameters.front().empty() ? "1" : "0";
3702
0
    }
3703
0
    static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$");
3704
3705
0
    for (auto const& param : parameters) {
3706
0
      if (!linkerIdValidator.find(param)) {
3707
0
        reportError(eval, content->GetOriginalExpression(),
3708
0
                    "Expression syntax not recognized.");
3709
0
        return std::string();
3710
0
      }
3711
3712
0
      if (param == linkerId) {
3713
0
        return "1";
3714
0
      }
3715
0
    }
3716
0
    return "0";
3717
0
  }
3718
};
3719
}
3720
3721
static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
3722
{
3723
10
  LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
3724
3725
34
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3726
3727
  std::string Evaluate(
3728
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3729
    GeneratorExpressionContent const* content,
3730
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3731
14
  {
3732
14
    if (!eval->HeadTarget || !dagChecker ||
3733
9
        !(dagChecker->EvaluatingLinkExpression() ||
3734
9
          dagChecker->EvaluatingLinkLibraries() ||
3735
8
          dagChecker->EvaluatingLinkerLauncher())) {
3736
8
      reportError(
3737
8
        eval, content->GetOriginalExpression(),
3738
8
        "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
3739
8
        "to specify link libraries, link directories, link options, link "
3740
8
        "depends, and link wrappers.");
3741
8
      return std::string();
3742
8
    }
3743
3744
6
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3745
6
    std::string genName = gg->GetName();
3746
6
    if (genName.find("Makefiles") == std::string::npos &&
3747
6
        genName.find("Ninja") == std::string::npos &&
3748
6
        genName.find("FASTBuild") == std::string::npos &&
3749
6
        genName.find("Visual Studio") == std::string::npos &&
3750
6
        genName.find("Xcode") == std::string::npos &&
3751
6
        genName.find("Watcom WMake") == std::string::npos &&
3752
6
        genName.find("Green Hills MULTI") == std::string::npos) {
3753
6
      reportError(
3754
6
        eval, content->GetOriginalExpression(),
3755
6
        "$<LINK_LANG_AND_ID:lang,id> not supported for this generator.");
3756
6
      return std::string();
3757
6
    }
3758
3759
0
    if (dagChecker->EvaluatingLinkLibraries()) {
3760
0
      eval->HadHeadSensitiveCondition = true;
3761
0
      eval->HadLinkLanguageSensitiveCondition = true;
3762
0
    }
3763
3764
0
    std::string const& lang = eval->Context.Language;
3765
0
    if (lang == parameters.front()) {
3766
0
      std::vector<std::string> idParameter((parameters.cbegin() + 1),
3767
0
                                           parameters.cend());
3768
0
      return LinkerId::Evaluate(idParameter, eval, content, lang);
3769
0
    }
3770
0
    return "0";
3771
0
  }
3772
} linkLanguageAndIdNode;
3773
3774
struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
3775
{
3776
  CompilerLinkerIdNode(char const* lang)
3777
80
    : Language(lang)
3778
80
  {
3779
80
  }
3780
3781
50
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3782
3783
  std::string Evaluate(
3784
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3785
    GeneratorExpressionContent const* content,
3786
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3787
50
  {
3788
50
    if (!eval->HeadTarget) {
3789
3
      reportError(
3790
3
        eval, content->GetOriginalExpression(),
3791
3
        cmStrCat(
3792
3
          "$<", this->Language,
3793
3
          "_COMPILER_LINKER_ID> may only be used with binary targets. It may "
3794
3
          "not be used with add_custom_command or add_custom_target."));
3795
3
      return {};
3796
3
    }
3797
47
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3798
47
                                      this->Language);
3799
50
  }
3800
3801
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3802
                                   cm::GenEx::Evaluation* eval,
3803
                                   GeneratorExpressionContent const* content,
3804
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3805
                                   std::string const& lang) const
3806
47
  {
3807
47
    std::string const& compilerLinkerId =
3808
47
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3809
47
        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
3810
47
    if (parameters.empty()) {
3811
47
      return compilerLinkerId;
3812
47
    }
3813
0
    if (compilerLinkerId.empty()) {
3814
0
      return parameters.front().empty() ? "1" : "0";
3815
0
    }
3816
0
    static cmsys::RegularExpression compilerLinkerIdValidator(
3817
0
      "^[A-Za-z0-9_]*$");
3818
3819
0
    for (auto const& param : parameters) {
3820
0
      if (!compilerLinkerIdValidator.find(param)) {
3821
0
        reportError(eval, content->GetOriginalExpression(),
3822
0
                    "Expression syntax not recognized.");
3823
0
        return std::string();
3824
0
      }
3825
3826
0
      if (param == compilerLinkerId) {
3827
0
        return "1";
3828
0
      }
3829
0
    }
3830
0
    return "0";
3831
0
  }
3832
3833
  char const* const Language;
3834
};
3835
3836
static CompilerLinkerIdNode const cCompilerLinkerIdNode("C"),
3837
  cxxCompilerLinkerIdNode("CXX"), cudaCompilerLinkerIdNode("CUDA"),
3838
  objcCompilerLinkerIdNode("OBJC"), objcxxCompilerLinkerIdNode("OBJCXX"),
3839
  fortranCompilerLinkerIdNode("Fortran"), hipCompilerLinkerIdNode("HIP"),
3840
  syclCompilerLinkerIdNode("SYCL");
3841
3842
struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
3843
{
3844
  CompilerLinkerFrontendVariantNode(char const* lang)
3845
80
    : Language(lang)
3846
80
  {
3847
80
  }
3848
3849
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3850
3851
  std::string Evaluate(
3852
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3853
    GeneratorExpressionContent const* content,
3854
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3855
0
  {
3856
0
    if (!eval->HeadTarget) {
3857
0
      reportError(
3858
0
        eval, content->GetOriginalExpression(),
3859
0
        cmStrCat(
3860
0
          "$<", this->Language,
3861
0
          "_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary "
3862
0
          "targets. It may not be used with add_custom_command or "
3863
0
          "add_custom_target."));
3864
0
      return {};
3865
0
    }
3866
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3867
0
                                      this->Language);
3868
0
  }
3869
3870
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3871
                                   cm::GenEx::Evaluation* eval,
3872
                                   GeneratorExpressionContent const* content,
3873
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3874
                                   std::string const& lang) const
3875
0
  {
3876
0
    std::string const& compilerLinkerFrontendVariant =
3877
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3878
0
        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
3879
0
    if (parameters.empty()) {
3880
0
      return compilerLinkerFrontendVariant;
3881
0
    }
3882
0
    if (compilerLinkerFrontendVariant.empty()) {
3883
0
      return parameters.front().empty() ? "1" : "0";
3884
0
    }
3885
0
    static cmsys::RegularExpression compilerLinkerFrontendVariantValidator(
3886
0
      "^[A-Za-z0-9_]*$");
3887
3888
0
    for (auto const& param : parameters) {
3889
0
      if (!compilerLinkerFrontendVariantValidator.find(param)) {
3890
0
        reportError(eval, content->GetOriginalExpression(),
3891
0
                    "Expression syntax not recognized.");
3892
0
        return {};
3893
0
      }
3894
0
      if (param == compilerLinkerFrontendVariant) {
3895
0
        return "1";
3896
0
      }
3897
0
    }
3898
0
    return "0";
3899
0
  }
3900
3901
  char const* const Language;
3902
};
3903
3904
static CompilerLinkerFrontendVariantNode const
3905
  cCompilerLinkerFrontendVariantNode("C"),
3906
  cxxCompilerLinkerFrontendVariantNode("CXX"),
3907
  cudaCompilerLinkerFrontendVariantNode("CUDA"),
3908
  objcCompilerLinkerFrontendVariantNode("OBJC"),
3909
  objcxxCompilerLinkerFrontendVariantNode("OBJCXX"),
3910
  fortranCompilerLinkerFrontendVariantNode("Fortran"),
3911
  hipCompilerLinkerFrontendVariantNode("HIP"),
3912
  syclCompilerLinkerFrontendVariantNode("SYCL");
3913
3914
static const struct LinkLibraryNode : public cmGeneratorExpressionNode
3915
{
3916
10
  LinkLibraryNode() {} // NOLINT(modernize-use-equals-default)
3917
3918
2.24k
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3919
3920
  std::string Evaluate(
3921
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3922
    GeneratorExpressionContent const* content,
3923
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3924
2.23k
  {
3925
2.23k
    using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
3926
3927
2.23k
    if (!eval->HeadTarget || !dagChecker ||
3928
2.22k
        !dagChecker->EvaluatingLinkLibraries(nullptr,
3929
2.22k
                                             ForGenex::LINK_LIBRARY)) {
3930
13
      reportError(eval, content->GetOriginalExpression(),
3931
13
                  "$<LINK_LIBRARY:...> may only be used with binary targets "
3932
13
                  "to specify link libraries through 'LINK_LIBRARIES', "
3933
13
                  "'INTERFACE_LINK_LIBRARIES', and "
3934
13
                  "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
3935
13
      return std::string();
3936
13
    }
3937
3938
2.22k
    cmList list{ parameters.begin(), parameters.end() };
3939
2.22k
    if (list.empty()) {
3940
2
      reportError(
3941
2
        eval, content->GetOriginalExpression(),
3942
2
        "$<LINK_LIBRARY:...> expects a feature name as first argument.");
3943
2
      return std::string();
3944
2
    }
3945
2.22k
    if (list.size() == 1) {
3946
      // no libraries specified, ignore this genex
3947
142
      return std::string();
3948
142
    }
3949
3950
2.08k
    static cmsys::RegularExpression featureNameValidator("^[A-Za-z0-9_]+$");
3951
2.08k
    auto const& feature = list.front();
3952
2.08k
    if (!featureNameValidator.find(feature)) {
3953
19
      reportError(eval, content->GetOriginalExpression(),
3954
19
                  cmStrCat("The feature name '", feature,
3955
19
                           "' contains invalid characters."));
3956
19
      return std::string();
3957
19
    }
3958
3959
2.06k
    auto const LL_BEGIN = cmStrCat("<LINK_LIBRARY:", feature, '>');
3960
2.06k
    auto const LL_END = cmStrCat("</LINK_LIBRARY:", feature, '>');
3961
3962
    // filter out $<LINK_LIBRARY:..> tags with same feature
3963
    // and raise an error for any different feature
3964
10.6k
    cm::erase_if(list, [&](std::string const& item) -> bool {
3965
10.6k
      return item == LL_BEGIN || item == LL_END;
3966
10.6k
    });
3967
2.06k
    auto it =
3968
2.06k
      std::find_if(list.cbegin() + 1, list.cend(),
3969
8.00k
                   [&feature](std::string const& item) -> bool {
3970
8.00k
                     return cmHasPrefix(item, "<LINK_LIBRARY:"_s) &&
3971
24
                       item.substr(14, item.find('>', 14) - 14) != feature;
3972
8.00k
                   });
3973
2.06k
    if (it != list.cend()) {
3974
22
      reportError(
3975
22
        eval, content->GetOriginalExpression(),
3976
22
        "$<LINK_LIBRARY:...> with different features cannot be nested.");
3977
22
      return std::string();
3978
22
    }
3979
    // $<LINK_GROUP:...> must not appear as part of $<LINK_LIBRARY:...>
3980
2.03k
    it = std::find_if(list.cbegin() + 1, list.cend(),
3981
7.53k
                      [](std::string const& item) -> bool {
3982
7.53k
                        return cmHasPrefix(item, "<LINK_GROUP:"_s);
3983
7.53k
                      });
3984
2.03k
    if (it != list.cend()) {
3985
24
      reportError(eval, content->GetOriginalExpression(),
3986
24
                  "$<LINK_GROUP:...> cannot be nested inside a "
3987
24
                  "$<LINK_LIBRARY:...> expression.");
3988
24
      return std::string();
3989
24
    }
3990
3991
2.01k
    list.front() = LL_BEGIN;
3992
2.01k
    list.push_back(LL_END);
3993
3994
2.01k
    return list.to_string();
3995
2.03k
  }
3996
} linkLibraryNode;
3997
3998
static const struct LinkGroupNode : public cmGeneratorExpressionNode
3999
{
4000
10
  LinkGroupNode() {} // NOLINT(modernize-use-equals-default)
4001
4002
1.79k
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4003
4004
  std::string Evaluate(
4005
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4006
    GeneratorExpressionContent const* content,
4007
    cmGeneratorExpressionDAGChecker* dagChecker) const override
4008
1.72k
  {
4009
1.72k
    using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
4010
4011
1.72k
    if (!eval->HeadTarget || !dagChecker ||
4012
1.71k
        !dagChecker->EvaluatingLinkLibraries(nullptr, ForGenex::LINK_GROUP)) {
4013
24
      reportError(
4014
24
        eval, content->GetOriginalExpression(),
4015
24
        "$<LINK_GROUP:...> may only be used with binary targets "
4016
24
        "to specify group of link libraries through 'LINK_LIBRARIES', "
4017
24
        "'INTERFACE_LINK_LIBRARIES', and "
4018
24
        "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
4019
24
      return std::string();
4020
24
    }
4021
4022
1.70k
    cmList list{ parameters.begin(), parameters.end() };
4023
1.70k
    if (list.empty()) {
4024
2
      reportError(
4025
2
        eval, content->GetOriginalExpression(),
4026
2
        "$<LINK_GROUP:...> expects a feature name as first argument.");
4027
2
      return std::string();
4028
2
    }
4029
    // $<LINK_GROUP:..> cannot be nested
4030
1.70k
    if (std::find_if(list.cbegin(), list.cend(),
4031
4.99k
                     [](std::string const& item) -> bool {
4032
4.99k
                       return cmHasPrefix(item, "<LINK_GROUP"_s);
4033
4.99k
                     }) != list.cend()) {
4034
2
      reportError(eval, content->GetOriginalExpression(),
4035
2
                  "$<LINK_GROUP:...> cannot be nested.");
4036
2
      return std::string();
4037
2
    }
4038
1.69k
    if (list.size() == 1) {
4039
      // no libraries specified, ignore this genex
4040
73
      return std::string();
4041
73
    }
4042
4043
1.62k
    static cmsys::RegularExpression featureNameValidator("^[A-Za-z0-9_]+$");
4044
1.62k
    auto const& feature = list.front();
4045
1.62k
    if (!featureNameValidator.find(feature)) {
4046
26
      reportError(eval, content->GetOriginalExpression(),
4047
26
                  cmStrCat("The feature name '", feature,
4048
26
                           "' contains invalid characters."));
4049
26
      return std::string();
4050
26
    }
4051
4052
1.59k
    auto const LG_BEGIN = cmStrCat(
4053
1.59k
      "<LINK_GROUP:", feature, ':',
4054
1.59k
      cmJoin(cmRange<decltype(list.cbegin())>(list.cbegin() + 1, list.cend()),
4055
1.59k
             "|"_s),
4056
1.59k
      '>');
4057
1.59k
    auto const LG_END = cmStrCat("</LINK_GROUP:", feature, '>');
4058
4059
1.59k
    list.front() = LG_BEGIN;
4060
1.59k
    list.push_back(LG_END);
4061
4062
1.59k
    return list.to_string();
4063
1.62k
  }
4064
} linkGroupNode;
4065
4066
static const struct HostLinkNode : public cmGeneratorExpressionNode
4067
{
4068
10
  HostLinkNode() {} // NOLINT(modernize-use-equals-default)
4069
4070
30
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
4071
4072
  std::string Evaluate(
4073
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4074
    GeneratorExpressionContent const* content,
4075
    cmGeneratorExpressionDAGChecker* dagChecker) const override
4076
21
  {
4077
21
    if (!eval->HeadTarget || !dagChecker ||
4078
21
        !dagChecker->EvaluatingLinkOptionsExpression()) {
4079
21
      reportError(eval, content->GetOriginalExpression(),
4080
21
                  "$<HOST_LINK:...> may only be used with binary targets "
4081
21
                  "to specify link options.");
4082
21
      return std::string();
4083
21
    }
4084
4085
0
    return eval->HeadTarget->IsDeviceLink() ? std::string()
4086
0
                                            : cmList::to_string(parameters);
4087
21
  }
4088
} hostLinkNode;
4089
4090
static const struct DeviceLinkNode : public cmGeneratorExpressionNode
4091
{
4092
10
  DeviceLinkNode() {} // NOLINT(modernize-use-equals-default)
4093
4094
12
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
4095
4096
  std::string Evaluate(
4097
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4098
    GeneratorExpressionContent const* content,
4099
    cmGeneratorExpressionDAGChecker* dagChecker) const override
4100
11
  {
4101
11
    if (!eval->HeadTarget || !dagChecker ||
4102
11
        !dagChecker->EvaluatingLinkOptionsExpression()) {
4103
11
      reportError(eval, content->GetOriginalExpression(),
4104
11
                  "$<DEVICE_LINK:...> may only be used with binary targets "
4105
11
                  "to specify link options.");
4106
11
      return std::string();
4107
11
    }
4108
4109
0
    if (eval->HeadTarget->IsDeviceLink()) {
4110
0
      cmList list{ parameters.begin(), parameters.end() };
4111
0
      auto const DL_BEGIN = "<DEVICE_LINK>"_s;
4112
0
      auto const DL_END = "</DEVICE_LINK>"_s;
4113
0
      cm::erase_if(list, [&](std::string const& item) {
4114
0
        return item == DL_BEGIN || item == DL_END;
4115
0
      });
4116
4117
0
      list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
4118
0
      list.push_back(static_cast<std::string>(DL_END));
4119
4120
0
      return list.to_string();
4121
0
    }
4122
4123
0
    return std::string();
4124
0
  }
4125
} deviceLinkNode;
4126
4127
static const struct GlobalPropertyNode : public cmGeneratorExpressionNode
4128
{
4129
10
  GlobalPropertyNode() {} // NOLINT(modernize-use-equals-default)
4130
4131
  // This node handles errors on parameter count itself.
4132
158
  int NumExpectedParameters() const override { return 1; }
4133
4134
  std::string Evaluate(
4135
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4136
    GeneratorExpressionContent const* content,
4137
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
4138
156
  {
4139
156
    auto const& propertyName = parameters[0];
4140
4141
156
    if (propertyName.empty()) {
4142
3
      reportError(eval, content->GetOriginalExpression(),
4143
3
                  "$<GLOBAL_PROPERTY:property> expression requires a "
4144
3
                  "non-empty property name.");
4145
3
      return std::string{};
4146
3
    }
4147
153
    if (!IsValidPropertyName(eval, content, propertyName)) {
4148
13
      return std::string{};
4149
13
    }
4150
140
    cmake* cm = eval->Context.LG->GetCMakeInstance();
4151
140
    return cm->GetState()->GetGlobalProperty(propertyName);
4152
153
  }
4153
} globalPropertyNode;
4154
4155
static const struct DirectoryPropertyNode : public cmGeneratorExpressionNode
4156
{
4157
10
  DirectoryPropertyNode() {} // NOLINT(modernize-use-equals-default)
4158
4159
  // This node handles errors on parameter count itself.
4160
0
  int NumExpectedParameters() const override { return 2; }
4161
4162
  std::string Evaluate(
4163
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4164
    GeneratorExpressionContent const* content,
4165
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
4166
0
  {
4167
0
    auto const& directoryName = parameters[0];
4168
0
    auto const& propertyName = parameters[1];
4169
4170
0
    if (directoryName.empty()) {
4171
0
      reportError(
4172
0
        eval, content->GetOriginalExpression(),
4173
0
        "$<DIRECTORY_PROPERTY:directory,property> expression requires a "
4174
0
        "non-empty directory name.");
4175
0
      return std::string{};
4176
0
    }
4177
0
    if (propertyName.empty()) {
4178
0
      reportError(
4179
0
        eval, content->GetOriginalExpression(),
4180
0
        "$<DIRECTORY_PROPERTY:directory,property> expression requires a "
4181
0
        "non-empty property name.");
4182
0
      return std::string{};
4183
0
    }
4184
0
    if (!IsValidPropertyName(eval, content, propertyName)) {
4185
0
      return std::string{};
4186
0
    }
4187
4188
0
    cmValue value;
4189
0
    cmGetDirectoryPropertyResult status = cmGetDirectoryProperty(
4190
0
      directoryName, propertyName, *eval->Context.LG->GetMakefile(), value);
4191
0
    if (status == cmGetDirectoryPropertyResult::DirectoryNotFound) {
4192
0
      reportError(
4193
0
        eval, content->GetOriginalExpression(),
4194
0
        cmStrCat("Directory \"", directoryName, "\" was not found."));
4195
0
      return std::string{};
4196
0
    }
4197
4198
0
    return value;
4199
0
  }
4200
} directoryPropertyNode;
4201
4202
namespace {
4203
bool GetFileSet(std::vector<std::string> const& parameters,
4204
                cm::GenEx::Evaluation* eval,
4205
                GeneratorExpressionContent const* content,
4206
                cmGeneratorTarget const*& target,
4207
                cmGeneratorFileSet const*& fileSet)
4208
98
{
4209
98
  auto const& fileSetName = parameters[0];
4210
98
  auto targetName = parameters[1];
4211
98
  fileSet = nullptr;
4212
4213
98
  auto const TARGET = "TARGET:"_s;
4214
4215
98
  if (cmHasPrefix(targetName, TARGET)) {
4216
92
    targetName = targetName.substr(TARGET.length());
4217
92
    if (targetName.empty()) {
4218
0
      reportError(eval, content->GetOriginalExpression(),
4219
0
                  cmStrCat("No value provided for the ", TARGET, " option."));
4220
0
      return false;
4221
0
    }
4222
4223
92
    cmLocalGenerator const* lg = eval->CurrentTarget
4224
92
      ? eval->CurrentTarget->GetLocalGenerator()
4225
92
      : eval->Context.LG;
4226
92
    target = lg->FindGeneratorTargetToUse(targetName);
4227
92
    if (!target) {
4228
23
      reportError(eval, content->GetOriginalExpression(),
4229
23
                  cmStrCat("Non-existent target: ", targetName));
4230
23
      return false;
4231
23
    }
4232
69
    fileSet = target->GetFileSet(fileSetName);
4233
69
  } else {
4234
6
    reportError(eval, content->GetOriginalExpression(),
4235
6
                cmStrCat("Invalid option. ", TARGET, " expected."));
4236
6
    return false;
4237
6
  }
4238
69
  return true;
4239
98
}
4240
}
4241
4242
static const struct FileSetExistsNode : public cmGeneratorExpressionNode
4243
{
4244
10
  FileSetExistsNode() {} // NOLINT(modernize-use-equals-default)
4245
4246
  // This node handles errors on parameter count itself.
4247
86
  int NumExpectedParameters() const override { return 2; }
4248
4249
  std::string Evaluate(
4250
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4251
    GeneratorExpressionContent const* content,
4252
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
4253
70
  {
4254
70
    if (parameters[0].empty()) {
4255
1
      reportError(
4256
1
        eval, content->GetOriginalExpression(),
4257
1
        "$<FILE_SET_EXISTS:fileset,TARGET:tgt> expression requires a "
4258
1
        "non-empty FILE_SET name.");
4259
1
      return std::string{};
4260
1
    }
4261
4262
69
    cmGeneratorTarget const* target = nullptr;
4263
69
    cmGeneratorFileSet const* fileSet = nullptr;
4264
69
    if (!GetFileSet(parameters, eval, content, target, fileSet)) {
4265
24
      return std::string{};
4266
24
    }
4267
4268
45
    return fileSet ? "1" : "0";
4269
69
  }
4270
} fileSetExistsNode;
4271
4272
static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
4273
{
4274
10
  FileSetPropertyNode() {} // NOLINT(modernize-use-equals-default)
4275
4276
  // This node handles errors on parameter count itself.
4277
49
  int NumExpectedParameters() const override { return 3; }
4278
4279
  std::string Evaluate(
4280
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4281
    GeneratorExpressionContent const* content,
4282
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
4283
36
  {
4284
36
    std::string const& fileSetName = parameters.front();
4285
36
    std::string const& propertyName = parameters.back();
4286
4287
36
    if (fileSetName.empty() && propertyName.empty()) {
4288
0
      reportError(eval, content->GetOriginalExpression(),
4289
0
                  "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression "
4290
0
                  "requires a non-empty FILE_SET name and property name.");
4291
0
      return std::string{};
4292
0
    }
4293
36
    if (fileSetName.empty()) {
4294
3
      reportError(
4295
3
        eval, content->GetOriginalExpression(),
4296
3
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
4297
3
        "non-empty FILE_SET name.");
4298
3
      return std::string{};
4299
3
    }
4300
33
    if (propertyName.empty()) {
4301
0
      reportError(
4302
0
        eval, content->GetOriginalExpression(),
4303
0
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
4304
0
        "non-empty property name.");
4305
0
      return std::string{};
4306
0
    }
4307
33
    if (!IsValidPropertyName(eval, content, propertyName)) {
4308
4
      return std::string{};
4309
4
    }
4310
4311
29
    cmGeneratorTarget const* target = nullptr;
4312
29
    cmGeneratorFileSet const* fileSet = nullptr;
4313
29
    if (!GetFileSet(parameters, eval, content, target, fileSet)) {
4314
5
      return std::string{};
4315
5
    }
4316
24
    if (!fileSet) {
4317
7
      reportError(
4318
7
        eval, content->GetOriginalExpression(),
4319
7
        cmStrCat("FILE_SET \"", fileSetName, "\" is not known from CMake."));
4320
7
      return std::string{};
4321
7
    }
4322
4323
17
    auto result = fileSet->GetProperty(propertyName);
4324
4325
17
    if (propertyName == "BASE_DIRS"_s || propertyName == "SOURCES"_s ||
4326
17
        propertyName == "INTERFACE_SOURCES"_s ||
4327
17
        propertyName == "INCLUDE_DIRECTORIES"_s ||
4328
17
        propertyName == "INTERFACE_INCLUDE_DIRECTORIES"_s ||
4329
17
        propertyName == "COMPILE_OPTIONS"_s ||
4330
17
        propertyName == "INTERFACE_COMPILE_OPTIONS"_s ||
4331
17
        propertyName == "COMPILE_DEFINITIONS"_s ||
4332
17
        propertyName == "INTERFACE_COMPILE_DEFINITIONS"_s) {
4333
0
      cmGeneratorExpressionDAGChecker dagChecker{
4334
0
        target,           propertyName,  content,
4335
0
        dagCheckerParent, eval->Context, eval->Backtrace,
4336
0
      };
4337
0
      switch (dagChecker.Check()) {
4338
0
        case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4339
0
          dagChecker.ReportError(eval, content->GetOriginalExpression());
4340
0
          return std::string{};
4341
0
        case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
4342
          // No error. We just skip cyclic references.
4343
0
          return std::string{};
4344
0
        case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4345
0
        case cmGeneratorExpressionDAGChecker::DAG:
4346
0
          break;
4347
0
      }
4348
4349
0
      return cmGeneratorExpression::StripEmptyListElements(
4350
0
        this->EvaluateDependentExpression(result, eval, target, &dagChecker,
4351
0
                                          target));
4352
0
    }
4353
4354
17
    return result;
4355
17
  }
4356
} fileSetPropertyNode;
4357
4358
namespace {
4359
bool GetSourceFile(
4360
  cmRange<std::vector<std::string>::const_iterator> parameters,
4361
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
4362
  cmSourceFile*& sourceFile)
4363
2.35k
{
4364
2.35k
  auto sourceName = *parameters.begin();
4365
2.35k
  auto* makefile = eval->Context.LG->GetMakefile();
4366
2.35k
  sourceFile = nullptr;
4367
4368
2.35k
  if (parameters.size() == 2) {
4369
23
    auto const& option = *parameters.advance(1).begin();
4370
23
    auto const DIRECTORY = "DIRECTORY:"_s;
4371
23
    auto const TARGET_DIRECTORY = "TARGET_DIRECTORY:"_s;
4372
23
    if (cmHasPrefix(option, DIRECTORY)) {
4373
0
      auto dir = option.substr(DIRECTORY.length());
4374
0
      if (dir.empty()) {
4375
0
        reportError(
4376
0
          eval, content->GetOriginalExpression(),
4377
0
          cmStrCat("No value provided for the ", DIRECTORY, " option."));
4378
0
        return false;
4379
0
      }
4380
0
      dir = cmSystemTools::CollapseFullPath(
4381
0
        dir, makefile->GetCurrentSourceDirectory());
4382
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(dir);
4383
0
      if (!makefile) {
4384
0
        reportError(
4385
0
          eval, content->GetOriginalExpression(),
4386
0
          cmStrCat("Directory \"", dir, "\" is not known from CMake."));
4387
0
        return false;
4388
0
      }
4389
23
    } else if (cmHasPrefix(option, TARGET_DIRECTORY)) {
4390
0
      auto targetName = option.substr(TARGET_DIRECTORY.length());
4391
0
      if (targetName.empty()) {
4392
0
        reportError(eval, content->GetOriginalExpression(),
4393
0
                    cmStrCat("No value provided for the ", TARGET_DIRECTORY,
4394
0
                             " option."));
4395
0
        return false;
4396
0
      }
4397
0
      auto* target = makefile->FindTargetToUse(targetName);
4398
0
      if (!target) {
4399
0
        reportError(eval, content->GetOriginalExpression(),
4400
0
                    cmStrCat("Non-existent target: ", targetName));
4401
0
        return false;
4402
0
      }
4403
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(
4404
0
        target->GetProperty("BINARY_DIR"));
4405
23
    } else {
4406
23
      reportError(eval, content->GetOriginalExpression(),
4407
23
                  cmStrCat("Invalid option. ", DIRECTORY, " or ",
4408
23
                           TARGET_DIRECTORY, " expected."));
4409
23
      return false;
4410
23
    }
4411
4412
0
    sourceName = cmSystemTools::CollapseFullPath(
4413
0
      sourceName,
4414
0
      eval->Context.LG->GetMakefile()->GetCurrentSourceDirectory());
4415
0
  }
4416
4417
2.33k
  sourceFile = makefile->GetSource(sourceName);
4418
2.33k
  return true;
4419
2.35k
}
4420
}
4421
4422
static const struct SourceExistsNode : public cmGeneratorExpressionNode
4423
{
4424
10
  SourceExistsNode() {} // NOLINT(modernize-use-equals-default)
4425
4426
  // This node handles errors on parameter count itself.
4427
2.15k
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4428
4429
  std::string Evaluate(
4430
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4431
    GeneratorExpressionContent const* content,
4432
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
4433
2.15k
  {
4434
2.15k
    if (parameters.size() > 2) {
4435
7
      reportError(eval, content->GetOriginalExpression(),
4436
7
                  "$<SOURCE_EXISTS:...> expression requires at most two "
4437
7
                  "parameters.");
4438
7
      return std::string{};
4439
7
    }
4440
4441
2.14k
    if (parameters[0].empty()) {
4442
3
      reportError(eval, content->GetOriginalExpression(),
4443
3
                  "$<SOURCE_EXISTS:src> expression requires a "
4444
3
                  "non-empty source name.");
4445
3
      return std::string{};
4446
3
    }
4447
4448
2.14k
    cmSourceFile* sourceFile = nullptr;
4449
2.14k
    if (!GetSourceFile(cmMakeRange(parameters), eval, content, sourceFile)) {
4450
12
      return std::string{};
4451
12
    }
4452
4453
2.13k
    return sourceFile ? "1" : "0";
4454
2.14k
  }
4455
} sourceExistsNode;
4456
4457
static const struct SourcePropertyNode : public cmGeneratorExpressionNode
4458
{
4459
10
  SourcePropertyNode() {} // NOLINT(modernize-use-equals-default)
4460
4461
  // This node handles errors on parameter count itself.
4462
244
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
4463
4464
  std::string Evaluate(
4465
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4466
    GeneratorExpressionContent const* content,
4467
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
4468
239
  {
4469
239
    if (parameters.size() > 3) {
4470
3
      reportError(eval, content->GetOriginalExpression(),
4471
3
                  "$<SOURCE_PROPERTY:...> expression requires at most three "
4472
3
                  "parameters.");
4473
3
      return std::string{};
4474
3
    }
4475
4476
236
    std::string sourceName = parameters.front();
4477
236
    std::string const& propertyName = parameters.back();
4478
4479
236
    if (sourceName.empty() && propertyName.empty()) {
4480
0
      reportError(eval, content->GetOriginalExpression(),
4481
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
4482
0
                  "non-empty source name and property name.");
4483
0
      return std::string{};
4484
0
    }
4485
236
    if (sourceName.empty()) {
4486
9
      reportError(eval, content->GetOriginalExpression(),
4487
9
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
4488
9
                  "non-empty source name.");
4489
9
      return std::string{};
4490
9
    }
4491
227
    if (propertyName.empty()) {
4492
2
      reportError(eval, content->GetOriginalExpression(),
4493
2
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
4494
2
                  "non-empty property name.");
4495
2
      return std::string{};
4496
2
    }
4497
225
    if (!IsValidPropertyName(eval, content, propertyName)) {
4498
10
      return std::string{};
4499
10
    }
4500
4501
215
    cmSourceFile* sourceFile = nullptr;
4502
215
    if (!GetSourceFile(cmMakeRange(parameters).retreat(1), eval, content,
4503
215
                       sourceFile)) {
4504
11
      return std::string{};
4505
11
    }
4506
204
    if (!sourceFile) {
4507
25
      reportError(
4508
25
        eval, content->GetOriginalExpression(),
4509
25
        cmStrCat("Source file \"", sourceName, "\" is not known from CMake."));
4510
25
      return std::string{};
4511
25
    }
4512
4513
179
    if (propertyName == "OBJECT_NAME"_s) {
4514
0
      return eval->Context.LG->GetCustomObjectFileName(*sourceFile);
4515
0
    }
4516
4517
179
    std::string result = sourceFile->GetPropertyForUser(propertyName);
4518
4519
179
    if (propertyName == "INCLUDE_DIRECTORIES"_s ||
4520
179
        propertyName == "COMPILE_DEFINITIONS"_s ||
4521
79
        propertyName == "COMPILE_OPTIONS"_s ||
4522
79
        propertyName == "COMPILE_FLAGS"_s ||
4523
79
        propertyName == "OBJECT_OUTPUTS"_s ||
4524
79
        propertyName == "VS_DEPLOYMENT_CONTENT"_s ||
4525
100
        propertyName == "VS_SETTINGS"_s) {
4526
100
      if (eval->HeadTarget) {
4527
99
        cmGeneratorExpressionDAGChecker dagChecker{
4528
99
          eval->HeadTarget, propertyName,  content,
4529
99
          dagCheckerParent, eval->Context, eval->Backtrace,
4530
99
        };
4531
99
        switch (dagChecker.Check()) {
4532
0
          case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4533
1
          case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
4534
1
            dagChecker.ReportError(eval, content->GetOriginalExpression());
4535
1
            return std::string{};
4536
0
          }
4537
0
          case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4538
98
          case cmGeneratorExpressionDAGChecker::DAG:
4539
98
            break;
4540
99
        }
4541
4542
98
        return cmGeneratorExpression::StripEmptyListElements(
4543
98
          this->EvaluateDependentExpression(result, eval, eval->HeadTarget,
4544
98
                                            &dagChecker, eval->CurrentTarget));
4545
99
      }
4546
4547
1
      return cmGeneratorExpression::StripEmptyListElements(
4548
1
        this->EvaluateDependentExpression(result, eval, eval->HeadTarget,
4549
1
                                          dagCheckerParent,
4550
1
                                          eval->CurrentTarget));
4551
100
    }
4552
4553
79
    return result;
4554
179
  }
4555
} sourcePropertyNode;
4556
4557
static const struct RulePropertyNode : public cmGeneratorExpressionNode
4558
{
4559
10
  RulePropertyNode() {} // NOLINT(modernize-use-equals-default)
4560
4561
  // This node handles errors on parameter count itself.
4562
0
  int NumExpectedParameters() const override { return 2; }
4563
4564
  std::string Evaluate(
4565
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4566
    GeneratorExpressionContent const* content,
4567
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
4568
0
  {
4569
0
    std::string ruleName = parameters.front();
4570
0
    std::string const& propertyName = parameters.back();
4571
4572
0
    if (ruleName.empty() && propertyName.empty()) {
4573
0
      reportError(eval, content->GetOriginalExpression(),
4574
0
                  "$<RULE_PROPERTY:rule,prop> expression requires a "
4575
0
                  "non-empty rule name and property name.");
4576
0
      return std::string{};
4577
0
    }
4578
0
    if (ruleName.empty()) {
4579
0
      reportError(eval, content->GetOriginalExpression(),
4580
0
                  "$<RULE_PROPERTY:rule,prop> expression requires a "
4581
0
                  "non-empty rule name.");
4582
0
      return std::string{};
4583
0
    }
4584
0
    if (propertyName.empty()) {
4585
0
      reportError(eval, content->GetOriginalExpression(),
4586
0
                  "$<RULE_PROPERTY:src,prop> expression requires a "
4587
0
                  "non-empty property name.");
4588
0
      return std::string{};
4589
0
    }
4590
0
    if (!IsValidPropertyName(eval, content, propertyName)) {
4591
0
      return std::string{};
4592
0
    }
4593
4594
0
    cmValue propertyValue;
4595
0
    cmGeneratorRule* genRule = nullptr;
4596
4597
0
    genRule = eval->Context.LG->FindGeneratorRuleToUse(ruleName);
4598
0
    if (!genRule) {
4599
0
      reportError(eval, content->GetOriginalExpression(),
4600
0
                  cmStrCat("Rule \"", ruleName, "\" is not known to CMake."));
4601
0
      return std::string{};
4602
0
    }
4603
4604
    // retrieve associated target
4605
0
    cmGeneratorTarget* target = eval->Context.LG->FindGeneratorTargetToUse(
4606
0
      genRule->GetTarget()->GetName());
4607
0
    if (!target) {
4608
0
      reportError(eval, content->GetOriginalExpression(),
4609
0
                  cmStrCat("Internal error for rule \"",
4610
0
                           genRule->GetRule()->GetName(), "\"."));
4611
0
      return std::string{};
4612
0
    }
4613
4614
0
    propertyValue = genRule->GetProperty(propertyName);
4615
4616
0
    static cmsys::RegularExpression commandIndex("^COMMAND_[0-9]+$");
4617
0
    if (propertyValue &&
4618
0
        (propertyName == "OUTPUT"_s || propertyName == "COMMAND"_s ||
4619
0
         commandIndex.find(propertyName) || propertyName == "DEPENDS"_s ||
4620
0
         propertyName == "DEPFILE"_s ||
4621
0
         propertyName == "INCLUDE_DIRECTORIES"_s ||
4622
0
         propertyName == "COMPILE_OPTIONS"_s ||
4623
0
         propertyName == "COMPILE_DEFINITIONS"_s ||
4624
0
         propertyName == "WORKING_DIRECTORY"_s ||
4625
0
         propertyName == "COMMENT"_s)) {
4626
0
      cmGeneratorExpressionDAGChecker dagChecker{
4627
0
        target,           propertyName,  content,
4628
0
        dagCheckerParent, eval->Context, eval->Backtrace,
4629
0
      };
4630
0
      switch (dagChecker.Check()) {
4631
0
        case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4632
0
          reportError(eval, content->GetOriginalExpression(),
4633
0
                      cmStrCat("Self reference on rule \"",
4634
0
                               genRule->GetRule()->GetName(), "\"."));
4635
0
          return std::string{};
4636
0
        case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
4637
          // No error. We just skip cyclic references.
4638
0
          return std::string{};
4639
0
        case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4640
0
          CM_FALLTHROUGH;
4641
0
        case cmGeneratorExpressionDAGChecker::DAG:
4642
0
          break;
4643
0
      }
4644
4645
0
      return cmGeneratorExpression::StripEmptyListElements(
4646
0
        this->EvaluateDependentExpression(propertyValue, eval, target,
4647
0
                                          &dagChecker, target));
4648
0
    }
4649
0
    return propertyValue;
4650
0
  }
4651
} rulePropertyNode;
4652
4653
static std::string getLinkedTargetsContent(
4654
  cmGeneratorTarget const* target, std::string const& prop,
4655
  cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
4656
  cmGeneratorTarget::UseTo usage)
4657
4.08k
{
4658
4.08k
  std::string result;
4659
4.08k
  if (cmLinkImplementationLibraries const* impl =
4660
4.08k
        target->GetLinkImplementationLibraries(
4661
4.08k
          eval->Context.Config, cmGeneratorTarget::UseTo::Compile)) {
4662
53.9k
    for (cmLinkItem const& lib : impl->Libraries) {
4663
53.9k
      if (lib.Target) {
4664
        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
4665
        // caller's property and hand-evaluate it as if it were compiled.
4666
        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
4667
3.30k
        cm::GenEx::Context libContext(eval->Context);
4668
        // FIXME: Why have we long used the target's local generator
4669
        // instead of that of the evaluation context?
4670
3.30k
        libContext.LG = target->GetLocalGenerator();
4671
3.30k
        cm::GenEx::Evaluation libEval(
4672
3.30k
          std::move(libContext), eval->Quiet, target, target,
4673
3.30k
          eval->EvaluateForBuildsystem, lib.Backtrace);
4674
3.30k
        std::string libResult = lib.Target->EvaluateInterfaceProperty(
4675
3.30k
          prop, &libEval, dagChecker, usage);
4676
3.30k
        if (!libResult.empty()) {
4677
566
          if (result.empty()) {
4678
566
            result = std::move(libResult);
4679
566
          } else {
4680
0
            result.reserve(result.size() + 1 + libResult.size());
4681
0
            result += ";";
4682
0
            result += libResult;
4683
0
          }
4684
566
        }
4685
3.30k
      }
4686
53.9k
    }
4687
4.08k
  }
4688
4.08k
  return result;
4689
4.08k
}
4690
4691
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
4692
{
4693
10
  TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
4694
4695
  // This node handles errors on parameter count itself.
4696
13.5k
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4697
4698
  static char const* GetErrorText(std::string const& targetName,
4699
                                  std::string const& propertyName)
4700
5.00k
  {
4701
5.00k
    if (targetName.empty() && propertyName.empty()) {
4702
0
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
4703
0
             "target name and property name.";
4704
0
    }
4705
5.00k
    if (targetName.empty()) {
4706
12
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
4707
12
             "target name.";
4708
12
    }
4709
4.99k
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
4710
21
      if (!IsValidPropertyName(propertyName)) {
4711
11
        return "Target name and property name not supported.";
4712
11
      }
4713
10
      return "Target name not supported.";
4714
21
    }
4715
4.97k
    return nullptr;
4716
4.99k
  }
4717
4718
  std::string Evaluate(
4719
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4720
    GeneratorExpressionContent const* content,
4721
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
4722
13.5k
  {
4723
13.5k
    cmGeneratorTarget const* target = nullptr;
4724
13.5k
    std::string targetName;
4725
13.5k
    std::string propertyName;
4726
4727
13.5k
    if (parameters.size() == 2) {
4728
5.00k
      targetName = parameters[0];
4729
5.00k
      propertyName = parameters[1];
4730
4731
5.00k
      if (char const* e = GetErrorText(targetName, propertyName)) {
4732
33
        reportError(eval, content->GetOriginalExpression(), e);
4733
33
        return std::string();
4734
33
      }
4735
4.97k
      if (propertyName == "ALIASED_TARGET"_s) {
4736
37
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
4737
30
          if (cmGeneratorTarget* tgt =
4738
30
                eval->Context.LG->FindGeneratorTargetToUse(targetName)) {
4739
30
            return tgt->GetName();
4740
30
          }
4741
30
        }
4742
7
        return std::string();
4743
37
      }
4744
4.93k
      if (propertyName == "ALIAS_GLOBAL"_s) {
4745
51
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
4746
13
          return eval->Context.LG->GetGlobalGenerator()->IsAlias(targetName)
4747
13
            ? "TRUE"
4748
13
            : "FALSE";
4749
13
        }
4750
38
        return std::string();
4751
51
      }
4752
4.88k
      cmLocalGenerator const* lg = eval->CurrentTarget
4753
4.88k
        ? eval->CurrentTarget->GetLocalGenerator()
4754
4.88k
        : eval->Context.LG;
4755
4.88k
      target = lg->FindGeneratorTargetToUse(targetName);
4756
4757
4.88k
      if (!target) {
4758
21
        reportError(eval, content->GetOriginalExpression(),
4759
21
                    cmStrCat("Target \"", targetName, "\" not found."));
4760
21
        return std::string();
4761
21
      }
4762
4.86k
      eval->AllTargets.insert(target);
4763
4764
8.54k
    } else if (parameters.size() == 1) {
4765
8.54k
      target = eval->HeadTarget;
4766
8.54k
      propertyName = parameters[0];
4767
4768
      // Keep track of the properties seen while processing.
4769
      // The evaluation of the LINK_LIBRARIES generator expressions
4770
      // will check this to ensure that properties have one consistent
4771
      // value for all evaluations.
4772
8.54k
      eval->SeenTargetProperties.insert(propertyName);
4773
4774
8.54k
      eval->HadHeadSensitiveCondition = true;
4775
8.54k
      if (!target) {
4776
8
        reportError(
4777
8
          eval, content->GetOriginalExpression(),
4778
8
          "$<TARGET_PROPERTY:prop>  may only be used with binary targets.  "
4779
8
          "It may not be used with add_custom_command or add_custom_target. "
4780
8
          " "
4781
8
          " "
4782
8
          "Specify the target to read a property from using the "
4783
8
          "$<TARGET_PROPERTY:tgt,prop> signature instead.");
4784
8
        return std::string();
4785
8
      }
4786
8.54k
    } else {
4787
7
      reportError(
4788
7
        eval, content->GetOriginalExpression(),
4789
7
        "$<TARGET_PROPERTY:...> expression requires one or two parameters");
4790
7
      return std::string();
4791
7
    }
4792
4793
13.3k
    if (propertyName == "SOURCES") {
4794
0
      eval->SourceSensitiveTargets.insert(target);
4795
0
    }
4796
4797
13.3k
    if (propertyName.empty()) {
4798
7
      reportError(
4799
7
        eval, content->GetOriginalExpression(),
4800
7
        "$<TARGET_PROPERTY:...> expression requires a non-empty property "
4801
7
        "name.");
4802
7
      return std::string();
4803
7
    }
4804
4805
13.3k
    if (!IsValidPropertyName(eval, content, propertyName)) {
4806
153
      return std::string();
4807
153
    }
4808
4809
13.3k
    assert(target);
4810
4811
13.2k
    if (propertyName == "LINKER_LANGUAGE") {
4812
0
      if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
4813
0
          (dagCheckerParent->EvaluatingLinkLibraries() ||
4814
0
           dagCheckerParent->EvaluatingSources())) {
4815
0
        reportError(
4816
0
          eval, content->GetOriginalExpression(),
4817
0
          "LINKER_LANGUAGE target property can not be used while evaluating "
4818
0
          "link libraries for a static library");
4819
0
        return std::string();
4820
0
      }
4821
0
      return target->GetLinkerLanguage(eval->Context.Config);
4822
0
    }
4823
4824
13.2k
    bool const evaluatingLinkLibraries =
4825
13.2k
      dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries();
4826
4827
13.2k
    std::string interfacePropertyName;
4828
13.2k
    bool isInterfaceProperty = false;
4829
13.2k
    cmGeneratorTarget::UseTo usage = cmGeneratorTarget::UseTo::Compile;
4830
4831
13.2k
    if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
4832
13.2k
          target->IsTransitiveProperty(propertyName, eval->Context,
4833
13.2k
                                       dagCheckerParent)) {
4834
5.02k
      interfacePropertyName = std::string(transitiveProp->InterfaceName);
4835
5.02k
      isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
4836
5.02k
      usage = transitiveProp->Usage;
4837
5.02k
    }
4838
4839
13.2k
    if (dagCheckerParent) {
4840
      // This $<TARGET_PROPERTY:...> node has been reached while evaluating
4841
      // another target property value.  Check that the outermost evaluation
4842
      // expects such nested evaluations.
4843
2.43k
      if (dagCheckerParent->EvaluatingGenexExpression() ||
4844
2.43k
          dagCheckerParent->EvaluatingPICExpression() ||
4845
2.43k
          dagCheckerParent->EvaluatingLinkerLauncher()) {
4846
        // No check required.
4847
2.43k
      } else if (evaluatingLinkLibraries) {
4848
1.64k
        if (!interfacePropertyName.empty() &&
4849
4
            interfacePropertyName != "INTERFACE_LINK_LIBRARIES"_s) {
4850
4
          reportError(
4851
4
            eval, content->GetOriginalExpression(),
4852
4
            "$<TARGET_PROPERTY:...> expression in link libraries "
4853
4
            "evaluation depends on target property which is transitive "
4854
4
            "over the link libraries, creating a recursion.");
4855
4
          return std::string();
4856
4
        }
4857
1.64k
      } else {
4858
792
        assert(dagCheckerParent->EvaluatingTransitiveProperty());
4859
792
      }
4860
2.43k
    }
4861
4862
13.2k
    if (isInterfaceProperty) {
4863
920
      return cmGeneratorExpression::StripEmptyListElements(
4864
920
        target->EvaluateInterfaceProperty(propertyName, eval, dagCheckerParent,
4865
920
                                          usage));
4866
920
    }
4867
4868
12.3k
    cmGeneratorExpressionDAGChecker dagChecker{
4869
12.3k
      target,           propertyName,  content,
4870
12.3k
      dagCheckerParent, eval->Context, eval->Backtrace,
4871
12.3k
    };
4872
4873
12.3k
    switch (dagChecker.Check()) {
4874
0
      case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4875
0
        dagChecker.ReportError(eval, content->GetOriginalExpression());
4876
0
        return std::string();
4877
0
      case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
4878
        // No error. We just skip cyclic references.
4879
0
        return std::string();
4880
441
      case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4881
        // We handle transitive properties above.  For non-transitive
4882
        // properties we accept repeats anyway.
4883
12.3k
      case cmGeneratorExpressionDAGChecker::DAG:
4884
12.3k
        break;
4885
12.3k
    }
4886
4887
12.3k
    std::string result;
4888
12.3k
    bool haveProp = false;
4889
12.3k
    if (cmValue p = target->GetProperty(propertyName)) {
4890
4.52k
      result = *p;
4891
4.52k
      haveProp = true;
4892
7.78k
    } else if (evaluatingLinkLibraries) {
4893
878
      return std::string();
4894
878
    }
4895
4896
    // Properties named by COMPATIBLE_INTERFACE_ properties combine over
4897
    // the transitive link closure as a single order-independent value.
4898
    // Imported targets do not themselves have a defined value for these
4899
    // properties, but they can contribute to the value of a non-imported
4900
    // dependent.
4901
    //
4902
    // For COMPATIBLE_INTERFACE_{BOOL,STRING}:
4903
    // * If set on this target, use the value directly.  It is checked
4904
    //   elsewhere for consistency over the transitive link closure.
4905
    // * If not set on this target, compute the value from the closure.
4906
    //
4907
    // For COMPATIBLE_INTERFACE_NUMBER_{MAX,MIN} we always compute the value
4908
    // from this target and the transitive link closure to get the max or min.
4909
11.4k
    if (!haveProp && !target->IsImported()) {
4910
6.41k
      if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
4911
6.41k
                                                       eval->Context.Config)) {
4912
47
        eval->HadContextSensitiveCondition = true;
4913
47
        return target->GetLinkInterfaceDependentBoolProperty(
4914
47
                 propertyName, eval->Context.Config)
4915
47
          ? "1"
4916
47
          : "0";
4917
47
      }
4918
6.36k
      if (target->IsLinkInterfaceDependentStringProperty(
4919
6.36k
            propertyName, eval->Context.Config)) {
4920
873
        eval->HadContextSensitiveCondition = true;
4921
873
        char const* propContent =
4922
873
          target->GetLinkInterfaceDependentStringProperty(
4923
873
            propertyName, eval->Context.Config);
4924
873
        return propContent ? propContent : "";
4925
873
      }
4926
6.36k
    }
4927
10.5k
    if (!evaluatingLinkLibraries && !target->IsImported()) {
4928
9.23k
      if (target->IsLinkInterfaceDependentNumberMinProperty(
4929
9.23k
            propertyName, eval->Context.Config)) {
4930
0
        eval->HadContextSensitiveCondition = true;
4931
0
        char const* propContent =
4932
0
          target->GetLinkInterfaceDependentNumberMinProperty(
4933
0
            propertyName, eval->Context.Config);
4934
0
        return propContent ? propContent : "";
4935
0
      }
4936
9.23k
      if (target->IsLinkInterfaceDependentNumberMaxProperty(
4937
9.23k
            propertyName, eval->Context.Config)) {
4938
16
        eval->HadContextSensitiveCondition = true;
4939
16
        char const* propContent =
4940
16
          target->GetLinkInterfaceDependentNumberMaxProperty(
4941
16
            propertyName, eval->Context.Config);
4942
16
        return propContent ? propContent : "";
4943
16
      }
4944
9.23k
    }
4945
4946
    // Some properties, such as usage requirements, combine over the
4947
    // transitive link closure as an ordered list.
4948
10.4k
    if (!interfacePropertyName.empty()) {
4949
4.08k
      result = cmGeneratorExpression::StripEmptyListElements(
4950
4.08k
        this->EvaluateDependentExpression(result, eval, target, &dagChecker,
4951
4.08k
                                          target));
4952
4.08k
      std::string linkedTargetsContent = getLinkedTargetsContent(
4953
4.08k
        target, interfacePropertyName, eval, &dagChecker, usage);
4954
4.08k
      if (!linkedTargetsContent.empty()) {
4955
566
        if (result.empty()) {
4956
566
          result = std::move(linkedTargetsContent);
4957
566
        } else {
4958
0
          result =
4959
0
            cmStrCat(std::move(result), ';', std::move(linkedTargetsContent));
4960
0
        }
4961
566
      }
4962
4.08k
    }
4963
10.4k
    return result;
4964
10.5k
  }
4965
} targetPropertyNode;
4966
4967
static const struct targetIntermediateDirNode
4968
  : public cmGeneratorExpressionNode
4969
{
4970
10
  targetIntermediateDirNode() {} // NOLINT(modernize-use-equals-default)
4971
4972
  static char const* GetErrorText(std::string const& targetName)
4973
20
  {
4974
20
    if (targetName.empty()) {
4975
3
      return "$<TARGET_INTERMEDIATE_DIR:tgt> expression requires a non-empty "
4976
3
             "target name.";
4977
3
    }
4978
17
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
4979
6
      return "Target name not supported.";
4980
6
    }
4981
11
    return nullptr;
4982
17
  }
4983
4984
  std::string Evaluate(
4985
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4986
    GeneratorExpressionContent const* content,
4987
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4988
20
  {
4989
20
    cmGeneratorTarget const* target = nullptr;
4990
20
    std::string targetName;
4991
4992
20
    if (parameters.size() == 1) {
4993
20
      targetName = parameters[0];
4994
4995
20
      if (char const* e = GetErrorText(targetName)) {
4996
9
        reportError(eval, content->GetOriginalExpression(), e);
4997
9
        return std::string();
4998
9
      }
4999
11
      cmLocalGenerator const* lg = eval->CurrentTarget
5000
11
        ? eval->CurrentTarget->GetLocalGenerator()
5001
11
        : eval->Context.LG;
5002
11
      target = lg->FindGeneratorTargetToUse(targetName);
5003
5004
11
      if (!target) {
5005
9
        reportError(eval, content->GetOriginalExpression(),
5006
9
                    cmStrCat("Target \"", targetName, "\" not found."));
5007
9
        return std::string();
5008
9
      }
5009
2
      eval->AllTargets.insert(target);
5010
5011
2
    } else {
5012
0
      reportError(
5013
0
        eval, content->GetOriginalExpression(),
5014
0
        "$<TARGET_INTERMEDIATE_DIR:...> expression requires one parameter");
5015
0
      return std::string();
5016
0
    }
5017
5018
20
    assert(target);
5019
5020
2
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_INTERMEDIATE_DIR",
5021
2
                                    target)) {
5022
0
      return std::string();
5023
0
    }
5024
5025
2
    return cmSystemTools::CollapseFullPath(
5026
2
      target->GetObjectDirectory(eval->Context.Config));
5027
2
  }
5028
} targetIntermediateDirNode;
5029
5030
static const struct TargetNameNode : public cmGeneratorExpressionNode
5031
{
5032
10
  TargetNameNode() {} // NOLINT(modernize-use-equals-default)
5033
5034
51
  bool GeneratesContent() const override { return true; }
5035
5036
51
  bool AcceptsArbitraryContentParameter() const override { return true; }
5037
237
  bool RequiresLiteralInput() const override { return true; }
5038
5039
  std::string Evaluate(
5040
    std::vector<std::string> const& parameters,
5041
    cm::GenEx::Evaluation* /*eval*/,
5042
    GeneratorExpressionContent const* /*content*/,
5043
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5044
92
  {
5045
92
    return parameters.front();
5046
92
  }
5047
5048
51
  int NumExpectedParameters() const override { return 1; }
5049
5050
} targetNameNode;
5051
5052
static const struct TargetObjectsNode : public cmGeneratorExpressionNode
5053
{
5054
10
  TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
5055
5056
  std::string Evaluate(
5057
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5058
    GeneratorExpressionContent const* content,
5059
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5060
616
  {
5061
616
    std::string const& tgtName = parameters.front();
5062
616
    cmGeneratorTarget* gt =
5063
616
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
5064
616
    if (!gt) {
5065
16
      reportError(eval, content->GetOriginalExpression(),
5066
16
                  cmStrCat("Objects of target \"", tgtName,
5067
16
                           "\" referenced but no such target exists."));
5068
16
      return std::string();
5069
16
    }
5070
600
    cm::TargetType type = gt->GetType();
5071
600
    if (type != cm::TargetType::EXECUTABLE &&
5072
600
        type != cm::TargetType::STATIC_LIBRARY &&
5073
525
        type != cm::TargetType::SHARED_LIBRARY &&
5074
525
        type != cm::TargetType::MODULE_LIBRARY &&
5075
525
        type != cm::TargetType::OBJECT_LIBRARY) {
5076
0
      reportError(
5077
0
        eval, content->GetOriginalExpression(),
5078
0
        cmStrCat("Objects of target \"", tgtName,
5079
0
                 "\" referenced but is not one of the allowed target types "
5080
0
                 "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT)."));
5081
0
      return std::string();
5082
0
    }
5083
600
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
5084
600
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_OBJECTS", gt)) {
5085
0
      return std::string();
5086
0
    }
5087
5088
600
    std::vector<std::string> sourceFilePaths;
5089
600
    for (auto const& arg : cmMakeRange(parameters).advance(1)) {
5090
0
      if (cmHasLiteralPrefix(arg, "SOURCE_FILES:")) {
5091
0
        cm::string_view listView{ arg.c_str() + cmStrLen("SOURCE_FILES:") };
5092
0
        std::size_t semicolon;
5093
0
        std::size_t start = 0;
5094
0
        do {
5095
0
          semicolon = listView.find(';', start);
5096
0
          sourceFilePaths.push_back(
5097
0
            std::string{ listView.substr(start, semicolon - start) });
5098
0
          start = semicolon + 1;
5099
0
        } while (semicolon != cm::string_view::npos);
5100
0
      } else {
5101
0
        reportError(eval, content->GetOriginalExpression(),
5102
0
                    cmStrCat("Unrecognized argument:\n  ", arg));
5103
0
        return std::string();
5104
0
      }
5105
0
    }
5106
5107
600
    if (gt->IsImported() && !sourceFilePaths.empty()) {
5108
0
      reportError(
5109
0
        eval, content->GetOriginalExpression(),
5110
0
        cmStrCat("Cannot use SOURCE_FILES argument on imported target \"",
5111
0
                 tgtName, '"'));
5112
0
      return std::string();
5113
0
    }
5114
600
    std::set<cmSourceFile const*> sourceFiles;
5115
1.07k
    for (auto const& sf : gt->GetSourceFiles(eval->Context.Config)) {
5116
1.07k
      sourceFiles.insert(sf.Value);
5117
1.07k
    }
5118
600
    std::set<cmSourceFile const*> filteredSourceFiles;
5119
600
    for (auto const& path : sourceFilePaths) {
5120
0
      if (!cmSystemTools::FileIsFullPath(path)) {
5121
0
        reportError(
5122
0
          eval, content->GetOriginalExpression(),
5123
0
          cmStrCat("Source file:\n  ", path, "\nis not an absolute path"));
5124
0
        return std::string();
5125
0
      }
5126
5127
0
      auto const* sf = gt->Makefile->GetSource(path);
5128
0
      if (!sf || !sourceFiles.count(sf)) {
5129
0
        reportError(eval, content->GetOriginalExpression(),
5130
0
                    cmStrCat("Source file:\n  ", path,
5131
0
                             "\ndoes not exist for target \"", tgtName, '"'));
5132
0
        return std::string();
5133
0
      }
5134
0
      filteredSourceFiles.insert(sf);
5135
0
    }
5136
5137
600
    cmList objects;
5138
5139
600
    if (gt->IsImported()) {
5140
45
      cmValue loc = nullptr;
5141
45
      cmValue imp = nullptr;
5142
45
      std::string suffix;
5143
45
      if (gt->Target->GetMappedConfig(eval->Context.Config, loc, imp,
5144
45
                                      suffix)) {
5145
45
        objects.assign(*loc);
5146
45
      }
5147
45
      eval->HadContextSensitiveCondition = true;
5148
555
    } else {
5149
555
      auto const filter =
5150
1.07k
        [&filteredSourceFiles](cmSourceFile const& sf) -> bool {
5151
1.07k
        return filteredSourceFiles.empty() || filteredSourceFiles.count(&sf);
5152
1.07k
      };
5153
555
      gt->GetTargetObjectNames(eval->Context.Config, filter, objects);
5154
5155
555
      std::string obj_dir;
5156
555
      if (eval->EvaluateForBuildsystem && !gg->SupportsCrossConfigs()) {
5157
        // Use object file directory with buildsystem placeholder.
5158
553
        obj_dir = gt->ObjectDirectory;
5159
553
        eval->HadContextSensitiveCondition = gt->HasContextDependentSources();
5160
553
      } else {
5161
        // Use object file directory with per-config location.
5162
2
        obj_dir = gt->GetObjectDirectory(eval->Context.Config);
5163
2
        eval->HadContextSensitiveCondition = true;
5164
2
      }
5165
5166
1.07k
      for (auto& o : objects) {
5167
1.07k
        o = cmStrCat(obj_dir, std::move(o));
5168
1.07k
      }
5169
555
    }
5170
5171
    // Create the cmSourceFile instances in the referencing directory.
5172
600
    cmMakefile* mf = eval->Context.LG->GetMakefile();
5173
1.12k
    for (std::string const& o : objects) {
5174
1.12k
      mf->AddTargetObject(tgtName, o);
5175
1.12k
    }
5176
5177
600
    return objects.to_string();
5178
600
  }
5179
5180
616
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
5181
} targetObjectsNode;
5182
5183
struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
5184
{
5185
  std::vector<std::string> CollectDlls(
5186
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5187
    GeneratorExpressionContent const* content) const
5188
14
  {
5189
14
    std::string const& tgtName = parameters.front();
5190
14
    cmGeneratorTarget* gt =
5191
14
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
5192
14
    if (!gt) {
5193
14
      reportError(eval, content->GetOriginalExpression(),
5194
14
                  cmStrCat("Objects of target \"", tgtName,
5195
14
                           "\" referenced but no such target exists."));
5196
14
      return std::vector<std::string>();
5197
14
    }
5198
0
    cm::TargetType type = gt->GetType();
5199
0
    if (type != cm::TargetType::EXECUTABLE &&
5200
0
        type != cm::TargetType::SHARED_LIBRARY &&
5201
0
        type != cm::TargetType::MODULE_LIBRARY) {
5202
0
      reportError(
5203
0
        eval, content->GetOriginalExpression(),
5204
0
        cmStrCat("Objects of target \"", tgtName,
5205
0
                 "\" referenced but is not one of the allowed target types "
5206
0
                 "(EXECUTABLE, SHARED, MODULE)."));
5207
0
      return std::vector<std::string>();
5208
0
    }
5209
5210
0
    if (auto* cli = gt->GetLinkInformation(eval->Context.Config)) {
5211
0
      std::vector<std::string> dllPaths;
5212
0
      auto const& dlls = cli->GetRuntimeDLLs();
5213
5214
0
      for (auto const& dll : dlls) {
5215
0
        if (auto loc = dll->MaybeGetLocation(eval->Context.Config)) {
5216
0
          dllPaths.emplace_back(*loc);
5217
0
        }
5218
0
      }
5219
5220
0
      return dllPaths;
5221
0
    }
5222
5223
0
    return std::vector<std::string>();
5224
0
  }
5225
};
5226
5227
static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode
5228
{
5229
10
  TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
5230
5231
  std::string Evaluate(
5232
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5233
    GeneratorExpressionContent const* content,
5234
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5235
14
  {
5236
14
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
5237
14
    return cmList::to_string(dlls);
5238
14
  }
5239
} targetRuntimeDllsNode;
5240
5241
static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode
5242
{
5243
10
  TargetRuntimeDllDirsNode() {} // NOLINT(modernize-use-equals-default)
5244
5245
  std::string Evaluate(
5246
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5247
    GeneratorExpressionContent const* content,
5248
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5249
0
  {
5250
0
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
5251
0
    std::vector<std::string> dllDirs;
5252
0
    for (std::string const& dll : dlls) {
5253
0
      std::string directory = cmSystemTools::GetFilenamePath(dll);
5254
0
      if (std::find(dllDirs.begin(), dllDirs.end(), directory) ==
5255
0
          dllDirs.end()) {
5256
0
        dllDirs.push_back(directory);
5257
0
      }
5258
0
    }
5259
0
    return cmList::to_string(dllDirs);
5260
0
  }
5261
} targetRuntimeDllDirsNode;
5262
5263
static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
5264
{
5265
10
  CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
5266
5267
107
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
5268
5269
  std::string Evaluate(
5270
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5271
    GeneratorExpressionContent const* content,
5272
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5273
103
  {
5274
103
    cmGeneratorTarget const* target = eval->HeadTarget;
5275
103
    if (!target) {
5276
4
      reportError(
5277
4
        eval, content->GetOriginalExpression(),
5278
4
        "$<COMPILE_FEATURE> may only be used with binary targets.  It may "
5279
4
        "not be used with add_custom_command or add_custom_target.");
5280
4
      return std::string();
5281
4
    }
5282
99
    eval->HadHeadSensitiveCondition = true;
5283
5284
99
    using LangMap = std::map<std::string, cmList>;
5285
99
    static LangMap availableFeatures;
5286
5287
99
    LangMap testedFeatures;
5288
99
    cmStandardLevelResolver standardResolver(eval->Context.LG->GetMakefile());
5289
99
    for (std::string const& p : parameters) {
5290
99
      std::string error;
5291
99
      std::string lang;
5292
99
      if (!standardResolver.CompileFeatureKnown(
5293
99
            eval->HeadTarget->Target->GetName(), p, lang, &error)) {
5294
87
        reportError(eval, content->GetOriginalExpression(), error);
5295
87
        return std::string();
5296
87
      }
5297
12
      testedFeatures[lang].push_back(p);
5298
5299
12
      if (availableFeatures.find(lang) == availableFeatures.end()) {
5300
1
        cmValue featuresKnown =
5301
1
          standardResolver.CompileFeaturesAvailable(lang, &error);
5302
1
        if (!featuresKnown) {
5303
0
          reportError(eval, content->GetOriginalExpression(), error);
5304
0
          return std::string();
5305
0
        }
5306
1
        availableFeatures[lang].assign(featuresKnown);
5307
1
      }
5308
12
    }
5309
5310
12
    bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
5311
5312
12
    for (auto const& lit : testedFeatures) {
5313
12
      std::vector<std::string> const& langAvailable =
5314
12
        availableFeatures[lit.first];
5315
12
      cmValue standardDefault = eval->Context.LG->GetMakefile()->GetDefinition(
5316
12
        cmStrCat("CMAKE_", lit.first, "_STANDARD_DEFAULT"));
5317
12
      for (std::string const& it : lit.second) {
5318
12
        if (!cm::contains(langAvailable, it)) {
5319
0
          return "0";
5320
0
        }
5321
12
        if (standardDefault && standardDefault->empty()) {
5322
          // This compiler has no notion of language standard levels.
5323
          // All features known for the language are always available.
5324
0
          continue;
5325
0
        }
5326
12
        if (!standardResolver.HaveStandardAvailable(
5327
12
              target, lit.first, eval->Context.Config, it)) {
5328
0
          if (evalLL) {
5329
0
            cmValue l =
5330
0
              target->GetLanguageStandard(lit.first, eval->Context.Config);
5331
0
            if (!l) {
5332
0
              l = standardDefault;
5333
0
            }
5334
0
            assert(l);
5335
0
            eval->MaxLanguageStandard[target][lit.first] = *l;
5336
0
          } else {
5337
0
            return "0";
5338
0
          }
5339
0
        }
5340
12
      }
5341
12
    }
5342
12
    return "1";
5343
12
  }
5344
} compileFeaturesNode;
5345
5346
static char const* targetPolicyWhitelist[] = {
5347
  nullptr
5348
#define TARGET_POLICY_STRING(POLICY) , #POLICY
5349
5350
  CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
5351
5352
#undef TARGET_POLICY_STRING
5353
};
5354
5355
static cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
5356
                                                char const* policy)
5357
2
{
5358
2
#define RETURN_POLICY(POLICY)                                                 \
5359
4
  if (strcmp(policy, #POLICY) == 0) {                                         \
5360
2
    return tgt->GetPolicyStatus##POLICY();                                    \
5361
2
  }
5362
5363
4
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
5364
5365
0
#undef RETURN_POLICY
5366
5367
0
  CM_UNREACHABLE;
5368
0
  return cmPolicies::WARN;
5369
2
}
5370
5371
static cmPolicies::PolicyID policyForString(char const* policy_id)
5372
0
{
5373
0
#define RETURN_POLICY_ID(POLICY_ID)                                           \
5374
0
  if (strcmp(policy_id, #POLICY_ID) == 0) {                                   \
5375
0
    return cmPolicies::POLICY_ID;                                             \
5376
0
  }
5377
5378
0
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
5379
5380
0
#undef RETURN_POLICY_ID
5381
5382
0
  CM_UNREACHABLE;
5383
0
  return cmPolicies::CMPCOUNT;
5384
0
}
5385
5386
static const struct TargetPolicyNode : public cmGeneratorExpressionNode
5387
{
5388
10
  TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
5389
5390
34
  int NumExpectedParameters() const override { return 1; }
5391
5392
  std::string Evaluate(
5393
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5394
    GeneratorExpressionContent const* content,
5395
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5396
31
  {
5397
31
    if (!eval->HeadTarget) {
5398
4
      reportError(
5399
4
        eval, content->GetOriginalExpression(),
5400
4
        "$<TARGET_POLICY:prop> may only be used with binary targets.  It "
5401
4
        "may not be used with add_custom_command or add_custom_target.");
5402
4
      return std::string();
5403
4
    }
5404
5405
27
    eval->HadContextSensitiveCondition = true;
5406
27
    eval->HadHeadSensitiveCondition = true;
5407
5408
1.37k
    for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
5409
1.35k
      char const* policy = targetPolicyWhitelist[i];
5410
1.35k
      if (parameters.front() == policy) {
5411
2
        cmLocalGenerator* lg = eval->HeadTarget->GetLocalGenerator();
5412
2
        switch (statusForTarget(eval->HeadTarget, policy)) {
5413
0
          case cmPolicies::WARN:
5414
0
            lg->IssuePolicyWarning(policyForString(policy));
5415
0
            CM_FALLTHROUGH;
5416
0
          case cmPolicies::OLD:
5417
0
            return "0";
5418
2
          case cmPolicies::NEW:
5419
2
            return "1";
5420
2
        }
5421
2
      }
5422
1.35k
    }
5423
25
    reportError(
5424
25
      eval, content->GetOriginalExpression(),
5425
25
      "$<TARGET_POLICY:prop> may only be used with a limited number of "
5426
25
      "policies.  Currently it may be used with the following policies:\n"
5427
5428
25
#define STRINGIFY_HELPER(X) #X
5429
25
#define STRINGIFY(X) STRINGIFY_HELPER(X)
5430
5431
25
#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
5432
5433
25
      CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
5434
5435
25
#undef TARGET_POLICY_LIST_ITEM
5436
25
    );
5437
25
    return std::string();
5438
27
  }
5439
5440
} targetPolicyNode;
5441
5442
static const struct InstallPrefixNode : public cmGeneratorExpressionNode
5443
{
5444
10
  InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
5445
5446
5
  bool GeneratesContent() const override { return true; }
5447
5
  int NumExpectedParameters() const override { return 0; }
5448
5449
  std::string Evaluate(
5450
    std::vector<std::string> const& /*parameters*/,
5451
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
5452
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5453
5
  {
5454
5
    reportError(eval, content->GetOriginalExpression(),
5455
5
                "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
5456
5
                "should never be evaluated.");
5457
5
    return std::string();
5458
5
  }
5459
5460
} installPrefixNode;
5461
5462
class ArtifactDirTag;
5463
class ArtifactLinkerTag;
5464
class ArtifactLinkerLibraryTag;
5465
class ArtifactLinkerImportTag;
5466
class ArtifactNameTag;
5467
class ArtifactImportTag;
5468
class ArtifactPathTag;
5469
class ArtifactPdbTag;
5470
class ArtifactSonameTag;
5471
class ArtifactSonameImportTag;
5472
class ArtifactBundleDirTag;
5473
class ArtifactBundleDirNameTag;
5474
class ArtifactBundleContentDirTag;
5475
5476
template <typename ArtifactT, typename ComponentT>
5477
struct TargetFilesystemArtifactDependency
5478
{
5479
  static void AddDependency(cmGeneratorTarget* target,
5480
                            cm::GenEx::Evaluation* eval)
5481
2.41k
  {
5482
2.41k
    eval->DependTargets.insert(target);
5483
2.41k
    eval->AllTargets.insert(target);
5484
2.41k
  }
TargetFilesystemArtifactDependency<ArtifactNameTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Line
Count
Source
5481
2.05k
  {
5482
2.05k
    eval->DependTargets.insert(target);
5483
2.05k
    eval->AllTargets.insert(target);
5484
2.05k
  }
TargetFilesystemArtifactDependency<ArtifactImportTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Line
Count
Source
5481
11
  {
5482
11
    eval->DependTargets.insert(target);
5483
11
    eval->AllTargets.insert(target);
5484
11
  }
TargetFilesystemArtifactDependency<ArtifactLinkerTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Line
Count
Source
5481
37
  {
5482
37
    eval->DependTargets.insert(target);
5483
37
    eval->AllTargets.insert(target);
5484
37
  }
Unexecuted instantiation: TargetFilesystemArtifactDependency<ArtifactLinkerLibraryTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Unexecuted instantiation: TargetFilesystemArtifactDependency<ArtifactLinkerImportTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
TargetFilesystemArtifactDependency<ArtifactSonameTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Line
Count
Source
5481
310
  {
5482
310
    eval->DependTargets.insert(target);
5483
310
    eval->AllTargets.insert(target);
5484
310
  }
Unexecuted instantiation: TargetFilesystemArtifactDependency<ArtifactSonameImportTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
TargetFilesystemArtifactDependency<ArtifactPdbTag, ArtifactPathTag>::AddDependency(cmGeneratorTarget*, cm::GenEx::Evaluation*)
Line
Count
Source
5481
2
  {
5482
2
    eval->DependTargets.insert(target);
5483
2
    eval->AllTargets.insert(target);
5484
2
  }
5485
};
5486
5487
struct TargetFilesystemArtifactDependencyCMP0112
5488
{
5489
  static void AddDependency(cmGeneratorTarget* target,
5490
                            cm::GenEx::Evaluation* eval)
5491
1.37k
  {
5492
1.37k
    eval->AllTargets.insert(target);
5493
1.37k
    cmLocalGenerator const* const lg = eval->Context.LG;
5494
1.37k
    switch (target->GetPolicyStatusCMP0112()) {
5495
0
      case cmPolicies::WARN:
5496
0
        if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
5497
0
              "CMAKE_POLICY_WARNING_CMP0112")) {
5498
0
          lg->IssuePolicyWarning(
5499
0
            cmPolicies::CMP0112, {},
5500
0
            cmStrCat("Dependency being added to target:\n  \""_s,
5501
0
                     target->GetName(), "\"\n"_s),
5502
0
            eval->Backtrace);
5503
0
        }
5504
0
        CM_FALLTHROUGH;
5505
0
      case cmPolicies::OLD:
5506
0
        eval->DependTargets.insert(target);
5507
0
        break;
5508
1.37k
      case cmPolicies::NEW:
5509
1.37k
        break;
5510
1.37k
    }
5511
1.37k
  }
5512
};
5513
5514
template <typename ArtifactT>
5515
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactNameTag>
5516
  : TargetFilesystemArtifactDependencyCMP0112
5517
{
5518
};
5519
template <typename ArtifactT>
5520
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactDirTag>
5521
  : TargetFilesystemArtifactDependencyCMP0112
5522
{
5523
};
5524
template <>
5525
struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag,
5526
                                          ArtifactPathTag>
5527
  : TargetFilesystemArtifactDependencyCMP0112
5528
{
5529
};
5530
template <>
5531
struct TargetFilesystemArtifactDependency<ArtifactBundleDirNameTag,
5532
                                          ArtifactPathTag>
5533
  : TargetFilesystemArtifactDependencyCMP0112
5534
{
5535
};
5536
template <>
5537
struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag,
5538
                                          ArtifactPathTag>
5539
  : TargetFilesystemArtifactDependencyCMP0112
5540
{
5541
};
5542
5543
template <typename ArtifactT>
5544
struct TargetFilesystemArtifactResultCreator
5545
{
5546
  static std::string Create(cmGeneratorTarget* target,
5547
                            cm::GenEx::Evaluation* eval,
5548
                            GeneratorExpressionContent const* content);
5549
};
5550
5551
template <>
5552
struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
5553
{
5554
  static std::string Create(cmGeneratorTarget* target,
5555
                            cm::GenEx::Evaluation* eval,
5556
                            GeneratorExpressionContent const* content)
5557
310
  {
5558
    // The target soname file (.so.1).
5559
310
    if (target->IsDLLPlatform()) {
5560
0
      ::reportError(eval, content->GetOriginalExpression(),
5561
0
                    "TARGET_SONAME_FILE is not allowed "
5562
0
                    "for DLL target platforms.");
5563
0
      return std::string();
5564
0
    }
5565
310
    if (target->GetType() != cm::TargetType::SHARED_LIBRARY) {
5566
1
      ::reportError(eval, content->GetOriginalExpression(),
5567
1
                    "TARGET_SONAME_FILE is allowed only for "
5568
1
                    "SHARED libraries.");
5569
1
      return std::string();
5570
1
    }
5571
309
    if (target->IsArchivedAIXSharedLibrary()) {
5572
0
      ::reportError(eval, content->GetOriginalExpression(),
5573
0
                    "TARGET_SONAME_FILE is not allowed for "
5574
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
5575
0
      return std::string();
5576
0
    }
5577
309
    std::string result =
5578
309
      cmStrCat(target->GetDirectory(eval->Context.Config), '/',
5579
309
               target->GetSOName(eval->Context.Config));
5580
309
    return result;
5581
309
  }
5582
};
5583
5584
template <>
5585
struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag>
5586
{
5587
  static std::string Create(cmGeneratorTarget* target,
5588
                            cm::GenEx::Evaluation* eval,
5589
                            GeneratorExpressionContent const* content)
5590
0
  {
5591
    // The target soname file (.so.1).
5592
0
    if (target->IsDLLPlatform()) {
5593
0
      ::reportError(eval, content->GetOriginalExpression(),
5594
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed "
5595
0
                    "for DLL target platforms.");
5596
0
      return std::string();
5597
0
    }
5598
0
    if (target->GetType() != cm::TargetType::SHARED_LIBRARY) {
5599
0
      ::reportError(eval, content->GetOriginalExpression(),
5600
0
                    "TARGET_SONAME_IMPORT_FILE is allowed only for "
5601
0
                    "SHARED libraries.");
5602
0
      return std::string();
5603
0
    }
5604
0
    if (target->IsArchivedAIXSharedLibrary()) {
5605
0
      ::reportError(eval, content->GetOriginalExpression(),
5606
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed for "
5607
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
5608
0
      return std::string();
5609
0
    }
5610
5611
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5612
0
      return cmStrCat(
5613
0
        target->GetDirectory(eval->Context.Config,
5614
0
                             cmStateEnums::ImportLibraryArtifact),
5615
0
        '/',
5616
0
        target->GetSOName(eval->Context.Config,
5617
0
                          cmStateEnums::ImportLibraryArtifact));
5618
0
    }
5619
0
    return std::string{};
5620
0
  }
5621
};
5622
5623
template <>
5624
struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
5625
{
5626
  static std::string Create(cmGeneratorTarget* target,
5627
                            cm::GenEx::Evaluation* eval,
5628
                            GeneratorExpressionContent const* content)
5629
2
  {
5630
2
    if (target->IsImported()) {
5631
2
      ::reportError(eval, content->GetOriginalExpression(),
5632
2
                    "TARGET_PDB_FILE not allowed for IMPORTED targets.");
5633
2
      return std::string();
5634
2
    }
5635
5636
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
5637
5638
0
    std::string pdbSupportVar =
5639
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
5640
5641
0
    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
5642
0
      ::reportError(eval, content->GetOriginalExpression(),
5643
0
                    "TARGET_PDB_FILE is not supported by the target linker.");
5644
0
      return std::string();
5645
0
    }
5646
5647
0
    cm::TargetType targetType = target->GetType();
5648
5649
0
    if (targetType != cm::TargetType::SHARED_LIBRARY &&
5650
0
        targetType != cm::TargetType::MODULE_LIBRARY &&
5651
0
        targetType != cm::TargetType::EXECUTABLE) {
5652
0
      ::reportError(eval, content->GetOriginalExpression(),
5653
0
                    "TARGET_PDB_FILE is allowed only for "
5654
0
                    "targets with linker created artifacts.");
5655
0
      return std::string();
5656
0
    }
5657
5658
0
    std::string result =
5659
0
      cmStrCat(target->GetPDBDirectory(eval->Context.Config), '/',
5660
0
               target->GetPDBName(eval->Context.Config));
5661
0
    return result;
5662
0
  }
5663
};
5664
5665
template <>
5666
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
5667
{
5668
  static std::string Create(cmGeneratorTarget* target,
5669
                            cm::GenEx::Evaluation* eval,
5670
                            GeneratorExpressionContent const* content)
5671
674
  {
5672
    // The file used to link to the target (.so, .lib, .a) or import file
5673
    // (.lib,  .tbd).
5674
674
    if (!target->IsLinkable()) {
5675
2
      ::reportError(eval, content->GetOriginalExpression(),
5676
2
                    "TARGET_LINKER_FILE is allowed only for libraries and "
5677
2
                    "executables with ENABLE_EXPORTS.");
5678
2
      return std::string();
5679
2
    }
5680
672
    cmStateEnums::ArtifactType artifact =
5681
672
      target->HasImportLibrary(eval->Context.Config)
5682
672
      ? cmStateEnums::ImportLibraryArtifact
5683
672
      : cmStateEnums::RuntimeBinaryArtifact;
5684
672
    return target->GetFullPath(eval->Context.Config, artifact);
5685
674
  }
5686
};
5687
5688
template <>
5689
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag>
5690
{
5691
  static std::string Create(cmGeneratorTarget* target,
5692
                            cm::GenEx::Evaluation* eval,
5693
                            GeneratorExpressionContent const* content)
5694
0
  {
5695
    // The file used to link to the target (.dylib, .so, .a).
5696
0
    if (!target->IsLinkable() ||
5697
0
        target->GetType() == cm::TargetType::EXECUTABLE) {
5698
0
      ::reportError(eval, content->GetOriginalExpression(),
5699
0
                    "TARGET_LINKER_LIBRARY_FILE is allowed only for libraries "
5700
0
                    "with ENABLE_EXPORTS.");
5701
0
      return std::string();
5702
0
    }
5703
5704
0
    if (!target->IsDLLPlatform() ||
5705
0
        target->GetType() == cm::TargetType::STATIC_LIBRARY) {
5706
0
      return target->GetFullPath(eval->Context.Config,
5707
0
                                 cmStateEnums::RuntimeBinaryArtifact);
5708
0
    }
5709
0
    return std::string{};
5710
0
  }
5711
};
5712
5713
template <>
5714
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag>
5715
{
5716
  static std::string Create(cmGeneratorTarget* target,
5717
                            cm::GenEx::Evaluation* eval,
5718
                            GeneratorExpressionContent const* content)
5719
0
  {
5720
    // The file used to link to the target (.lib, .tbd).
5721
0
    if (!target->IsLinkable()) {
5722
0
      ::reportError(
5723
0
        eval, content->GetOriginalExpression(),
5724
0
        "TARGET_LINKER_IMPORT_FILE is allowed only for libraries and "
5725
0
        "executables with ENABLE_EXPORTS.");
5726
0
      return std::string();
5727
0
    }
5728
5729
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5730
0
      return target->GetFullPath(eval->Context.Config,
5731
0
                                 cmStateEnums::ImportLibraryArtifact);
5732
0
    }
5733
0
    return std::string{};
5734
0
  }
5735
};
5736
5737
template <>
5738
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
5739
{
5740
  static std::string Create(cmGeneratorTarget* target,
5741
                            cm::GenEx::Evaluation* eval,
5742
                            GeneratorExpressionContent const* content)
5743
0
  {
5744
0
    if (target->IsImported()) {
5745
0
      ::reportError(eval, content->GetOriginalExpression(),
5746
0
                    "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
5747
0
      return std::string();
5748
0
    }
5749
0
    if (!target->IsBundleOnApple()) {
5750
0
      ::reportError(eval, content->GetOriginalExpression(),
5751
0
                    "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
5752
0
      return std::string();
5753
0
    }
5754
5755
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
5756
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
5757
0
                                        cmGeneratorTarget::BundleDirLevel);
5758
0
  }
5759
};
5760
5761
template <>
5762
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag>
5763
{
5764
  static std::string Create(cmGeneratorTarget* target,
5765
                            cm::GenEx::Evaluation* eval,
5766
                            GeneratorExpressionContent const* content)
5767
0
  {
5768
0
    if (target->IsImported()) {
5769
0
      ::reportError(
5770
0
        eval, content->GetOriginalExpression(),
5771
0
        "TARGET_BUNDLE_DIR_NAME not allowed for IMPORTED targets.");
5772
0
      return std::string();
5773
0
    }
5774
0
    if (!target->IsBundleOnApple()) {
5775
0
      ::reportError(
5776
0
        eval, content->GetOriginalExpression(),
5777
0
        "TARGET_BUNDLE_DIR_NAME is allowed only for Bundle targets.");
5778
0
      return std::string();
5779
0
    }
5780
5781
0
    auto level = cmGeneratorTarget::BundleDirLevel;
5782
0
    auto config = eval->Context.Config;
5783
0
    if (target->IsAppBundleOnApple()) {
5784
0
      return target->GetAppBundleDirectory(config, level);
5785
0
    }
5786
0
    if (target->IsFrameworkOnApple()) {
5787
0
      return target->GetFrameworkDirectory(config, level);
5788
0
    }
5789
0
    if (target->IsCFBundleOnApple()) {
5790
0
      return target->GetCFBundleDirectory(config, level);
5791
0
    }
5792
0
    return std::string();
5793
0
  }
5794
};
5795
5796
template <>
5797
struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
5798
{
5799
  static std::string Create(cmGeneratorTarget* target,
5800
                            cm::GenEx::Evaluation* eval,
5801
                            GeneratorExpressionContent const* content)
5802
0
  {
5803
0
    if (target->IsImported()) {
5804
0
      ::reportError(
5805
0
        eval, content->GetOriginalExpression(),
5806
0
        "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
5807
0
      return std::string();
5808
0
    }
5809
0
    if (!target->IsBundleOnApple()) {
5810
0
      ::reportError(
5811
0
        eval, content->GetOriginalExpression(),
5812
0
        "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
5813
0
      return std::string();
5814
0
    }
5815
5816
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
5817
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
5818
0
                                        cmGeneratorTarget::ContentLevel);
5819
0
  }
5820
};
5821
5822
template <>
5823
struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
5824
{
5825
  static std::string Create(cmGeneratorTarget* target,
5826
                            cm::GenEx::Evaluation* eval,
5827
                            GeneratorExpressionContent const* /*unused*/)
5828
2.78k
  {
5829
2.78k
    return target->GetFullPath(eval->Context.Config,
5830
2.78k
                               cmStateEnums::RuntimeBinaryArtifact, true);
5831
2.78k
  }
5832
};
5833
5834
template <>
5835
struct TargetFilesystemArtifactResultCreator<ArtifactImportTag>
5836
{
5837
  static std::string Create(cmGeneratorTarget* target,
5838
                            cm::GenEx::Evaluation* eval,
5839
                            GeneratorExpressionContent const* /*unused*/)
5840
11
  {
5841
11
    if (target->HasImportLibrary(eval->Context.Config)) {
5842
0
      return target->GetFullPath(eval->Context.Config,
5843
0
                                 cmStateEnums::ImportLibraryArtifact, true);
5844
0
    }
5845
11
    return std::string{};
5846
11
  }
5847
};
5848
5849
template <typename ArtifactT>
5850
struct TargetFilesystemArtifactResultGetter
5851
{
5852
  static std::string Get(std::string const& result);
5853
};
5854
5855
template <>
5856
struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
5857
{
5858
  static std::string Get(std::string const& result)
5859
642
  {
5860
642
    return cmSystemTools::GetFilenameName(result);
5861
642
  }
5862
};
5863
5864
template <>
5865
struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
5866
{
5867
  static std::string Get(std::string const& result)
5868
726
  {
5869
726
    return cmSystemTools::GetFilenamePath(result);
5870
726
  }
5871
};
5872
5873
template <>
5874
struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
5875
{
5876
2.41k
  static std::string Get(std::string const& result) { return result; }
5877
};
5878
5879
struct TargetArtifactBase : public cmGeneratorExpressionNode
5880
{
5881
430
  TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
5882
5883
protected:
5884
  cmGeneratorTarget* GetTarget(
5885
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5886
    GeneratorExpressionContent const* content,
5887
    cmGeneratorExpressionDAGChecker* dagChecker) const
5888
3.93k
  {
5889
    // Lookup the referenced target.
5890
3.93k
    std::string const& name = parameters.front();
5891
5892
3.93k
    if (!cmGeneratorExpression::IsValidTargetName(name)) {
5893
99
      ::reportError(eval, content->GetOriginalExpression(),
5894
99
                    "Expression syntax not recognized.");
5895
99
      return nullptr;
5896
99
    }
5897
3.83k
    cmGeneratorTarget* target =
5898
3.83k
      eval->Context.LG->FindGeneratorTargetToUse(name);
5899
3.83k
    if (!target) {
5900
44
      ::reportError(eval, content->GetOriginalExpression(),
5901
44
                    cmStrCat("No target \"", name, '"'));
5902
44
      return nullptr;
5903
44
    }
5904
3.79k
    if (target->GetType() >= cm::TargetType::OBJECT_LIBRARY &&
5905
3
        target->GetType() != cm::TargetType::UNKNOWN_LIBRARY) {
5906
3
      ::reportError(
5907
3
        eval, content->GetOriginalExpression(),
5908
3
        cmStrCat("Target \"", name, "\" is not an executable or library."));
5909
3
      return nullptr;
5910
3
    }
5911
3.78k
    if (dagChecker &&
5912
2.86k
        (dagChecker->EvaluatingLinkLibraries(target) ||
5913
2.86k
         (dagChecker->EvaluatingSources() &&
5914
2
          target == dagChecker->TopTarget()))) {
5915
2
      ::reportError(eval, content->GetOriginalExpression(),
5916
2
                    "Expressions which require the linker language may not "
5917
2
                    "be used while evaluating link libraries");
5918
2
      return nullptr;
5919
2
    }
5920
5921
3.78k
    return target;
5922
3.78k
  }
5923
};
5924
5925
template <typename ArtifactT, typename ComponentT>
5926
struct TargetFilesystemArtifact : public TargetArtifactBase
5927
{
5928
270
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5928
10
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
5929
5930
3.95k
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
2.09k
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactNameTag>::NumExpectedParameters() const
Line
Count
Source
5930
25
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactDirTag>::NumExpectedParameters() const
Line
Count
Source
5930
744
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactImportTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
17
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactImportTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactImportTag, ArtifactDirTag>::NumExpectedParameters() const
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
41
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactNameTag>::NumExpectedParameters() const
Line
Count
Source
5930
653
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactDirTag>::NumExpectedParameters() const
Line
Count
Source
5930
3
  int NumExpectedParameters() const override { return 1; }
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
7
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactDirTag>::NumExpectedParameters() const
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
6
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactDirTag>::NumExpectedParameters() const
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
324
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameTag, ArtifactDirTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactPathTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactDirTag>::NumExpectedParameters() const
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
27
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactPdbTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactPdbTag, ArtifactDirTag>::NumExpectedParameters() const
TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>::NumExpectedParameters() const
Line
Count
Source
5930
7
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactBundleDirNameTag, ArtifactNameTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag>::NumExpectedParameters() const
5931
5932
  std::string Evaluate(
5933
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5934
    GeneratorExpressionContent const* content,
5935
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5936
3.91k
  {
5937
3.91k
    cmGeneratorTarget* target =
5938
3.91k
      this->GetTarget(parameters, eval, content, dagChecker);
5939
3.91k
    if (!target) {
5940
133
      return std::string();
5941
133
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
3.78k
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
3.78k
      target, eval);
5947
5948
3.78k
    std::string result =
5949
3.78k
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
3.78k
                                                               content);
5951
3.78k
    if (eval->HadError) {
5952
5
      return std::string();
5953
5
    }
5954
3.77k
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
3.78k
  }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
2.09k
  {
5937
2.09k
    cmGeneratorTarget* target =
5938
2.09k
      this->GetTarget(parameters, eval, content, dagChecker);
5939
2.09k
    if (!target) {
5940
39
      return std::string();
5941
39
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
2.05k
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
2.05k
      target, eval);
5947
5948
2.05k
    std::string result =
5949
2.05k
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
2.05k
                                                               content);
5951
2.05k
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
2.05k
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
2.05k
  }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
18
  {
5937
18
    cmGeneratorTarget* target =
5938
18
      this->GetTarget(parameters, eval, content, dagChecker);
5939
18
    if (!target) {
5940
11
      return std::string();
5941
11
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
7
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
7
      target, eval);
5947
5948
7
    std::string result =
5949
7
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
7
                                                               content);
5951
7
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
7
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
7
  }
TargetFilesystemArtifact<ArtifactNameTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
742
  {
5937
742
    cmGeneratorTarget* target =
5938
742
      this->GetTarget(parameters, eval, content, dagChecker);
5939
742
    if (!target) {
5940
16
      return std::string();
5941
16
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
726
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
726
      target, eval);
5947
5948
726
    std::string result =
5949
726
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
726
                                                               content);
5951
726
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
726
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
726
  }
TargetFilesystemArtifact<ArtifactImportTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
15
  {
5937
15
    cmGeneratorTarget* target =
5938
15
      this->GetTarget(parameters, eval, content, dagChecker);
5939
15
    if (!target) {
5940
4
      return std::string();
5941
4
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
11
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
11
      target, eval);
5947
5948
11
    std::string result =
5949
11
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
11
                                                               content);
5951
11
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
11
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
11
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactImportTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactImportTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
40
  {
5937
40
    cmGeneratorTarget* target =
5938
40
      this->GetTarget(parameters, eval, content, dagChecker);
5939
40
    if (!target) {
5940
3
      return std::string();
5941
3
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
37
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
37
      target, eval);
5947
5948
37
    std::string result =
5949
37
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
37
                                                               content);
5951
37
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
37
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
37
  }
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
652
  {
5937
652
    cmGeneratorTarget* target =
5938
652
      this->GetTarget(parameters, eval, content, dagChecker);
5939
652
    if (!target) {
5940
17
      return std::string();
5941
17
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
635
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
635
      target, eval);
5947
5948
635
    std::string result =
5949
635
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
635
                                                               content);
5951
635
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
635
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
635
  }
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
3
  {
5937
3
    cmGeneratorTarget* target =
5938
3
      this->GetTarget(parameters, eval, content, dagChecker);
5939
3
    if (!target) {
5940
1
      return std::string();
5941
1
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
2
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
2
      target, eval);
5947
5948
2
    std::string result =
5949
2
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
2
                                                               content);
5951
2
    if (eval->HadError) {
5952
2
      return std::string();
5953
2
    }
5954
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
2
  }
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
5
  {
5937
5
    cmGeneratorTarget* target =
5938
5
      this->GetTarget(parameters, eval, content, dagChecker);
5939
5
    if (!target) {
5940
5
      return std::string();
5941
5
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
0
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
0
      target, eval);
5947
5948
0
    std::string result =
5949
0
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
0
                                                               content);
5951
0
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
0
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
3
  {
5937
3
    cmGeneratorTarget* target =
5938
3
      this->GetTarget(parameters, eval, content, dagChecker);
5939
3
    if (!target) {
5940
3
      return std::string();
5941
3
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
0
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
0
      target, eval);
5947
5948
0
    std::string result =
5949
0
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
0
                                                               content);
5951
0
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
0
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
319
  {
5937
319
    cmGeneratorTarget* target =
5938
319
      this->GetTarget(parameters, eval, content, dagChecker);
5939
319
    if (!target) {
5940
9
      return std::string();
5941
9
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
310
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
310
      target, eval);
5947
5948
310
    std::string result =
5949
310
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
310
                                                               content);
5951
310
    if (eval->HadError) {
5952
1
      return std::string();
5953
1
    }
5954
309
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
310
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
20
  {
5937
20
    cmGeneratorTarget* target =
5938
20
      this->GetTarget(parameters, eval, content, dagChecker);
5939
20
    if (!target) {
5940
18
      return std::string();
5941
18
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
2
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
2
      target, eval);
5947
5948
2
    std::string result =
5949
2
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
2
                                                               content);
5951
2
    if (eval->HadError) {
5952
2
      return std::string();
5953
2
    }
5954
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
2
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactPdbTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactPdbTag, ArtifactDirTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
5936
7
  {
5937
7
    cmGeneratorTarget* target =
5938
7
      this->GetTarget(parameters, eval, content, dagChecker);
5939
7
    if (!target) {
5940
7
      return std::string();
5941
7
    }
5942
    // Not a dependent target if we are querying for ArtifactDirTag,
5943
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5944
    // and ArtifactBundleContentDirTag
5945
0
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5946
0
      target, eval);
5947
5948
0
    std::string result =
5949
0
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5950
0
                                                               content);
5951
0
    if (eval->HadError) {
5952
0
      return std::string();
5953
0
    }
5954
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5955
0
  }
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactBundleDirNameTag, ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
5956
};
5957
5958
template <typename ArtifactT>
5959
struct TargetFilesystemArtifactNodeGroup
5960
{
5961
  TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
5962
80
  {
5963
80
  }
TargetFilesystemArtifactNodeGroup<ArtifactNameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5962
10
  {
5963
10
  }
5964
5965
  TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
5966
  TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
5967
  TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
5968
};
5969
5970
static TargetFilesystemArtifactNodeGroup<ArtifactNameTag> const
5971
  targetNodeGroup;
5972
5973
static TargetFilesystemArtifactNodeGroup<ArtifactImportTag> const
5974
  targetImportNodeGroup;
5975
5976
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag> const
5977
  targetLinkerNodeGroup;
5978
5979
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag> const
5980
  targetLinkerLibraryNodeGroup;
5981
5982
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag> const
5983
  targetLinkerImportNodeGroup;
5984
5985
static TargetFilesystemArtifactNodeGroup<ArtifactSonameTag> const
5986
  targetSoNameNodeGroup;
5987
5988
static TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag> const
5989
  targetSoNameImportNodeGroup;
5990
5991
static TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> const
5992
  targetPdbNodeGroup;
5993
5994
static TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag> const
5995
  targetBundleDirNode;
5996
5997
static TargetFilesystemArtifact<ArtifactBundleDirNameTag,
5998
                                ArtifactNameTag> const targetBundleDirNameNode;
5999
6000
static TargetFilesystemArtifact<ArtifactBundleContentDirTag,
6001
                                ArtifactPathTag> const
6002
  targetBundleContentDirNode;
6003
6004
//
6005
// To retrieve base name for various artifacts
6006
//
6007
enum class Postfix
6008
{
6009
  Unspecified,
6010
  Exclude,
6011
  Include
6012
};
6013
6014
template <typename ArtifactT>
6015
struct TargetOutputNameArtifactResultGetter
6016
{
6017
  static std::string Get(cmGeneratorTarget* target,
6018
                         cm::GenEx::Evaluation* eval,
6019
                         GeneratorExpressionContent const* content,
6020
                         Postfix postfix);
6021
};
6022
6023
template <>
6024
struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
6025
{
6026
  static std::string Get(cmGeneratorTarget* target,
6027
                         cm::GenEx::Evaluation* eval,
6028
                         GeneratorExpressionContent const* /*unused*/,
6029
                         Postfix postfix)
6030
0
  {
6031
0
    auto output = target->GetOutputName(eval->Context.Config,
6032
0
                                        cmStateEnums::RuntimeBinaryArtifact);
6033
0
    return postfix != Postfix::Exclude
6034
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6035
0
      : output;
6036
0
  }
6037
};
6038
6039
template <>
6040
struct TargetOutputNameArtifactResultGetter<ArtifactImportTag>
6041
{
6042
  static std::string Get(cmGeneratorTarget* target,
6043
                         cm::GenEx::Evaluation* eval,
6044
                         GeneratorExpressionContent const* /*unused*/,
6045
                         Postfix postfix)
6046
0
  {
6047
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6048
0
      auto output = target->GetOutputName(eval->Context.Config,
6049
0
                                          cmStateEnums::ImportLibraryArtifact);
6050
0
      return postfix != Postfix::Exclude
6051
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6052
0
        : output;
6053
0
    }
6054
0
    return std::string{};
6055
0
  }
6056
};
6057
6058
template <>
6059
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
6060
{
6061
  static std::string Get(cmGeneratorTarget* target,
6062
                         cm::GenEx::Evaluation* eval,
6063
                         GeneratorExpressionContent const* content,
6064
                         Postfix postfix)
6065
0
  {
6066
    // The library file used to link to the target (.so, .lib, .a) or import
6067
    // file (.lin,  .tbd).
6068
0
    if (!target->IsLinkable()) {
6069
0
      ::reportError(eval, content->GetOriginalExpression(),
6070
0
                    "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
6071
0
                    "libraries and executables with ENABLE_EXPORTS.");
6072
0
      return std::string();
6073
0
    }
6074
0
    cmStateEnums::ArtifactType artifact =
6075
0
      target->HasImportLibrary(eval->Context.Config)
6076
0
      ? cmStateEnums::ImportLibraryArtifact
6077
0
      : cmStateEnums::RuntimeBinaryArtifact;
6078
0
    auto output = target->GetOutputName(eval->Context.Config, artifact);
6079
0
    return postfix != Postfix::Exclude
6080
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6081
0
      : output;
6082
0
  }
6083
};
6084
6085
template <>
6086
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag>
6087
{
6088
  static std::string Get(cmGeneratorTarget* target,
6089
                         cm::GenEx::Evaluation* eval,
6090
                         GeneratorExpressionContent const* content,
6091
                         Postfix postfix)
6092
0
  {
6093
    // The library file used to link to the target (.so, .lib, .a).
6094
0
    if (!target->IsLinkable() ||
6095
0
        target->GetType() == cm::TargetType::EXECUTABLE) {
6096
0
      ::reportError(eval, content->GetOriginalExpression(),
6097
0
                    "TARGET_LINKER_LIBRARY_FILE_BASE_NAME is allowed only for "
6098
0
                    "libraries with ENABLE_EXPORTS.");
6099
0
      return std::string();
6100
0
    }
6101
6102
0
    if (!target->IsDLLPlatform() ||
6103
0
        target->GetType() == cm::TargetType::STATIC_LIBRARY) {
6104
0
      auto output = target->GetOutputName(eval->Context.Config,
6105
0
                                          cmStateEnums::ImportLibraryArtifact);
6106
0
      return postfix != Postfix::Exclude
6107
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6108
0
        : output;
6109
0
    }
6110
0
    return std::string{};
6111
0
  }
6112
};
6113
6114
template <>
6115
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag>
6116
{
6117
  static std::string Get(cmGeneratorTarget* target,
6118
                         cm::GenEx::Evaluation* eval,
6119
                         GeneratorExpressionContent const* content,
6120
                         Postfix postfix)
6121
0
  {
6122
    // The import file used to link to the target (.lib, .tbd).
6123
0
    if (!target->IsLinkable()) {
6124
0
      ::reportError(eval, content->GetOriginalExpression(),
6125
0
                    "TARGET_LINKER_IMPORT_FILE_BASE_NAME is allowed only for "
6126
0
                    "libraries and executables with ENABLE_EXPORTS.");
6127
0
      return std::string();
6128
0
    }
6129
6130
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6131
0
      auto output = target->GetOutputName(eval->Context.Config,
6132
0
                                          cmStateEnums::ImportLibraryArtifact);
6133
0
      return postfix != Postfix::Exclude
6134
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6135
0
        : output;
6136
0
    }
6137
0
    return std::string{};
6138
0
  }
6139
};
6140
6141
template <>
6142
struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
6143
{
6144
  static std::string Get(cmGeneratorTarget* target,
6145
                         cm::GenEx::Evaluation* eval,
6146
                         GeneratorExpressionContent const* content,
6147
                         Postfix postfix)
6148
0
  {
6149
0
    if (target->IsImported()) {
6150
0
      ::reportError(
6151
0
        eval, content->GetOriginalExpression(),
6152
0
        "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
6153
0
      return std::string();
6154
0
    }
6155
6156
0
    cmLocalGenerator const* const lg = eval->Context.LG;
6157
6158
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
6159
6160
0
    std::string pdbSupportVar =
6161
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
6162
6163
0
    if (!lg->GetMakefile()->IsOn(pdbSupportVar)) {
6164
0
      ::reportError(
6165
0
        eval, content->GetOriginalExpression(),
6166
0
        "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
6167
0
      return std::string();
6168
0
    }
6169
6170
0
    cm::TargetType targetType = target->GetType();
6171
6172
0
    if (targetType != cm::TargetType::SHARED_LIBRARY &&
6173
0
        targetType != cm::TargetType::MODULE_LIBRARY &&
6174
0
        targetType != cm::TargetType::EXECUTABLE) {
6175
0
      ::reportError(eval, content->GetOriginalExpression(),
6176
0
                    "TARGET_PDB_FILE_BASE_NAME is allowed only for "
6177
0
                    "targets with linker created artifacts.");
6178
0
      return std::string();
6179
0
    }
6180
6181
0
    auto output = target->GetPDBOutputName(eval->Context.Config);
6182
6183
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::NEW) {
6184
0
      return postfix != Postfix::Exclude
6185
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
6186
0
        : output;
6187
0
    }
6188
6189
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::WARN &&
6190
0
        postfix != Postfix::Unspecified) {
6191
0
      lg->IssuePolicyWarning(
6192
0
        cmPolicies::CMP0202, {},
6193
0
        "\"POSTFIX\" option is recognized only when the policy is set to NEW."
6194
0
        "  Since the policy is not set, the OLD behavior will be used."_s,
6195
0
        eval->Backtrace);
6196
0
    }
6197
6198
0
    return output;
6199
0
  }
6200
};
6201
6202
template <typename ArtifactT>
6203
struct TargetFileBaseNameArtifact : public TargetArtifactBase
6204
{
6205
60
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactNameTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactPdbTag>::TargetFileBaseNameArtifact()
Line
Count
Source
6205
10
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
6206
6207
7
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
TargetFileBaseNameArtifact<ArtifactNameTag>::NumExpectedParameters() const
Line
Count
Source
6207
7
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactImportTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerImportTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactPdbTag>::NumExpectedParameters() const
6208
6209
  std::string Evaluate(
6210
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
6211
    GeneratorExpressionContent const* content,
6212
    cmGeneratorExpressionDAGChecker* dagChecker) const override
6213
6
  {
6214
6
    if (parameters.size() > 2) {
6215
3
      ::reportError(eval, content->GetOriginalExpression(),
6216
3
                    "Unexpected parameters, require one or two parameters.");
6217
3
      return std::string{};
6218
3
    }
6219
6220
3
    cmGeneratorTarget* target =
6221
3
      this->GetTarget(parameters, eval, content, dagChecker);
6222
3
    if (!target) {
6223
3
      return std::string();
6224
3
    }
6225
6226
0
    Postfix postfix = Postfix::Unspecified;
6227
0
    if (parameters.size() == 2) {
6228
0
      if (parameters[1] == "POSTFIX:INCLUDE") {
6229
0
        postfix = Postfix::Include;
6230
0
      } else if (parameters[1] == "POSTFIX:EXCLUDE") {
6231
0
        postfix = Postfix::Exclude;
6232
0
      } else {
6233
0
        ::reportError(eval, content->GetOriginalExpression(),
6234
0
                      "Wrong second parameter: \"POSTFIX:INCLUDE\" or "
6235
0
                      "\"POSTFIX:EXCLUDE\" is expected");
6236
0
      }
6237
0
    }
6238
6239
0
    std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
6240
0
      target, eval, content, postfix);
6241
0
    if (eval->HadError) {
6242
0
      return std::string();
6243
0
    }
6244
0
    return result;
6245
0
  }
TargetFileBaseNameArtifact<ArtifactNameTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
6213
6
  {
6214
6
    if (parameters.size() > 2) {
6215
3
      ::reportError(eval, content->GetOriginalExpression(),
6216
3
                    "Unexpected parameters, require one or two parameters.");
6217
3
      return std::string{};
6218
3
    }
6219
6220
3
    cmGeneratorTarget* target =
6221
3
      this->GetTarget(parameters, eval, content, dagChecker);
6222
3
    if (!target) {
6223
3
      return std::string();
6224
3
    }
6225
6226
0
    Postfix postfix = Postfix::Unspecified;
6227
0
    if (parameters.size() == 2) {
6228
0
      if (parameters[1] == "POSTFIX:INCLUDE") {
6229
0
        postfix = Postfix::Include;
6230
0
      } else if (parameters[1] == "POSTFIX:EXCLUDE") {
6231
0
        postfix = Postfix::Exclude;
6232
0
      } else {
6233
0
        ::reportError(eval, content->GetOriginalExpression(),
6234
0
                      "Wrong second parameter: \"POSTFIX:INCLUDE\" or "
6235
0
                      "\"POSTFIX:EXCLUDE\" is expected");
6236
0
      }
6237
0
    }
6238
6239
0
    std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
6240
0
      target, eval, content, postfix);
6241
0
    if (eval->HadError) {
6242
0
      return std::string();
6243
0
    }
6244
0
    return result;
6245
0
  }
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactImportTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactLinkerImportTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileBaseNameArtifact<ArtifactPdbTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
6246
};
6247
6248
static TargetFileBaseNameArtifact<ArtifactNameTag> const
6249
  targetFileBaseNameNode;
6250
static TargetFileBaseNameArtifact<ArtifactImportTag> const
6251
  targetImportFileBaseNameNode;
6252
static TargetFileBaseNameArtifact<ArtifactLinkerTag> const
6253
  targetLinkerFileBaseNameNode;
6254
static TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag> const
6255
  targetLinkerLibraryFileBaseNameNode;
6256
static TargetFileBaseNameArtifact<ArtifactLinkerImportTag> const
6257
  targetLinkerImportFileBaseNameNode;
6258
static TargetFileBaseNameArtifact<ArtifactPdbTag> const
6259
  targetPdbFileBaseNameNode;
6260
6261
class ArtifactFilePrefixTag;
6262
class ArtifactImportFilePrefixTag;
6263
class ArtifactLinkerFilePrefixTag;
6264
class ArtifactLinkerLibraryFilePrefixTag;
6265
class ArtifactLinkerImportFilePrefixTag;
6266
class ArtifactFileSuffixTag;
6267
class ArtifactImportFileSuffixTag;
6268
class ArtifactLinkerFileSuffixTag;
6269
class ArtifactLinkerLibraryFileSuffixTag;
6270
class ArtifactLinkerImportFileSuffixTag;
6271
6272
template <typename ArtifactT>
6273
struct TargetFileArtifactResultGetter
6274
{
6275
  static std::string Get(cmGeneratorTarget* target,
6276
                         cm::GenEx::Evaluation* eval,
6277
                         GeneratorExpressionContent const* content);
6278
};
6279
6280
template <>
6281
struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
6282
{
6283
  static std::string Get(cmGeneratorTarget* target,
6284
                         cm::GenEx::Evaluation* eval,
6285
                         GeneratorExpressionContent const*)
6286
1
  {
6287
1
    return target->GetFilePrefix(eval->Context.Config);
6288
1
  }
6289
};
6290
template <>
6291
struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag>
6292
{
6293
  static std::string Get(cmGeneratorTarget* target,
6294
                         cm::GenEx::Evaluation* eval,
6295
                         GeneratorExpressionContent const*)
6296
0
  {
6297
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6298
0
      return target->GetFilePrefix(eval->Context.Config,
6299
0
                                   cmStateEnums::ImportLibraryArtifact);
6300
0
    }
6301
0
    return std::string{};
6302
0
  }
6303
};
6304
template <>
6305
struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
6306
{
6307
  static std::string Get(cmGeneratorTarget* target,
6308
                         cm::GenEx::Evaluation* eval,
6309
                         GeneratorExpressionContent const* content)
6310
0
  {
6311
0
    if (!target->IsLinkable()) {
6312
0
      ::reportError(
6313
0
        eval, content->GetOriginalExpression(),
6314
0
        "TARGET_LINKER_FILE_PREFIX is allowed only for libraries and "
6315
0
        "executables with ENABLE_EXPORTS.");
6316
0
      return std::string();
6317
0
    }
6318
6319
0
    cmStateEnums::ArtifactType artifact =
6320
0
      target->HasImportLibrary(eval->Context.Config)
6321
0
      ? cmStateEnums::ImportLibraryArtifact
6322
0
      : cmStateEnums::RuntimeBinaryArtifact;
6323
6324
0
    return target->GetFilePrefix(eval->Context.Config, artifact);
6325
0
  }
6326
};
6327
template <>
6328
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag>
6329
{
6330
  static std::string Get(cmGeneratorTarget* target,
6331
                         cm::GenEx::Evaluation* eval,
6332
                         GeneratorExpressionContent const* content)
6333
0
  {
6334
0
    if (!target->IsLinkable() ||
6335
0
        target->GetType() == cm::TargetType::EXECUTABLE) {
6336
0
      ::reportError(
6337
0
        eval, content->GetOriginalExpression(),
6338
0
        "TARGET_LINKER_LIBRARY_FILE_PREFIX is allowed only for libraries "
6339
0
        "with ENABLE_EXPORTS.");
6340
0
      return std::string();
6341
0
    }
6342
6343
0
    if (!target->IsDLLPlatform() ||
6344
0
        target->GetType() == cm::TargetType::STATIC_LIBRARY) {
6345
0
      return target->GetFilePrefix(eval->Context.Config,
6346
0
                                   cmStateEnums::RuntimeBinaryArtifact);
6347
0
    }
6348
0
    return std::string{};
6349
0
  }
6350
};
6351
template <>
6352
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag>
6353
{
6354
  static std::string Get(cmGeneratorTarget* target,
6355
                         cm::GenEx::Evaluation* eval,
6356
                         GeneratorExpressionContent const* content)
6357
0
  {
6358
0
    if (!target->IsLinkable()) {
6359
0
      ::reportError(
6360
0
        eval, content->GetOriginalExpression(),
6361
0
        "TARGET_LINKER_IMPORT_FILE_PREFIX is allowed only for libraries and "
6362
0
        "executables with ENABLE_EXPORTS.");
6363
0
      return std::string();
6364
0
    }
6365
6366
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6367
0
      return target->GetFilePrefix(eval->Context.Config,
6368
0
                                   cmStateEnums::ImportLibraryArtifact);
6369
0
    }
6370
0
    return std::string{};
6371
0
  }
6372
};
6373
template <>
6374
struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
6375
{
6376
  static std::string Get(cmGeneratorTarget* target,
6377
                         cm::GenEx::Evaluation* eval,
6378
                         GeneratorExpressionContent const*)
6379
1
  {
6380
1
    return target->GetFileSuffix(eval->Context.Config);
6381
1
  }
6382
};
6383
template <>
6384
struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag>
6385
{
6386
  static std::string Get(cmGeneratorTarget* target,
6387
                         cm::GenEx::Evaluation* eval,
6388
                         GeneratorExpressionContent const*)
6389
0
  {
6390
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6391
0
      return target->GetFileSuffix(eval->Context.Config,
6392
0
                                   cmStateEnums::ImportLibraryArtifact);
6393
0
    }
6394
0
    return std::string{};
6395
0
  }
6396
};
6397
template <>
6398
struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
6399
{
6400
  static std::string Get(cmGeneratorTarget* target,
6401
                         cm::GenEx::Evaluation* eval,
6402
                         GeneratorExpressionContent const* content)
6403
0
  {
6404
0
    if (!target->IsLinkable()) {
6405
0
      ::reportError(
6406
0
        eval, content->GetOriginalExpression(),
6407
0
        "TARGET_LINKER_FILE_SUFFIX is allowed only for libraries and "
6408
0
        "executables with ENABLE_EXPORTS.");
6409
0
      return std::string();
6410
0
    }
6411
6412
0
    cmStateEnums::ArtifactType artifact =
6413
0
      target->HasImportLibrary(eval->Context.Config)
6414
0
      ? cmStateEnums::ImportLibraryArtifact
6415
0
      : cmStateEnums::RuntimeBinaryArtifact;
6416
6417
0
    return target->GetFileSuffix(eval->Context.Config, artifact);
6418
0
  }
6419
};
6420
template <>
6421
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag>
6422
{
6423
  static std::string Get(cmGeneratorTarget* target,
6424
                         cm::GenEx::Evaluation* eval,
6425
                         GeneratorExpressionContent const* content)
6426
0
  {
6427
0
    if (!target->IsLinkable() ||
6428
0
        target->GetType() == cm::TargetType::STATIC_LIBRARY) {
6429
0
      ::reportError(eval, content->GetOriginalExpression(),
6430
0
                    "TARGET_LINKER_LIBRARY_FILE_SUFFIX is allowed only for "
6431
0
                    "libraries with ENABLE_EXPORTS.");
6432
0
      return std::string();
6433
0
    }
6434
6435
0
    if (!target->IsDLLPlatform() ||
6436
0
        target->GetType() == cm::TargetType::STATIC_LIBRARY) {
6437
0
      return target->GetFileSuffix(eval->Context.Config,
6438
0
                                   cmStateEnums::RuntimeBinaryArtifact);
6439
0
    }
6440
0
    return std::string{};
6441
0
  }
6442
};
6443
template <>
6444
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag>
6445
{
6446
  static std::string Get(cmGeneratorTarget* target,
6447
                         cm::GenEx::Evaluation* eval,
6448
                         GeneratorExpressionContent const* content)
6449
0
  {
6450
0
    if (!target->IsLinkable()) {
6451
0
      ::reportError(
6452
0
        eval, content->GetOriginalExpression(),
6453
0
        "TARGET_LINKER_IMPORT_FILE_SUFFIX is allowed only for libraries and "
6454
0
        "executables with ENABLE_EXPORTS.");
6455
0
      return std::string();
6456
0
    }
6457
6458
0
    if (target->HasImportLibrary(eval->Context.Config)) {
6459
0
      return target->GetFileSuffix(eval->Context.Config,
6460
0
                                   cmStateEnums::ImportLibraryArtifact);
6461
0
    }
6462
0
    return std::string{};
6463
0
  }
6464
};
6465
6466
template <typename ArtifactT>
6467
struct TargetFileArtifact : public TargetArtifactBase
6468
{
6469
100
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
6469
10
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
6470
6471
18
  int NumExpectedParameters() const override { return 1; }
TargetFileArtifact<ArtifactFilePrefixTag>::NumExpectedParameters() const
Line
Count
Source
6471
10
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFileArtifact<ArtifactImportFilePrefixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerFilePrefixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>::NumExpectedParameters() const
TargetFileArtifact<ArtifactFileSuffixTag>::NumExpectedParameters() const
Line
Count
Source
6471
8
  int NumExpectedParameters() const override { return 1; }
Unexecuted instantiation: TargetFileArtifact<ArtifactImportFileSuffixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerFileSuffixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>::NumExpectedParameters() const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>::NumExpectedParameters() const
6472
6473
  std::string Evaluate(
6474
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
6475
    GeneratorExpressionContent const* content,
6476
    cmGeneratorExpressionDAGChecker* dagChecker) const override
6477
14
  {
6478
14
    cmGeneratorTarget* target =
6479
14
      this->GetTarget(parameters, eval, content, dagChecker);
6480
14
    if (!target) {
6481
12
      return std::string();
6482
12
    }
6483
6484
2
    std::string result =
6485
2
      TargetFileArtifactResultGetter<ArtifactT>::Get(target, eval, content);
6486
2
    if (eval->HadError) {
6487
0
      return std::string();
6488
0
    }
6489
2
    return result;
6490
2
  }
TargetFileArtifact<ArtifactFilePrefixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
6477
8
  {
6478
8
    cmGeneratorTarget* target =
6479
8
      this->GetTarget(parameters, eval, content, dagChecker);
6480
8
    if (!target) {
6481
7
      return std::string();
6482
7
    }
6483
6484
1
    std::string result =
6485
1
      TargetFileArtifactResultGetter<ArtifactT>::Get(target, eval, content);
6486
1
    if (eval->HadError) {
6487
0
      return std::string();
6488
0
    }
6489
1
    return result;
6490
1
  }
Unexecuted instantiation: TargetFileArtifact<ArtifactImportFilePrefixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerFilePrefixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
TargetFileArtifact<ArtifactFileSuffixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Line
Count
Source
6477
6
  {
6478
6
    cmGeneratorTarget* target =
6479
6
      this->GetTarget(parameters, eval, content, dagChecker);
6480
6
    if (!target) {
6481
5
      return std::string();
6482
5
    }
6483
6484
1
    std::string result =
6485
1
      TargetFileArtifactResultGetter<ArtifactT>::Get(target, eval, content);
6486
1
    if (eval->HadError) {
6487
0
      return std::string();
6488
0
    }
6489
1
    return result;
6490
1
  }
Unexecuted instantiation: TargetFileArtifact<ArtifactImportFileSuffixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerFileSuffixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
Unexecuted instantiation: TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>::Evaluate(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, cm::GenEx::Evaluation*, GeneratorExpressionContent const*, cmGeneratorExpressionDAGChecker*) const
6491
};
6492
6493
static TargetFileArtifact<ArtifactFilePrefixTag> const targetFilePrefixNode;
6494
static TargetFileArtifact<ArtifactImportFilePrefixTag> const
6495
  targetImportFilePrefixNode;
6496
static TargetFileArtifact<ArtifactLinkerFilePrefixTag> const
6497
  targetLinkerFilePrefixNode;
6498
static TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag> const
6499
  targetLinkerLibraryFilePrefixNode;
6500
static TargetFileArtifact<ArtifactLinkerImportFilePrefixTag> const
6501
  targetLinkerImportFilePrefixNode;
6502
static TargetFileArtifact<ArtifactFileSuffixTag> const targetFileSuffixNode;
6503
static TargetFileArtifact<ArtifactImportFileSuffixTag> const
6504
  targetImportFileSuffixNode;
6505
static TargetFileArtifact<ArtifactLinkerFileSuffixTag> const
6506
  targetLinkerFileSuffixNode;
6507
static TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag> const
6508
  targetLinkerLibraryFileSuffixNode;
6509
static TargetFileArtifact<ArtifactLinkerImportFileSuffixTag> const
6510
  targetLinkerImportFileSuffixNode;
6511
6512
static const struct ShellPathNode : public cmGeneratorExpressionNode
6513
{
6514
10
  ShellPathNode() {} // NOLINT(modernize-use-equals-default)
6515
6516
  std::string Evaluate(
6517
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
6518
    GeneratorExpressionContent const* content,
6519
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
6520
57
  {
6521
57
    cmList list_in{ parameters.front() };
6522
57
    if (list_in.empty()) {
6523
3
      reportError(eval, content->GetOriginalExpression(),
6524
3
                  "\"\" is not an absolute path.");
6525
3
      return std::string();
6526
3
    }
6527
54
    cmStateSnapshot snapshot = eval->Context.LG->GetStateSnapshot();
6528
54
    cmOutputConverter converter(snapshot);
6529
54
    char const* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
6530
54
    std::vector<std::string> list_out;
6531
54
    list_out.reserve(list_in.size());
6532
231
    for (auto const& in : list_in) {
6533
231
      if (!cmSystemTools::FileIsFullPath(in)) {
6534
12
        reportError(eval, content->GetOriginalExpression(),
6535
12
                    cmStrCat('"', in, "\" is not an absolute path."));
6536
12
        return std::string();
6537
12
      }
6538
219
      list_out.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
6539
219
    }
6540
42
    return cmJoin(list_out, separator);
6541
54
  }
6542
} shellPathNode;
6543
6544
cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
6545
  std::string const& identifier)
6546
55.6k
{
6547
55.6k
  static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
6548
55.6k
    { "0", &zeroNode },
6549
55.6k
    { "1", &oneNode },
6550
55.6k
    { "AND", &andNode },
6551
55.6k
    { "OR", &orNode },
6552
55.6k
    { "NOT", &notNode },
6553
55.6k
    { "ARGS", &argsNode },
6554
55.6k
    { "C_COMPILER_ID", &cCompilerIdNode },
6555
55.6k
    { "CXX_COMPILER_ID", &cxxCompilerIdNode },
6556
55.6k
    { "OBJC_COMPILER_ID", &objcCompilerIdNode },
6557
55.6k
    { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode },
6558
55.6k
    { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
6559
55.6k
    { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
6560
55.6k
    { "HIP_COMPILER_ID", &hipCompilerIdNode },
6561
55.6k
    { "SYCL_COMPILER_ID", &syclCompilerIdNode },
6562
55.6k
    { "VERSION_GREATER", &versionGreaterNode },
6563
55.6k
    { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
6564
55.6k
    { "VERSION_LESS", &versionLessNode },
6565
55.6k
    { "VERSION_LESS_EQUAL", &versionLessEqNode },
6566
55.6k
    { "VERSION_EQUAL", &versionEqualNode },
6567
55.6k
    { "C_COMPILER_VERSION", &cCompilerVersionNode },
6568
55.6k
    { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
6569
55.6k
    { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
6570
55.6k
    { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode },
6571
55.6k
    { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode },
6572
55.6k
    { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
6573
55.6k
    { "HIP_COMPILER_VERSION", &hipCompilerVersionNode },
6574
55.6k
    { "SYCL_COMPILER_VERSION", &syclCompilerVersionNode },
6575
55.6k
    { "C_COMPILER_FRONTEND_VARIANT", &cCompilerFrontendVariantNode },
6576
55.6k
    { "CXX_COMPILER_FRONTEND_VARIANT", &cxxCompilerFrontendVariantNode },
6577
55.6k
    { "CUDA_COMPILER_FRONTEND_VARIANT", &cudaCompilerFrontendVariantNode },
6578
55.6k
    { "OBJC_COMPILER_FRONTEND_VARIANT", &objcCompilerFrontendVariantNode },
6579
55.6k
    { "OBJCXX_COMPILER_FRONTEND_VARIANT", &objcxxCompilerFrontendVariantNode },
6580
55.6k
    { "Fortran_COMPILER_FRONTEND_VARIANT",
6581
55.6k
      &fortranCompilerFrontendVariantNode },
6582
55.6k
    { "HIP_COMPILER_FRONTEND_VARIANT", &hipCompilerFrontendVariantNode },
6583
55.6k
    { "SYCL_COMPILER_FRONTEND_VARIANT", &syclCompilerFrontendVariantNode },
6584
55.6k
    { "PLATFORM_ID", &platformIdNode },
6585
55.6k
    { "COMPILE_FEATURES", &compileFeaturesNode },
6586
55.6k
    { "CONFIGURATION", &configurationNode },
6587
55.6k
    { "CONFIG", &configurationTestNode },
6588
55.6k
    { "TARGET_FILE", &targetNodeGroup.File },
6589
55.6k
    { "TARGET_IMPORT_FILE", &targetImportNodeGroup.File },
6590
55.6k
    { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
6591
55.6k
    { "TARGET_LINKER_LIBRARY_FILE", &targetLinkerLibraryNodeGroup.File },
6592
55.6k
    { "TARGET_LINKER_IMPORT_FILE", &targetLinkerImportNodeGroup.File },
6593
55.6k
    { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
6594
55.6k
    { "TARGET_SONAME_IMPORT_FILE", &targetSoNameImportNodeGroup.File },
6595
55.6k
    { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
6596
55.6k
    { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
6597
55.6k
    { "TARGET_IMPORT_FILE_BASE_NAME", &targetImportFileBaseNameNode },
6598
55.6k
    { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
6599
55.6k
    { "TARGET_LINKER_LIBRARY_FILE_BASE_NAME",
6600
55.6k
      &targetLinkerLibraryFileBaseNameNode },
6601
55.6k
    { "TARGET_LINKER_IMPORT_FILE_BASE_NAME",
6602
55.6k
      &targetLinkerImportFileBaseNameNode },
6603
55.6k
    { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
6604
55.6k
    { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
6605
55.6k
    { "TARGET_IMPORT_FILE_PREFIX", &targetImportFilePrefixNode },
6606
55.6k
    { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
6607
55.6k
    { "TARGET_LINKER_LIBRARY_FILE_PREFIX",
6608
55.6k
      &targetLinkerLibraryFilePrefixNode },
6609
55.6k
    { "TARGET_LINKER_IMPORT_FILE_PREFIX", &targetLinkerImportFilePrefixNode },
6610
55.6k
    { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
6611
55.6k
    { "TARGET_IMPORT_FILE_SUFFIX", &targetImportFileSuffixNode },
6612
55.6k
    { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
6613
55.6k
    { "TARGET_LINKER_LIBRARY_FILE_SUFFIX",
6614
55.6k
      &targetLinkerLibraryFileSuffixNode },
6615
55.6k
    { "TARGET_LINKER_IMPORT_FILE_SUFFIX", &targetLinkerImportFileSuffixNode },
6616
55.6k
    { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
6617
55.6k
    { "TARGET_IMPORT_FILE_NAME", &targetImportNodeGroup.FileName },
6618
55.6k
    { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
6619
55.6k
    { "TARGET_LINKER_LIBRARY_FILE_NAME",
6620
55.6k
      &targetLinkerLibraryNodeGroup.FileName },
6621
55.6k
    { "TARGET_LINKER_IMPORT_FILE_NAME",
6622
55.6k
      &targetLinkerImportNodeGroup.FileName },
6623
55.6k
    { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
6624
55.6k
    { "TARGET_SONAME_IMPORT_FILE_NAME",
6625
55.6k
      &targetSoNameImportNodeGroup.FileName },
6626
55.6k
    { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
6627
55.6k
    { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
6628
55.6k
    { "TARGET_IMPORT_FILE_DIR", &targetImportNodeGroup.FileDir },
6629
55.6k
    { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
6630
55.6k
    { "TARGET_LINKER_LIBRARY_FILE_DIR",
6631
55.6k
      &targetLinkerLibraryNodeGroup.FileDir },
6632
55.6k
    { "TARGET_LINKER_IMPORT_FILE_DIR", &targetLinkerImportNodeGroup.FileDir },
6633
55.6k
    { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
6634
55.6k
    { "TARGET_SONAME_IMPORT_FILE_DIR", &targetSoNameImportNodeGroup.FileDir },
6635
55.6k
    { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
6636
55.6k
    { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
6637
55.6k
    { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode },
6638
55.6k
    { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
6639
55.6k
    { "STREQUAL", &strEqualNode },
6640
55.6k
    { "STRLESS", &strLessNode },
6641
55.6k
    { "STRLESS_EQUAL", &strLessEqualNode },
6642
55.6k
    { "STRGREATER", &strGreaterNode },
6643
55.6k
    { "STRGREATER_EQUAL", &strGreaterEqualNode },
6644
55.6k
    { "STRING", &stringNode },
6645
55.6k
    { "EQUAL", &equalNode },
6646
55.6k
    { "IN_LIST", &inListNode },
6647
55.6k
    { "FILTER", &filterNode },
6648
55.6k
    { "REMOVE_DUPLICATES", &removeDuplicatesNode },
6649
55.6k
    { "LIST", &listNode },
6650
55.6k
    { "LOWER_CASE", &lowerCaseNode },
6651
55.6k
    { "UPPER_CASE", &upperCaseNode },
6652
55.6k
    { "PATH", &pathNode },
6653
55.6k
    { "PATH_EQUAL", &pathEqualNode },
6654
55.6k
    { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
6655
55.6k
    { "BOOL", &boolNode },
6656
55.6k
    { "_0", &boundOperandNode0 },
6657
55.6k
    { "_1", &boundOperandNode1 },
6658
55.6k
    { "IF", &ifNode },
6659
55.6k
    { "ANGLE-R", &angle_rNode },
6660
55.6k
    { "COMMA", &commaNode },
6661
55.6k
    { "SEMICOLON", &semicolonNode },
6662
55.6k
    { "QUOTE", &quoteNode },
6663
55.6k
    { "GLOBAL_PROPERTY", &globalPropertyNode },
6664
55.6k
    { "DIRECTORY_PROPERTY", &directoryPropertyNode },
6665
55.6k
    { "RULE_PROPERTY", &rulePropertyNode },
6666
55.6k
    { "SOURCE_EXISTS", &sourceExistsNode },
6667
55.6k
    { "SOURCE_PROPERTY", &sourcePropertyNode },
6668
55.6k
    { "FILE_SET_EXISTS", &fileSetExistsNode },
6669
55.6k
    { "FILE_SET_PROPERTY", &fileSetPropertyNode },
6670
55.6k
    { "TARGET_PROPERTY", &targetPropertyNode },
6671
55.6k
    { "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
6672
55.6k
    { "TARGET_NAME", &targetNameNode },
6673
55.6k
    { "TARGET_OBJECTS", &targetObjectsNode },
6674
55.6k
    { "TARGET_POLICY", &targetPolicyNode },
6675
55.6k
    { "TARGET_EXISTS", &targetExistsNode },
6676
55.6k
    { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
6677
55.6k
    { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
6678
55.6k
    { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
6679
55.6k
    { "TARGET_RUNTIME_DLL_DIRS", &targetRuntimeDllDirsNode },
6680
55.6k
    { "GENEX_EVAL", &genexEvalNode },
6681
55.6k
    { "BUILD_INTERFACE", &buildInterfaceNode },
6682
55.6k
    { "INSTALL_INTERFACE", &installInterfaceNode },
6683
55.6k
    { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode },
6684
55.6k
    { "INSTALL_PREFIX", &installPrefixNode },
6685
55.6k
    { "JOIN", &joinNode },
6686
55.6k
    { "COMPILE_ONLY", &compileOnlyNode },
6687
55.6k
    { "LINK_ONLY", &linkOnlyNode },
6688
55.6k
    { "COMPILE_LANG_AND_ID", &languageAndIdNode },
6689
55.6k
    { "COMPILE_LANGUAGE", &languageNode },
6690
55.6k
    { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
6691
55.6k
    { "LINK_LANGUAGE", &linkLanguageNode },
6692
55.6k
    { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
6693
55.6k
    { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
6694
55.6k
    { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
6695
55.6k
    { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
6696
55.6k
    { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
6697
55.6k
    { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
6698
55.6k
    { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
6699
55.6k
    { "SYCL_COMPILER_LINKER_ID", &syclCompilerLinkerIdNode },
6700
55.6k
    { "C_COMPILER_LINKER_FRONTEND_VARIANT",
6701
55.6k
      &cCompilerLinkerFrontendVariantNode },
6702
55.6k
    { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
6703
55.6k
      &cxxCompilerLinkerFrontendVariantNode },
6704
55.6k
    { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
6705
55.6k
      &cudaCompilerLinkerFrontendVariantNode },
6706
55.6k
    { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
6707
55.6k
      &objcCompilerLinkerFrontendVariantNode },
6708
55.6k
    { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
6709
55.6k
      &objcxxCompilerLinkerFrontendVariantNode },
6710
55.6k
    { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
6711
55.6k
      &fortranCompilerLinkerFrontendVariantNode },
6712
55.6k
    { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
6713
55.6k
      &hipCompilerLinkerFrontendVariantNode },
6714
55.6k
    { "SYCL_COMPILER_LINKER_FRONTEND_VARIANT",
6715
55.6k
      &syclCompilerLinkerFrontendVariantNode },
6716
55.6k
    { "LINK_LIBRARY", &linkLibraryNode },
6717
55.6k
    { "LINK_GROUP", &linkGroupNode },
6718
55.6k
    { "HOST_LINK", &hostLinkNode },
6719
55.6k
    { "DEVICE_LINK", &deviceLinkNode },
6720
55.6k
    { "SHELL_PATH", &shellPathNode }
6721
55.6k
  };
6722
6723
55.6k
  {
6724
55.6k
    auto itr = nodeMap.find(identifier);
6725
55.6k
    if (itr != nodeMap.end()) {
6726
54.4k
      return itr->second;
6727
54.4k
    }
6728
55.6k
  }
6729
1.11k
  return nullptr;
6730
55.6k
}
6731
6732
void reportError(cm::GenEx::Evaluation* eval, std::string const& expr,
6733
                 std::string const& result)
6734
4.15k
{
6735
4.15k
  eval->HadError = true;
6736
4.15k
  if (eval->Quiet) {
6737
0
    return;
6738
0
  }
6739
6740
4.15k
  eval->Context.LG->GetCMakeInstance()->IssueMessage(
6741
4.15k
    MessageType::FATAL_ERROR,
6742
4.15k
    cmStrCat("Error evaluating generator expression:\n"
6743
4.15k
             "  ",
6744
4.15k
             expr, '\n', result),
6745
4.15k
    eval->Backtrace);
6746
4.15k
}