Coverage Report

Created: 2026-07-14 07:09

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 "cmValue.h"
59
#include "cmake.h"
60
61
namespace {
62
63
bool HasKnownObjectFileLocation(cm::GenEx::Evaluation* eval,
64
                                GeneratorExpressionContent const* content,
65
                                std::string const& genex,
66
                                cmGeneratorTarget const* target)
67
0
{
68
0
  std::string reason;
69
0
  if (!eval->EvaluateForBuildsystem &&
70
0
      !target->Target->HasKnownObjectFileLocation(&reason)) {
71
0
    std::ostringstream e;
72
0
    e << "The evaluation of the " << genex
73
0
      << " generator expression "
74
0
         "is only suitable for consumption by CMake (limited"
75
0
      << reason
76
0
      << ").  "
77
0
         "It is not suitable for writing out elsewhere.";
78
0
    reportError(eval, content->GetOriginalExpression(), e.str());
79
0
    return false;
80
0
  }
81
0
  return true;
82
0
}
83
84
} // namespace
85
86
std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
87
  std::string const& prop, cm::GenEx::Evaluation* eval,
88
  cmGeneratorTarget const* headTarget,
89
  cmGeneratorExpressionDAGChecker* dagChecker,
90
  cmGeneratorTarget const* currentTarget)
91
0
{
92
0
  cmGeneratorExpression ge(*eval->Context.LG->GetCMakeInstance(),
93
0
                           eval->Backtrace);
94
0
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
95
0
  cge->SetEvaluateForBuildsystem(eval->EvaluateForBuildsystem);
96
0
  cge->SetQuiet(eval->Quiet);
97
0
  std::string result =
98
0
    cge->Evaluate(eval->Context, dagChecker, headTarget, currentTarget);
99
0
  if (cge->GetHadContextSensitiveCondition()) {
100
0
    eval->HadContextSensitiveCondition = true;
101
0
  }
102
0
  if (cge->GetHadHeadSensitiveCondition()) {
103
0
    eval->HadHeadSensitiveCondition = true;
104
0
  }
105
0
  if (cge->GetHadLinkLanguageSensitiveCondition()) {
106
0
    eval->HadLinkLanguageSensitiveCondition = true;
107
0
  }
108
0
  return result;
109
0
}
110
111
// Re-evaluate the unevaluated <body> subtree of a binding operation with the
112
// given operands bound (accessible as $<_0>, $<_1>, ...).  A fresh Evaluation
113
// is built from a copied, mutated Context so that nested binding operations
114
// can shadow the operands and restore them on exit.
115
static std::string EvaluateBodyWithBoundOperands(
116
  cmGeneratorExpressionEvaluatorVector const& bodyExpr,
117
  std::vector<std::string> operands, cm::GenEx::Evaluation* eval,
118
  cmGeneratorExpressionDAGChecker* dagChecker)
119
0
{
120
0
  cm::GenEx::Context elemContext = eval->Context; // copy
121
0
  elemContext.SetBoundOperands(std::move(operands));
122
0
  cm::GenEx::Evaluation elemEval(
123
0
    elemContext, eval->Quiet, eval->HeadTarget, eval->CurrentTarget,
124
0
    eval->EvaluateForBuildsystem, eval->Backtrace);
125
126
0
  std::string result;
127
0
  for (auto const& pExprEval : bodyExpr) {
128
0
    result += pExprEval->Evaluate(&elemEval, dagChecker);
129
0
    if (elemEval.HadError) {
130
0
      eval->HadError = true;
131
0
      return std::string{};
132
0
    }
133
0
  }
134
0
  eval->HadContextSensitiveCondition |= elemEval.HadContextSensitiveCondition;
135
0
  eval->HadHeadSensitiveCondition |= elemEval.HadHeadSensitiveCondition;
136
0
  eval->HadLinkLanguageSensitiveCondition |=
137
0
    elemEval.HadLinkLanguageSensitiveCondition;
138
0
  eval->DependTargets.insert(elemEval.DependTargets.begin(),
139
0
                             elemEval.DependTargets.end());
140
0
  eval->AllTargets.insert(elemEval.AllTargets.begin(),
141
0
                          elemEval.AllTargets.end());
142
0
  eval->SeenTargetProperties.insert(elemEval.SeenTargetProperties.begin(),
143
0
                                    elemEval.SeenTargetProperties.end());
144
0
  eval->SourceSensitiveTargets.insert(elemEval.SourceSensitiveTargets.begin(),
145
0
                                      elemEval.SourceSensitiveTargets.end());
146
0
  for (auto const& entry : elemEval.MaxLanguageStandard) {
147
0
    eval->MaxLanguageStandard[entry.first].insert(entry.second.begin(),
148
0
                                                  entry.second.end());
149
0
  }
150
0
  return result;
151
0
}
152
153
static std::string EvaluateBodyWithBoundOperand(
154
  cmGeneratorExpressionEvaluatorVector const& bodyExpr,
155
  std::string const& operand, cm::GenEx::Evaluation* eval,
156
  cmGeneratorExpressionDAGChecker* dagChecker)
157
0
{
158
0
  return EvaluateBodyWithBoundOperands(bodyExpr, { operand }, eval,
159
0
                                       dagChecker);
160
0
}
161
162
// Evaluate `predicateBody` once per element of `list`, binding `$<_0>` to the
163
// element (reusing EvaluateBodyWithBoundOperand).  Each result must be exactly
164
// "0" or "1".  Returns the per-element boolean mask, or cm::nullopt after
165
// reporting an error (non-boolean result, or a failure inside the body).
166
static cm::optional<std::vector<bool>> EvaluatePredicateMask(
167
  cmGeneratorExpressionEvaluatorVector const& predicateBody,
168
  cmList const& list, cm::string_view subCommand, cm::GenEx::Evaluation* eval,
169
  GeneratorExpressionContent const* content,
170
  cmGeneratorExpressionDAGChecker* dagChecker)
