Coverage Report

Created: 2026-06-15 07:03

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