Coverage Report

Created: 2026-09-14 06:43

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