171
0
{
172
0
  cm::optional<std::vector<bool>> result;
173
0
  std::vector<bool> mask;
174
0
  mask.reserve(list.size());
175
0
  for (auto const& element : list) {
176
0
    std::string r =
177
0
      EvaluateBodyWithBoundOperand(predicateBody, element, eval, dagChecker);
178
0
    if (eval->HadError) {
179
0
      return result;
180
0
    }
181
0
    if (r == "1") {
182
0
      mask.push_back(true);
183
0
    } else if (r == "0") {
184
0
      mask.push_back(false);
185
0
    } else {
186
0
      reportError(
187
0
        eval, content->GetOriginalExpression(),
188
0
        cmStrCat("sub-command ", subCommand,
189
0
                 ", PREDICATE body must evaluate to \"0\" or \"1\", but "
190
0
                 "evaluated to \"",
191
0
                 r, "\"."));
192
0
      return result;
193
0
    }
194
0
  }
195
0
  result = std::move(mask);
196
0
  return result;
197
0
}
198
199
static const struct ZeroNode : public cmGeneratorExpressionNode
200
{
201
8
  ZeroNode() {} // NOLINT(modernize-use-equals-default)
202
203
0
  bool GeneratesContent() const override { return false; }
204
205
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
206
207
  std::string Evaluate(
208
    std::vector<std::string> const& /*parameters*/,
209
    cm::GenEx::Evaluation* /*eval*/,
210
    GeneratorExpressionContent const* /*content*/,
211
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
212
0
  {
213
0
    return std::string();
214
0
  }
215
} zeroNode;
216
217
static const struct OneNode : public cmGeneratorExpressionNode
218
{
219
12
  OneNode() {} // NOLINT(modernize-use-equals-default)
220
221
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
222
223
  std::string Evaluate(
224
    std::vector<std::string> const& parameters,
225
    cm::GenEx::Evaluation* /*eval*/,
226
    GeneratorExpressionContent const* /*content*/,
227
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
228
0
  {
229
0
    return parameters.front();
230
0
  }
231
} oneNode;
232
233
struct BoundOperandNode : public cmGeneratorExpressionNode
234
{
235
  explicit BoundOperandNode(std::size_t index)
236
8
    : Index(index)
237
8
  {
238
8
  }
239
240
0
  int NumExpectedParameters() const override { return 0; }
241
242
  std::string Evaluate(
243
    std::vector<std::string> const& /*parameters*/,
244
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
245
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
246
0
  {
247
0
    if (!eval->Context.HasBoundOperand(this->Index)) {
248
0
      std::size_t const count = eval->Context.BoundOperandCount();
249
0
      if (count == 0) {
250
0
        reportError(eval, content->GetOriginalExpression(),
251
0
                    cmStrCat("$<_", this->Index,
252
0
                             "> may only be used inside the body of a binding "
253
0
                             "operation."));
254
0
      } else {
255
0
        reportError(
256
0
          eval, content->GetOriginalExpression(),
257
0
          cmStrCat(
258
0
            "$<_", this->Index,
259
0
            "> is out of range for the current binding operation, which "
260
0
            "binds only ",
261
0
            count, " operand(s) (maximum $<_", count - 1, ">)."));
262
0
      }
263
0
      return std::string();
264
0
    }
265
0
    return eval->Context.GetBoundOperand(this->Index);
266
0
  }
267
268
  std::size_t Index;
269
};
270
static BoundOperandNode const boundOperandNode0{ 0 };
271
static BoundOperandNode const boundOperandNode1{ 1 };
272
273
static const struct OneNode buildInterfaceNode;
274
275
static const struct ZeroNode installInterfaceNode;
276
277
static const struct OneNode buildLocalInterfaceNode;
278
279
struct BooleanOpNode : public cmGeneratorExpressionNode
280
{
281
  BooleanOpNode(char const* op_, char const* successVal_,
282
                char const* failureVal_)
283
8
    : op(op_)
284
8
    , successVal(successVal_)
285
8
    , failureVal(failureVal_)
286
8
  {
287
8
  }
288
289
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
290
291
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
292
                                   std::string& def_value) const override
293
0
  {
294
0
    if (!parameters.empty() && parameters.back() == failureVal) {
295
0
      def_value = failureVal;
296
0
      return false;
297
0
    }
298
0
    return true;
299
0
  }
300
301
  std::string Evaluate(std::vector<std::string> const& parameters,
302
                       cm::GenEx::Evaluation* eval,
303
                       GeneratorExpressionContent const* content,
304
                       cmGeneratorExpressionDAGChecker*) const override
305
0
  {
306
0
    for (std::string const& param : parameters) {
307
0
      if (param == this->failureVal) {
308
0
        return this->failureVal;
309
0
      }
310
0
      if (param != this->successVal) {
311
0
        std::ostringstream e;
312
0
        e << "Parameters to $<" << this->op;
313
0
        e << "> must resolve to either '0' or '1'.";
314
0
        reportError(eval, content->GetOriginalExpression(), e.str());
315
0
        return std::string();
316
0
      }
317
0
    }
318
0
    return this->successVal;
319
0
  }
320
321
  char const *const op, *const successVal, *const failureVal;
322
};
323
324
static BooleanOpNode const andNode("AND", "1", "0"), orNode("OR", "0", "1");
325
326
static const struct NotNode : public cmGeneratorExpressionNode
327
{
328
4
  NotNode() {} // NOLINT(modernize-use-equals-default)
329
330
  std::string Evaluate(
331
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
332
    GeneratorExpressionContent const* content,
333
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
334
0
  {
335
0
    if (parameters.front() != "0" && parameters.front() != "1") {
336
0
      reportError(
337
0
        eval, content->GetOriginalExpression(),
338
0
        "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
339
0
      return std::string();
340
0
    }
341
0
    return parameters.front() == "0" ? "1" : "0";
342
0
  }
343
} notNode;
344
345
static const struct BoolNode : public cmGeneratorExpressionNode
346
{
347
4
  BoolNode() {} // NOLINT(modernize-use-equals-default)
348
349
0
  int NumExpectedParameters() const override { return 1; }
350
351
  std::string Evaluate(
352
    std::vector<std::string> const& parameters,
353
    cm::GenEx::Evaluation* /*eval*/,
354
    GeneratorExpressionContent const* /*content*/,
355
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
356
0
  {
357
0
    return !cmIsOff(parameters.front()) ? "1" : "0";
358
0
  }
359
} boolNode;
360
361
static const struct IfNode : public cmGeneratorExpressionNode
362
{
363
4
  IfNode() {} // NOLINT(modernize-use-equals-default)
364
365
0
  int NumExpectedParameters() const override { return 3; }
366
367
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
368
                                   std::string&) const override
369
0
  {
370
0
    return (parameters.empty() ||
371
0
            parameters[0] != cmStrCat(parameters.size() - 1, ""));
372
0
  }
373
374
  std::string Evaluate(std::vector<std::string> const& parameters,
375
                       cm::GenEx::Evaluation* eval,
376
                       GeneratorExpressionContent const* content,
377
                       cmGeneratorExpressionDAGChecker*) const override
378
0
  {
379
0
    if (parameters[0] != "1" && parameters[0] != "0") {
380
0
      reportError(eval, content->GetOriginalExpression(),
381
0
                  "First parameter to $<IF> must resolve to exactly one '0' "
382
0
                  "or '1' value.");
383
0
      return std::string();
384
0
    }
385
0
    return parameters[0] == "1" ? parameters[1] : parameters[2];
386
0
  }
387
} ifNode;
388
389
static const struct StrEqualNode : public cmGeneratorExpressionNode
390
{
391
4
  StrEqualNode() {} // NOLINT(modernize-use-equals-default)
392
393
0
  int NumExpectedParameters() const override { return 2; }
394
395
  std::string Evaluate(
396
    std::vector<std::string> const& parameters,
397
    cm::GenEx::Evaluation* /*eval*/,
398
    GeneratorExpressionContent const* /*content*/,
399
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
400
0
  {
401
0
    return cm::CMakeString{ parameters.front() }.Compare(
402
0
             cm::CMakeString::CompOperator::EQUAL, parameters[1])
403
0
      ? "1"
404
0
      : "0";
405
0
  }
406
} strEqualNode;
407
static const struct StrLessNode : public cmGeneratorExpressionNode
408
{
409
4
  StrLessNode() {} // NOLINT(modernize-use-equals-default)
410
411
0
  int NumExpectedParameters() const override { return 2; }
412
413
  std::string Evaluate(
414
    std::vector<std::string> const& parameters,
415
    cm::GenEx::Evaluation* /*eval*/,
416
    GeneratorExpressionContent const* /*content*/,
417
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
418
0
  {
419
0
    return cm::CMakeString{ parameters.front() }.Compare(
420
0
             cm::CMakeString::CompOperator::LESS, parameters[1])
421
0
      ? "1"
422
0
      : "0";
423
0
  }
424
} strLessNode;
425
static const struct StrLessEqualNode : public cmGeneratorExpressionNode
426
{
427
4
  StrLessEqualNode() {} // NOLINT(modernize-use-equals-default)
428
429
0
  int NumExpectedParameters() const override { return 2; }
430
431
  std::string Evaluate(
432
    std::vector<std::string> const& parameters,
433
    cm::GenEx::Evaluation* /*eval*/,
434
    GeneratorExpressionContent const* /*content*/,
435
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
436
0
  {
437
0
    return cm::CMakeString{ parameters.front() }.Compare(
438
0
             cm::CMakeString::CompOperator::LESS_EQUAL, parameters[1])
439
0
      ? "1"
440
0
      : "0";
441
0
  }
442
} strLessEqualNode;
443
static const struct StrGreaterNode : public cmGeneratorExpressionNode
444
{
445
4
  StrGreaterNode() {} // NOLINT(modernize-use-equals-default)
446
447
0
  int NumExpectedParameters() const override { return 2; }
448
449
  std::string Evaluate(
450
    std::vector<std::string> const& parameters,
451
    cm::GenEx::Evaluation* /*eval*/,
452
    GeneratorExpressionContent const* /*content*/,
453
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
454
0
  {
455
0
    return cm::CMakeString{ parameters.front() }.Compare(
456
0
             cm::CMakeString::CompOperator::GREATER, parameters[1])
457
0
      ? "1"
458
0
      : "0";
459
0
  }
460
} strGreaterNode;
461
static const struct StrGreaterEqualNode : public cmGeneratorExpressionNode
462
{
463
4
  StrGreaterEqualNode() {} // NOLINT(modernize-use-equals-default)
464
465
0
  int NumExpectedParameters() const override { return 2; }
466
467
  std::string Evaluate(
468
    std::vector<std::string> const& parameters,
469
    cm::GenEx::Evaluation* /*eval*/,
470
    GeneratorExpressionContent const* /*content*/,
471
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
472
0
  {
473
0
    return cm::CMakeString{ parameters.front() }.Compare(
474
0
             cm::CMakeString::CompOperator::GREATER_EQUAL, parameters[1])
475
0
      ? "1"
476
0
      : "0";
477
0
  }
478
} strGreaterEqualNode;
479
480
static const struct EqualNode : public cmGeneratorExpressionNode
481
{
482
4
  EqualNode() {} // NOLINT(modernize-use-equals-default)
483
484
0
  int NumExpectedParameters() const override { return 2; }
485
486
  std::string Evaluate(
487
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
488
    GeneratorExpressionContent const* content,
489
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
490
0
  {
491
0
    long numbers[2];
492
0
    for (int i = 0; i < 2; ++i) {
493
0
      if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
494
0
        reportError(eval, content->GetOriginalExpression(),
495
0
                    cmStrCat("$<EQUAL> parameter ", parameters[i],
496
0
                             " is not a valid integer."));
497
0
        return {};
498
0
      }
499
0
    }
500
0
    return numbers[0] == numbers[1] ? "1" : "0";
501
0
  }
502
503
  static bool ParameterToLong(char const* param, long* outResult)
504
0
  {
505
0
    char const isNegative = param[0] == '-';
506
507
0
    int base = 0;
508
0
    if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
509
0
      base = 2;
510
0
      param += 2;
511
0
    } else if (cmHasLiteralPrefix(param, "-0b") ||
512
0
               cmHasLiteralPrefix(param, "-0B") ||
513
0
               cmHasLiteralPrefix(param, "+0b") ||
514
0
               cmHasLiteralPrefix(param, "+0B")) {
515
0
      base = 2;
516
0
      param += 3;
517
0
    }
518
519
0
    char* pEnd;
520
0
    long result = strtol(param, &pEnd, base);
521
0
    if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
522
0
      return false;
523
0
    }
524
0
    if (isNegative && result > 0) {
525
0
      result *= -1;
526
0
    }
527
0
    *outResult = result;
528
0
    return true;
529
0
  }
530
} equalNode;
531
532
static const struct InListNode : public cmGeneratorExpressionNode
533
{
534
4
  InListNode() {} // NOLINT(modernize-use-equals-default)
535
536
0
  int NumExpectedParameters() const override { return 2; }
537
538
  std::string Evaluate(
539
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
540
    GeneratorExpressionContent const* /*content*/,
541
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
542
0
  {
543
0
    cmList values;
544
0
    cmList checkValues;
545
0
    bool check = false;
546
0
    cmLocalGenerator const* const lg = eval->Context.LG;
547
0
    switch (lg->GetPolicyStatus(cmPolicies::CMP0085)) {
548
0
      case cmPolicies::WARN:
549
0
        if (parameters.front().empty()) {
550
0
          check = true;
551
0
          checkValues.assign(parameters[1], cmList::EmptyElements::Yes);
552
0
        }
553
0
        CM_FALLTHROUGH;
554
0
      case cmPolicies::OLD:
555
0
        values.assign(parameters[1]);
556
0
        if (check && values != checkValues) {
557
0
          lg->IssuePolicyWarning(
558
0
            cmPolicies::CMP0085, {},
559
0
            cmStrCat("Search Item:\n  \""_s, parameters.front(),
560
0
                     "\"\nList:\n  \""_s, parameters[1], "\"\n"_s),
561
0
            eval->Backtrace);
562
0
          return "0";
563
0
        }
564
0
        if (values.empty()) {
565
0
          return "0";
566
0
        }
567
0
        break;
568
0
      case cmPolicies::NEW:
569
0
        values.assign(parameters[1], cmList::EmptyElements::Yes);
570
0
        break;
571
0
    }
572
573
0
    return values.find(parameters.front()) != cmList::npos ? "1" : "0";
574
0
  }
575
} inListNode;
576
577
static const struct FilterNode : public cmGeneratorExpressionNode
578
{
579
4
  FilterNode() {} // NOLINT(modernize-use-equals-default)
580
581
0
  int NumExpectedParameters() const override { return 3; }
582
583
  std::string Evaluate(
584
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
585
    GeneratorExpressionContent const* content,
586
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
587
0
  {
588
0
    if (parameters.size() != 3) {
589
0
      reportError(eval, content->GetOriginalExpression(),
590
0
                  "$<FILTER:...> expression requires three parameters");
591
0
      return {};
592
0
    }
593
594
0
    if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
595
0
      reportError(
596
0
        eval, content->GetOriginalExpression(),
597
0
        "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
598
0
      return {};
599
0
    }
600
601
0
    try {
602
0
      return cmList{ parameters.front(), cmList::EmptyElements::Yes }
603
0
        .filter(parameters[2],
604
0
                parameters[1] == "EXCLUDE" ? cmList::FilterMode::EXCLUDE
605
0
                                           : cmList::FilterMode::INCLUDE)
606
0
        .to_string();
607
0
    } catch (std::invalid_argument&) {
608
0
      reportError(eval, content->GetOriginalExpression(),
609
0
                  "$<FILTER:...> failed to compile regex");
610
0
      return {};
611
0
    }
612
0
  }
613
} filterNode;
614
615
static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
616
{
617
4
  RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
618
619
0
  int NumExpectedParameters() const override { return 1; }
620
621
  std::string Evaluate(
622
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
623
    GeneratorExpressionContent const* content,
624
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
625
0
  {
626
0
    if (parameters.size() != 1) {
627
0
      reportError(
628
0
        eval, content->GetOriginalExpression(),
629
0
        "$<REMOVE_DUPLICATES:...> expression requires one parameter");
630
0
    }
631
632
0
    return cmList{ parameters.front(), cmList::EmptyElements::Yes }
633
0
      .remove_duplicates()
634
0
      .to_string();
635
0
  }
636
637
} removeDuplicatesNode;
638
639
static const struct TargetExistsNode : public cmGeneratorExpressionNode
640
{
641
4
  TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
642
643
0
  int NumExpectedParameters() const override { return 1; }
644
645
  std::string Evaluate(
646
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
647
    GeneratorExpressionContent const* content,
648
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
649
0
  {
650
0
    if (parameters.size() != 1) {
651
0
      reportError(eval, content->GetOriginalExpression(),
652
0
                  "$<TARGET_EXISTS:...> expression requires one parameter");
653
0
      return std::string();
654
0
    }
655
656
0
    std::string const& targetName = parameters.front();
657
0
    if (targetName.empty() ||
658
0
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
659
0
      reportError(eval, content->GetOriginalExpression(),
660
0
                  "$<TARGET_EXISTS:tgt> expression requires a non-empty "
661
0
                  "valid target name.");
662
0
      return std::string();
663
0
    }
664
665
0
    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName) ? "1"
666
0
                                                                        : "0";
667
0
  }
668
} targetExistsNode;
669
670
static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
671
{
672
4
  TargetNameIfExistsNode() {} // NOLINT(modernize-use-equals-default)
673
674
0
  int NumExpectedParameters() const override { return 1; }
675
676
  std::string Evaluate(
677
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
678
    GeneratorExpressionContent const* content,
679
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
680
0
  {
681
0
    if (parameters.size() != 1) {
682
0
      reportError(eval, content->GetOriginalExpression(),
683
0
                  "$<TARGET_NAME_IF_EXISTS:...> expression requires one "
684
0
                  "parameter");
685
0
      return std::string();
686
0
    }
687
688
0
    std::string const& targetName = parameters.front();
689
0
    if (targetName.empty() ||
690
0
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
691
0
      reportError(eval, content->GetOriginalExpression(),
692
0
                  "$<TARGET_NAME_IF_EXISTS:tgt> expression requires a "
693
0
                  "non-empty valid target name.");
694
0
      return std::string();
695
0
    }
696
697
0
    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName)
698
0
      ? targetName
699
0
      : std::string();
700
0
  }
701
} targetNameIfExistsNode;
702
703
struct GenexEvaluator : public cmGeneratorExpressionNode
704
{
705
8
  GenexEvaluator() {} // NOLINT(modernize-use-equals-default)
706
707
protected:
708
  std::string EvaluateExpression(
709
    std::string const& genexOperator, std::string const& expression,
710
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
711
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const
712
0
  {
713
0
    if (eval->HeadTarget) {
714
0
      cmGeneratorExpressionDAGChecker dagChecker{
715
0
        eval->HeadTarget, cmStrCat(genexOperator, ':', expression),
716
0
        content,          dagCheckerParent,
717
0
        eval->Context,    eval->Backtrace,
718
0
      };
719
0
      switch (dagChecker.Check()) {
720
0
        case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
721
0
        case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
722
0
          dagChecker.ReportError(eval, content->GetOriginalExpression());
723
0
          return std::string();
724
0
        }
725
0
        case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
726
0
        case cmGeneratorExpressionDAGChecker::DAG:
727
0
          break;
728
0
      }
729
730
0
      return this->EvaluateDependentExpression(
731
0
        expression, eval, eval->HeadTarget, &dagChecker, eval->CurrentTarget);
732
0
    }
733
734
0
    return this->EvaluateDependentExpression(
735
0
      expression, eval, eval->HeadTarget, dagCheckerParent,
736
0
      eval->CurrentTarget);
737
0
  }
738
};
739
740
static const struct TargetGenexEvalNode : public GenexEvaluator
741
{
742
4
  TargetGenexEvalNode() {} // NOLINT(modernize-use-equals-default)
743
744
0
  int NumExpectedParameters() const override { return 2; }
745
746
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
747
748
  std::string Evaluate(
749
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
750
    GeneratorExpressionContent const* content,
751
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
752
0
  {
753
0
    std::string const& targetName = parameters.front();
754
0
    if (targetName.empty() ||
755
0
        !cmGeneratorExpression::IsValidTargetName(targetName)) {
756
0
      reportError(eval, content->GetOriginalExpression(),
757
0
                  "$<TARGET_GENEX_EVAL:tgt, ...> expression requires a "
758
0
                  "non-empty valid target name.");
759
0
      return std::string();
760
0
    }
761
762
0
    auto const* target =
763
0
      eval->Context.LG->FindGeneratorTargetToUse(targetName);
764
0
    if (!target) {
765
0
      std::ostringstream e;
766
0
      e << "$<TARGET_GENEX_EVAL:tgt, ...> target \"" << targetName
767
0
        << "\" not found.";
768
0
      reportError(eval, content->GetOriginalExpression(), e.str());
769
0
      return std::string();
770
0
    }
771
772
0
    std::string const& expression = parameters[1];
773
0
    if (expression.empty()) {
774
0
      return expression;
775
0
    }
776
777
    // Replace the surrounding context with the named target.
778
0
    cm::GenEx::Evaluation targetEval(eval->Context, eval->Quiet, target,
779
0
                                     target, eval->EvaluateForBuildsystem,
780
0
                                     eval->Backtrace);
781
782
0
    return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
783
0
                                    &targetEval, content, dagCheckerParent);
784
0
  }
785
} targetGenexEvalNode;
786
787
static const struct GenexEvalNode : public GenexEvaluator
788
{
789
4
  GenexEvalNode() {} // NOLINT(modernize-use-equals-default)
790
791
0
  int NumExpectedParameters() const override { return 1; }
792
793
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
794
795
  std::string Evaluate(
796
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
797
    GeneratorExpressionContent const* content,
798
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
799
0
  {
800
0
    std::string const& expression = parameters[0];
801
0
    if (expression.empty()) {
802
0
      return expression;
803
0
    }
804
805
0
    return this->EvaluateExpression("GENEX_EVAL", expression, eval, content,
806
0
                                    dagCheckerParent);
807
0
  }
808
} genexEvalNode;
809
810
static const struct LowerCaseNode : public cmGeneratorExpressionNode
811
{
812
4
  LowerCaseNode() {} // NOLINT(modernize-use-equals-default)
813
814
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
815
816
  std::string Evaluate(
817
    std::vector<std::string> const& parameters,
818
    cm::GenEx::Evaluation* /*eval*/,
819
    GeneratorExpressionContent const* /*content*/,
820
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
821
0
  {
822
0
    return cmSystemTools::LowerCase(parameters.front());
823
0
  }
824
} lowerCaseNode;
825
826
static const struct UpperCaseNode : public cmGeneratorExpressionNode
827
{
828
4
  UpperCaseNode() {} // NOLINT(modernize-use-equals-default)
829
830
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
831
832
  std::string Evaluate(
833
    std::vector<std::string> const& parameters,
834
    cm::GenEx::Evaluation* /*eval*/,
835
    GeneratorExpressionContent const* /*content*/,
836
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
837
0
  {
838
0
    return cmSystemTools::UpperCase(parameters.front());
839
0
  }
840
} upperCaseNode;
841
842
namespace {
843
template <typename Container>
844
class Range : public cmRange<typename Container::const_iterator>
845
{
846
private:
847
  using Base = cmRange<typename Container::const_iterator>;
848
849
public:
850
  using const_iterator = typename Container::const_iterator;
851
  using value_type = typename Container::value_type;
852
  using size_type = typename Container::size_type;
853
  using difference_type = typename Container::difference_type;
854
  using const_reference = typename Container::const_reference;
855
856
  Range(Container const& container)
857
0
    : Base(container.begin(), container.end())
858
0
  {
859
0
  }
860
861
  const_reference operator[](size_type pos) const
862
0
  {
863
0
    return *(this->begin() + pos);
864
0
  }
865
866
0
  const_reference front() const { return *this->begin(); }
867
0
  const_reference back() const { return *std::prev(this->end()); }
868
869
  Range& advance(difference_type amount) &
870
0
  {
871
0
    Base::advance(amount);
872
0
    return *this;
873
0
  }
874
  Range advance(difference_type amount) &&
875
0
  {
876
0
    Base::advance(amount);
877
0
    return std::move(*this);
878
0
  }
879
};
880
881
using Arguments = Range<std::vector<std::string>>;
882
883
bool CheckGenExParameters(cm::GenEx::Evaluation* eval,
884
                          GeneratorExpressionContent const* cnt,
885
                          cm::string_view genex, cm::string_view option,
886
                          std::size_t count, int required = 1,
887
                          bool exactly = true)
888
0
{
889
0
  if (static_cast<int>(count) < required ||
890
0
      (exactly && static_cast<int>(count) > required)) {
891
0
    std::string nbParameters;
892
0
    switch (required) {
893
0
      case 1:
894
0
        nbParameters = "one parameter";
895
0
        break;
896
0
      case 2:
897
0
        nbParameters = "two parameters";
898
0
        break;
899
0
      case 3:
900
0
        nbParameters = "three parameters";
901
0
        break;
902
0
      case 4:
903
0
        nbParameters = "four parameters";
904
0
        break;
905
0
      default:
906
0
        nbParameters = cmStrCat(required, " parameters");
907
0
    }
908
0
    reportError(eval, cnt->GetOriginalExpression(),
909
0
                cmStrCat("$<", genex, ':', option, "> expression requires ",
910
0
                         (exactly ? "exactly" : "at least"), ' ', nbParameters,
911
0
                         '.'));
912
0
    return false;
913
0
  }
914
0
  return true;
915
0
};
916
917
template <typename IndexType>
918
bool GetNumericArgument(std::string const& arg, IndexType& value)
919
0
{
920
0
  try {
921
0
    std::size_t pos;
922
923
0
    if (sizeof(IndexType) == sizeof(long)) {
924
0
      value = std::stol(arg, &pos);
925
0
    } else {
926
0
      value = std::stoll(arg, &pos);
927
0
    }
928
929
0
    if (pos != arg.length()) {
930
      // this is not a number
931
0
      return false;
932
0
    }
933
0
  } catch (std::invalid_argument const&) {
934
0
    return false;
935
0
  }
936
937
0
  return true;
938
0
}
939
940
template <typename IndexType>
941
bool GetNumericArguments(
942
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt,
943
  Arguments args, std::vector<IndexType>& indexes,
944
  cmList::ExpandElements expandElements = cmList::ExpandElements::No)
945
0
{
946
0
  using IndexRange = cmRange<Arguments::const_iterator>;
947
0
  IndexRange arguments(args.begin(), args.end());
948
0
  cmList list;
949
0
  if (expandElements == cmList::ExpandElements::Yes) {
950
0
    list = cmList{ args.begin(), args.end(), expandElements };
951
0
    arguments = IndexRange{ list.begin(), list.end() };
952
0
  }
953
954
0
  for (auto const& value : arguments) {
955
0
    IndexType index;
956
0
    if (!GetNumericArgument(value, index)) {
957
0
      reportError(eval, cnt->GetOriginalExpression(),
958
0
                  cmStrCat("index: \"", value, "\" is not a valid index"));
959
0
      return false;
960
0
    }
961
0
    indexes.push_back(index);
962
0
  }
963
0
  return true;
964
0
}
965
966
bool CheckPathParametersEx(cm::GenEx::Evaluation* eval,
967
                           GeneratorExpressionContent const* cnt,
968
                           cm::string_view option, std::size_t count,
969
                           int required = 1, bool exactly = true)
970
0
{
971
0
  return CheckGenExParameters(eval, cnt, "PATH"_s, option, count, required,
972
0
                              exactly);
973
0
}
974
bool CheckPathParameters(cm::GenEx::Evaluation* eval,
975
                         GeneratorExpressionContent const* cnt,
976
                         cm::string_view option, Arguments args,
977
                         int required = 1)
978
0
{
979
0
  return CheckPathParametersEx(eval, cnt, option, args.size(), required);
980
0
};
981
982
std::string ToString(bool isTrue)
983
0
{
984
0
  return isTrue ? "1" : "0";
985
0
};
986
}
987
988
static const struct PathNode : public cmGeneratorExpressionNode
989
{
990
4
  PathNode() {} // NOLINT(modernize-use-equals-default)
991
992
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
993
994
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
995
996
  std::string Evaluate(
997
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
998
    GeneratorExpressionContent const* content,
999
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1000
0
  {
1001
0
    static auto processList =
1002
0
      [](std::string const& arg,
1003
0
         std::function<void(std::string&)> transform) -> std::string {
1004
0
      cmList list{ arg };
1005
0
      std::for_each(list.begin(), list.end(), std::move(transform));
1006
0
      return list.to_string();
1007
0
    };
1008
1009
0
    static std::unordered_map<
1010
0
      cm::string_view,
1011
0
      std::function<std::string(cm::GenEx::Evaluation*,
1012
0
                                GeneratorExpressionContent const*,
1013
0
                                Arguments&)>>
1014
0
      pathCommands{
1015
0
        { "GET_ROOT_NAME"_s,
1016
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1017
0
             Arguments& args) -> std::string {
1018
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_NAME"_s, args) &&
1019
0
                !args.front().empty()) {
1020
0
              return processList(args.front(), [](std::string& value) {
1021
0
                value = cmCMakePath{ value }.GetRootName().String();
1022
0
              });
1023
0
            }
1024
0
            return std::string{};
1025
0
          } },
1026
0
        { "GET_ROOT_DIRECTORY"_s,
1027
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1028
0
             Arguments& args) -> std::string {
1029
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_DIRECTORY"_s, args) &&
1030
0
                !args.front().empty()) {
1031
0
              return processList(args.front(), [](std::string& value) {
1032
0
                value = cmCMakePath{ value }.GetRootDirectory().String();
1033
0
              });
1034
0
            }
1035
0
            return std::string{};
1036
0
          } },
1037
0
        { "GET_ROOT_PATH"_s,
1038
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1039
0
             Arguments& args) -> std::string {
1040
0
            if (CheckPathParameters(ev, cnt, "GET_ROOT_PATH"_s, args) &&
1041
0
                !args.front().empty()) {
1042
0
              return processList(args.front(), [](std::string& value) {
1043
0
                value = cmCMakePath{ value }.GetRootPath().String();
1044
0
              });
1045
0
            }
1046
0
            return std::string{};
1047
0
          } },
1048
0
        { "GET_FILENAME"_s,
1049
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1050
0
             Arguments& args) -> std::string {
1051
0
            if (CheckPathParameters(ev, cnt, "GET_FILENAME"_s, args) &&
1052
0
                !args.front().empty()) {
1053
0
              return processList(args.front(), [](std::string& value) {
1054
0
                value = cmCMakePath{ value }.GetFileName().String();
1055
0
              });
1056
0
            }
1057
0
            return std::string{};
1058
0
          } },
1059
0
        { "GET_EXTENSION"_s,
1060
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1061
0
             Arguments& args) -> std::string {
1062
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1063
0
            if (lastOnly) {
1064
0
              args.advance(1);
1065
0
            }
1066
0
            if (CheckPathParametersEx(ev, cnt,
1067
0
                                      lastOnly ? "GET_EXTENSION,LAST_ONLY"_s
1068
0
                                               : "GET_EXTENSION"_s,
1069
0
                                      args.size())) {
1070
0
              if (args.front().empty()) {
1071
0
                return std::string{};
1072
0
              }
1073
0
              if (lastOnly) {
1074
0
                return processList(args.front(), [](std::string& value) {
1075
0
                  value = cmCMakePath{ value }.GetExtension().String();
1076
0
                });
1077
0
              }
1078
0
              return processList(args.front(), [](std::string& value) {
1079
0
                value = cmCMakePath{ value }.GetWideExtension().String();
1080
0
              });
1081
0
            }
1082
0
            return std::string{};
1083
0
          } },
1084
0
        { "GET_STEM"_s,
1085
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1086
0
             Arguments& args) -> std::string {
1087
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1088
0
            if (lastOnly) {
1089
0
              args.advance(1);
1090
0
            }
1091
0
            if (CheckPathParametersEx(
1092
0
                  ev, cnt, lastOnly ? "GET_STEM,LAST_ONLY"_s : "GET_STEM"_s,
1093
0
                  args.size())) {
1094
0
              if (args.front().empty()) {
1095
0
                return std::string{};
1096
0
              }
1097
0
              if (lastOnly) {
1098
0
                return processList(args.front(), [](std::string& value) {
1099
0
                  value = cmCMakePath{ value }.GetStem().String();
1100
0
                });
1101
0
              }
1102
0
              return processList(args.front(), [](std::string& value) {
1103
0
                value = cmCMakePath{ value }.GetNarrowStem().String();
1104
0
              });
1105
0
            }
1106
0
            return std::string{};
1107
0
          } },
1108
0
        { "GET_RELATIVE_PART"_s,
1109
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1110
0
             Arguments& args) -> std::string {
1111
0
            if (CheckPathParameters(ev, cnt, "GET_RELATIVE_PART"_s, args) &&
1112
0
                !args.front().empty()) {
1113
0
              return processList(args.front(), [](std::string& value) {
1114
0
                value = cmCMakePath{ value }.GetRelativePath().String();
1115
0
              });
1116
0
            }
1117
0
            return std::string{};
1118
0
          } },
1119
0
        { "GET_PARENT_PATH"_s,
1120
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1121
0
             Arguments& args) -> std::string {
1122
0
            if (CheckPathParameters(ev, cnt, "GET_PARENT_PATH"_s, args)) {
1123
0
              return processList(args.front(), [](std::string& value) {
1124
0
                value = cmCMakePath{ value }.GetParentPath().String();
1125
0
              });
1126
0
            }
1127
0
            return std::string{};
1128
0
          } },
1129
0
        { "HAS_ROOT_NAME"_s,
1130
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1131
0
             Arguments& args) -> std::string {
1132
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_NAME"_s, args)
1133
0
              ? ToString(cmCMakePath{ args.front() }.HasRootName())
1134
0
              : std::string{ "0" };
1135
0
          } },
1136
0
        { "HAS_ROOT_DIRECTORY"_s,
1137
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1138
0
             Arguments& args) -> std::string {
1139
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_DIRECTORY"_s, args)
1140
0
              ? ToString(cmCMakePath{ args.front() }.HasRootDirectory())
1141
0
              : std::string{ "0" };
1142
0
          } },
1143
0
        { "HAS_ROOT_PATH"_s,
1144
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1145
0
             Arguments& args) -> std::string {
1146
0
            return CheckPathParameters(ev, cnt, "HAS_ROOT_PATH"_s, args)
1147
0
              ? ToString(cmCMakePath{ args.front() }.HasRootPath())
1148
0
              : std::string{ "0" };
1149
0
          } },
1150
0
        { "HAS_FILENAME"_s,
1151
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1152
0
             Arguments& args) -> std::string {
1153
0
            return CheckPathParameters(ev, cnt, "HAS_FILENAME"_s, args)
1154
0
              ? ToString(cmCMakePath{ args.front() }.HasFileName())
1155
0
              : std::string{ "0" };
1156
0
          } },
1157
0
        { "HAS_EXTENSION"_s,
1158
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1159
0
             Arguments& args) -> std::string {
1160
0
            return CheckPathParameters(ev, cnt, "HAS_EXTENSION"_s, args) &&
1161
0
                !args.front().empty()
1162
0
              ? ToString(cmCMakePath{ args.front() }.HasExtension())
1163
0
              : std::string{ "0" };
1164
0
          } },
1165
0
        { "HAS_STEM"_s,
1166
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1167
0
             Arguments& args) -> std::string {
1168
0
            return CheckPathParameters(ev, cnt, "HAS_STEM"_s, args)
1169
0
              ? ToString(cmCMakePath{ args.front() }.HasStem())
1170
0
              : std::string{ "0" };
1171
0
          } },
1172
0
        { "HAS_RELATIVE_PART"_s,
1173
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1174
0
             Arguments& args) -> std::string {
1175
0
            return CheckPathParameters(ev, cnt, "HAS_RELATIVE_PART"_s, args)
1176
0
              ? ToString(cmCMakePath{ args.front() }.HasRelativePath())
1177
0
              : std::string{ "0" };
1178
0
          } },
1179
0
        { "HAS_PARENT_PATH"_s,
1180
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1181
0
             Arguments& args) -> std::string {
1182
0
            return CheckPathParameters(ev, cnt, "HAS_PARENT_PATH"_s, args)
1183
0
              ? ToString(cmCMakePath{ args.front() }.HasParentPath())
1184
0
              : std::string{ "0" };
1185
0
          } },
1186
0
        { "IS_ABSOLUTE"_s,
1187
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1188
0
             Arguments& args) -> std::string {
1189
0
            return CheckPathParameters(ev, cnt, "IS_ABSOLUTE"_s, args)
1190
0
              ? ToString(cmCMakePath{ args.front() }.IsAbsolute())
1191
0
              : std::string{ "0" };
1192
0
          } },
1193
0
        { "IS_RELATIVE"_s,
1194
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1195
0
             Arguments& args) -> std::string {
1196
0
            return CheckPathParameters(ev, cnt, "IS_RELATIVE"_s, args)
1197
0
              ? ToString(cmCMakePath{ args.front() }.IsRelative())
1198
0
              : std::string{ "0" };
1199
0
          } },
1200
0
        { "IS_PREFIX"_s,
1201
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1202
0
             Arguments& args) -> std::string {
1203
0
            bool normalize = args.front() == "NORMALIZE"_s;
1204
0
            if (normalize) {
1205
0
              args.advance(1);
1206
0
            }
1207
0
            if (CheckPathParametersEx(
1208
0
                  ev, cnt, normalize ? "IS_PREFIX,NORMALIZE"_s : "IS_PREFIX"_s,
1209
0
                  args.size(), 2)) {
1210
0
              if (normalize) {
1211
0
                return ToString(cmCMakePath{ args[0] }.Normal().IsPrefix(
1212
0
                  cmCMakePath{ args[1] }.Normal()));
1213
0
              }
1214
0
              return ToString(
1215
0
                cmCMakePath{ args[0] }.IsPrefix(cmCMakePath{ args[1] }));
1216
0
            }
1217
0
            return std::string{};
1218
0
          } },
1219
0
        { "CMAKE_PATH"_s,
1220
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1221
0
             Arguments& args) -> std::string {
1222
0
            bool normalize = args.front() == "NORMALIZE"_s;
1223
0
            if (normalize) {
1224
0
              args.advance(1);
1225
0
            }
1226
0
            if (CheckPathParametersEx(ev, cnt,
1227
0
                                      normalize ? "CMAKE_PATH,NORMALIZE"_s
1228
0
                                                : "CMAKE_PATH"_s,
1229
0
                                      args.size(), 1)) {
1230
0
              return processList(
1231
0
                args.front(), [normalize](std::string& value) {
1232
0
                  auto path = cmCMakePath{ value, cmCMakePath::auto_format };
1233
0
                  value = normalize ? path.Normal().GenericString()
1234
0
                                    : path.GenericString();
1235
0
                });
1236
0
            }
1237
0
            return std::string{};
1238
0
          } },
1239
0
        { "NATIVE_PATH"_s,
1240
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1241
0
             Arguments& args) -> std::string {
1242
0
            bool normalize = args.front() == "NORMALIZE"_s;
1243
0
            if (normalize) {
1244
0
              args.advance(1);
1245
0
            }
1246
0
            if (CheckPathParametersEx(ev, cnt,
1247
0
                                      normalize ? "NATIVE_PATH,NORMALIZE"_s
1248
0
                                                : "NATIVE_PATH"_s,
1249
0
                                      args.size(), 1)) {
1250
0
              return processList(
1251
0
                args.front(), [normalize](std::string& value) {
1252
0
                  auto path = cmCMakePath{ value };
1253
0
                  value = normalize ? path.Normal().NativeString()
1254
0
                                    : path.NativeString();
1255
0
                });
1256
0
            }
1257
0
            return std::string{};
1258
0
          } },
1259
0
        { "APPEND"_s,
1260
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1261
0
             Arguments& args) -> std::string {
1262
0
            if (CheckPathParametersEx(ev, cnt, "APPEND"_s, args.size(), 1,
1263
0
                                      false)) {
1264
0
              auto const& list = args.front();
1265
0
              args.advance(1);
1266
1267
0
              return processList(list, [&args](std::string& value) {
1268
0
                cmCMakePath path{ value };
1269
0
                for (auto const& p : args) {
1270
0
                  path /= p;
1271
0
                }
1272
0
                value = path.String();
1273
0
              });
1274
0
            }
1275
0
            return std::string{};
1276
0
          } },
1277
0
        { "REMOVE_FILENAME"_s,
1278
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1279
0
             Arguments& args) -> std::string {
1280
0
            if (CheckPathParameters(ev, cnt, "REMOVE_FILENAME"_s, args) &&
1281
0
                !args.front().empty()) {
1282
0
              return processList(args.front(), [](std::string& value) {
1283
0
                value = cmCMakePath{ value }.RemoveFileName().String();
1284
0
              });
1285
0
            }
1286
0
            return std::string{};
1287
0
          } },
1288
0
        { "REPLACE_FILENAME"_s,
1289
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1290
0
             Arguments& args) -> std::string {
1291
0
            if (CheckPathParameters(ev, cnt, "REPLACE_FILENAME"_s, args, 2)) {
1292
0
              return processList(args.front(), [&args](std::string& value) {
1293
0
                value = cmCMakePath{ value }
1294
0
                          .ReplaceFileName(cmCMakePath{ args[1] })
1295
0
                          .String();
1296
0
              });
1297
0
            }
1298
0
            return std::string{};
1299
0
          } },
1300
0
        { "REMOVE_EXTENSION"_s,
1301
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1302
0
             Arguments& args) -> std::string {
1303
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1304
0
            if (lastOnly) {
1305
0
              args.advance(1);
1306
0
            }
1307
0
            if (CheckPathParametersEx(ev, cnt,
1308
0
                                      lastOnly ? "REMOVE_EXTENSION,LAST_ONLY"_s
1309
0
                                               : "REMOVE_EXTENSION"_s,
1310
0
                                      args.size())) {
1311
0
              if (args.front().empty()) {
1312
0
                return std::string{};
1313
0
              }
1314
0
              if (lastOnly) {
1315
0
                return processList(args.front(), [](std::string& value) {
1316
0
                  value = cmCMakePath{ value }.RemoveExtension().String();
1317
0
                });
1318
0
              }
1319
0
              return processList(args.front(), [](std::string& value) {
1320
0
                value = cmCMakePath{ value }.RemoveWideExtension().String();
1321
0
              });
1322
0
            }
1323
0
            return std::string{};
1324
0
          } },
1325
0
        { "REPLACE_EXTENSION"_s,
1326
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1327
0
             Arguments& args) -> std::string {
1328
0
            bool lastOnly = args.front() == "LAST_ONLY"_s;
1329
0
            if (lastOnly) {
1330
0
              args.advance(1);
1331
0
            }
1332
0
            if (CheckPathParametersEx(ev, cnt,
1333
0
                                      lastOnly
1334
0
                                        ? "REPLACE_EXTENSION,LAST_ONLY"_s
1335
0
                                        : "REPLACE_EXTENSION"_s,
1336
0
                                      args.size(), 2)) {
1337
0
              if (lastOnly) {
1338
0
                return processList(args.front(), [&args](std::string& value) {
1339
0
                  value = cmCMakePath{ value }
1340
0
                            .ReplaceExtension(cmCMakePath{ args[1] })
1341
0
                            .String();
1342
0
                });
1343
0
              }
1344
0
              return processList(args.front(), [&args](std::string& value) {
1345
0
                value = cmCMakePath{ value }
1346
0
                          .ReplaceWideExtension(cmCMakePath{ args[1] })
1347
0
                          .String();
1348
0
              });
1349
0
            }
1350
0
            return std::string{};
1351
0
          } },
1352
0
        { "NORMAL_PATH"_s,
1353
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1354
0
             Arguments& args) -> std::string {
1355
0
            if (CheckPathParameters(ev, cnt, "NORMAL_PATH"_s, args) &&
1356
0
                !args.front().empty()) {
1357
0
              return processList(args.front(), [](std::string& value) {
1358
0
                value = cmCMakePath{ value }.Normal().String();
1359
0
              });
1360
0
            }
1361
0
            return std::string{};
1362
0
          } },
1363
0
        { "RELATIVE_PATH"_s,
1364
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1365
0
             Arguments& args) -> std::string {
1366
0
            if (CheckPathParameters(ev, cnt, "RELATIVE_PATH"_s, args, 2)) {
1367
0
              return processList(args.front(), [&args](std::string& value) {
1368
0
                value = cmCMakePath{ value }.Relative(args[1]).String();
1369
0
              });
1370
0
            }
1371
0
            return std::string{};
1372
0
          } },
1373
0
        { "ABSOLUTE_PATH"_s,
1374
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1375
0
             Arguments& args) -> std::string {
1376
0
            bool normalize = args.front() == "NORMALIZE"_s;
1377
0
            if (normalize) {
1378
0
              args.advance(1);
1379
0
            }
1380
0
            if (CheckPathParametersEx(ev, cnt,
1381
0
                                      normalize ? "ABSOLUTE_PATH,NORMALIZE"_s
1382
0
                                                : "ABSOLUTE_PATH"_s,
1383
0
                                      args.size(), 2)) {
1384
0
              return processList(
1385
0
                args.front(), [&args, normalize](std::string& value) {
1386
0
                  auto path = cmCMakePath{ value }.Absolute(args[1]);
1387
0
                  value = normalize ? path.Normal().String() : path.String();
1388
0
                });
1389
0
            }
1390
0
            return std::string{};
1391
0
          } }
1392
0
      };
1393
1394
0
    if (cm::contains(pathCommands, parameters.front())) {
1395
0
      auto args = Arguments{ parameters }.advance(1);
1396
0
      return pathCommands[parameters.front()](eval, content, args);
1397
0
    }
1398
1399
0
    reportError(eval, content->GetOriginalExpression(),
1400
0
                cmStrCat(parameters.front(), ": invalid option."));
1401
0
    return std::string{};
1402
0
  }
1403
} pathNode;
1404
1405
static const struct PathEqualNode : public cmGeneratorExpressionNode
1406
{
1407
4
  PathEqualNode() {} // NOLINT(modernize-use-equals-default)
1408
1409
0
  int NumExpectedParameters() const override { return 2; }
1410
1411
  std::string Evaluate(
1412
    std::vector<std::string> const& parameters,
1413
    cm::GenEx::Evaluation* /*eval*/,
1414
    GeneratorExpressionContent const* /*content*/,
1415
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1416
0
  {
1417
0
    return cmCMakePath{ parameters[0] } == cmCMakePath{ parameters[1] } ? "1"
1418
0
                                                                        : "0";
1419
0
  }
1420
} pathEqualNode;
1421
1422
namespace {
1423
inline bool CheckStringParametersEx(cm::GenEx::Evaluation* eval,
1424
                                    GeneratorExpressionContent const* cnt,
1425
                                    cm::string_view option, std::size_t count,
1426
                                    int required = 1, bool exactly = true)
1427
0
{
1428
0
  return CheckGenExParameters(eval, cnt, "STRING"_s, option, count, required,
1429
0
                              exactly);
1430
0
}
1431
inline bool CheckStringParameters(cm::GenEx::Evaluation* eval,
1432
                                  GeneratorExpressionContent const* cnt,
1433
                                  cm::string_view option, Arguments args,
1434
                                  int required = 1)
1435
0
{
1436
0
  return CheckStringParametersEx(eval, cnt, option, args.size(), required);
1437
0
};
1438
}
1439
1440
static const struct StringNode : public cmGeneratorExpressionNode
1441
{
1442
4
  StringNode() {} // NOLINT(modernize-use-equals-default)
1443
1444
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
1445
1446
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
1447
1448
  std::string Evaluate(
1449
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
1450
    GeneratorExpressionContent const* content,
1451
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
1452
0
  {
1453
0
    static std::unordered_map<
1454
0
      cm::string_view,
1455
0
      std::function<std::string(cm::GenEx::Evaluation*,
1456
0
                                GeneratorExpressionContent const*,
1457
0
                                Arguments&)>>
1458
0
      stringCommands{
1459
0
        { "LENGTH"_s,
1460
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1461
0
             Arguments& args) -> std::string {
1462
0
            if (CheckStringParameters(ev, cnt, "LENGTH"_s, args)) {
1463
0
              return std::to_string(cm::CMakeString{ args.front() }.Length());
1464
0
            }
1465
0
            return std::string{};
1466
0
          } },
1467
0
        { "SUBSTRING"_s,
1468
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1469
0
             Arguments& args) -> std::string {
1470
0
            if (CheckStringParameters(ev, cnt, "SUBSTRING"_s, args, 3)) {
1471
0
              cm::CMakeString str{ args.front() };
1472
0
              std::vector<long> indexes;
1473
0
              if (GetNumericArguments(ev, cnt, args.advance(1), indexes)) {
1474
0
                try {
1475
0
                  return str.Substring(indexes.front(), indexes.back());
1476
0
                } catch (std::out_of_range const& e) {
1477
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
1478
0
                  return std::string{};
1479
0
                }
1480
0
              }
1481
0
            }
1482
0
            return std::string{};
1483
0
          } },
1484
0
        { "FIND"_s,
1485
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1486
0
             Arguments& args) -> std::string {
1487
0
            if (CheckStringParametersEx(ev, cnt, "FIND"_s, args.size(), 2,
1488
0
                                        false)) {
1489
0
              if (args.size() > 3) {
1490
0
                reportError(ev, cnt->GetOriginalExpression(),
1491
0
                            "$<STRING:FIND> expression expects at "
1492
0
                            "most three parameters.");
1493
0
                return std::string{};
1494
0
              }
1495
1496
0
              auto const FROM = "FROM:"_s;
1497
1498
0
              cm::CMakeString str{ args.front() };
1499
0
              cm::CMakeString::FindFrom from =
1500
0
                cm::CMakeString::FindFrom::Begin;
1501
0
              cm::string_view substring;
1502
1503
0
              args.advance(1);
1504
0
              if (args.size() == 2) {
1505
0
                cm::CMakeString::FindFrom opt =
1506
0
                  static_cast<cm::CMakeString::FindFrom>(-1);
1507
1508
0
                for (auto const& arg : args) {
1509
0
                  if (cmHasPrefix(arg, FROM)) {
1510
0
                    if (arg != "FROM:BEGIN"_s && arg != "FROM:END"_s) {
1511
0
                      reportError(
1512
0
                        ev, cnt->GetOriginalExpression(),
1513
0
                        cmStrCat("Invalid value for '", FROM,
1514
0
                                 "' option. 'BEGIN' or 'END' expected."));
1515
0
                      return std::string{};
1516
0
                    }
1517
0
                    opt = arg == "FROM:BEGIN"_s
1518
0
                      ? cm::CMakeString::FindFrom::Begin
1519
0
                      : cm::CMakeString::FindFrom::End;
1520
0
                  } else {
1521
0
                    substring = arg;
1522
0
                  }
1523
0
                }
1524
0
                if (opt == static_cast<cm::CMakeString::FindFrom>(-1)) {
1525
0
                  reportError(
1526
0
                    ev, cnt->GetOriginalExpression(),
1527
0
                    cmStrCat("Expected option '", FROM, "' is missing."));
1528
0
                  return std::string{};
1529
0
                }
1530
0
                from = opt;
1531
0
              } else {
1532
0
                substring = args.front();
1533
0
              }
1534
0
              auto pos = str.Find(substring, from);
1535
0
              return pos == cm::CMakeString::npos ? "-1" : std::to_string(pos);
1536
0
            }
1537
0
            return std::string{};
1538
0
          } },
1539
0
        { "MATCH"_s,
1540
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1541
0
             Arguments& args) -> std::string {
1542
0
            if (CheckStringParametersEx(ev, cnt, "MATCH"_s, args.size(), 2,
1543
0
                                        false)) {
1544
0
              if (args.size() > 3) {
1545
0
                reportError(ev, cnt->GetOriginalExpression(),
1546
0
                            "$<STRING:MATCH> expression expects at "
1547
0
                            "most three parameters.");
1548
0
                return std::string{};
1549
0
              }
1550
1551
0
              auto const SEEK = "SEEK:"_s;
1552
1553
0
              cm::CMakeString str{ args.front() };
1554
0
              cm::CMakeString::MatchItems seek =
1555
0
                cm::CMakeString::MatchItems::Once;
1556
0
              auto const* regex = &args[1];
1557
1558
0
              args.advance(1);
1559
0
              if (args.size() == 2) {
1560
0
                cm::CMakeString::MatchItems opt =
1561
0
                  static_cast<cm::CMakeString::MatchItems>(-1);
1562
1563
0
                for (auto const& arg : args) {
1564
0
                  if (cmHasPrefix(arg, SEEK)) {
1565
0
                    if (arg != "SEEK:ONCE"_s && arg != "SEEK:ALL"_s) {
1566
0
                      reportError(
1567
0
                        ev, cnt->GetOriginalExpression(),
1568
0
                        cmStrCat("Invalid value for '", SEEK,
1569
0
                                 "' option. 'ONCE' or 'ALL' expected."));
1570
0
                      return std::string{};
1571
0
                    }
1572
0
                    opt = arg == "SEEK:ONCE"_s
1573
0
                      ? cm::CMakeString::MatchItems::Once
1574
0
                      : cm::CMakeString::MatchItems::All;
1575
0
                  } else {
1576
0
                    regex = &arg;
1577
0
                  }
1578
0
                }
1579
0
                if (opt == static_cast<cm::CMakeString::MatchItems>(-1)) {
1580
0
                  reportError(
1581
0
                    ev, cnt->GetOriginalExpression(),
1582
0
                    cmStrCat("Expected option '", SEEK, "' is missing."));
1583
0
                  return std::string{};
1584
0
                }
1585
0
                seek = opt;
1586
0
              }
1587
1588
0
              try {
1589
0
                return str.Match(*regex, seek).to_string();
1590
0
              } catch (std::invalid_argument const& e) {
1591
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1592
0
                return std::string{};
1593
0
              }
1594
0
            }
1595
0
            return std::string{};
1596
0
          } },
1597
0
        { "JOIN"_s,
1598
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1599
0
             Arguments& args) -> std::string {
1600
0
            if (CheckStringParametersEx(ev, cnt, "JOIN"_s, args.size(), 2,
1601
0
                                        false)) {
1602
0
              auto const& glue = args.front();
1603
0
              return cm::CMakeString{ args.advance(1), glue };
1604
0
            }
1605
0
            return std::string{};
1606
0
          } },
1607
0
        { "ASCII"_s,
1608
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1609
0
             Arguments& args) -> std::string {
1610
0
            if (CheckStringParametersEx(ev, cnt, "ASCII"_s, args.size(), 1,
1611
0
                                        false)) {
1612
0
              try {
1613
0
                return cm::CMakeString{}.FromASCII(args);
1614
0
              } catch (std::invalid_argument const& e) {
1615
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1616
0
                return std::string{};
1617
0
              }
1618
0
            }
1619
0
            return std::string{};
1620
0
          } },
1621
0
        { "TIMESTAMP"_s,
1622
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1623
0
             Arguments& args) -> std::string {
1624
0
            cm::string_view format;
1625
0
            cm::CMakeString::UTC utc = cm::CMakeString::UTC::No;
1626
1627
0
            if (args.size() == 2 && args.front() != "UTC"_s &&
1628
0
                args.back() != "UTC"_s) {
1629
0
              reportError(ev, cnt->GetOriginalExpression(),
1630
0
                          "'UTC' option is expected.");
1631
0
              return std::string{};
1632
0
            }
1633
0
            if (args.size() > 2) {
1634
0
              reportError(ev, cnt->GetOriginalExpression(),
1635
0
                          "$<STRING:TIMESTAMP> expression expects at most two "
1636
0
                          "parameters.");
1637
0
              return std::string{};
1638
0
            }
1639
1640
0
            for (auto const& arg : args) {
1641
0
              if (arg == "UTC"_s) {
1642
0
                utc = cm::CMakeString::UTC::Yes;
1643
0
              } else {
1644
0
                format = arg;
1645
0
              }
1646
0
            }
1647
0
            return cm::CMakeString{}.Timestamp(format, utc);
1648
0
          } },
1649
0
        { "RANDOM"_s,
1650
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1651
0
             Arguments& args) -> std::string {
1652
0
            auto const ALPHABET = "ALPHABET:"_s;
1653
0
            auto const LENGTH = "LENGTH:"_s;
1654
0
            auto const RANDOM_SEED = "RANDOM_SEED:"_s;
1655
1656
0
            if (args.size() > 3) {
1657
0
              reportError(ev, cnt->GetOriginalExpression(),
1658
0
                          "$<STRING:RANDOM> expression expects at most three "
1659
0
                          "parameters.");
1660
0
              return std::string{};
1661
0
            }
1662
1663
0
            cm::string_view alphabet;
1664
0
            std::size_t length = 5;
1665
0
            bool seed_specified = false;
1666
0
            unsigned int seed = 0;
1667
0
            for (auto const& arg : args) {
1668
0
              if (cmHasPrefix(arg, ALPHABET)) {
1669
0
                alphabet = cm::string_view{ arg.c_str() + ALPHABET.length() };
1670
0
                continue;
1671
0
              }
1672
0
              if (cmHasPrefix(arg, LENGTH)) {
1673
0
                try {
1674
0
                  length = std::stoul(arg.substr(LENGTH.size()));
1675
0
                } catch (std::exception const&) {
1676
0
                  reportError(ev, cnt->GetOriginalExpression(),
1677
0
                              cmStrCat(arg, ": invalid numeric value for '",
1678
0
                                       LENGTH, "' option."));
1679
0
                  return std::string{};
1680
0
                }
1681
0
                continue;
1682
0
              }
1683
0
              if (cmHasPrefix(arg, RANDOM_SEED)) {
1684
0
                try {
1685
0
                  seed_specified = true;
1686
0
                  seed = static_cast<unsigned int>(
1687
0
                    std::stoul(arg.substr(RANDOM_SEED.size())));
1688
0
                } catch (std::exception const&) {
1689
0
                  reportError(ev, cnt->GetOriginalExpression(),
1690
0
                              cmStrCat(arg, ": invalid numeric value for '",
1691
0
                                       RANDOM_SEED, "' option."));
1692
0
                  return std::string{};
1693
0
                }
1694
0
                continue;
1695
0
              }
1696
0
              reportError(ev, cnt->GetOriginalExpression(),
1697
0
                          cmStrCat(arg, ": invalid parameter."));
1698
0
              return std::string{};
1699
0
            }
1700
1701
0
            try {
1702
0
              if (seed_specified) {
1703
0
                return cm::CMakeString{}.Random(seed, length, alphabet);
1704
0
              }
1705
0
              return cm::CMakeString{}.Random(length, alphabet);
1706
0
            } catch (std::exception const& e) {
1707
0
              reportError(ev, cnt->GetOriginalExpression(), e.what());
1708
0
              return std::string{};
1709
0
            }
1710
0
          } },
1711
0
        { "UUID"_s,
1712
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1713
0
             Arguments& args) -> std::string {
1714
0
            if (CheckStringParametersEx(ev, cnt, "UUID"_s, args.size(), 2,
1715
0
                                        false)) {
1716
0
              auto const NAMESPACE = "NAMESPACE:"_s;
1717
0
              auto const NAME = "NAME:"_s;
1718
0
              auto const TYPE = "TYPE:"_s;
1719
0
              auto const CASE = "CASE:"_s;
1720
1721
0
              if (args.size() > 4) {
1722
0
                reportError(ev, cnt->GetOriginalExpression(),
1723
0
                            "$<STRING:UUID> expression expects at most four "
1724
0
                            "parameters.");
1725
0
                return std::string{};
1726
0
              }
1727
1728
0
              cm::string_view nameSpace;
1729
0
              cm::string_view name;
1730
0
              cm::CMakeString::UUIDType type =
1731
0
                static_cast<cm::CMakeString::UUIDType>(-1);
1732
0
              cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower;
1733
0
              for (auto const& arg : args) {
1734
0
                if (cmHasPrefix(arg, NAMESPACE)) {
1735
0
                  nameSpace =
1736
0
                    cm::string_view{ arg.c_str() + NAMESPACE.length() };
1737
0
                  if (nameSpace.empty()) {
1738
0
                    reportError(
1739
0
                      ev, cnt->GetOriginalExpression(),
1740
0
                      cmStrCat("Invalid value for '", NAMESPACE, "' option."));
1741
0
                    return std::string{};
1742
0
                  }
1743
0
                  continue;
1744
0
                }
1745
0
                if (cmHasPrefix(arg, NAME)) {
1746
0
                  name = cm::string_view{ arg.c_str() + NAME.length() };
1747
0
                  continue;
1748
0
                }
1749
0
                if (cmHasPrefix(arg, TYPE)) {
1750
0
                  auto value = cm::string_view{ arg.c_str() + TYPE.length() };
1751
0
                  if (value != "MD5"_s && value != "SHA1"_s) {
1752
0
                    reportError(
1753
0
                      ev, cnt->GetOriginalExpression(),
1754
0
                      cmStrCat("Invalid value for '", TYPE,
1755
0
                               "' option. 'MD5' or 'SHA1' expected."));
1756
0
                    return std::string{};
1757
0
                  }
1758
0
                  type = value == "MD5"_s ? cm::CMakeString::UUIDType::MD5
1759
0
                                          : cm::CMakeString::UUIDType::SHA1;
1760
0
                  continue;
1761
0
                }
1762
0
                if (cmHasPrefix(arg, CASE)) {
1763
0
                  auto value = cm::string_view{ arg.c_str() + CASE.length() };
1764
0
                  if (value != "UPPER"_s && value != "LOWER"_s) {
1765
0
                    reportError(
1766
0
                      ev, cnt->GetOriginalExpression(),
1767
0
                      cmStrCat("Invalid value for '", CASE,
1768
0
                               "' option. 'UPPER' or 'LOWER' expected."));
1769
0
                    return std::string{};
1770
0
                  }
1771
0
                  uuidCase = value == "UPPER"_s ? cm::CMakeString::Case::Upper
1772
0
                                                : cm::CMakeString::Case::Lower;
1773
0
                  continue;
1774
0
                }
1775
0
                reportError(ev, cnt->GetOriginalExpression(),
1776
0
                            cmStrCat(arg, ": invalid parameter."));
1777
0
                return std::string{};
1778
0
              }
1779
0
              if (nameSpace.empty()) {
1780
0
                reportError(
1781
0
                  ev, cnt->GetOriginalExpression(),
1782
0
                  cmStrCat("Required option '", NAMESPACE, "' is missing."));
1783
0
                return std::string{};
1784
0
              }
1785
0
              if (type == static_cast<cm::CMakeString::UUIDType>(-1)) {
1786
0
                reportError(
1787
0
                  ev, cnt->GetOriginalExpression(),
1788
0
                  cmStrCat("Required option '", TYPE, "' is missing."));
1789
0
                return std::string{};
1790
0
              }
1791
1792
0
              try {
1793
0
                return cm::CMakeString{}.UUID(nameSpace, name, type, uuidCase);
1794
0
              } catch (std::exception const& e) {
1795
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1796
0
                return std::string{};
1797
0
              }
1798
0
            }
1799
0
            return std::string{};
1800
0
          } },
1801
0
        { "REPLACE"_s,
1802
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1803
0
             Arguments& args) -> std::string {
1804
0
            if (CheckStringParametersEx(ev, cnt, "REPLACE"_s, args.size(), 3,
1805
0
                                        false)) {
1806
0
              if (args.size() > 4) {
1807
0
                reportError(ev, cnt->GetOriginalExpression(),
1808
0
                            "$<STRING:REPLACE> expression expects at "
1809
0
                            "most four parameters.");
1810
0
                return std::string{};
1811
0
              }
1812
1813
0
              cm::CMakeString::Regex isRegex = cm::CMakeString::Regex::No;
1814
0
              if (args.size() == 4) {
1815
0
                cm::string_view type = args.front();
1816
0
                if (type != "STRING"_s && type != "REGEX"_s) {
1817
0
                  reportError(
1818
0
                    ev, cnt->GetOriginalExpression(),
1819
0
                    cmStrCat(
1820
0
                      '\'', type,
1821
0
                      "' is unexpected. 'STRING' or 'REGEX' expected."));
1822
0
                  return std::string{};
1823
0
                }
1824
0
                isRegex = type == "STRING"_s ? cm::CMakeString::Regex::No
1825
0
                                             : cm::CMakeString::Regex::Yes;
1826
0
                args.advance(1);
1827
0
              }
1828
1829
0
              try {
1830
0
                return cm::CMakeString{ args.front() }.Replace(
1831
0
                  args[1], args[2], isRegex);
1832
0
              } catch (std::invalid_argument const& e) {
1833
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
1834
0
                return std::string{};
1835
0
              }
1836
0
            }
1837
0
            return std::string{};
1838
0
          } },
1839
0
        { "APPEND"_s,
1840
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1841
0
             Arguments& args) -> std::string {
1842
0
            if (CheckStringParametersEx(ev, cnt, "APPEND"_s, args.size(), 2,
1843
0
                                        false)) {
1844
0
              cm::CMakeString data{ args.front() };
1845
0
              return data.Append(args.advance(1));
1846
0
            }
1847
0
            return std::string{};
1848
0
          } },
1849
0
        { "PREPEND"_s,
1850
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1851
0
             Arguments& args) -> std::string {
1852
0
            if (CheckStringParametersEx(ev, cnt, "PREPEND "_s, args.size(), 2,
1853
0
                                        false)) {
1854
0
              cm::CMakeString data{ args.front() };
1855
0
              return data.Prepend(args.advance(1));
1856
0
            }
1857
0
            return std::string{};
1858
0
          } },
1859
0
        { "TOLOWER"_s,
1860
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1861
0
             Arguments& args) -> std::string {
1862
0
            if (CheckStringParameters(ev, cnt, "TOLOWER"_s, args, 1)) {
1863
0
              return cm::CMakeString{}.ToLower(args.front());
1864
0
            }
1865
0
            return std::string{};
1866
0
          } },
1867
0
        { "TOUPPER"_s,
1868
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1869
0
             Arguments& args) -> std::string {
1870
0
            if (CheckStringParameters(ev, cnt, "TOUPPER"_s, args, 1)) {
1871
0
              return cm::CMakeString{}.ToUpper(args.front());
1872
0
            }
1873
0
            return std::string{};
1874
0
          } },
1875
0
        { "STRIP"_s,
1876
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1877
0
             Arguments& args) -> std::string {
1878
0
            if (CheckStringParameters(ev, cnt, "STRIP"_s, args, 2)) {
1879
0
              if (args.front() != "SPACES"_s) {
1880
0
                reportError(ev, cnt->GetOriginalExpression(),
1881
0
                            cmStrCat('\'', args.front(),
1882
0
                                     "' is unexpected. 'SPACES' expected."));
1883
0
                return std::string{};
1884
0
              }
1885
1886
0
              return cm::CMakeString{ args[1] }.Strip();
1887
0
            }
1888
0
            return std::string{};
1889
0
          } },
1890
0
        { "QUOTE"_s,
1891
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1892
0
             Arguments& args) -> std::string {
1893
0
            if (CheckStringParameters(ev, cnt, "QUOTE"_s, args, 2)) {
1894
0
              if (args.front() != "REGEX"_s) {
1895
0
                reportError(ev, cnt->GetOriginalExpression(),
1896
0
                            cmStrCat('\'', args.front(),
1897
0
                                     "' is unexpected. 'REGEX' expected."));
1898
0
                return std::string{};
1899
0
              }
1900
1901
0
              return cm::CMakeString{ args[1] }.Quote();
1902
0
            }
1903
0
            return std::string{};
1904
0
          } },
1905
0
        { "HEX"_s,
1906
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1907
0
             Arguments& args) -> std::string {
1908
0
            if (CheckStringParameters(ev, cnt, "HEX"_s, args, 1)) {
1909
0
              return cm::CMakeString{ args.front() }.ToHexadecimal();
1910
0
            }
1911
0
            return std::string{};
1912
0
          } },
1913
0
        { "HASH"_s,
1914
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1915
0
             Arguments& args) -> std::string {
1916
0
            if (CheckStringParameters(ev, cnt, "HASH"_s, args, 2)) {
1917
0
              auto const ALGORITHM = "ALGORITHM:"_s;
1918
1919
0
              if (cmHasPrefix(args[1], ALGORITHM)) {
1920
0
                try {
1921
0
                  auto const algo =
1922
0
                    cm::string_view{ args[1].c_str() + ALGORITHM.length() };
1923
0
                  if (algo.empty()) {
1924
0
                    reportError(
1925
0
                      ev, cnt->GetOriginalExpression(),
1926
0
                      cmStrCat("Missing value for '", ALGORITHM, "' option."));
1927
0
                    return std::string{};
1928
0
                  }
1929
0
                  return cm::CMakeString{ args.front() }.Hash(algo);
1930
0
                } catch (std::exception const& e) {
1931
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
1932
0
                  return std::string{};
1933
0
                }
1934
0
              }
1935
0
              reportError(ev, cnt->GetOriginalExpression(),
1936
0
                          cmStrCat(args[1], ": invalid parameter. Option '",
1937
0
                                   ALGORITHM, "' expected."));
1938
0
            }
1939
0
            return std::string{};
1940
0
          } },
1941
0
        { "MAKE_C_IDENTIFIER"_s,
1942
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
1943
0
             Arguments& args) -> std::string {
1944
0
            if (CheckStringParameters(ev, cnt, "MAKE_C_IDENTIFIER"_s, args,
1945
0
                                      1)) {
1946
0
              return cm::CMakeString{ args.front() }.MakeCIdentifier();
1947
0
            }
1948
0
            return std::string{};
1949
0
          } }
1950
0
      };
1951
1952
0
    if (parameters.front().empty()) {
1953
0
      reportError(eval, content->GetOriginalExpression(),
1954
0
                  "$<STRING> expression requires at least one parameter.");
1955
0
      return std::string{};
1956
0
    }
1957
1958
0
    if (cm::contains(stringCommands, parameters.front())) {
1959
0
      auto args = Arguments{ parameters }.advance(1);
1960
0
      return stringCommands[parameters.front()](eval, content, args);
1961
0
    }
1962
1963
0
    reportError(eval, content->GetOriginalExpression(),
1964
0
                cmStrCat(parameters.front(), ": invalid option."));
1965
0
    return std::string{};
1966
0
  }
1967
} stringNode;
1968
1969
namespace {
1970
inline bool CheckListParametersEx(cm::GenEx::Evaluation* eval,
1971
                                  GeneratorExpressionContent const* cnt,
1972
                                  cm::string_view option, std::size_t count,
1973
                                  int required = 1, bool exactly = true)
1974
0
{
1975
0
  return CheckGenExParameters(eval, cnt, "LIST"_s, option, count, required,
1976
0
                              exactly);
1977
0
}
1978
inline bool CheckListParameters(cm::GenEx::Evaluation* eval,
1979
                                GeneratorExpressionContent const* cnt,
1980
                                cm::string_view option, Arguments args,
1981
                                int required = 1)
1982
0
{
1983
0
  return CheckListParametersEx(eval, cnt, option, args.size(), required);
1984
0
};
1985
1986
inline cmList GetList(std::string const& list)
1987
0
{
1988
0
  return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes };
1989
0
}
1990
1991
struct TransformActionDescriptor
1992
{
1993
  cmList::TransformAction Action;
1994
  int Arity;
1995
};
1996
1997
// Look up a canned TRANSFORM action by name (APPLY is handled separately).
1998
cm::optional<TransformActionDescriptor> FindTransformActionDescriptor(
1999
  std::string const& name)
2000
0
{
2001
0
  static std::unordered_map<cm::string_view, TransformActionDescriptor> const
2002
0
    descriptors{
2003
0
      { "APPEND"_s, { cmList::TransformAction::APPEND, 1 } },
2004
0
      { "PREPEND"_s, { cmList::TransformAction::PREPEND, 1 } },
2005
0
      { "TOUPPER"_s, { cmList::TransformAction::TOUPPER, 0 } },
2006
0
      { "TOLOWER"_s, { cmList::TransformAction::TOLOWER, 0 } },
2007
0
      { "STRIP"_s, { cmList::TransformAction::STRIP, 0 } },
2008
0
      { "REPLACE"_s, { cmList::TransformAction::REPLACE, 2 } },
2009
0
    };
2010
0
  auto it = descriptors.find(name);
2011
0
  if (it == descriptors.end()) {
2012
0
    return cm::nullopt;
2013
0
  }
2014
0
  return it->second;
2015
0
}
2016
2017
// Index in `parameters` at which a TRANSFORM action's selector region begins,
2018
// or nullopt if this is not a TRANSFORM or the action is unknown.  For the
2019
// APPLY action the <body> occupies slot 3, so the selector starts at slot 4.
2020
cm::optional<std::size_t> TransformSelectorStart(
2021
  std::vector<std::string> const& parameters)
2022
0
{
2023
0
  if (parameters.size() < 3 || parameters[0] != "TRANSFORM") {
2024
0
    return cm::nullopt;
2025
0
  }
2026
0
  std::string const& action = parameters[2];
2027
0
  if (action == "APPLY") {
2028
0
    return std::size_t{ 4 };
2029
0
  }
2030
0
  if (auto d = FindTransformActionDescriptor(action)) {
2031
0
    return std::size_t{ 3 } + static_cast<std::size_t>(d->Arity);
2032
0
  }
2033
0
  return cm::nullopt;
2034
0
}
2035
2036
// Handle $<LIST:TRANSFORM,...,PREDICATE,<body>>.  `predIndex` is the index of
2037
// the PREDICATE token in `parameters`; the <body> follows it.  PREDICATE is
2038
// the sole selector: only elements whose predicate is "1" are transformed.
2039
std::string EvaluateTransformPredicate(
2040
  std::vector<std::string> const& parameters, std::size_t predIndex,
2041
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
2042
  cmGeneratorExpressionDAGChecker* dagChecker)
2043
0
{
2044
  // PREDICATE must take exactly one <body> and not be combined with another
2045
  // selector (AT/FOR/REGEX) or trailing tokens.
2046
0
  if (parameters.size() < predIndex + 2) {
2047
0
    reportError(eval, content->GetOriginalExpression(),
2048
0
                "sub-command TRANSFORM, selector PREDICATE expects a <body> "
2049
0
                "argument.");
2050
0
    return std::string();
2051
0
  }
2052
0
  if (parameters.size() > predIndex + 2) {
2053
0
    reportError(eval, content->GetOriginalExpression(),
2054
0
                "sub-command TRANSFORM, selector PREDICATE expects a single "
2055
0
                "<body> argument and cannot be combined with another "
2056
0
                "selector.");
2057
0
    return std::string();
2058
0
  }
2059
2060
0
  cmList list = GetList(parameters[1]);
2061
0
  if (list.empty()) {
2062
0
    return std::string();
2063
0
  }
2064
2065
0
  cmGeneratorExpressionEvaluatorVector const& predicateBody =
2066
0
    content->GetParamChildren()[predIndex + 1];
2067
0
  auto mask = EvaluatePredicateMask(predicateBody, list, "TRANSFORM"_s, eval,
2068
0
                                    content, dagChecker);
2069
0
  if (!mask) {
2070
0
    return std::string();
2071
0
  }
2072
2073
0
  if (parameters[2] == "APPLY") {
2074
0
    cmGeneratorExpressionEvaluatorVector const& applyBody =
2075
0
      content->GetParamChildren()[3];
2076
0
    std::vector<std::string> out;
2077
0
    out.reserve(list.size());
2078
0
    std::size_t i = 0;
2079
0
    for (auto const& element : list) {
2080
0
      if ((*mask)[i]) {
2081
0
        out.push_back(
2082
0
          EvaluateBodyWithBoundOperand(applyBody, element, eval, dagChecker));
2083
0
        if (eval->HadError) {
2084
0
          return std::string();
2085
0
        }
2086
0
      } else {
2087
0
        out.push_back(element);
2088
0
      }
2089
0
      ++i;
2090
0
    }
2091
0
    return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2092
0
                   cmList::EmptyElements::Yes }
2093
0
      .to_string();
2094
0
  }
2095
2096
0
  std::string const& action = parameters[2];
2097
0
  auto descriptor = FindTransformActionDescriptor(action);
2098
0
  if (!descriptor) {
2099
0
    reportError(
2100
0
      eval, content->GetOriginalExpression(),
2101
0
      cmStrCat(" sub-command TRANSFORM, ", action, " invalid action."));
2102
0
    return std::string();
2103
0
  }
2104
2105
  // Action arguments occupy parameters[3 .. predIndex); TransformSelectorStart
2106
  // guarantees there are exactly descriptor->Arity of them.
2107
0
  std::vector<std::string> arguments(parameters.begin() + 3,
2108
0
                                     parameters.begin() + predIndex);
2109
2110
0
  std::vector<cmList::index_type> indices;
2111
0
  for (std::size_t i = 0; i < mask->size(); ++i) {
2112
0
    if ((*mask)[i]) {
2113
0
      indices.push_back(static_cast<cmList::index_type>(i));
2114
0
    }
2115
0
  }
2116
0
  if (indices.empty()) {
2117
    // No element selected: TRANSFORM is a no-op.
2118
0
    return list.to_string();
2119
0
  }
2120
2121
0
  auto selector =
2122
0
    cmList::TransformSelector::New<cmList::TransformSelector::AT>(
2123
0
      std::move(indices));
2124
0
  selector->Makefile = eval->Context.LG->GetMakefile();
2125
0
  try {
2126
0
    return list.transform(descriptor->Action, arguments, std::move(selector))
2127
0
      .to_string();
2128
0
  } catch (cmList::transform_error& e) {
2129
0
    reportError(eval, content->GetOriginalExpression(), e.what());
2130
0
    return std::string();
2131
0
  }
2132
0
}
2133
2134
enum class SortOptionResult
2135
{
2136
  NotRecognized, // `arg` is not a SORT option keyword
2137
  Parsed,        // recognized and applied to `sortConfig`
2138
  Error,         // recognized but malformed or duplicate (already reported)
2139
};
2140
2141
// Parse one $<LIST:SORT> colon-option (COMPARE:/CASE:/ORDER:) into sortConfig.
2142
SortOptionResult ParseSortOption(std::string const& arg,
2143
                                 cmList::SortConfiguration& sortConfig,
2144
                                 cm::GenEx::Evaluation* eval,
2145
                                 GeneratorExpressionContent const* content)
2146
0
{
2147
0
  using SortConfig = cmList::SortConfiguration;
2148
0
  auto const COMPARE = "COMPARE:"_s;
2149
0
  auto const CASE = "CASE:"_s;
2150
0
  auto const ORDER = "ORDER:"_s;
2151
2152
0
  if (cmHasPrefix(arg, COMPARE)) {
2153
0
    if (sortConfig.Compare != SortConfig::CompareMethod::DEFAULT) {
2154
0
      reportError(eval, content->GetOriginalExpression(),
2155
0
                  "sub-command SORT, COMPARE option has been specified "
2156
0
                  "multiple times.");
2157
0
      return SortOptionResult::Error;
2158
0
    }
2159
0
    auto option = cm::string_view{ arg.c_str() + COMPARE.length() };
2160
0
    if (option == "STRING"_s) {
2161
0
      sortConfig.Compare = SortConfig::CompareMethod::STRING;
2162
0
    } else if (option == "FILE_BASENAME"_s) {
2163
0
      sortConfig.Compare = SortConfig::CompareMethod::FILE_BASENAME;
2164
0
    } else if (option == "NATURAL"_s) {
2165
0
      sortConfig.Compare = SortConfig::CompareMethod::NATURAL;
2166
0
    } else {
2167
0
      reportError(eval, content->GetOriginalExpression(),
2168
0
                  cmStrCat("sub-command SORT, an invalid COMPARE option has "
2169
0
                           "been specified: \"",
2170
0
                           option, "\"."));
2171
0
      return SortOptionResult::Error;
2172
0
    }
2173
0
    return SortOptionResult::Parsed;
2174
0
  }
2175
2176
0
  if (cmHasPrefix(arg, CASE)) {
2177
0
    if (sortConfig.Case != SortConfig::CaseSensitivity::DEFAULT) {
2178
0
      reportError(eval, content->GetOriginalExpression(),
2179
0
                  "sub-command SORT, CASE option has been specified multiple "
2180
0
                  "times.");
2181
0
      return SortOptionResult::Error;
2182
0
    }
2183
0
    auto option = cm::string_view{ arg.c_str() + CASE.length() };
2184
0
    if (option == "SENSITIVE"_s) {
2185
0
      sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE;
2186
0
    } else if (option == "INSENSITIVE"_s) {
2187
0
      sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE;
2188
0
    } else {
2189
0
      reportError(eval, content->GetOriginalExpression(),
2190
0
                  cmStrCat("sub-command SORT, an invalid CASE option has been "
2191
0
                           "specified: \"",
2192
0
                           option, "\"."));
2193
0
      return SortOptionResult::Error;
2194
0
    }
2195
0
    return SortOptionResult::Parsed;
2196
0
  }
2197
2198
0
  if (cmHasPrefix(arg, ORDER)) {
2199
0
    if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) {
2200
0
      reportError(eval, content->GetOriginalExpression(),
2201
0
                  "sub-command SORT, ORDER option has been specified multiple "
2202
0
                  "times.");
2203
0
      return SortOptionResult::Error;
2204
0
    }
2205
0
    auto option = cm::string_view{ arg.c_str() + ORDER.length() };
2206
0
    if (option == "ASCENDING"_s) {
2207
0
      sortConfig.Order = SortConfig::OrderMode::ASCENDING;
2208
0
    } else if (option == "DESCENDING"_s) {
2209
0
      sortConfig.Order = SortConfig::OrderMode::DESCENDING;
2210
0
    } else {
2211
0
      reportError(
2212
0
        eval, content->GetOriginalExpression(),
2213
0
        cmStrCat("sub-command SORT, an invalid ORDER option has been "
2214
0
                 "specified: \"",
2215
0
                 option, "\"."));
2216
0
      return SortOptionResult::Error;
2217
0
    }
2218
0
    return SortOptionResult::Parsed;
2219
0
  }
2220
2221
0
  return SortOptionResult::NotRecognized;
2222
0
}
2223
2224
// $<LIST:SORT,...,COMPARATOR,body>: sort with a per-comparison genex body, the
2225
// two elements bound to $<_0> and $<_1>; body must yield "0" or "1".
2226
std::string EvaluateSortComparator(std::vector<std::string> const& parameters,
2227
                                   std::size_t comparatorIndex,
2228
                                   cm::GenEx::Evaluation* eval,
2229
                                   GeneratorExpressionContent const* content,
2230
                                   cmGeneratorExpressionDAGChecker* dagChecker)
2231
0
{
2232
0
  if (comparatorIndex + 1 >= parameters.size()) {
2233
0
    reportError(eval, content->GetOriginalExpression(),
2234
0
                "sub-command SORT, COMPARATOR expects a <body> argument.");
2235
0
    return std::string();
2236
0
  }
2237
0
  cmGeneratorExpressionEvaluatorVector const& bodyExpr =
2238
0
    content->GetParamChildren()[comparatorIndex + 1];
2239
2240
0
  using SortConfig = cmList::SortConfiguration;
2241
0
  SortConfig sortConfig;
2242
0
  sortConfig.Compare = SortConfig::CompareMethod::COMPARATOR;
2243
0
  for (std::size_t i = 2; i < parameters.size(); ++i) {
2244
0
    if (i == comparatorIndex || i == comparatorIndex + 1) {
2245
0
      continue; // COMPARATOR keyword + its (empty) body slot
2246
0
    }
2247
0
    std::string const& arg = parameters[i];
2248
    // COMPARATOR defines the ordering, so reject COMPARE:; CASE:/ORDER: are
2249
    // accepted as in list(SORT ... COMPARATOR) (CASE: folds the body
2250
    // operands).
2251
0
    if (cmHasPrefix(arg, "COMPARE:"_s)) {
2252
0
      reportError(eval, content->GetOriginalExpression(),
2253
0
                  "sub-command SORT, option \"COMPARE\" is incompatible with "
2254
0
                  "\"COMPARATOR\".");
2255
0
      return std::string();
2256
0
    }
2257
0
    switch (ParseSortOption(arg, sortConfig, eval, content)) {
2258
0
      case SortOptionResult::Parsed:
2259
0
        break;
2260
0
      case SortOptionResult::Error:
2261
0
        return std::string();
2262
0
      case SortOptionResult::NotRecognized:
2263
0
        reportError(
2264
0
          eval, content->GetOriginalExpression(),
2265
0
          cmStrCat("sub-command SORT, option \"", arg, "\" is invalid."));
2266
0
        return std::string();
2267
0
    }
2268
0
  }
2269
2270
0
  cmList list = GetList(parameters[1]);
2271
0
  if (list.size() < 2) {
2272
0
    return list.to_string();
2273
0
  }
2274
2275
  // The strict-weak-ordering guard in cmList::sort may call this twice per
2276
  // pair, so the body can be evaluated up to twice per comparison.
2277
0
  auto comparator = [&](std::string const& a, std::string const& b) -> bool {
2278
0
    std::string r =
2279
0
      EvaluateBodyWithBoundOperands(bodyExpr, { a, b }, eval, dagChecker);
2280
0
    if (eval->HadError) {
2281
0
      throw cmList::transform_error(std::string{}); // body already reported
2282
0
    }
2283
0
    if (r == "1") {
2284
0
      return true;
2285
0
    }
2286
0
    if (r == "0") {
2287
0
      return false;
2288
0
    }
2289
0
    throw cmList::transform_error(
2290
0
      cmStrCat("sub-command SORT, COMPARATOR body must evaluate to \"0\" or "
2291
0
               "\"1\", but evaluated to \"",
2292
0
               r, "\"."));
2293
0
  };
2294
2295
0
  try {
2296
0
    list.sort(sortConfig, comparator);
2297
0
  } catch (std::invalid_argument& e) {
2298
0
    if (!eval->HadError) {
2299
0
      reportError(eval, content->GetOriginalExpression(), e.what());
2300
0
    }
2301
0
    return std::string();
2302
0
  }
2303
0
  return list.to_string();
2304
0
}
2305
2306
// Parse the optional trailing selector of a $<LIST:TRANSFORM,...> action
2307
// (AT <i>... / FOR <start> <stop> [<step>] / REGEX <re>) into a
2308
// cmList::TransformSelector.  Returns nullptr (after reporting via `eval`) on
2309
// a malformed selector; empty `tokens` yields a select-all selector.
2310
std::unique_ptr<cmList::TransformSelector> ParseTransformSelector(
2311
  std::vector<std::string> const& tokens, cm::GenEx::Evaluation* eval,
2312
  GeneratorExpressionContent const* content)
2313
0
{
2314
0
  static std::string const REGEX{ "REGEX" };
2315
0
  static std::string const AT{ "AT" };
2316
0
  static std::string const FOR{ "FOR" };
2317
2318
0
  std::unique_ptr<cmList::TransformSelector> selector;
2319
2320
0
  std::size_t i = 0;
2321
0
  while (i < tokens.size()) {
2322
0
    std::string const& tok = tokens[i];
2323
2324
0
    if ((tok == REGEX || tok == AT || tok == FOR) && selector) {
2325
0
      reportError(
2326
0
        eval, content->GetOriginalExpression(),
2327
0
        cmStrCat("sub-command TRANSFORM, selector already specified (",
2328
0
                 selector->GetTag(), ")."));
2329
0
      return nullptr;
2330
0
    }
2331
2332
0
    if (tok == REGEX) {
2333
0
      if (i + 1 >= tokens.size()) {
2334
0
        reportError(eval, content->GetOriginalExpression(),
2335
0
                    "sub-command TRANSFORM, selector REGEX expects "
2336
0
                    "'regular expression' argument.");
2337
0
        return nullptr;
2338
0
      }
2339
0
      selector =
2340
0
        cmList::TransformSelector::New<cmList::TransformSelector::REGEX>(
2341
0
          tokens[i + 1]);
2342
0
      i += 2;
2343
0
      continue;
2344
0
    }
2345
2346
0
    if (tok == AT) {
2347
0
      ++i;
2348
0
      std::vector<cmList::index_type> indexes;
2349
0
      for (; i < tokens.size(); ++i) {
2350
0
        cmList indexList{ tokens[i] };
2351
0
        for (auto const& index : indexList) {
2352
0
          cmList::index_type value;
2353
0
          if (!GetNumericArgument(index, value)) {
2354
0
            reportError(eval, content->GetOriginalExpression(),
2355
0
                        cmStrCat("sub-command TRANSFORM, selector AT: '",
2356
0
                                 index, "': unexpected argument."));
2357
0
            return nullptr;
2358
0
          }
2359
0
          indexes.push_back(value);
2360
0
        }
2361
0
      }
2362
0
      if (indexes.empty()) {
2363
0
        reportError(eval, content->GetOriginalExpression(),
2364
0
                    "sub-command TRANSFORM, selector AT expects at least one "
2365
0
                    "numeric value.");
2366
0
        return nullptr;
2367
0
      }
2368
0
      selector = cmList::TransformSelector::New<cmList::TransformSelector::AT>(
2369
0
        std::move(indexes));
2370
0
      continue;
2371
0
    }
2372
2373
0
    if (tok == FOR) {
2374
0
      if (i + 2 >= tokens.size()) {
2375
0
        reportError(eval, content->GetOriginalExpression(),
2376
0
                    "sub-command TRANSFORM, selector FOR expects, at least, "
2377
0
                    "two arguments.");
2378
0
        return nullptr;
2379
0
      }
2380
0
      cmList::index_type start = 0;
2381
0
      cmList::index_type stop = 0;
2382
0
      cmList::index_type step = 1;
2383
0
      if (!GetNumericArgument(tokens[i + 1], start) ||
2384
0
          !GetNumericArgument(tokens[i + 2], stop)) {
2385
0
        reportError(eval, content->GetOriginalExpression(),
2386
0
                    "sub-command TRANSFORM, selector FOR expects, at least, "
2387
0
                    "two numeric values.");
2388
0
        return nullptr;
2389
0
      }
2390
0
      i += 3;
2391
0
      if (i < tokens.size()) {
2392
0
        if (!GetNumericArgument(tokens[i], step)) {
2393
0
          step = -1;
2394
0
        }
2395
0
        ++i;
2396
0
      }
2397
0
      if (step <= 0) {
2398
0
        reportError(eval, content->GetOriginalExpression(),
2399
0
                    "sub-command TRANSFORM, selector FOR expects positive "
2400
0
                    "numeric value for <step>.");
2401
0
        return nullptr;
2402
0
      }
2403
0
      selector =
2404
0
        cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
2405
0
          { start, stop, step });
2406
0
      continue;
2407
0
    }
2408
2409
0
    std::vector<std::string> const rest(tokens.begin() + i, tokens.end());
2410
0
    reportError(eval, content->GetOriginalExpression(),
2411
0
                cmStrCat("sub-command TRANSFORM, '", cmJoin(rest, ", "),
2412
0
                         "': unexpected argument(s)."));
2413
0
    return nullptr;
2414
0
  }
2415
2416
0
  if (!selector) {
2417
0
    selector = cmList::TransformSelector::New();
2418
0
  }
2419
0
  return selector;
2420
0
}
2421
}
2422
2423
static const struct ListNode : public cmGeneratorExpressionNode
2424
{
2425
4
  ListNode() {} // NOLINT(modernize-use-equals-default)
2426
2427
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
2428
2429
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
2430
2431
  bool ShouldEvaluateNextParameter(std::vector<std::string> const& parameters,
2432
                                   std::string&) const override
2433
0
  {
2434
    // Leave the FILTER PREDICATE <body> (slot 4) unevaluated so $<_0> is never
2435
    // evaluated unbound.
2436
0
    if (parameters.size() == 4 && parameters[0] == "FILTER" &&
2437
0
        parameters[3] == "PREDICATE") {
2438
0
      return false;
2439
0
    }
2440
    // Leave a TRANSFORM PREDICATE selector's <body> unevaluated.  PREDICATE is
2441
    // the selector keyword only when it sits exactly at the selector position
2442
    // (not when it is a literal action argument such as APPEND PREDICATE).
2443
0
    if (auto start = TransformSelectorStart(parameters)) {
2444
0
      if (parameters.size() == *start + 1 &&
2445
0
          parameters.back() == "PREDICATE") {
2446
0
        return false;
2447
0
      }
2448
0
    }
2449
    // Leave the SORT COMPARATOR <body> unevaluated; a bare COMPARATOR token is
2450
    // unambiguous since SORT's other options are colon-style.
2451
0
    if (parameters.size() >= 3 && parameters[0] == "SORT" &&
2452
0
        parameters.back() == "COMPARATOR") {
2453
0
      return false;
2454
0
    }
2455
    // Skip the APPLY <body> (4th parameter) so $<_0> is not evaluated unbound;
2456
    // selector args (5th+) evaluate normally.
2457
0
    return !(parameters.size() == 3 && parameters[0] == "TRANSFORM" &&
2458
0
             parameters[2] == "APPLY");
2459
0
  }
2460
2461
  std::string Evaluate(
2462
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
2463
    GeneratorExpressionContent const* content,
2464
    cmGeneratorExpressionDAGChecker* dagChecker) const override
2465
0
  {
2466
    // TRANSFORM ... PREDICATE <body>: genex-native predicate selector, usable
2467
    // with any action (canned or APPLY).  Handled here (not in the
2468
    // listCommands lambda) because the predicate <body> needs the DAG checker.
2469
0
    if (parameters.size() >= 3 && parameters[0] == "TRANSFORM") {
2470
0
      if (auto start = TransformSelectorStart(parameters)) {
2471
0
        if (*start < parameters.size() && parameters[*start] == "PREDICATE") {
2472
0
          return EvaluateTransformPredicate(parameters, *start, eval, content,
2473
0
                                            dagChecker);
2474
0
        }
2475
0
      }
2476
0
    }
2477
2478
0
    if (parameters.size() >= 3 && parameters[0] == "TRANSFORM" &&
2479
0
        parameters[2] == "APPLY") {
2480
0
      if (parameters.size() < 4) {
2481
0
        reportError(
2482
0
          eval, content->GetOriginalExpression(),
2483
0
          "sub-command TRANSFORM, action APPLY expects a <body> argument.");
2484
0
        return std::string();
2485
0
      }
2486
0
      cmList list = GetList(parameters[1]);
2487
0
      if (list.empty()) {
2488
0
        return std::string{};
2489
0
      }
2490
0
      cmGeneratorExpressionEvaluatorVector const& bodyExpr =
2491
0
        content->GetParamChildren()[3];
2492
0
      std::vector<std::string> const selectorTokens(parameters.begin() + 4,
2493
0
                                                    parameters.end());
2494
0
      std::unique_ptr<cmList::TransformSelector> selector =
2495
0
        ParseTransformSelector(selectorTokens, eval, content);
2496
0
      if (!selector) {
2497
0
        return std::string();
2498
0
      }
2499
      // selector->Makefile is left unset: the REGEX/AT/FOR selectors never
2500
      // consult it, and the only one that does (list()'s PREDICATE) cannot
2501
      // reach here.
2502
0
      std::vector<bool> selected;
2503
0
      try {
2504
0
        selected = list.GetTransformSelection(*selector);
2505
0
      } catch (cmList::transform_error& e) {
2506
0
        reportError(eval, content->GetOriginalExpression(), e.what());
2507
0
        return std::string();
2508
0
      }
2509
2510
0
      std::vector<std::string> out;
2511
0
      out.reserve(list.size());
2512
0
      std::size_t i = 0;
2513
0
      for (auto const& element : list) {
2514
0
        if (i < selected.size() && selected[i]) {
2515
0
          out.push_back(
2516
0
            EvaluateBodyWithBoundOperand(bodyExpr, element, eval, dagChecker));
2517
0
          if (eval->HadError) {
2518
0
            return std::string();
2519
0
          }
2520
0
        } else {
2521
0
          out.push_back(element);
2522
0
        }
2523
0
        ++i;
2524
0
      }
2525
      // Join per-element results with ';'; keep empty elements so a body that
2526
      // yields "" is not dropped.
2527
0
      return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2528
0
                     cmList::EmptyElements::Yes }
2529
0
        .to_string();
2530
0
    }
2531
2532
    // FILTER ... PREDICATE <body>: genex-native predicate filter.
2533
0
    if (parameters.size() >= 4 && parameters[0] == "FILTER" &&
2534
0
        parameters[3] == "PREDICATE") {
2535
0
      if (parameters.size() != 5) {
2536
0
        reportError(eval, content->GetOriginalExpression(),
2537
0
                    "sub-command FILTER, PREDICATE expects a single <body> "
2538
0
                    "argument.");
2539
0
        return std::string();
2540
0
      }
2541
0
      std::string const& op = parameters[2];
2542
0
      if (op != "INCLUDE" && op != "EXCLUDE") {
2543
0
        reportError(
2544
0
          eval, content->GetOriginalExpression(),
2545
0
          cmStrCat("sub-command FILTER does not recognize operator \"", op,
2546
0
                   "\". It must be either INCLUDE or EXCLUDE."));
2547
0
        return std::string();
2548
0
      }
2549
0
      cmList list = GetList(parameters[1]);
2550
0
      if (list.empty()) {
2551
0
        return std::string();
2552
0
      }
2553
0
      cmGeneratorExpressionEvaluatorVector const& predicateBody =
2554
0
        content->GetParamChildren()[4];
2555
0
      auto mask = EvaluatePredicateMask(predicateBody, list, "FILTER"_s, eval,
2556
0
                                        content, dagChecker);
2557
0
      if (!mask) {
2558
0
        return std::string();
2559
0
      }
2560
0
      bool const keepWhenTrue = (op == "INCLUDE");
2561
0
      std::vector<std::string> out;
2562
0
      std::size_t i = 0;
2563
0
      for (auto const& element : list) {
2564
0
        if ((*mask)[i] == keepWhenTrue) {
2565
0
          out.push_back(element);
2566
0
        }
2567
0
        ++i;
2568
0
      }
2569
0
      return cmList{ out.begin(), out.end(), cmList::ExpandElements::No,
2570
0
                     cmList::EmptyElements::Yes }
2571
0
        .to_string();
2572
0
    }
2573
2574
    // SORT COMPARATOR is handled here, not the listCommands SORT lambda,
2575
    // because the body needs the DAG checker.
2576
0
    if (parameters.size() >= 3 && parameters[0] == "SORT") {
2577
0
      for (std::size_t i = 2; i < parameters.size(); ++i) {
2578
0
        if (parameters[i] == "COMPARATOR") {
2579
0
          return EvaluateSortComparator(parameters, i, eval, content,
2580
0
                                        dagChecker);
2581
0
        }
2582
0
      }
2583
0
    }
2584
2585
0
    static std::unordered_map<
2586
0
      cm::string_view,
2587
0
      std::function<std::string(cm::GenEx::Evaluation*,
2588
0
                                GeneratorExpressionContent const*,
2589
0
                                Arguments&)>>
2590
0
      listCommands{
2591
0
        { "LENGTH"_s,
2592
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2593
0
             Arguments& args) -> std::string {
2594
0
            if (CheckListParameters(ev, cnt, "LENGTH"_s, args)) {
2595
0
              return std::to_string(GetList(args.front()).size());
2596
0
            }
2597
0
            return std::string{};
2598
0
          } },
2599
0
        { "GET"_s,
2600
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2601
0
             Arguments& args) -> std::string {
2602
0
            if (CheckListParametersEx(ev, cnt, "GET"_s, args.size(), 2,
2603
0
                                      false)) {
2604
0
              auto list = GetList(args.front());
2605
0
              if (list.empty()) {
2606
0
                reportError(ev, cnt->GetOriginalExpression(),
2607
0
                            "given empty list");
2608
0
                return std::string{};
2609
0
              }
2610
2611
0
              std::vector<cmList::index_type> indexes;
2612
0
              if (!GetNumericArguments(ev, cnt, args.advance(1), indexes,
2613
0
                                       cmList::ExpandElements::Yes)) {
2614
0
                return std::string{};
2615
0
              }
2616
0
              try {
2617
0
                return list.get_items(indexes.begin(), indexes.end())
2618
0
                  .to_string();
2619
0
              } catch (std::out_of_range& e) {
2620
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2621
0
                return std::string{};
2622
0
              }
2623
0
            }
2624
0
            return std::string{};
2625
0
          } },
2626
0
        { "JOIN"_s,
2627
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2628
0
             Arguments& args) -> std::string {
2629
0
            if (CheckListParameters(ev, cnt, "JOIN"_s, args, 2)) {
2630
0
              return GetList(args.front()).join(args[1]);
2631
0
            }
2632
0
            return std::string{};
2633
0
          } },
2634
0
        { "SUBLIST"_s,
2635
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2636
0
             Arguments& args) -> std::string {
2637
0
            if (CheckListParameters(ev, cnt, "SUBLIST"_s, args, 3)) {
2638
0
              auto list = GetList(args.front());
2639
0
              if (!list.empty()) {
2640
0
                std::vector<cmList::index_type> indexes;
2641
0
                if (!GetNumericArguments(ev, cnt, args.advance(1), indexes)) {
2642
0
                  return std::string{};
2643
0
                }
2644
0
                if (indexes[0] < 0) {
2645
0
                  reportError(ev, cnt->GetOriginalExpression(),
2646
0
                              cmStrCat("begin index: ", indexes[0],
2647
0
                                       " is out of range 0 - ",
2648
0
                                       list.size() - 1));
2649
0
                  return std::string{};
2650
0
                }
2651
0
                if (indexes[1] < -1) {
2652
0
                  reportError(ev, cnt->GetOriginalExpression(),
2653
0
                              cmStrCat("length: ", indexes[1],
2654
0
                                       " should be -1 or greater"));
2655
0
                  return std::string{};
2656
0
                }
2657
0
                try {
2658
0
                  return list
2659
0
                    .sublist(static_cast<cmList::size_type>(indexes[0]),
2660
0
                             static_cast<cmList::size_type>(indexes[1]))
2661
0
                    .to_string();
2662
0
                } catch (std::out_of_range& e) {
2663
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
2664
0
                  return std::string{};
2665
0
                }
2666
0
              }
2667
0
            }
2668
0
            return std::string{};
2669
0
          } },
2670
0
        { "FIND"_s,
2671
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2672
0
             Arguments& args) -> std::string {
2673
0
            if (CheckListParameters(ev, cnt, "FIND"_s, args, 2)) {
2674
0
              auto list = GetList(args.front());
2675
0
              auto index = list.find(args[1]);
2676
0
              return index == cmList::npos ? "-1" : std::to_string(index);
2677
0
            }
2678
0
            return std::string{};
2679
0
          } },
2680
0
        { "APPEND"_s,
2681
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2682
0
             Arguments& args) -> std::string {
2683
0
            if (CheckListParametersEx(ev, cnt, "APPEND"_s, args.size(), 2,
2684
0
                                      false)) {
2685
0
              auto list = args.front();
2686
0
              args.advance(1);
2687
0
              return cmList::append(list, args.begin(), args.end());
2688
0
            }
2689
0
            return std::string{};
2690
0
          } },
2691
0
        { "PREPEND"_s,
2692
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2693
0
             Arguments& args) -> std::string {
2694
0
            if (CheckListParametersEx(ev, cnt, "PREPEND"_s, args.size(), 2,
2695
0
                                      false)) {
2696
0
              auto list = args.front();
2697
0
              args.advance(1);
2698
0
              return cmList::prepend(list, args.begin(), args.end());
2699
0
            }
2700
0
            return std::string{};
2701
0
          } },
2702
0
        { "INSERT"_s,
2703
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2704
0
             Arguments& args) -> std::string {
2705
0
            if (CheckListParametersEx(ev, cnt, "INSERT"_s, args.size(), 3,
2706
0
                                      false)) {
2707
0
              cmList::index_type index;
2708
0
              if (!GetNumericArgument(args[1], index)) {
2709
0
                reportError(
2710
0
                  ev, cnt->GetOriginalExpression(),
2711
0
                  cmStrCat("index: \"", args[1], "\" is not a valid index"));
2712
0
                return std::string{};
2713
0
              }
2714
0
              try {
2715
0
                auto list = GetList(args.front());
2716
0
                args.advance(2);
2717
0
                list.insert_items(index, args.begin(), args.end(),
2718
0
                                  cmList::ExpandElements::No,
2719
0
                                  cmList::EmptyElements::Yes);
2720
0
                return list.to_string();
2721
0
              } catch (std::out_of_range& e) {
2722
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2723
0
                return std::string{};
2724
0
              }
2725
0
            }
2726
0
            return std::string{};
2727
0
          } },
2728
0
        { "POP_BACK"_s,
2729
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2730
0
             Arguments& args) -> std::string {
2731
0
            if (CheckListParameters(ev, cnt, "POP_BACK"_s, args)) {
2732
0
              auto list = GetList(args.front());
2733
0
              if (!list.empty()) {
2734
0
                list.pop_back();
2735
0
                return list.to_string();
2736
0
              }
2737
0
            }
2738
0
            return std::string{};
2739
0
          } },
2740
0
        { "POP_FRONT"_s,
2741
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2742
0
             Arguments& args) -> std::string {
2743
0
            if (CheckListParameters(ev, cnt, "POP_FRONT"_s, args)) {
2744
0
              auto list = GetList(args.front());
2745
0
              if (!list.empty()) {
2746
0
                list.pop_front();
2747
0
                return list.to_string();
2748
0
              }
2749
0
            }
2750
0
            return std::string{};
2751
0
          } },
2752
0
        { "REMOVE_DUPLICATES"_s,
2753
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2754
0
             Arguments& args) -> std::string {
2755
0
            if (CheckListParameters(ev, cnt, "REMOVE_DUPLICATES"_s, args)) {
2756
0
              return GetList(args.front()).remove_duplicates().to_string();
2757
0
            }
2758
0
            return std::string{};
2759
0
          } },
2760
0
        { "REMOVE_ITEM"_s,
2761
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2762
0
             Arguments& args) -> std::string {
2763
0
            if (CheckListParametersEx(ev, cnt, "REMOVE_ITEM"_s, args.size(), 2,
2764
0
                                      false)) {
2765
0
              auto list = GetList(args.front());
2766
0
              args.advance(1);
2767
0
              cmList items{ args.begin(), args.end(),
2768
0
                            cmList::ExpandElements::Yes };
2769
0
              return list.remove_items(items.begin(), items.end()).to_string();
2770
0
            }
2771
0
            return std::string{};
2772
0
          } },
2773
0
        { "REMOVE_AT"_s,
2774
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2775
0
             Arguments& args) -> std::string {
2776
0
            if (CheckListParametersEx(ev, cnt, "REMOVE_AT"_s, args.size(), 2,
2777
0
                                      false)) {
2778
0
              auto list = GetList(args.front());
2779
0
              std::vector<cmList::index_type> indexes;
2780
0
              if (!GetNumericArguments(ev, cnt, args.advance(1), indexes,
2781
0
                                       cmList::ExpandElements::Yes)) {
2782
0
                return std::string{};
2783
0
              }
2784
0
              try {
2785
0
                return list.remove_items(indexes.begin(), indexes.end())
2786
0
                  .to_string();
2787
0
              } catch (std::out_of_range& e) {
2788
0
                reportError(ev, cnt->GetOriginalExpression(), e.what());
2789
0
                return std::string{};
2790
0
              }
2791
0
            }
2792
0
            return std::string{};
2793
0
          } },
2794
0
        { "FILTER"_s,
2795
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2796
0
             Arguments& args) -> std::string {
2797
            // args = [list, INCLUDE|EXCLUDE, <regex> | REGEX <regex>].
2798
            // (PREDICATE is handled up-front in Evaluate and never reaches
2799
            // here.)
2800
0
            bool const explicitRegex =
2801
0
              args.size() >= 3 && args[2] == "REGEX"_s;
2802
0
            int const required = explicitRegex ? 4 : 3;
2803
0
            if (CheckListParameters(ev, cnt, "FILTER"_s, args, required)) {
2804
0
              auto const& op = args[1];
2805
0
              if (op != "INCLUDE"_s && op != "EXCLUDE"_s) {
2806
0
                reportError(
2807
0
                  ev, cnt->GetOriginalExpression(),
2808
0
                  cmStrCat("sub-command FILTER does not recognize operator \"",
2809
0
                           op, "\". It must be either INCLUDE or EXCLUDE."));
2810
0
                return std::string{};
2811
0
              }
2812
0
              auto const& regex = explicitRegex ? args[3] : args[2];
2813
0
              try {
2814
0
                return GetList(args.front())
2815
0
                  .filter(regex,
2816
0
                          op == "INCLUDE"_s ? cmList::FilterMode::INCLUDE
2817
0
                                            : cmList::FilterMode::EXCLUDE)
2818
0
                  .to_string();
2819
0
              } catch (std::invalid_argument&) {
2820
0
                reportError(
2821
0
                  ev, cnt->GetOriginalExpression(),
2822
0
                  cmStrCat("sub-command FILTER, failed to compile regex \"",
2823
0
                           regex, "\"."));
2824
0
                return std::string{};
2825
0
              }
2826
0
            }
2827
0
            return std::string{};
2828
0
          } },
2829
0
        { "TRANSFORM"_s,
2830
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2831
0
             Arguments& args) -> std::string {
2832
0
            if (CheckListParametersEx(ev, cnt, "TRANSFORM"_s, args.size(), 2,
2833
0
                                      false)) {
2834
0
              auto list = GetList(args.front());
2835
0
              if (!list.empty()) {
2836
0
                std::string const actionName = args.advance(1).front();
2837
0
                auto descriptor = FindTransformActionDescriptor(actionName);
2838
0
                if (!descriptor) {
2839
0
                  reportError(ev, cnt->GetOriginalExpression(),
2840
0
                              cmStrCat(" sub-command TRANSFORM, ", actionName,
2841
0
                                       " invalid action."));
2842
0
                  return std::string{};
2843
0
                }
2844
2845
                // Action arguments
2846
0
                args.advance(1);
2847
0
                if (args.size() < descriptor->Arity) {
2848
0
                  reportError(ev, cnt->GetOriginalExpression(),
2849
0
                              cmStrCat("sub-command TRANSFORM, action ",
2850
0
                                       actionName, " expects ",
2851
0
                                       descriptor->Arity, " argument(s)."));
2852
0
                  return std::string{};
2853
0
                }
2854
0
                std::vector<std::string> arguments;
2855
0
                if (descriptor->Arity > 0) {
2856
0
                  arguments = std::vector<std::string>(
2857
0
                    args.begin(), args.begin() + descriptor->Arity);
2858
0
                  args.advance(descriptor->Arity);
2859
0
                }
2860
2861
0
                std::unique_ptr<cmList::TransformSelector> selector;
2862
2863
0
                try {
2864
0
                  std::vector<std::string> const tokens(args.begin(),
2865
0
                                                        args.end());
2866
0
                  selector = ParseTransformSelector(tokens, ev, cnt);
2867
0
                  if (!selector) {
2868
0
                    return std::string{};
2869
0
                  }
2870
0
                  selector->Makefile = ev->Context.LG->GetMakefile();
2871
2872
0
                  return list
2873
0
                    .transform(descriptor->Action, arguments,
2874
0
                               std::move(selector))
2875
0
                    .to_string();
2876
0
                } catch (cmList::transform_error& e) {
2877
0
                  reportError(ev, cnt->GetOriginalExpression(), e.what());
2878
0
                  return std::string{};
2879
0
                }
2880
0
              }
2881
0
            }
2882
0
            return std::string{};
2883
0
          } },
2884
0
        { "REVERSE"_s,
2885
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2886
0
             Arguments& args) -> std::string {
2887
0
            if (CheckListParameters(ev, cnt, "REVERSE"_s, args)) {
2888
0
              return GetList(args.front()).reverse().to_string();
2889
0
            }
2890
0
            return std::string{};
2891
0
          } },
2892
0
        { "SORT"_s,
2893
0
          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
2894
0
             Arguments& args) -> std::string {
2895
0
            if (CheckListParametersEx(ev, cnt, "SORT"_s, args.size(), 1,
2896
0
                                      false)) {
2897
0
              auto list = GetList(args.front());
2898
0
              args.advance(1);
2899
0
              cmList::SortConfiguration sortConfig;
2900
0
              for (auto const& arg : args) {
2901
0
                switch (ParseSortOption(arg, sortConfig, ev, cnt)) {
2902
0
                  case SortOptionResult::Parsed:
2903
0
                    break;
2904
0
                  case SortOptionResult::Error:
2905
0
                    return std::string{};
2906
0
                  case SortOptionResult::NotRecognized:
2907
0
                    reportError(ev, cnt->GetOriginalExpression(),
2908
0
                                cmStrCat("sub-command SORT, option \"", arg,
2909
0
                                         "\" is invalid."));
2910
0
                    return std::string{};
2911
0
                }
2912
0
              }
2913
2914
0
              return list.sort(sortConfig).to_string();
2915
0
            }
2916
0
            return std::string{};
2917
0
          } }
2918
0
      };
2919
2920
0
    if (cm::contains(listCommands, parameters.front())) {
2921
0
      auto args = Arguments{ parameters }.advance(1);
2922
0
      return listCommands[parameters.front()](eval, content, args);
2923
0
    }
2924
2925
0
    reportError(eval, content->GetOriginalExpression(),
2926
0
                cmStrCat(parameters.front(), ": invalid option."));
2927
0
    return std::string{};
2928
0
  }
2929
} listNode;
2930
2931
static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
2932
{
2933
4
  MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
2934
2935
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
2936
2937
  std::string Evaluate(
2938
    std::vector<std::string> const& parameters,
2939
    cm::GenEx::Evaluation* /*eval*/,
2940
    GeneratorExpressionContent const* /*content*/,
2941
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
2942
0
  {
2943
0
    return cmSystemTools::MakeCidentifier(parameters.front());
2944
0
  }
2945
} makeCIdentifierNode;
2946
2947
template <char C>
2948
struct CharacterNode : public cmGeneratorExpressionNode
2949
{
2950
16
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)62>::CharacterNode()
Line
Count
Source
2950
4
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)44>::CharacterNode()
Line
Count
Source
2950
4
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)59>::CharacterNode()
Line
Count
Source
2950
4
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
CharacterNode<(char)34>::CharacterNode()
Line
Count
Source
2950
4
  CharacterNode() {} // NOLINT(modernize-use-equals-default)
2951
2952
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
2953
2954
  std::string Evaluate(
2955
    std::vector<std::string> const& /*parameters*/,
2956
    cm::GenEx::Evaluation* /*eval*/,
2957
    GeneratorExpressionContent const* /*content*/,
2958
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
2959
0
  {
2960
0
    return { C };
2961
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
2962
};
2963
static CharacterNode<'>'> const angle_rNode;
2964
static CharacterNode<','> const commaNode;
2965
static CharacterNode<';'> const semicolonNode;
2966
static CharacterNode<'"'> const quoteNode;
2967
2968
struct CompilerIdNode : public cmGeneratorExpressionNode
2969
{
2970
  CompilerIdNode(char const* compilerLang)
2971
32
    : CompilerLanguage(compilerLang)
2972
32
  {
2973
32
  }
2974
2975
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
2976
2977
  std::string Evaluate(
2978
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
2979
    GeneratorExpressionContent const* content,
2980
    cmGeneratorExpressionDAGChecker* dagChecker) const override
2981
0
  {
2982
0
    if (!eval->HeadTarget) {
2983
0
      std::ostringstream e;
2984
0
      e << "$<" << this->CompilerLanguage
2985
0
        << "_COMPILER_ID> may only be used with binary targets.  It may "
2986
0
           "not be used with add_custom_command or add_custom_target.";
2987
0
      reportError(eval, content->GetOriginalExpression(), e.str());
2988
0
      return {};
2989
0
    }
2990
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
2991
0
                                      this->CompilerLanguage);
2992
0
  }
2993
2994
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
2995
                                   cm::GenEx::Evaluation* eval,
2996
                                   GeneratorExpressionContent const* content,
2997
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
2998
                                   std::string const& lang) const
2999
0
  {
3000
0
    std::string const& compilerId =
3001
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3002
0
        cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
3003
0
    if (parameters.empty()) {
3004
0
      return compilerId;
3005
0
    }
3006
0
    if (compilerId.empty()) {
3007
0
      return parameters.front().empty() ? "1" : "0";
3008
0
    }
3009
0
    static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
3010
3011
0
    for (auto const& param : parameters) {
3012
0
      if (!compilerIdValidator.find(param)) {
3013
0
        reportError(eval, content->GetOriginalExpression(),
3014
0
                    "Expression syntax not recognized.");
3015
0
        return std::string();
3016
0
      }
3017
3018
0
      if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
3019
0
        return "1";
3020
0
      }
3021
0
    }
3022
0
    return "0";
3023
0
  }
3024
3025
  char const* const CompilerLanguage;
3026
};
3027
3028
static CompilerIdNode const cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
3029
  cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"),
3030
  objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"),
3031
  hipCompilerIdNode("HIP"), ispcCompilerIdNode("ISPC");
3032
3033
struct CompilerVersionNode : public cmGeneratorExpressionNode
3034
{
3035
  CompilerVersionNode(char const* compilerLang)
3036
32
    : CompilerLanguage(compilerLang)
3037
32
  {
3038
32
  }
3039
3040
0
  int NumExpectedParameters() const override { return OneOrZeroParameters; }
3041
3042
  std::string Evaluate(
3043
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3044
    GeneratorExpressionContent const* content,
3045
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3046
0
  {
3047
0
    if (!eval->HeadTarget) {
3048
0
      std::ostringstream e;
3049
0
      e << "$<" << this->CompilerLanguage
3050
0
        << "_COMPILER_VERSION> may only be used with binary targets.  It "
3051
0
           "may not be used with add_custom_command or add_custom_target.";
3052
0
      reportError(eval, content->GetOriginalExpression(), e.str());
3053
0
      return {};
3054
0
    }
3055
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3056
0
                                      this->CompilerLanguage);
3057
0
  }
3058
3059
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3060
                                   cm::GenEx::Evaluation* eval,
3061
                                   GeneratorExpressionContent const* content,
3062
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3063
                                   std::string const& lang) const
3064
0
  {
3065
0
    std::string const& compilerVersion =
3066
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3067
0
        cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
3068
0
    if (parameters.empty()) {
3069
0
      return compilerVersion;
3070
0
    }
3071
3072
0
    static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
3073
0
    if (!compilerIdValidator.find(parameters.front())) {
3074
0
      reportError(eval, content->GetOriginalExpression(),
3075
0
                  "Expression syntax not recognized.");
3076
0
      return {};
3077
0
    }
3078
0
    if (compilerVersion.empty()) {
3079
0
      return parameters.front().empty() ? "1" : "0";
3080
0
    }
3081
3082
0
    return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
3083
0
                                         parameters.front(), compilerVersion)
3084
0
      ? "1"
3085
0
      : "0";
3086
0
  }
3087
3088
  char const* const CompilerLanguage;
3089
};
3090
3091
static CompilerVersionNode const cCompilerVersionNode("C"),
3092
  cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
3093
  objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"),
3094
  fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC"),
3095
  hipCompilerVersionNode("HIP");
3096
3097
struct CompilerFrontendVariantNode : public cmGeneratorExpressionNode
3098
{
3099
  CompilerFrontendVariantNode(char const* compilerLang)
3100
32
    : CompilerLanguage(compilerLang)
3101
32
  {
3102
32
  }
3103
3104
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3105
3106
  std::string Evaluate(
3107
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3108
    GeneratorExpressionContent const* content,
3109
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3110
0
  {
3111
0
    if (!eval->HeadTarget) {
3112
0
      std::ostringstream e;
3113
0
      e << "$<" << this->CompilerLanguage
3114
0
        << "_COMPILER_FRONTEND_VARIANT> may only be used with binary targets. "
3115
0
           " It may not be used with add_custom_command or add_custom_target.";
3116
0
      reportError(eval, content->GetOriginalExpression(), e.str());
3117
0
      return {};
3118
0
    }
3119
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3120
0
                                      this->CompilerLanguage);
3121
0
  }
3122
3123
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3124
                                   cm::GenEx::Evaluation* eval,
3125
                                   GeneratorExpressionContent const* content,
3126
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3127
                                   std::string const& lang) const
3128
0
  {
3129
0
    std::string const& compilerFrontendVariant =
3130
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3131
0
        cmStrCat("CMAKE_", lang, "_COMPILER_FRONTEND_VARIANT"));
3132
0
    if (parameters.empty()) {
3133
0
      return compilerFrontendVariant;
3134
0
    }
3135
0
    if (compilerFrontendVariant.empty()) {
3136
0
      return parameters.front().empty() ? "1" : "0";
3137
0
    }
3138
0
    static cmsys::RegularExpression compilerFrontendVariantValidator(
3139
0
      "^[A-Za-z0-9_]*$");
3140
3141
0
    for (auto const& param : parameters) {
3142
0
      if (!compilerFrontendVariantValidator.find(param)) {
3143
0
        reportError(eval, content->GetOriginalExpression(),
3144
0
                    "Expression syntax not recognized.");
3145
0
        return {};
3146
0
      }
3147
0
      if (strcmp(param.c_str(), compilerFrontendVariant.c_str()) == 0) {
3148
0
        return "1";
3149
0
      }
3150
0
    }
3151
0
    return "0";
3152
0
  }
3153
3154
  char const* const CompilerLanguage;
3155
};
3156
3157
static CompilerFrontendVariantNode const cCompilerFrontendVariantNode("C"),
3158
  cxxCompilerFrontendVariantNode("CXX"),
3159
  cudaCompilerFrontendVariantNode("CUDA"),
3160
  objcCompilerFrontendVariantNode("OBJC"),
3161
  objcxxCompilerFrontendVariantNode("OBJCXX"),
3162
  fortranCompilerFrontendVariantNode("Fortran"),
3163
  hipCompilerFrontendVariantNode("HIP"),
3164
  ispcCompilerFrontendVariantNode("ISPC");
3165
3166
struct PlatformIdNode : public cmGeneratorExpressionNode
3167
{
3168
4
  PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
3169
3170
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3171
3172
  std::string Evaluate(
3173
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3174
    GeneratorExpressionContent const* /*content*/,
3175
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3176
0
  {
3177
0
    std::string const& platformId =
3178
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
3179
0
    if (parameters.empty()) {
3180
0
      return platformId;
3181
0
    }
3182
3183
0
    if (platformId.empty()) {
3184
0
      return parameters.front().empty() ? "1" : "0";
3185
0
    }
3186
3187
0
    for (auto const& param : parameters) {
3188
0
      if (param == platformId) {
3189
0
        return "1";
3190
0
      }
3191
0
    }
3192
0
    return "0";
3193
0
  }
3194
};
3195
static struct PlatformIdNode platformIdNode;
3196
3197
template <cmSystemTools::CompareOp Op>
3198
struct VersionNode : public cmGeneratorExpressionNode
3199
{
3200
20
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)4>::VersionNode()
Line
Count
Source
3200
4
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)5>::VersionNode()
Line
Count
Source
3200
4
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)2>::VersionNode()
Line
Count
Source
3200
4
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)3>::VersionNode()
Line
Count
Source
3200
4
  VersionNode() {} // NOLINT(modernize-use-equals-default)
VersionNode<(cmSystemTools::CompareOp)1>::VersionNode()
Line
Count
Source
3200
4
  VersionNode() {} // NOLINT(modernize-use-equals-default)
3201
3202
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
3203
3204
  std::string Evaluate(
3205
    std::vector<std::string> const& parameters,
3206
    cm::GenEx::Evaluation* /*eval*/,
3207
    GeneratorExpressionContent const* /*content*/,
3208
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3209
0
  {
3210
0
    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
3211
0
      ? "1"
3212
0
      : "0";
3213
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
3214
};
3215
3216
static VersionNode<cmSystemTools::OP_GREATER> const versionGreaterNode;
3217
static VersionNode<cmSystemTools::OP_GREATER_EQUAL> const versionGreaterEqNode;
3218
static VersionNode<cmSystemTools::OP_LESS> const versionLessNode;
3219
static VersionNode<cmSystemTools::OP_LESS_EQUAL> const versionLessEqNode;
3220
static VersionNode<cmSystemTools::OP_EQUAL> const versionEqualNode;
3221
3222
static const struct CompileOnlyNode : public cmGeneratorExpressionNode
3223
{
3224
4
  CompileOnlyNode() {} // NOLINT(modernize-use-equals-default)
3225
3226
  std::string Evaluate(
3227
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3228
    GeneratorExpressionContent const* content,
3229
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3230
0
  {
3231
0
    if (!dagChecker) {
3232
0
      reportError(eval, content->GetOriginalExpression(),
3233
0
                  "$<COMPILE_ONLY:...> may only be used for linking");
3234
0
      return std::string();
3235
0
    }
3236
0
    if (dagChecker->GetTransitivePropertiesOnly()) {
3237
0
      return parameters.front();
3238
0
    }
3239
0
    return std::string{};
3240
0
  }
3241
} compileOnlyNode;
3242
3243
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
3244
{
3245
4
  LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
3246
3247
  std::string Evaluate(
3248
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3249
    GeneratorExpressionContent const* content,
3250
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3251
0
  {
3252
0
    if (!dagChecker) {
3253
0
      reportError(eval, content->GetOriginalExpression(),
3254
0
                  "$<LINK_ONLY:...> may only be used for linking");
3255
0
      return std::string();
3256
0
    }
3257
0
    if (!dagChecker->GetTransitivePropertiesOnlyCMP0131()) {
3258
0
      return parameters.front();
3259
0
    }
3260
0
    return std::string();
3261
0
  }
3262
} linkOnlyNode;
3263
3264
static const struct ConfigurationNode : public cmGeneratorExpressionNode
3265
{
3266
4
  ConfigurationNode() {} // NOLINT(modernize-use-equals-default)
3267
3268
0
  int NumExpectedParameters() const override { return 0; }
3269
3270
  std::string Evaluate(
3271
    std::vector<std::string> const& /*parameters*/,
3272
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* /*content*/,
3273
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3274
0
  {
3275
0
    eval->HadContextSensitiveCondition = true;
3276
0
    return eval->Context.Config;
3277
0
  }
3278
} configurationNode;
3279
3280
static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
3281
{
3282
4
  ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default)
3283
3284
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3285
3286
  std::string Evaluate(
3287
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3288
    GeneratorExpressionContent const* content,
3289
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
3290
0
  {
3291
0
    if (parameters.empty()) {
3292
0
      return configurationNode.Evaluate(parameters, eval, content, nullptr);
3293
0
    }
3294
3295
0
    eval->HadContextSensitiveCondition = true;
3296
3297
    // First, validate our arguments.
3298
0
    static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
3299
0
    bool firstParam = true;
3300
0
    for (auto const& param : parameters) {
3301
0
      if (!configValidator.find(param)) {
3302
0
        if (firstParam) {
3303
0
          reportError(eval, content->GetOriginalExpression(),
3304
0
                      "Expression syntax not recognized.");
3305
0
          return std::string();
3306
0
        }
3307
        // for backwards compat invalid config names are only errors as
3308
        // the first parameter
3309
0
        std::ostringstream e;
3310
        /* clang-format off */
3311
0
        e << "Warning evaluating generator expression:\n"
3312
0
          << "  " << content->GetOriginalExpression() << "\n"
3313
0
          << "The config name of \"" << param << "\" is invalid";
3314
        /* clang-format on */
3315
0
        eval->Context.LG->GetCMakeInstance()->IssueMessage(
3316
0
          MessageType::WARNING, e.str(), eval->Backtrace);
3317
0
      }
3318
0
      firstParam = false;
3319
0
    }
3320
3321
    // Partially determine the context(s) in which the expression should be
3322
    // evaluated.
3323
    //
3324
    // If CMPxxxx is NEW, the context is exactly one of the imported target's
3325
    // selected configuration, if applicable and if the target was imported
3326
    // from CPS, or the consuming target's configuration otherwise. Here, we
3327
    // determine if we are in that 'otherwise' branch.
3328
    //
3329
    // Longer term, we need a way for non-CPS users to match the selected
3330
    // configuration of the imported target. At that time, CPS should switch
3331
    // to that mechanism and the CPS-specific logic here should be dropped.
3332
    // (We can do that because CPS doesn't use generator expressions directly;
3333
    // rather, CMake generates them on import.)
3334
0
    bool const targetIsImported =
3335
0
      (eval->CurrentTarget && eval->CurrentTarget->IsImported());
3336
0
    bool const useConsumerConfig =
3337
0
      (targetIsImported &&
3338
0
       eval->CurrentTarget->Target->GetOrigin() != cmTarget::Origin::Cps);
3339
3340
0
    if (!targetIsImported || useConsumerConfig) {
3341
      // Does the consuming target's configuration match any of the arguments?
3342
0
      for (auto const& param : parameters) {
3343
0
        if (eval->Context.Config.empty()) {
3344
0
          if (param.empty()) {
3345
0
            return "1";
3346
0
          }
3347
0
        } else if (cmsysString_strcasecmp(param.c_str(),
3348
0
                                          eval->Context.Config.c_str()) == 0) {
3349
0
          return "1";
3350
0
        }
3351
0
      }
3352
0
    }
3353
3354
0
    if (targetIsImported) {
3355
0
      cmValue loc = nullptr;
3356
0
      cmValue imp = nullptr;
3357
0
      std::string suffix;
3358
0
      if (eval->CurrentTarget->Target->GetMappedConfig(eval->Context.Config,
3359
0
                                                       loc, imp, suffix)) {
3360
        // Finish determine the context(s) in which the expression should be
3361
        // evaluated. Note that we use the consumer's policy, so that end users
3362
        // can override the imported target's policy. This may be needed if
3363
        // upstream has changed their policy version without realizing that
3364
        // consumers were depending on the OLD behavior.
3365
0
        bool const oldPolicy = [&] {
3366
0
          if (!useConsumerConfig) {
3367
            // Targets imported from CPS shall use only the selected
3368
            // configuration of the imported target.
3369
0
            return false;
3370
0
          }
3371
0
          cmLocalGenerator const* const lg = eval->Context.LG;
3372
0
          switch (eval->HeadTarget->GetPolicyStatusCMP0199()) {
3373
0
            case cmPolicies::WARN:
3374
0
              if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
3375
0
                    "CMAKE_POLICY_WARNING_CMP0199")) {
3376
0
                lg->IssuePolicyWarning(
3377
0
                  cmPolicies::CMP0199, {},
3378
0
                  cmStrCat("Evaluation of $<CONFIG> for imported target  \""_s,
3379
0
                           eval->CurrentTarget->GetName(), "\", used by \""_s,
3380
0
                           eval->HeadTarget->GetName(),
3381
0
                           "\", may match multiple configurations."_s),
3382
0
                  eval->Backtrace);
3383
0
              }
3384
0
              CM_FALLTHROUGH;
3385
0
            case cmPolicies::OLD:
3386
0
              return true;
3387
0
            case cmPolicies::NEW:
3388
0
              return false;
3389
0
          }
3390
3391
          // Should be unreachable
3392
0
          assert(false);
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
  assert(false && "Unreachable code. Not a valid policy");
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
  assert(false && "Unreachable code. Not a valid policy");
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
}