Coverage Report

Created: 2026-03-12 06:35

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
    switch (eval->Context.LG->GetPolicyStatus(cmPolicies::CMP0085)) {
418
0
      case cmPolicies::WARN:
419
0
        if (parameters.front().empty()) {
420
0
          check = true;
421
0
          checkValues.assign(parameters[1], cmList::EmptyElements::Yes);
422
0
        }
423
0
        CM_FALLTHROUGH;
424
0
      case cmPolicies::OLD:
425
0
        values.assign(parameters[1]);
426
0
        if (check && values != checkValues) {
427
0
          std::ostringstream e;
428
0
          e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
429
0
            << "\nSearch Item:\n  \"" << parameters.front()
430
0
            << "\"\nList:\n  \"" << parameters[1] << "\"\n";
431
0
          eval->Context.LG->GetCMakeInstance()->IssueMessage(
432
0
            MessageType ::AUTHOR_WARNING, e.str(), 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
                std::string const err =
2897
0
                  cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0199),
2898
0
                           "\nEvaluation of $<CONFIG> for imported target  \"",
2899
0
                           eval->CurrentTarget->GetName(), "\", used by \"",
2900
0
                           eval->HeadTarget->GetName(),
2901
0
                           "\", may match multiple configurations.\n");
2902
0
                lg->GetCMakeInstance()->IssueMessage(
2903
0
                  MessageType ::AUTHOR_WARNING, err, eval->Backtrace);
2904
0
              }
2905
0
              CM_FALLTHROUGH;
2906
0
            case cmPolicies::OLD:
2907
0
              return true;
2908
0
            case cmPolicies::NEW:
2909
0
              return false;
2910
0
          }
2911
2912
          // Should be unreachable
2913
0
          assert(false);
2914
0
          return false;
2915
0
        }();
2916
2917
0
        if (oldPolicy) {
2918
          // If CMPxxxx is OLD (and we aren't dealing with a target imported
2919
          // form CPS), we already evaluated in the context of the consuming
2920
          // target. Next, for imported targets, we will evaluate based on the
2921
          // mapped configurations.
2922
          //
2923
          // If the target has a MAP_IMPORTED_CONFIG_<CONFIG> property for the
2924
          // consumer's <CONFIG>, we will match *any* config in that list,
2925
          // regardless of whether it's valid or of what GetMappedConfig
2926
          // actually picked. This will result in $<CONFIG> producing '1' for
2927
          // multiple configs, and is almost certainly wrong, but it's what
2928
          // CMake did for a very long time, and... Hyrum's Law.
2929
0
          cmList mappedConfigs;
2930
0
          std::string mapProp =
2931
0
            cmStrCat("MAP_IMPORTED_CONFIG_",
2932
0
                     cmSystemTools::UpperCase(eval->Context.Config));
2933
0
          if (cmValue mapValue = eval->CurrentTarget->GetProperty(mapProp)) {
2934
0
            mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue));
2935
2936
0
            for (auto const& param : parameters) {
2937
0
              if (cm::contains(mappedConfigs,
2938
0
                               cmSystemTools::UpperCase(param))) {
2939
0
                return "1";
2940
0
              }
2941
0
            }
2942
2943
0
            return "0";
2944
0
          }
2945
0
        }
2946
2947
        // Finally, check if we selected (possibly via mapping) a configuration
2948
        // for this imported target, and if we should evaluate the expression
2949
        // in the context of the same.
2950
        //
2951
        // For targets imported from CPS, this is the only context we evaluate
2952
        // the expression.
2953
0
        if (!suffix.empty()) {
2954
0
          for (auto const& param : parameters) {
2955
0
            if (cmStrCat('_', cmSystemTools::UpperCase(param)) == suffix) {
2956
0
              return "1";
2957
0
            }
2958
0
          }
2959
0
        }
2960
0
      }
2961
0
    }
2962
2963
0
    return "0";
2964
0
  }
2965
} configurationTestNode;
2966
2967
static const struct JoinNode : public cmGeneratorExpressionNode
2968
{
2969
4
  JoinNode() {} // NOLINT(modernize-use-equals-default)
2970
2971
0
  int NumExpectedParameters() const override { return 2; }
2972
2973
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
2974
2975
  std::string Evaluate(
2976
    std::vector<std::string> const& parameters,
2977
    cm::GenEx::Evaluation* /*eval*/,
2978
    GeneratorExpressionContent const* /*content*/,
2979
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
2980
0
  {
2981
0
    return cmList{ parameters.front() }.join(parameters[1]);
2982
0
  }
2983
} joinNode;
2984
2985
static const struct CompileLanguageNode : public cmGeneratorExpressionNode
2986
{
2987
4
  CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
2988
2989
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
2990
2991
  std::string Evaluate(
2992
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
2993
    GeneratorExpressionContent const* content,
2994
    cmGeneratorExpressionDAGChecker* dagChecker) const override
2995
0
  {
2996
0
    if (eval->Context.Language.empty() &&
2997
0
        (!dagChecker || !dagChecker->EvaluatingCompileExpression())) {
2998
0
      reportError(
2999
0
        eval, content->GetOriginalExpression(),
3000
0
        "$<COMPILE_LANGUAGE:...> may only be used to specify include "
3001
0
        "directories, compile definitions, compile options, and to evaluate "
3002
0
        "components of the file(GENERATE) command.");
3003
0
      return std::string();
3004
0
    }
3005
3006
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3007
0
    std::string genName = gg->GetName();
3008
0
    if (genName.find("Makefiles") == std::string::npos &&
3009
0
        genName.find("Ninja") == std::string::npos &&
3010
0
        genName.find("Visual Studio") == std::string::npos &&
3011
0
        genName.find("Xcode") == std::string::npos &&
3012
0
        genName.find("Watcom WMake") == std::string::npos &&
3013
0
        genName.find("FASTBuild") == std::string::npos &&
3014
0
        genName.find("Green Hills MULTI") == std::string::npos) {
3015
0
      reportError(eval, content->GetOriginalExpression(),
3016
0
                  "$<COMPILE_LANGUAGE:...> not supported for this generator.");
3017
0
      return std::string();
3018
0
    }
3019
0
    if (parameters.empty()) {
3020
0
      return eval->Context.Language;
3021
0
    }
3022
3023
0
    for (auto const& param : parameters) {
3024
0
      if (eval->Context.Language == param) {
3025
0
        return "1";
3026
0
      }
3027
0
    }
3028
0
    return "0";
3029
0
  }
3030
} languageNode;
3031
3032
static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
3033
{
3034
4
  CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
3035
3036
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3037
3038
  std::string Evaluate(
3039
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3040
    GeneratorExpressionContent const* content,
3041
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3042
0
  {
3043
0
    if (!eval->HeadTarget ||
3044
0
        (eval->Context.Language.empty() &&
3045
0
         (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) {
3046
      // reportError(eval, content->GetOriginalExpression(), "");
3047
0
      reportError(
3048
0
        eval, content->GetOriginalExpression(),
3049
0
        "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary "
3050
0
        "targets "
3051
0
        "to specify include directories, compile definitions, and compile "
3052
0
        "options.  It may not be used with the add_custom_command, "
3053
0
        "add_custom_target, or file(GENERATE) commands.");
3054
0
      return std::string();
3055
0
    }
3056
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3057
0
    std::string genName = gg->GetName();
3058
0
    if (genName.find("Makefiles") == std::string::npos &&
3059
0
        genName.find("Ninja") == std::string::npos &&
3060
0
        genName.find("FASTBuild") == std::string::npos &&
3061
0
        genName.find("Visual Studio") == std::string::npos &&
3062
0
        genName.find("Xcode") == std::string::npos &&
3063
0
        genName.find("Watcom WMake") == std::string::npos &&
3064
0
        genName.find("Green Hills MULTI") == std::string::npos) {
3065
0
      reportError(
3066
0
        eval, content->GetOriginalExpression(),
3067
0
        "$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
3068
0
      return std::string();
3069
0
    }
3070
3071
0
    std::string const& lang = eval->Context.Language;
3072
0
    if (lang == parameters.front()) {
3073
0
      std::vector<std::string> idParameter((parameters.cbegin() + 1),
3074
0
                                           parameters.cend());
3075
0
      return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
3076
0
        idParameter, eval, content, dagChecker, lang);
3077
0
    }
3078
0
    return "0";
3079
0
  }
3080
} languageAndIdNode;
3081
3082
static const struct LinkLanguageNode : public cmGeneratorExpressionNode
3083
{
3084
4
  LinkLanguageNode() {} // NOLINT(modernize-use-equals-default)
3085
3086
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3087
3088
  std::string Evaluate(
3089
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3090
    GeneratorExpressionContent const* content,
3091
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3092
0
  {
3093
0
    if (!eval->HeadTarget || !dagChecker ||
3094
0
        !(dagChecker->EvaluatingLinkExpression() ||
3095
0
          dagChecker->EvaluatingLinkLibraries() ||
3096
0
          dagChecker->EvaluatingLinkerLauncher())) {
3097
0
      reportError(eval, content->GetOriginalExpression(),
3098
0
                  "$<LINK_LANGUAGE:...> may only be used with binary targets "
3099
0
                  "to specify link libraries, link directories, link options "
3100
0
                  "and link depends.");
3101
0
      return std::string();
3102
0
    }
3103
0
    if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) {
3104
0
      reportError(
3105
0
        eval, content->GetOriginalExpression(),
3106
0
        "$<LINK_LANGUAGE> is not supported in link libraries expression.");
3107
0
      return std::string();
3108
0
    }
3109
3110
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3111
0
    std::string genName = gg->GetName();
3112
0
    if (genName.find("Makefiles") == std::string::npos &&
3113
0
        genName.find("Ninja") == std::string::npos &&
3114
0
        genName.find("FASTBuild") == std::string::npos &&
3115
0
        genName.find("Visual Studio") == std::string::npos &&
3116
0
        genName.find("Xcode") == std::string::npos &&
3117
0
        genName.find("Watcom WMake") == std::string::npos &&
3118
0
        genName.find("Green Hills MULTI") == std::string::npos) {
3119
0
      reportError(eval, content->GetOriginalExpression(),
3120
0
                  "$<LINK_LANGUAGE:...> not supported for this generator.");
3121
0
      return std::string();
3122
0
    }
3123
3124
0
    if (dagChecker->EvaluatingLinkLibraries()) {
3125
0
      eval->HadHeadSensitiveCondition = true;
3126
0
      eval->HadLinkLanguageSensitiveCondition = true;
3127
0
    }
3128
3129
0
    if (parameters.empty()) {
3130
0
      return eval->Context.Language;
3131
0
    }
3132
3133
0
    for (auto const& param : parameters) {
3134
0
      if (eval->Context.Language == param) {
3135
0
        return "1";
3136
0
      }
3137
0
    }
3138
0
    return "0";
3139
0
  }
3140
} linkLanguageNode;
3141
3142
namespace {
3143
struct LinkerId
3144
{
3145
  static std::string Evaluate(std::vector<std::string> const& parameters,
3146
                              cm::GenEx::Evaluation* eval,
3147
                              GeneratorExpressionContent const* content,
3148
                              std::string const& lang)
3149
0
  {
3150
0
    std::string const& linkerId =
3151
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
3152
0
                                                         "_COMPILER_ID");
3153
0
    if (parameters.empty()) {
3154
0
      return linkerId;
3155
0
    }
3156
0
    if (linkerId.empty()) {
3157
0
      return parameters.front().empty() ? "1" : "0";
3158
0
    }
3159
0
    static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$");
3160
3161
0
    for (auto const& param : parameters) {
3162
0
      if (!linkerIdValidator.find(param)) {
3163
0
        reportError(eval, content->GetOriginalExpression(),
3164
0
                    "Expression syntax not recognized.");
3165
0
        return std::string();
3166
0
      }
3167
3168
0
      if (param == linkerId) {
3169
0
        return "1";
3170
0
      }
3171
0
    }
3172
0
    return "0";
3173
0
  }
3174
};
3175
}
3176
3177
static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
3178
{
3179
4
  LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
3180
3181
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3182
3183
  std::string Evaluate(
3184
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3185
    GeneratorExpressionContent const* content,
3186
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3187
0
  {
3188
0
    if (!eval->HeadTarget || !dagChecker ||
3189
0
        !(dagChecker->EvaluatingLinkExpression() ||
3190
0
          dagChecker->EvaluatingLinkLibraries() ||
3191
0
          dagChecker->EvaluatingLinkerLauncher())) {
3192
0
      reportError(
3193
0
        eval, content->GetOriginalExpression(),
3194
0
        "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
3195
0
        "to specify link libraries, link directories, link options, and "
3196
0
        "link "
3197
0
        "depends.");
3198
0
      return std::string();
3199
0
    }
3200
3201
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
3202
0
    std::string genName = gg->GetName();
3203
0
    if (genName.find("Makefiles") == std::string::npos &&
3204
0
        genName.find("Ninja") == std::string::npos &&
3205
0
        genName.find("FASTBuild") == std::string::npos &&
3206
0
        genName.find("Visual Studio") == std::string::npos &&
3207
0
        genName.find("Xcode") == std::string::npos &&
3208
0
        genName.find("Watcom WMake") == std::string::npos &&
3209
0
        genName.find("Green Hills MULTI") == std::string::npos) {
3210
0
      reportError(
3211
0
        eval, content->GetOriginalExpression(),
3212
0
        "$<LINK_LANG_AND_ID:lang,id> not supported for this generator.");
3213
0
      return std::string();
3214
0
    }
3215
3216
0
    if (dagChecker->EvaluatingLinkLibraries()) {
3217
0
      eval->HadHeadSensitiveCondition = true;
3218
0
      eval->HadLinkLanguageSensitiveCondition = true;
3219
0
    }
3220
3221
0
    std::string const& lang = eval->Context.Language;
3222
0
    if (lang == parameters.front()) {
3223
0
      std::vector<std::string> idParameter((parameters.cbegin() + 1),
3224
0
                                           parameters.cend());
3225
0
      return LinkerId::Evaluate(idParameter, eval, content, lang);
3226
0
    }
3227
0
    return "0";
3228
0
  }
3229
} linkLanguageAndIdNode;
3230
3231
struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
3232
{
3233
  CompilerLinkerIdNode(char const* lang)
3234
28
    : Language(lang)
3235
28
  {
3236
28
  }
3237
3238
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3239
3240
  std::string Evaluate(
3241
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3242
    GeneratorExpressionContent const* content,
3243
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3244
0
  {
3245
0
    if (!eval->HeadTarget) {
3246
0
      reportError(
3247
0
        eval, content->GetOriginalExpression(),
3248
0
        cmStrCat(
3249
0
          "$<", this->Language,
3250
0
          "_COMPILER_LINKER_ID> may only be used with binary targets. It may "
3251
0
          "not be used with add_custom_command or add_custom_target."));
3252
0
      return {};
3253
0
    }
3254
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3255
0
                                      this->Language);
3256
0
  }
3257
3258
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3259
                                   cm::GenEx::Evaluation* eval,
3260
                                   GeneratorExpressionContent const* content,
3261
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3262
                                   std::string const& lang) const
3263
0
  {
3264
0
    std::string const& compilerLinkerId =
3265
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3266
0
        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
3267
0
    if (parameters.empty()) {
3268
0
      return compilerLinkerId;
3269
0
    }
3270
0
    if (compilerLinkerId.empty()) {
3271
0
      return parameters.front().empty() ? "1" : "0";
3272
0
    }
3273
0
    static cmsys::RegularExpression compilerLinkerIdValidator(
3274
0
      "^[A-Za-z0-9_]*$");
3275
3276
0
    for (auto const& param : parameters) {
3277
0
      if (!compilerLinkerIdValidator.find(param)) {
3278
0
        reportError(eval, content->GetOriginalExpression(),
3279
0
                    "Expression syntax not recognized.");
3280
0
        return std::string();
3281
0
      }
3282
3283
0
      if (param == compilerLinkerId) {
3284
0
        return "1";
3285
0
      }
3286
0
    }
3287
0
    return "0";
3288
0
  }
3289
3290
  char const* const Language;
3291
};
3292
3293
static CompilerLinkerIdNode const cCompilerLinkerIdNode("C"),
3294
  cxxCompilerLinkerIdNode("CXX"), cudaCompilerLinkerIdNode("CUDA"),
3295
  objcCompilerLinkerIdNode("OBJC"), objcxxCompilerLinkerIdNode("OBJCXX"),
3296
  fortranCompilerLinkerIdNode("Fortran"), hipCompilerLinkerIdNode("HIP");
3297
3298
struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
3299
{
3300
  CompilerLinkerFrontendVariantNode(char const* lang)
3301
28
    : Language(lang)
3302
28
  {
3303
28
  }
3304
3305
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3306
3307
  std::string Evaluate(
3308
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3309
    GeneratorExpressionContent const* content,
3310
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3311
0
  {
3312
0
    if (!eval->HeadTarget) {
3313
0
      reportError(
3314
0
        eval, content->GetOriginalExpression(),
3315
0
        cmStrCat(
3316
0
          "$<", this->Language,
3317
0
          "_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary "
3318
0
          "targets. It may not be used with add_custom_command or "
3319
0
          "add_custom_target."));
3320
0
      return {};
3321
0
    }
3322
0
    return this->EvaluateWithLanguage(parameters, eval, content, dagChecker,
3323
0
                                      this->Language);
3324
0
  }
3325
3326
  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
3327
                                   cm::GenEx::Evaluation* eval,
3328
                                   GeneratorExpressionContent const* content,
3329
                                   cmGeneratorExpressionDAGChecker* /*unused*/,
3330
                                   std::string const& lang) const
3331
0
  {
3332
0
    std::string const& compilerLinkerFrontendVariant =
3333
0
      eval->Context.LG->GetMakefile()->GetSafeDefinition(
3334
0
        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
3335
0
    if (parameters.empty()) {
3336
0
      return compilerLinkerFrontendVariant;
3337
0
    }
3338
0
    if (compilerLinkerFrontendVariant.empty()) {
3339
0
      return parameters.front().empty() ? "1" : "0";
3340
0
    }
3341
0
    static cmsys::RegularExpression compilerLinkerFrontendVariantValidator(
3342
0
      "^[A-Za-z0-9_]*$");
3343
3344
0
    for (auto const& param : parameters) {
3345
0
      if (!compilerLinkerFrontendVariantValidator.find(param)) {
3346
0
        reportError(eval, content->GetOriginalExpression(),
3347
0
                    "Expression syntax not recognized.");
3348
0
        return {};
3349
0
      }
3350
0
      if (param == compilerLinkerFrontendVariant) {
3351
0
        return "1";
3352
0
      }
3353
0
    }
3354
0
    return "0";
3355
0
  }
3356
3357
  char const* const Language;
3358
};
3359
3360
static CompilerLinkerFrontendVariantNode const
3361
  cCompilerLinkerFrontendVariantNode("C"),
3362
  cxxCompilerLinkerFrontendVariantNode("CXX"),
3363
  cudaCompilerLinkerFrontendVariantNode("CUDA"),
3364
  objcCompilerLinkerFrontendVariantNode("OBJC"),
3365
  objcxxCompilerLinkerFrontendVariantNode("OBJCXX"),
3366
  fortranCompilerLinkerFrontendVariantNode("Fortran"),
3367
  hipCompilerLinkerFrontendVariantNode("HIP");
3368
3369
static const struct LinkLibraryNode : public cmGeneratorExpressionNode
3370
{
3371
4
  LinkLibraryNode() {} // NOLINT(modernize-use-equals-default)
3372
3373
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3374
3375
  std::string Evaluate(
3376
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3377
    GeneratorExpressionContent const* content,
3378
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3379
0
  {
3380
0
    using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
3381
3382
0
    if (!eval->HeadTarget || !dagChecker ||
3383
0
        !dagChecker->EvaluatingLinkLibraries(nullptr,
3384
0
                                             ForGenex::LINK_LIBRARY)) {
3385
0
      reportError(eval, content->GetOriginalExpression(),
3386
0
                  "$<LINK_LIBRARY:...> may only be used with binary targets "
3387
0
                  "to specify link libraries through 'LINK_LIBRARIES', "
3388
0
                  "'INTERFACE_LINK_LIBRARIES', and "
3389
0
                  "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
3390
0
      return std::string();
3391
0
    }
3392
3393
0
    cmList list{ parameters.begin(), parameters.end() };
3394
0
    if (list.empty()) {
3395
0
      reportError(
3396
0
        eval, content->GetOriginalExpression(),
3397
0
        "$<LINK_LIBRARY:...> expects a feature name as first argument.");
3398
0
      return std::string();
3399
0
    }
3400
0
    if (list.size() == 1) {
3401
      // no libraries specified, ignore this genex
3402
0
      return std::string();
3403
0
    }
3404
3405
0
    static cmsys::RegularExpression featureNameValidator("^[A-Za-z0-9_]+$");
3406
0
    auto const& feature = list.front();
3407
0
    if (!featureNameValidator.find(feature)) {
3408
0
      reportError(eval, content->GetOriginalExpression(),
3409
0
                  cmStrCat("The feature name '", feature,
3410
0
                           "' contains invalid characters."));
3411
0
      return std::string();
3412
0
    }
3413
3414
0
    auto const LL_BEGIN = cmStrCat("<LINK_LIBRARY:", feature, '>');
3415
0
    auto const LL_END = cmStrCat("</LINK_LIBRARY:", feature, '>');
3416
3417
    // filter out $<LINK_LIBRARY:..> tags with same feature
3418
    // and raise an error for any different feature
3419
0
    cm::erase_if(list, [&](std::string const& item) -> bool {
3420
0
      return item == LL_BEGIN || item == LL_END;
3421
0
    });
3422
0
    auto it =
3423
0
      std::find_if(list.cbegin() + 1, list.cend(),
3424
0
                   [&feature](std::string const& item) -> bool {
3425
0
                     return cmHasPrefix(item, "<LINK_LIBRARY:"_s) &&
3426
0
                       item.substr(14, item.find('>', 14) - 14) != feature;
3427
0
                   });
3428
0
    if (it != list.cend()) {
3429
0
      reportError(
3430
0
        eval, content->GetOriginalExpression(),
3431
0
        "$<LINK_LIBRARY:...> with different features cannot be nested.");
3432
0
      return std::string();
3433
0
    }
3434
    // $<LINK_GROUP:...> must not appear as part of $<LINK_LIBRARY:...>
3435
0
    it = std::find_if(list.cbegin() + 1, list.cend(),
3436
0
                      [](std::string const& item) -> bool {
3437
0
                        return cmHasPrefix(item, "<LINK_GROUP:"_s);
3438
0
                      });
3439
0
    if (it != list.cend()) {
3440
0
      reportError(eval, content->GetOriginalExpression(),
3441
0
                  "$<LINK_GROUP:...> cannot be nested inside a "
3442
0
                  "$<LINK_LIBRARY:...> expression.");
3443
0
      return std::string();
3444
0
    }
3445
3446
0
    list.front() = LL_BEGIN;
3447
0
    list.push_back(LL_END);
3448
3449
0
    return list.to_string();
3450
0
  }
3451
} linkLibraryNode;
3452
3453
static const struct LinkGroupNode : public cmGeneratorExpressionNode
3454
{
3455
4
  LinkGroupNode() {} // NOLINT(modernize-use-equals-default)
3456
3457
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3458
3459
  std::string Evaluate(
3460
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3461
    GeneratorExpressionContent const* content,
3462
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3463
0
  {
3464
0
    using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
3465
3466
0
    if (!eval->HeadTarget || !dagChecker ||
3467
0
        !dagChecker->EvaluatingLinkLibraries(nullptr, ForGenex::LINK_GROUP)) {
3468
0
      reportError(
3469
0
        eval, content->GetOriginalExpression(),
3470
0
        "$<LINK_GROUP:...> may only be used with binary targets "
3471
0
        "to specify group of link libraries through 'LINK_LIBRARIES', "
3472
0
        "'INTERFACE_LINK_LIBRARIES', and "
3473
0
        "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
3474
0
      return std::string();
3475
0
    }
3476
3477
0
    cmList list{ parameters.begin(), parameters.end() };
3478
0
    if (list.empty()) {
3479
0
      reportError(
3480
0
        eval, content->GetOriginalExpression(),
3481
0
        "$<LINK_GROUP:...> expects a feature name as first argument.");
3482
0
      return std::string();
3483
0
    }
3484
    // $<LINK_GROUP:..> cannot be nested
3485
0
    if (std::find_if(list.cbegin(), list.cend(),
3486
0
                     [](std::string const& item) -> bool {
3487
0
                       return cmHasPrefix(item, "<LINK_GROUP"_s);
3488
0
                     }) != list.cend()) {
3489
0
      reportError(eval, content->GetOriginalExpression(),
3490
0
                  "$<LINK_GROUP:...> cannot be nested.");
3491
0
      return std::string();
3492
0
    }
3493
0
    if (list.size() == 1) {
3494
      // no libraries specified, ignore this genex
3495
0
      return std::string();
3496
0
    }
3497
3498
0
    static cmsys::RegularExpression featureNameValidator("^[A-Za-z0-9_]+$");
3499
0
    auto const& feature = list.front();
3500
0
    if (!featureNameValidator.find(feature)) {
3501
0
      reportError(eval, content->GetOriginalExpression(),
3502
0
                  cmStrCat("The feature name '", feature,
3503
0
                           "' contains invalid characters."));
3504
0
      return std::string();
3505
0
    }
3506
3507
0
    auto const LG_BEGIN = cmStrCat(
3508
0
      "<LINK_GROUP:", feature, ':',
3509
0
      cmJoin(cmRange<decltype(list.cbegin())>(list.cbegin() + 1, list.cend()),
3510
0
             "|"_s),
3511
0
      '>');
3512
0
    auto const LG_END = cmStrCat("</LINK_GROUP:", feature, '>');
3513
3514
0
    list.front() = LG_BEGIN;
3515
0
    list.push_back(LG_END);
3516
3517
0
    return list.to_string();
3518
0
  }
3519
} linkGroupNode;
3520
3521
static const struct HostLinkNode : public cmGeneratorExpressionNode
3522
{
3523
4
  HostLinkNode() {} // NOLINT(modernize-use-equals-default)
3524
3525
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3526
3527
  std::string Evaluate(
3528
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3529
    GeneratorExpressionContent const* content,
3530
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3531
0
  {
3532
0
    if (!eval->HeadTarget || !dagChecker ||
3533
0
        !dagChecker->EvaluatingLinkOptionsExpression()) {
3534
0
      reportError(eval, content->GetOriginalExpression(),
3535
0
                  "$<HOST_LINK:...> may only be used with binary targets "
3536
0
                  "to specify link options.");
3537
0
      return std::string();
3538
0
    }
3539
3540
0
    return eval->HeadTarget->IsDeviceLink() ? std::string()
3541
0
                                            : cmList::to_string(parameters);
3542
0
  }
3543
} hostLinkNode;
3544
3545
static const struct DeviceLinkNode : public cmGeneratorExpressionNode
3546
{
3547
4
  DeviceLinkNode() {} // NOLINT(modernize-use-equals-default)
3548
3549
0
  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
3550
3551
  std::string Evaluate(
3552
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3553
    GeneratorExpressionContent const* content,
3554
    cmGeneratorExpressionDAGChecker* dagChecker) const override
3555
0
  {
3556
0
    if (!eval->HeadTarget || !dagChecker ||
3557
0
        !dagChecker->EvaluatingLinkOptionsExpression()) {
3558
0
      reportError(eval, content->GetOriginalExpression(),
3559
0
                  "$<DEVICE_LINK:...> may only be used with binary targets "
3560
0
                  "to specify link options.");
3561
0
      return std::string();
3562
0
    }
3563
3564
0
    if (eval->HeadTarget->IsDeviceLink()) {
3565
0
      cmList list{ parameters.begin(), parameters.end() };
3566
0
      auto const DL_BEGIN = "<DEVICE_LINK>"_s;
3567
0
      auto const DL_END = "</DEVICE_LINK>"_s;
3568
0
      cm::erase_if(list, [&](std::string const& item) {
3569
0
        return item == DL_BEGIN || item == DL_END;
3570
0
      });
3571
3572
0
      list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
3573
0
      list.push_back(static_cast<std::string>(DL_END));
3574
3575
0
      return list.to_string();
3576
0
    }
3577
3578
0
    return std::string();
3579
0
  }
3580
} deviceLinkNode;
3581
3582
namespace {
3583
bool GetFileSet(std::vector<std::string> const& parameters,
3584
                cm::GenEx::Evaluation* eval,
3585
                GeneratorExpressionContent const* content,
3586
                cmGeneratorTarget const*& target,
3587
                cmGeneratorFileSet const*& fileSet)
3588
0
{
3589
0
  auto const& fileSetName = parameters[0];
3590
0
  auto targetName = parameters[1];
3591
0
  fileSet = nullptr;
3592
3593
0
  auto const TARGET = "TARGET:"_s;
3594
3595
0
  if (cmHasPrefix(targetName, TARGET)) {
3596
0
    targetName = targetName.substr(TARGET.length());
3597
0
    if (targetName.empty()) {
3598
0
      reportError(eval, content->GetOriginalExpression(),
3599
0
                  cmStrCat("No value provided for the ", TARGET, " option."));
3600
0
      return false;
3601
0
    }
3602
3603
0
    cmLocalGenerator const* lg = eval->CurrentTarget
3604
0
      ? eval->CurrentTarget->GetLocalGenerator()
3605
0
      : eval->Context.LG;
3606
0
    target = lg->FindGeneratorTargetToUse(targetName);
3607
0
    if (!target) {
3608
0
      reportError(eval, content->GetOriginalExpression(),
3609
0
                  cmStrCat("Non-existent target: ", targetName));
3610
0
      return false;
3611
0
    }
3612
0
    fileSet = target->GetFileSet(fileSetName);
3613
0
  } else {
3614
0
    reportError(eval, content->GetOriginalExpression(),
3615
0
                cmStrCat("Invalid option. ", TARGET, " expected."));
3616
0
    return false;
3617
0
  }
3618
0
  return true;
3619
0
}
3620
}
3621
3622
static const struct FileSetExistsNode : public cmGeneratorExpressionNode
3623
{
3624
4
  FileSetExistsNode() {} // NOLINT(modernize-use-equals-default)
3625
3626
  // This node handles errors on parameter count itself.
3627
0
  int NumExpectedParameters() const override { return 2; }
3628
3629
  std::string Evaluate(
3630
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3631
    GeneratorExpressionContent const* content,
3632
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3633
0
  {
3634
0
    if (parameters[0].empty()) {
3635
0
      reportError(
3636
0
        eval, content->GetOriginalExpression(),
3637
0
        "$<FILE_SET_EXISTS:fileset,TARGET:tgt> expression requires a "
3638
0
        "non-empty FILE_SET name.");
3639
0
      return std::string{};
3640
0
    }
3641
3642
0
    cmGeneratorTarget const* target = nullptr;
3643
0
    cmGeneratorFileSet const* fileSet = nullptr;
3644
0
    if (!GetFileSet(parameters, eval, content, target, fileSet)) {
3645
0
      return std::string{};
3646
0
    }
3647
3648
0
    return fileSet ? "1" : "0";
3649
0
  }
3650
} fileSetExistsNode;
3651
3652
static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
3653
{
3654
4
  FileSetPropertyNode() {} // NOLINT(modernize-use-equals-default)
3655
3656
  // This node handles errors on parameter count itself.
3657
0
  int NumExpectedParameters() const override { return 3; }
3658
3659
  std::string Evaluate(
3660
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3661
    GeneratorExpressionContent const* content,
3662
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
3663
0
  {
3664
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3665
3666
0
    std::string const& fileSetName = parameters.front();
3667
0
    std::string const& propertyName = parameters.back();
3668
3669
0
    if (fileSetName.empty() && propertyName.empty()) {
3670
0
      reportError(eval, content->GetOriginalExpression(),
3671
0
                  "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression "
3672
0
                  "requires a non-empty FILE_SET name and property name.");
3673
0
      return std::string{};
3674
0
    }
3675
0
    if (fileSetName.empty()) {
3676
0
      reportError(
3677
0
        eval, content->GetOriginalExpression(),
3678
0
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
3679
0
        "non-empty FILE_SET name.");
3680
0
      return std::string{};
3681
0
    }
3682
0
    if (propertyName.empty()) {
3683
0
      reportError(
3684
0
        eval, content->GetOriginalExpression(),
3685
0
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
3686
0
        "non-empty property name.");
3687
0
      return std::string{};
3688
0
    }
3689
0
    if (!propertyNameValidator.find(propertyName)) {
3690
0
      reportError(eval, content->GetOriginalExpression(),
3691
0
                  "Property name not supported.");
3692
0
      return std::string{};
3693
0
    }
3694
3695
0
    cmGeneratorTarget const* target = nullptr;
3696
0
    cmGeneratorFileSet const* fileSet = nullptr;
3697
0
    if (!GetFileSet(parameters, eval, content, target, fileSet)) {
3698
0
      return std::string{};
3699
0
    }
3700
0
    if (!fileSet) {
3701
0
      reportError(
3702
0
        eval, content->GetOriginalExpression(),
3703
0
        cmStrCat("FILE_SET \"", fileSetName, "\" is not known from CMake."));
3704
0
      return std::string{};
3705
0
    }
3706
3707
0
    auto result = fileSet->GetProperty(propertyName);
3708
3709
0
    if (propertyName == "BASE_DIRS"_s || propertyName == "SOURCES"_s ||
3710
0
        propertyName == "INTERFACE_SOURCES"_s) {
3711
0
      cmGeneratorExpressionDAGChecker dagChecker{
3712
0
        target,           propertyName,  content,
3713
0
        dagCheckerParent, eval->Context, eval->Backtrace,
3714
0
      };
3715
0
      switch (dagChecker.Check()) {
3716
0
        case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
3717
0
          dagChecker.ReportError(eval, content->GetOriginalExpression());
3718
0
          return std::string{};
3719
0
        case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
3720
          // No error. We just skip cyclic references.
3721
0
          return std::string{};
3722
0
        case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
3723
0
        case cmGeneratorExpressionDAGChecker::DAG:
3724
0
          break;
3725
0
      }
3726
3727
0
      return cmGeneratorExpression::StripEmptyListElements(
3728
0
        this->EvaluateDependentExpression(result, eval, target, &dagChecker,
3729
0
                                          target));
3730
0
    }
3731
3732
0
    return result;
3733
0
  }
3734
} fileSetPropertyNode;
3735
3736
namespace {
3737
bool GetSourceFile(
3738
  cmRange<std::vector<std::string>::const_iterator> parameters,
3739
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
3740
  cmSourceFile*& sourceFile)
3741
0
{
3742
0
  auto sourceName = *parameters.begin();
3743
0
  auto* makefile = eval->Context.LG->GetMakefile();
3744
0
  sourceFile = nullptr;
3745
3746
0
  if (parameters.size() == 2) {
3747
0
    auto const& option = *parameters.advance(1).begin();
3748
0
    auto const DIRECTORY = "DIRECTORY:"_s;
3749
0
    auto const TARGET_DIRECTORY = "TARGET_DIRECTORY:"_s;
3750
0
    if (cmHasPrefix(option, DIRECTORY)) {
3751
0
      auto dir = option.substr(DIRECTORY.length());
3752
0
      if (dir.empty()) {
3753
0
        reportError(
3754
0
          eval, content->GetOriginalExpression(),
3755
0
          cmStrCat("No value provided for the ", DIRECTORY, " option."));
3756
0
        return false;
3757
0
      }
3758
0
      dir = cmSystemTools::CollapseFullPath(
3759
0
        dir, makefile->GetCurrentSourceDirectory());
3760
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(dir);
3761
0
      if (!makefile) {
3762
0
        reportError(
3763
0
          eval, content->GetOriginalExpression(),
3764
0
          cmStrCat("Directory \"", dir, "\" is not known from CMake."));
3765
0
        return false;
3766
0
      }
3767
0
    } else if (cmHasPrefix(option, TARGET_DIRECTORY)) {
3768
0
      auto targetName = option.substr(TARGET_DIRECTORY.length());
3769
0
      if (targetName.empty()) {
3770
0
        reportError(eval, content->GetOriginalExpression(),
3771
0
                    cmStrCat("No value provided for the ", TARGET_DIRECTORY,
3772
0
                             " option."));
3773
0
        return false;
3774
0
      }
3775
0
      auto* target = makefile->FindTargetToUse(targetName);
3776
0
      if (!target) {
3777
0
        reportError(eval, content->GetOriginalExpression(),
3778
0
                    cmStrCat("Non-existent target: ", targetName));
3779
0
        return false;
3780
0
      }
3781
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(
3782
0
        target->GetProperty("BINARY_DIR"));
3783
0
    } else {
3784
0
      reportError(eval, content->GetOriginalExpression(),
3785
0
                  cmStrCat("Invalid option. ", DIRECTORY, " or ",
3786
0
                           TARGET_DIRECTORY, " expected."));
3787
0
      return false;
3788
0
    }
3789
3790
0
    sourceName = cmSystemTools::CollapseFullPath(
3791
0
      sourceName,
3792
0
      eval->Context.LG->GetMakefile()->GetCurrentSourceDirectory());
3793
0
  }
3794
3795
0
  sourceFile = makefile->GetSource(sourceName);
3796
0
  return true;
3797
0
}
3798
}
3799
3800
static const struct SourceExistsNode : public cmGeneratorExpressionNode
3801
{
3802
4
  SourceExistsNode() {} // NOLINT(modernize-use-equals-default)
3803
3804
  // This node handles errors on parameter count itself.
3805
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3806
3807
  std::string Evaluate(
3808
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3809
    GeneratorExpressionContent const* content,
3810
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3811
0
  {
3812
0
    if (parameters.size() > 2) {
3813
0
      reportError(eval, content->GetOriginalExpression(),
3814
0
                  "$<SOURCE_EXISTS:...> expression requires at most two "
3815
0
                  "parameters.");
3816
0
      return std::string{};
3817
0
    }
3818
3819
0
    if (parameters[0].empty()) {
3820
0
      reportError(eval, content->GetOriginalExpression(),
3821
0
                  "$<SOURCE_EXISTS:src> expression requires a "
3822
0
                  "non-empty source name.");
3823
0
      return std::string{};
3824
0
    }
3825
3826
0
    cmSourceFile* sourceFile = nullptr;
3827
0
    if (!GetSourceFile(cmMakeRange(parameters), eval, content, sourceFile)) {
3828
0
      return std::string{};
3829
0
    }
3830
3831
0
    return sourceFile ? "1" : "0";
3832
0
  }
3833
} sourceExistsNode;
3834
3835
static const struct SourcePropertyNode : public cmGeneratorExpressionNode
3836
{
3837
4
  SourcePropertyNode() {} // NOLINT(modernize-use-equals-default)
3838
3839
  // This node handles errors on parameter count itself.
3840
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3841
3842
  std::string Evaluate(
3843
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3844
    GeneratorExpressionContent const* content,
3845
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3846
0
  {
3847
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3848
3849
0
    if (parameters.size() > 3) {
3850
0
      reportError(eval, content->GetOriginalExpression(),
3851
0
                  "$<SOURCE_PROPERTY:...> expression requires at most three "
3852
0
                  "parameters.");
3853
0
      return std::string{};
3854
0
    }
3855
3856
0
    std::string sourceName = parameters.front();
3857
0
    std::string const& propertyName = parameters.back();
3858
3859
0
    if (sourceName.empty() && propertyName.empty()) {
3860
0
      reportError(eval, content->GetOriginalExpression(),
3861
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3862
0
                  "non-empty source name and property name.");
3863
0
      return std::string{};
3864
0
    }
3865
0
    if (sourceName.empty()) {
3866
0
      reportError(eval, content->GetOriginalExpression(),
3867
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3868
0
                  "non-empty source name.");
3869
0
      return std::string{};
3870
0
    }
3871
0
    if (propertyName.empty()) {
3872
0
      reportError(eval, content->GetOriginalExpression(),
3873
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3874
0
                  "non-empty property name.");
3875
0
      return std::string{};
3876
0
    }
3877
0
    if (!propertyNameValidator.find(propertyName)) {
3878
0
      reportError(eval, content->GetOriginalExpression(),
3879
0
                  "Property name not supported.");
3880
0
      return std::string{};
3881
0
    }
3882
3883
0
    cmSourceFile* sourceFile = nullptr;
3884
0
    if (!GetSourceFile(cmMakeRange(parameters).retreat(1), eval, content,
3885
0
                       sourceFile)) {
3886
0
      return std::string{};
3887
0
    }
3888
0
    if (!sourceFile) {
3889
0
      reportError(
3890
0
        eval, content->GetOriginalExpression(),
3891
0
        cmStrCat("Source file \"", sourceName, "\" is not known from CMake."));
3892
0
      return std::string{};
3893
0
    }
3894
3895
0
    return sourceFile->GetPropertyForUser(propertyName);
3896
0
  }
3897
} sourcePropertyNode;
3898
3899
static std::string getLinkedTargetsContent(
3900
  cmGeneratorTarget const* target, std::string const& prop,
3901
  cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
3902
  cmGeneratorTarget::UseTo usage)
3903
0
{
3904
0
  std::string result;
3905
0
  if (cmLinkImplementationLibraries const* impl =
3906
0
        target->GetLinkImplementationLibraries(
3907
0
          eval->Context.Config, cmGeneratorTarget::UseTo::Compile)) {
3908
0
    for (cmLinkItem const& lib : impl->Libraries) {
3909
0
      if (lib.Target) {
3910
        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
3911
        // caller's property and hand-evaluate it as if it were compiled.
3912
        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
3913
0
        cm::GenEx::Context libContext(eval->Context);
3914
        // FIXME: Why have we long used the target's local generator
3915
        // instead of that of the evaluation context?
3916
0
        libContext.LG = target->GetLocalGenerator();
3917
0
        cm::GenEx::Evaluation libEval(
3918
0
          std::move(libContext), eval->Quiet, target, target,
3919
0
          eval->EvaluateForBuildsystem, lib.Backtrace);
3920
0
        std::string libResult = lib.Target->EvaluateInterfaceProperty(
3921
0
          prop, &libEval, dagChecker, usage);
3922
0
        if (!libResult.empty()) {
3923
0
          if (result.empty()) {
3924
0
            result = std::move(libResult);
3925
0
          } else {
3926
0
            result.reserve(result.size() + 1 + libResult.size());
3927
0
            result += ";";
3928
0
            result += libResult;
3929
0
          }
3930
0
        }
3931
0
      }
3932
0
    }
3933
0
  }
3934
0
  return result;
3935
0
}
3936
3937
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
3938
{
3939
4
  TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
3940
3941
  // This node handles errors on parameter count itself.
3942
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3943
3944
  static char const* GetErrorText(std::string const& targetName,
3945
                                  std::string const& propertyName)
3946
0
  {
3947
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3948
0
    if (targetName.empty() && propertyName.empty()) {
3949
0
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
3950
0
             "target name and property name.";
3951
0
    }
3952
0
    if (targetName.empty()) {
3953
0
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
3954
0
             "target name.";
3955
0
    }
3956
0
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
3957
0
      if (!propertyNameValidator.find(propertyName)) {
3958
0
        return "Target name and property name not supported.";
3959
0
      }
3960
0
      return "Target name not supported.";
3961
0
    }
3962
0
    return nullptr;
3963
0
  }
3964
3965
  std::string Evaluate(
3966
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3967
    GeneratorExpressionContent const* content,
3968
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
3969
0
  {
3970
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3971
3972
0
    cmGeneratorTarget const* target = nullptr;
3973
0
    std::string targetName;
3974
0
    std::string propertyName;
3975
3976
0
    if (parameters.size() == 2) {
3977
0
      targetName = parameters[0];
3978
0
      propertyName = parameters[1];
3979
3980
0
      if (char const* e = GetErrorText(targetName, propertyName)) {
3981
0
        reportError(eval, content->GetOriginalExpression(), e);
3982
0
        return std::string();
3983
0
      }
3984
0
      if (propertyName == "ALIASED_TARGET"_s) {
3985
0
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
3986
0
          if (cmGeneratorTarget* tgt =
3987
0
                eval->Context.LG->FindGeneratorTargetToUse(targetName)) {
3988
0
            return tgt->GetName();
3989
0
          }
3990
0
        }
3991
0
        return std::string();
3992
0
      }
3993
0
      if (propertyName == "ALIAS_GLOBAL"_s) {
3994
0
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
3995
0
          return eval->Context.LG->GetGlobalGenerator()->IsAlias(targetName)
3996
0
            ? "TRUE"
3997
0
            : "FALSE";
3998
0
        }
3999
0
        return std::string();
4000
0
      }
4001
0
      cmLocalGenerator const* lg = eval->CurrentTarget
4002
0
        ? eval->CurrentTarget->GetLocalGenerator()
4003
0
        : eval->Context.LG;
4004
0
      target = lg->FindGeneratorTargetToUse(targetName);
4005
4006
0
      if (!target) {
4007
0
        std::ostringstream e;
4008
0
        e << "Target \"" << targetName << "\" not found.";
4009
0
        reportError(eval, content->GetOriginalExpression(), e.str());
4010
0
        return std::string();
4011
0
      }
4012
0
      eval->AllTargets.insert(target);
4013
4014
0
    } else if (parameters.size() == 1) {
4015
0
      target = eval->HeadTarget;
4016
0
      propertyName = parameters[0];
4017
4018
      // Keep track of the properties seen while processing.
4019
      // The evaluation of the LINK_LIBRARIES generator expressions
4020
      // will check this to ensure that properties have one consistent
4021
      // value for all evaluations.
4022
0
      eval->SeenTargetProperties.insert(propertyName);
4023
4024
0
      eval->HadHeadSensitiveCondition = true;
4025
0
      if (!target) {
4026
0
        reportError(
4027
0
          eval, content->GetOriginalExpression(),
4028
0
          "$<TARGET_PROPERTY:prop>  may only be used with binary targets.  "
4029
0
          "It may not be used with add_custom_command or add_custom_target. "
4030
0
          " "
4031
0
          " "
4032
0
          "Specify the target to read a property from using the "
4033
0
          "$<TARGET_PROPERTY:tgt,prop> signature instead.");
4034
0
        return std::string();
4035
0
      }
4036
0
    } else {
4037
0
      reportError(
4038
0
        eval, content->GetOriginalExpression(),
4039
0
        "$<TARGET_PROPERTY:...> expression requires one or two parameters");
4040
0
      return std::string();
4041
0
    }
4042
4043
0
    if (propertyName == "SOURCES") {
4044
0
      eval->SourceSensitiveTargets.insert(target);
4045
0
    }
4046
4047
0
    if (propertyName.empty()) {
4048
0
      reportError(
4049
0
        eval, content->GetOriginalExpression(),
4050
0
        "$<TARGET_PROPERTY:...> expression requires a non-empty property "
4051
0
        "name.");
4052
0
      return std::string();
4053
0
    }
4054
4055
0
    if (!propertyNameValidator.find(propertyName)) {
4056
0
      ::reportError(eval, content->GetOriginalExpression(),
4057
0
                    "Property name not supported.");
4058
0
      return std::string();
4059
0
    }
4060
4061
0
    assert(target);
4062
4063
0
    if (propertyName == "LINKER_LANGUAGE") {
4064
0
      if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
4065
0
          (dagCheckerParent->EvaluatingLinkLibraries() ||
4066
0
           dagCheckerParent->EvaluatingSources())) {
4067
0
        reportError(
4068
0
          eval, content->GetOriginalExpression(),
4069
0
          "LINKER_LANGUAGE target property can not be used while evaluating "
4070
0
          "link libraries for a static library");
4071
0
        return std::string();
4072
0
      }
4073
0
      return target->GetLinkerLanguage(eval->Context.Config);
4074
0
    }
4075
4076
0
    bool const evaluatingLinkLibraries =
4077
0
      dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries();
4078
4079
0
    std::string interfacePropertyName;
4080
0
    bool isInterfaceProperty = false;
4081
0
    cmGeneratorTarget::UseTo usage = cmGeneratorTarget::UseTo::Compile;
4082
4083
0
    if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
4084
0
          target->IsTransitiveProperty(propertyName, eval->Context,
4085
0
                                       dagCheckerParent)) {
4086
0
      interfacePropertyName = std::string(transitiveProp->InterfaceName);
4087
0
      isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
4088
0
      usage = transitiveProp->Usage;
4089
0
    }
4090
4091
0
    if (dagCheckerParent) {
4092
      // This $<TARGET_PROPERTY:...> node has been reached while evaluating
4093
      // another target property value.  Check that the outermost evaluation
4094
      // expects such nested evaluations.
4095
0
      if (dagCheckerParent->EvaluatingGenexExpression() ||
4096
0
          dagCheckerParent->EvaluatingPICExpression() ||
4097
0
          dagCheckerParent->EvaluatingLinkerLauncher()) {
4098
        // No check required.
4099
0
      } else if (evaluatingLinkLibraries) {
4100
0
        if (!interfacePropertyName.empty() &&
4101
0
            interfacePropertyName != "INTERFACE_LINK_LIBRARIES"_s) {
4102
0
          reportError(
4103
0
            eval, content->GetOriginalExpression(),
4104
0
            "$<TARGET_PROPERTY:...> expression in link libraries "
4105
0
            "evaluation depends on target property which is transitive "
4106
0
            "over the link libraries, creating a recursion.");
4107
0
          return std::string();
4108
0
        }
4109
0
      } else {
4110
0
        assert(dagCheckerParent->EvaluatingTransitiveProperty());
4111
0
      }
4112
0
    }
4113
4114
0
    if (isInterfaceProperty) {
4115
0
      return cmGeneratorExpression::StripEmptyListElements(
4116
0
        target->EvaluateInterfaceProperty(propertyName, eval, dagCheckerParent,
4117
0
                                          usage));
4118
0
    }
4119
4120
0
    cmGeneratorExpressionDAGChecker dagChecker{
4121
0
      target,           propertyName,  content,
4122
0
      dagCheckerParent, eval->Context, eval->Backtrace,
4123
0
    };
4124
4125
0
    switch (dagChecker.Check()) {
4126
0
      case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4127
0
        dagChecker.ReportError(eval, content->GetOriginalExpression());
4128
0
        return std::string();
4129
0
      case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
4130
        // No error. We just skip cyclic references.
4131
0
        return std::string();
4132
0
      case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4133
        // We handle transitive properties above.  For non-transitive
4134
        // properties we accept repeats anyway.
4135
0
      case cmGeneratorExpressionDAGChecker::DAG:
4136
0
        break;
4137
0
    }
4138
4139
0
    std::string result;
4140
0
    bool haveProp = false;
4141
0
    if (cmValue p = target->GetProperty(propertyName)) {
4142
0
      result = *p;
4143
0
      haveProp = true;
4144
0
    } else if (evaluatingLinkLibraries) {
4145
0
      return std::string();
4146
0
    }
4147
4148
    // Properties named by COMPATIBLE_INTERFACE_ properties combine over
4149
    // the transitive link closure as a single order-independent value.
4150
    // Imported targets do not themselves have a defined value for these
4151
    // properties, but they can contribute to the value of a non-imported
4152
    // dependent.
4153
    //
4154
    // For COMPATIBLE_INTERFACE_{BOOL,STRING}:
4155
    // * If set on this target, use the value directly.  It is checked
4156
    //   elsewhere for consistency over the transitive link closure.
4157
    // * If not set on this target, compute the value from the closure.
4158
    //
4159
    // For COMPATIBLE_INTERFACE_NUMBER_{MAX,MIN} we always compute the value
4160
    // from this target and the transitive link closure to get the max or min.
4161
0
    if (!haveProp && !target->IsImported()) {
4162
0
      if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
4163
0
                                                       eval->Context.Config)) {
4164
0
        eval->HadContextSensitiveCondition = true;
4165
0
        return target->GetLinkInterfaceDependentBoolProperty(
4166
0
                 propertyName, eval->Context.Config)
4167
0
          ? "1"
4168
0
          : "0";
4169
0
      }
4170
0
      if (target->IsLinkInterfaceDependentStringProperty(
4171
0
            propertyName, eval->Context.Config)) {
4172
0
        eval->HadContextSensitiveCondition = true;
4173
0
        char const* propContent =
4174
0
          target->GetLinkInterfaceDependentStringProperty(
4175
0
            propertyName, eval->Context.Config);
4176
0
        return propContent ? propContent : "";
4177
0
      }
4178
0
    }
4179
0
    if (!evaluatingLinkLibraries && !target->IsImported()) {
4180
0
      if (target->IsLinkInterfaceDependentNumberMinProperty(
4181
0
            propertyName, eval->Context.Config)) {
4182
0
        eval->HadContextSensitiveCondition = true;
4183
0
        char const* propContent =
4184
0
          target->GetLinkInterfaceDependentNumberMinProperty(
4185
0
            propertyName, eval->Context.Config);
4186
0
        return propContent ? propContent : "";
4187
0
      }
4188
0
      if (target->IsLinkInterfaceDependentNumberMaxProperty(
4189
0
            propertyName, eval->Context.Config)) {
4190
0
        eval->HadContextSensitiveCondition = true;
4191
0
        char const* propContent =
4192
0
          target->GetLinkInterfaceDependentNumberMaxProperty(
4193
0
            propertyName, eval->Context.Config);
4194
0
        return propContent ? propContent : "";
4195
0
      }
4196
0
    }
4197
4198
    // Some properties, such as usage requirements, combine over the
4199
    // transitive link closure as an ordered list.
4200
0
    if (!interfacePropertyName.empty()) {
4201
0
      result = cmGeneratorExpression::StripEmptyListElements(
4202
0
        this->EvaluateDependentExpression(result, eval, target, &dagChecker,
4203
0
                                          target));
4204
0
      std::string linkedTargetsContent = getLinkedTargetsContent(
4205
0
        target, interfacePropertyName, eval, &dagChecker, usage);
4206
0
      if (!linkedTargetsContent.empty()) {
4207
0
        result += (result.empty() ? "" : ";") + linkedTargetsContent;
4208
0
      }
4209
0
    }
4210
0
    return result;
4211
0
  }
4212
} targetPropertyNode;
4213
4214
static const struct targetIntermediateDirNode
4215
  : public cmGeneratorExpressionNode
4216
{
4217
4
  targetIntermediateDirNode() {} // NOLINT(modernize-use-equals-default)
4218
4219
  static char const* GetErrorText(std::string const& targetName)
4220
0
  {
4221
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
4222
0
    if (targetName.empty()) {
4223
0
      return "$<TARGET_INTERMEDIATE_DIR:tgt> expression requires a non-empty "
4224
0
             "target name.";
4225
0
    }
4226
0
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
4227
0
      return "Target name not supported.";
4228
0
    }
4229
0
    return nullptr;
4230
0
  }
4231
4232
  std::string Evaluate(
4233
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4234
    GeneratorExpressionContent const* content,
4235
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4236
0
  {
4237
0
    cmGeneratorTarget const* target = nullptr;
4238
0
    std::string targetName;
4239
4240
0
    if (parameters.size() == 1) {
4241
0
      targetName = parameters[0];
4242
4243
0
      if (char const* e = GetErrorText(targetName)) {
4244
0
        reportError(eval, content->GetOriginalExpression(), e);
4245
0
        return std::string();
4246
0
      }
4247
0
      cmLocalGenerator const* lg = eval->CurrentTarget
4248
0
        ? eval->CurrentTarget->GetLocalGenerator()
4249
0
        : eval->Context.LG;
4250
0
      target = lg->FindGeneratorTargetToUse(targetName);
4251
4252
0
      if (!target) {
4253
0
        std::ostringstream e;
4254
0
        e << "Target \"" << targetName << "\" not found.";
4255
0
        reportError(eval, content->GetOriginalExpression(), e.str());
4256
0
        return std::string();
4257
0
      }
4258
0
      eval->AllTargets.insert(target);
4259
4260
0
    } else {
4261
0
      reportError(
4262
0
        eval, content->GetOriginalExpression(),
4263
0
        "$<TARGET_INTERMEDIATE_DIR:...> expression requires one parameter");
4264
0
      return std::string();
4265
0
    }
4266
4267
0
    assert(target);
4268
4269
0
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_INTERMEDIATE_DIR",
4270
0
                                    target)) {
4271
0
      return std::string();
4272
0
    }
4273
4274
0
    return cmSystemTools::CollapseFullPath(
4275
0
      target->GetObjectDirectory(eval->Context.Config));
4276
0
  }
4277
} targetIntermediateDirNode;
4278
4279
static const struct TargetNameNode : public cmGeneratorExpressionNode
4280
{
4281
4
  TargetNameNode() {} // NOLINT(modernize-use-equals-default)
4282
4283
0
  bool GeneratesContent() const override { return true; }
4284
4285
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
4286
0
  bool RequiresLiteralInput() const override { return true; }
4287
4288
  std::string Evaluate(
4289
    std::vector<std::string> const& parameters,
4290
    cm::GenEx::Evaluation* /*eval*/,
4291
    GeneratorExpressionContent const* /*content*/,
4292
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4293
0
  {
4294
0
    return parameters.front();
4295
0
  }
4296
4297
0
  int NumExpectedParameters() const override { return 1; }
4298
4299
} targetNameNode;
4300
4301
static const struct TargetObjectsNode : public cmGeneratorExpressionNode
4302
{
4303
4
  TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
4304
4305
  std::string Evaluate(
4306
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4307
    GeneratorExpressionContent const* content,
4308
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4309
0
  {
4310
0
    std::string const& tgtName = parameters.front();
4311
0
    cmGeneratorTarget* gt =
4312
0
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
4313
0
    if (!gt) {
4314
0
      std::ostringstream e;
4315
0
      e << "Objects of target \"" << tgtName
4316
0
        << "\" referenced but no such target exists.";
4317
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4318
0
      return std::string();
4319
0
    }
4320
0
    cmStateEnums::TargetType type = gt->GetType();
4321
0
    if (type != cmStateEnums::EXECUTABLE &&
4322
0
        type != cmStateEnums::STATIC_LIBRARY &&
4323
0
        type != cmStateEnums::SHARED_LIBRARY &&
4324
0
        type != cmStateEnums::MODULE_LIBRARY &&
4325
0
        type != cmStateEnums::OBJECT_LIBRARY) {
4326
0
      std::ostringstream e;
4327
0
      e << "Objects of target \"" << tgtName
4328
0
        << "\" referenced but is not one of the allowed target types "
4329
0
        << "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT).";
4330
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4331
0
      return std::string();
4332
0
    }
4333
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
4334
0
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_OBJECTS", gt)) {
4335
0
      return std::string();
4336
0
    }
4337
4338
0
    std::vector<std::string> sourceFilePaths;
4339
0
    for (auto const& arg : cmMakeRange(parameters).advance(1)) {
4340
0
      if (cmHasLiteralPrefix(arg, "SOURCE_FILES:")) {
4341
0
        cm::string_view listView{ arg.c_str() + cmStrLen("SOURCE_FILES:") };
4342
0
        std::size_t semicolon;
4343
0
        std::size_t start = 0;
4344
0
        do {
4345
0
          semicolon = listView.find(';', start);
4346
0
          sourceFilePaths.push_back(
4347
0
            std::string{ listView.substr(start, semicolon - start) });
4348
0
          start = semicolon + 1;
4349
0
        } while (semicolon != cm::string_view::npos);
4350
0
      } else {
4351
0
        reportError(eval, content->GetOriginalExpression(),
4352
0
                    cmStrCat("Unrecognized argument:\n  ", arg));
4353
0
        return std::string();
4354
0
      }
4355
0
    }
4356
4357
0
    if (gt->IsImported() && !sourceFilePaths.empty()) {
4358
0
      reportError(
4359
0
        eval, content->GetOriginalExpression(),
4360
0
        cmStrCat("Cannot use SOURCE_FILES argument on imported target \"",
4361
0
                 tgtName, '"'));
4362
0
      return std::string();
4363
0
    }
4364
0
    std::set<cmSourceFile const*> sourceFiles;
4365
0
    for (auto const& sf : gt->GetSourceFiles(eval->Context.Config)) {
4366
0
      sourceFiles.insert(sf.Value);
4367
0
    }
4368
0
    std::set<cmSourceFile const*> filteredSourceFiles;
4369
0
    for (auto const& path : sourceFilePaths) {
4370
0
      if (!cmSystemTools::FileIsFullPath(path)) {
4371
0
        reportError(
4372
0
          eval, content->GetOriginalExpression(),
4373
0
          cmStrCat("Source file:\n  ", path, "\nis not an absolute path"));
4374
0
        return std::string();
4375
0
      }
4376
4377
0
      auto const* sf = gt->Makefile->GetSource(path);
4378
0
      if (!sf || !sourceFiles.count(sf)) {
4379
0
        reportError(eval, content->GetOriginalExpression(),
4380
0
                    cmStrCat("Source file:\n  ", path,
4381
0
                             "\ndoes not exist for target \"", tgtName, '"'));
4382
0
        return std::string();
4383
0
      }
4384
0
      filteredSourceFiles.insert(sf);
4385
0
    }
4386
4387
0
    cmList objects;
4388
4389
0
    if (gt->IsImported()) {
4390
0
      cmValue loc = nullptr;
4391
0
      cmValue imp = nullptr;
4392
0
      std::string suffix;
4393
0
      if (gt->Target->GetMappedConfig(eval->Context.Config, loc, imp,
4394
0
                                      suffix)) {
4395
0
        objects.assign(*loc);
4396
0
      }
4397
0
      eval->HadContextSensitiveCondition = true;
4398
0
    } else {
4399
0
      auto const filter =
4400
0
        [&filteredSourceFiles](cmSourceFile const& sf) -> bool {
4401
0
        return filteredSourceFiles.empty() || filteredSourceFiles.count(&sf);
4402
0
      };
4403
0
      gt->GetTargetObjectNames(eval->Context.Config, filter, objects);
4404
4405
0
      std::string obj_dir;
4406
0
      if (eval->EvaluateForBuildsystem && !gg->SupportsCrossConfigs()) {
4407
        // Use object file directory with buildsystem placeholder.
4408
0
        obj_dir = gt->ObjectDirectory;
4409
0
        eval->HadContextSensitiveCondition = gt->HasContextDependentSources();
4410
0
      } else {
4411
        // Use object file directory with per-config location.
4412
0
        obj_dir = gt->GetObjectDirectory(eval->Context.Config);
4413
0
        eval->HadContextSensitiveCondition = true;
4414
0
      }
4415
4416
0
      for (auto& o : objects) {
4417
0
        o = cmStrCat(obj_dir, o);
4418
0
      }
4419
0
    }
4420
4421
    // Create the cmSourceFile instances in the referencing directory.
4422
0
    cmMakefile* mf = eval->Context.LG->GetMakefile();
4423
0
    for (std::string const& o : objects) {
4424
0
      mf->AddTargetObject(tgtName, o);
4425
0
    }
4426
4427
0
    return objects.to_string();
4428
0
  }
4429
4430
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4431
} targetObjectsNode;
4432
4433
struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
4434
{
4435
  std::vector<std::string> CollectDlls(
4436
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4437
    GeneratorExpressionContent const* content) const
4438
0
  {
4439
0
    std::string const& tgtName = parameters.front();
4440
0
    cmGeneratorTarget* gt =
4441
0
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
4442
0
    if (!gt) {
4443
0
      std::ostringstream e;
4444
0
      e << "Objects of target \"" << tgtName
4445
0
        << "\" referenced but no such target exists.";
4446
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4447
0
      return std::vector<std::string>();
4448
0
    }
4449
0
    cmStateEnums::TargetType type = gt->GetType();
4450
0
    if (type != cmStateEnums::EXECUTABLE &&
4451
0
        type != cmStateEnums::SHARED_LIBRARY &&
4452
0
        type != cmStateEnums::MODULE_LIBRARY) {
4453
0
      std::ostringstream e;
4454
0
      e << "Objects of target \"" << tgtName
4455
0
        << "\" referenced but is not one of the allowed target types "
4456
0
        << "(EXECUTABLE, SHARED, MODULE).";
4457
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4458
0
      return std::vector<std::string>();
4459
0
    }
4460
4461
0
    if (auto* cli = gt->GetLinkInformation(eval->Context.Config)) {
4462
0
      std::vector<std::string> dllPaths;
4463
0
      auto const& dlls = cli->GetRuntimeDLLs();
4464
4465
0
      for (auto const& dll : dlls) {
4466
0
        if (auto loc = dll->MaybeGetLocation(eval->Context.Config)) {
4467
0
          dllPaths.emplace_back(*loc);
4468
0
        }
4469
0
      }
4470
4471
0
      return dllPaths;
4472
0
    }
4473
4474
0
    return std::vector<std::string>();
4475
0
  }
4476
};
4477
4478
static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode
4479
{
4480
4
  TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
4481
4482
  std::string Evaluate(
4483
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4484
    GeneratorExpressionContent const* content,
4485
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4486
0
  {
4487
0
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
4488
0
    return cmList::to_string(dlls);
4489
0
  }
4490
} targetRuntimeDllsNode;
4491
4492
static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode
4493
{
4494
4
  TargetRuntimeDllDirsNode() {} // NOLINT(modernize-use-equals-default)
4495
4496
  std::string Evaluate(
4497
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4498
    GeneratorExpressionContent const* content,
4499
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4500
0
  {
4501
0
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
4502
0
    std::vector<std::string> dllDirs;
4503
0
    for (std::string const& dll : dlls) {
4504
0
      std::string directory = cmSystemTools::GetFilenamePath(dll);
4505
0
      if (std::find(dllDirs.begin(), dllDirs.end(), directory) ==
4506
0
          dllDirs.end()) {
4507
0
        dllDirs.push_back(directory);
4508
0
      }
4509
0
    }
4510
0
    return cmList::to_string(dllDirs);
4511
0
  }
4512
} targetRuntimeDllDirsNode;
4513
4514
static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
4515
{
4516
4
  CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
4517
4518
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4519
4520
  std::string Evaluate(
4521
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4522
    GeneratorExpressionContent const* content,
4523
    cmGeneratorExpressionDAGChecker* dagChecker) const override
4524
0
  {
4525
0
    cmGeneratorTarget const* target = eval->HeadTarget;
4526
0
    if (!target) {
4527
0
      reportError(
4528
0
        eval, content->GetOriginalExpression(),
4529
0
        "$<COMPILE_FEATURE> may only be used with binary targets.  It may "
4530
0
        "not be used with add_custom_command or add_custom_target.");
4531
0
      return std::string();
4532
0
    }
4533
0
    eval->HadHeadSensitiveCondition = true;
4534
4535
0
    using LangMap = std::map<std::string, cmList>;
4536
0
    static LangMap availableFeatures;
4537
4538
0
    LangMap testedFeatures;
4539
0
    cmStandardLevelResolver standardResolver(eval->Context.LG->GetMakefile());
4540
0
    for (std::string const& p : parameters) {
4541
0
      std::string error;
4542
0
      std::string lang;
4543
0
      if (!standardResolver.CompileFeatureKnown(
4544
0
            eval->HeadTarget->Target->GetName(), p, lang, &error)) {
4545
0
        reportError(eval, content->GetOriginalExpression(), error);
4546
0
        return std::string();
4547
0
      }
4548
0
      testedFeatures[lang].push_back(p);
4549
4550
0
      if (availableFeatures.find(lang) == availableFeatures.end()) {
4551
0
        cmValue featuresKnown =
4552
0
          standardResolver.CompileFeaturesAvailable(lang, &error);
4553
0
        if (!featuresKnown) {
4554
0
          reportError(eval, content->GetOriginalExpression(), error);
4555
0
          return std::string();
4556
0
        }
4557
0
        availableFeatures[lang].assign(featuresKnown);
4558
0
      }
4559
0
    }
4560
4561
0
    bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
4562
4563
0
    for (auto const& lit : testedFeatures) {
4564
0
      std::vector<std::string> const& langAvailable =
4565
0
        availableFeatures[lit.first];
4566
0
      cmValue standardDefault = eval->Context.LG->GetMakefile()->GetDefinition(
4567
0
        cmStrCat("CMAKE_", lit.first, "_STANDARD_DEFAULT"));
4568
0
      for (std::string const& it : lit.second) {
4569
0
        if (!cm::contains(langAvailable, it)) {
4570
0
          return "0";
4571
0
        }
4572
0
        if (standardDefault && standardDefault->empty()) {
4573
          // This compiler has no notion of language standard levels.
4574
          // All features known for the language are always available.
4575
0
          continue;
4576
0
        }
4577
0
        if (!standardResolver.HaveStandardAvailable(
4578
0
              target, lit.first, eval->Context.Config, it)) {
4579
0
          if (evalLL) {
4580
0
            cmValue l =
4581
0
              target->GetLanguageStandard(lit.first, eval->Context.Config);
4582
0
            if (!l) {
4583
0
              l = standardDefault;
4584
0
            }
4585
0
            assert(l);
4586
0
            eval->MaxLanguageStandard[target][lit.first] = *l;
4587
0
          } else {
4588
0
            return "0";
4589
0
          }
4590
0
        }
4591
0
      }
4592
0
    }
4593
0
    return "1";
4594
0
  }
4595
} compileFeaturesNode;
4596
4597
static char const* targetPolicyWhitelist[] = {
4598
  nullptr
4599
#define TARGET_POLICY_STRING(POLICY) , #POLICY
4600
4601
  CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
4602
4603
#undef TARGET_POLICY_STRING
4604
};
4605
4606
static cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
4607
                                                char const* policy)
4608
0
{
4609
0
#define RETURN_POLICY(POLICY)                                                 \
4610
0
  if (strcmp(policy, #POLICY) == 0) {                                         \
4611
0
    return tgt->GetPolicyStatus##POLICY();                                    \
4612
0
  }
4613
4614
0
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
4615
4616
0
#undef RETURN_POLICY
4617
4618
0
  assert(false && "Unreachable code. Not a valid policy");
4619
0
  return cmPolicies::WARN;
4620
0
}
4621
4622
static cmPolicies::PolicyID policyForString(char const* policy_id)
4623
0
{
4624
0
#define RETURN_POLICY_ID(POLICY_ID)                                           \
4625
0
  if (strcmp(policy_id, #POLICY_ID) == 0) {                                   \
4626
0
    return cmPolicies::POLICY_ID;                                             \
4627
0
  }
4628
4629
0
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
4630
4631
0
#undef RETURN_POLICY_ID
4632
4633
0
  assert(false && "Unreachable code. Not a valid policy");
4634
0
  return cmPolicies::CMPCOUNT;
4635
0
}
4636
4637
static const struct TargetPolicyNode : public cmGeneratorExpressionNode
4638
{
4639
4
  TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
4640
4641
0
  int NumExpectedParameters() const override { return 1; }
4642
4643
  std::string Evaluate(
4644
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4645
    GeneratorExpressionContent const* content,
4646
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4647
0
  {
4648
0
    if (!eval->HeadTarget) {
4649
0
      reportError(
4650
0
        eval, content->GetOriginalExpression(),
4651
0
        "$<TARGET_POLICY:prop> may only be used with binary targets.  It "
4652
0
        "may not be used with add_custom_command or add_custom_target.");
4653
0
      return std::string();
4654
0
    }
4655
4656
0
    eval->HadContextSensitiveCondition = true;
4657
0
    eval->HadHeadSensitiveCondition = true;
4658
4659
0
    for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
4660
0
      char const* policy = targetPolicyWhitelist[i];
4661
0
      if (parameters.front() == policy) {
4662
0
        cmLocalGenerator* lg = eval->HeadTarget->GetLocalGenerator();
4663
0
        switch (statusForTarget(eval->HeadTarget, policy)) {
4664
0
          case cmPolicies::WARN:
4665
0
            lg->IssueMessage(
4666
0
              MessageType::AUTHOR_WARNING,
4667
0
              cmPolicies::GetPolicyWarning(policyForString(policy)));
4668
0
            CM_FALLTHROUGH;
4669
0
          case cmPolicies::OLD:
4670
0
            return "0";
4671
0
          case cmPolicies::NEW:
4672
0
            return "1";
4673
0
        }
4674
0
      }
4675
0
    }
4676
0
    reportError(
4677
0
      eval, content->GetOriginalExpression(),
4678
0
      "$<TARGET_POLICY:prop> may only be used with a limited number of "
4679
0
      "policies.  Currently it may be used with the following policies:\n"
4680
4681
0
#define STRINGIFY_HELPER(X) #X
4682
0
#define STRINGIFY(X) STRINGIFY_HELPER(X)
4683
4684
0
#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
4685
4686
0
      CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
4687
4688
0
#undef TARGET_POLICY_LIST_ITEM
4689
0
    );
4690
0
    return std::string();
4691
0
  }
4692
4693
} targetPolicyNode;
4694
4695
static const struct InstallPrefixNode : public cmGeneratorExpressionNode
4696
{
4697
4
  InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
4698
4699
0
  bool GeneratesContent() const override { return true; }
4700
0
  int NumExpectedParameters() const override { return 0; }
4701
4702
  std::string Evaluate(
4703
    std::vector<std::string> const& /*parameters*/,
4704
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
4705
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4706
0
  {
4707
0
    reportError(eval, content->GetOriginalExpression(),
4708
0
                "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
4709
0
                "should never be evaluated.");
4710
0
    return std::string();
4711
0
  }
4712
4713
} installPrefixNode;
4714
4715
class ArtifactDirTag;
4716
class ArtifactLinkerTag;
4717
class ArtifactLinkerLibraryTag;
4718
class ArtifactLinkerImportTag;
4719
class ArtifactNameTag;
4720
class ArtifactImportTag;
4721
class ArtifactPathTag;
4722
class ArtifactPdbTag;
4723
class ArtifactSonameTag;
4724
class ArtifactSonameImportTag;
4725
class ArtifactBundleDirTag;
4726
class ArtifactBundleDirNameTag;
4727
class ArtifactBundleContentDirTag;
4728
4729
template <typename ArtifactT, typename ComponentT>
4730
struct TargetFilesystemArtifactDependency
4731
{
4732
  static void AddDependency(cmGeneratorTarget* target,
4733
                            cm::GenEx::Evaluation* eval)
4734
0
  {
4735
0
    eval->DependTargets.insert(target);
4736
0
    eval->AllTargets.insert(target);
4737
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*)
4738
};
4739
4740
struct TargetFilesystemArtifactDependencyCMP0112
4741
{
4742
  static void AddDependency(cmGeneratorTarget* target,
4743
                            cm::GenEx::Evaluation* eval)
4744
0
  {
4745
0
    eval->AllTargets.insert(target);
4746
0
    cmLocalGenerator const* lg = eval->Context.LG;
4747
0
    switch (target->GetPolicyStatusCMP0112()) {
4748
0
      case cmPolicies::WARN:
4749
0
        if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
4750
0
              "CMAKE_POLICY_WARNING_CMP0112")) {
4751
0
          std::string err =
4752
0
            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0112),
4753
0
                     "\nDependency being added to target:\n  \"",
4754
0
                     target->GetName(), "\"\n");
4755
0
          lg->GetCMakeInstance()->IssueMessage(MessageType ::AUTHOR_WARNING,
4756
0
                                               err, eval->Backtrace);
4757
0
        }
4758
0
        CM_FALLTHROUGH;
4759
0
      case cmPolicies::OLD:
4760
0
        eval->DependTargets.insert(target);
4761
0
        break;
4762
0
      case cmPolicies::NEW:
4763
0
        break;
4764
0
    }
4765
0
  }
4766
};
4767
4768
template <typename ArtifactT>
4769
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactNameTag>
4770
  : TargetFilesystemArtifactDependencyCMP0112
4771
{
4772
};
4773
template <typename ArtifactT>
4774
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactDirTag>
4775
  : TargetFilesystemArtifactDependencyCMP0112
4776
{
4777
};
4778
template <>
4779
struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag,
4780
                                          ArtifactPathTag>
4781
  : TargetFilesystemArtifactDependencyCMP0112
4782
{
4783
};
4784
template <>
4785
struct TargetFilesystemArtifactDependency<ArtifactBundleDirNameTag,
4786
                                          ArtifactPathTag>
4787
  : TargetFilesystemArtifactDependencyCMP0112
4788
{
4789
};
4790
template <>
4791
struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag,
4792
                                          ArtifactPathTag>
4793
  : TargetFilesystemArtifactDependencyCMP0112
4794
{
4795
};
4796
4797
template <typename ArtifactT>
4798
struct TargetFilesystemArtifactResultCreator
4799
{
4800
  static std::string Create(cmGeneratorTarget* target,
4801
                            cm::GenEx::Evaluation* eval,
4802
                            GeneratorExpressionContent const* content);
4803
};
4804
4805
template <>
4806
struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
4807
{
4808
  static std::string Create(cmGeneratorTarget* target,
4809
                            cm::GenEx::Evaluation* eval,
4810
                            GeneratorExpressionContent const* content)
4811
0
  {
4812
    // The target soname file (.so.1).
4813
0
    if (target->IsDLLPlatform()) {
4814
0
      ::reportError(eval, content->GetOriginalExpression(),
4815
0
                    "TARGET_SONAME_FILE is not allowed "
4816
0
                    "for DLL target platforms.");
4817
0
      return std::string();
4818
0
    }
4819
0
    if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
4820
0
      ::reportError(eval, content->GetOriginalExpression(),
4821
0
                    "TARGET_SONAME_FILE is allowed only for "
4822
0
                    "SHARED libraries.");
4823
0
      return std::string();
4824
0
    }
4825
0
    if (target->IsArchivedAIXSharedLibrary()) {
4826
0
      ::reportError(eval, content->GetOriginalExpression(),
4827
0
                    "TARGET_SONAME_FILE is not allowed for "
4828
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
4829
0
      return std::string();
4830
0
    }
4831
0
    std::string result =
4832
0
      cmStrCat(target->GetDirectory(eval->Context.Config), '/',
4833
0
               target->GetSOName(eval->Context.Config));
4834
0
    return result;
4835
0
  }
4836
};
4837
4838
template <>
4839
struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag>
4840
{
4841
  static std::string Create(cmGeneratorTarget* target,
4842
                            cm::GenEx::Evaluation* eval,
4843
                            GeneratorExpressionContent const* content)
4844
0
  {
4845
    // The target soname file (.so.1).
4846
0
    if (target->IsDLLPlatform()) {
4847
0
      ::reportError(eval, content->GetOriginalExpression(),
4848
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed "
4849
0
                    "for DLL target platforms.");
4850
0
      return std::string();
4851
0
    }
4852
0
    if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
4853
0
      ::reportError(eval, content->GetOriginalExpression(),
4854
0
                    "TARGET_SONAME_IMPORT_FILE is allowed only for "
4855
0
                    "SHARED libraries.");
4856
0
      return std::string();
4857
0
    }
4858
0
    if (target->IsArchivedAIXSharedLibrary()) {
4859
0
      ::reportError(eval, content->GetOriginalExpression(),
4860
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed for "
4861
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
4862
0
      return std::string();
4863
0
    }
4864
4865
0
    if (target->HasImportLibrary(eval->Context.Config)) {
4866
0
      return cmStrCat(
4867
0
        target->GetDirectory(eval->Context.Config,
4868
0
                             cmStateEnums::ImportLibraryArtifact),
4869
0
        '/',
4870
0
        target->GetSOName(eval->Context.Config,
4871
0
                          cmStateEnums::ImportLibraryArtifact));
4872
0
    }
4873
0
    return std::string{};
4874
0
  }
4875
};
4876
4877
template <>
4878
struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
4879
{
4880
  static std::string Create(cmGeneratorTarget* target,
4881
                            cm::GenEx::Evaluation* eval,
4882
                            GeneratorExpressionContent const* content)
4883
0
  {
4884
0
    if (target->IsImported()) {
4885
0
      ::reportError(eval, content->GetOriginalExpression(),
4886
0
                    "TARGET_PDB_FILE not allowed for IMPORTED targets.");
4887
0
      return std::string();
4888
0
    }
4889
4890
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
4891
4892
0
    std::string pdbSupportVar =
4893
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
4894
4895
0
    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
4896
0
      ::reportError(eval, content->GetOriginalExpression(),
4897
0
                    "TARGET_PDB_FILE is not supported by the target linker.");
4898
0
      return std::string();
4899
0
    }
4900
4901
0
    cmStateEnums::TargetType targetType = target->GetType();
4902
4903
0
    if (targetType != cmStateEnums::SHARED_LIBRARY &&
4904
0
        targetType != cmStateEnums::MODULE_LIBRARY &&
4905
0
        targetType != cmStateEnums::EXECUTABLE) {
4906
0
      ::reportError(eval, content->GetOriginalExpression(),
4907
0
                    "TARGET_PDB_FILE is allowed only for "
4908
0
                    "targets with linker created artifacts.");
4909
0
      return std::string();
4910
0
    }
4911
4912
0
    std::string result =
4913
0
      cmStrCat(target->GetPDBDirectory(eval->Context.Config), '/',
4914
0
               target->GetPDBName(eval->Context.Config));
4915
0
    return result;
4916
0
  }
4917
};
4918
4919
template <>
4920
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
4921
{
4922
  static std::string Create(cmGeneratorTarget* target,
4923
                            cm::GenEx::Evaluation* eval,
4924
                            GeneratorExpressionContent const* content)
4925
0
  {
4926
    // The file used to link to the target (.so, .lib, .a) or import file
4927
    // (.lib,  .tbd).
4928
0
    if (!target->IsLinkable()) {
4929
0
      ::reportError(eval, content->GetOriginalExpression(),
4930
0
                    "TARGET_LINKER_FILE is allowed only for libraries and "
4931
0
                    "executables with ENABLE_EXPORTS.");
4932
0
      return std::string();
4933
0
    }
4934
0
    cmStateEnums::ArtifactType artifact =
4935
0
      target->HasImportLibrary(eval->Context.Config)
4936
0
      ? cmStateEnums::ImportLibraryArtifact
4937
0
      : cmStateEnums::RuntimeBinaryArtifact;
4938
0
    return target->GetFullPath(eval->Context.Config, artifact);
4939
0
  }
4940
};
4941
4942
template <>
4943
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag>
4944
{
4945
  static std::string Create(cmGeneratorTarget* target,
4946
                            cm::GenEx::Evaluation* eval,
4947
                            GeneratorExpressionContent const* content)
4948
0
  {
4949
    // The file used to link to the target (.dylib, .so, .a).
4950
0
    if (!target->IsLinkable() ||
4951
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
4952
0
      ::reportError(eval, content->GetOriginalExpression(),
4953
0
                    "TARGET_LINKER_LIBRARY_FILE is allowed only for libraries "
4954
0
                    "with ENABLE_EXPORTS.");
4955
0
      return std::string();
4956
0
    }
4957
4958
0
    if (!target->IsDLLPlatform() ||
4959
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
4960
0
      return target->GetFullPath(eval->Context.Config,
4961
0
                                 cmStateEnums::RuntimeBinaryArtifact);
4962
0
    }
4963
0
    return std::string{};
4964
0
  }
4965
};
4966
4967
template <>
4968
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag>
4969
{
4970
  static std::string Create(cmGeneratorTarget* target,
4971
                            cm::GenEx::Evaluation* eval,
4972
                            GeneratorExpressionContent const* content)
4973
0
  {
4974
    // The file used to link to the target (.lib, .tbd).
4975
0
    if (!target->IsLinkable()) {
4976
0
      ::reportError(
4977
0
        eval, content->GetOriginalExpression(),
4978
0
        "TARGET_LINKER_IMPORT_FILE is allowed only for libraries and "
4979
0
        "executables with ENABLE_EXPORTS.");
4980
0
      return std::string();
4981
0
    }
4982
4983
0
    if (target->HasImportLibrary(eval->Context.Config)) {
4984
0
      return target->GetFullPath(eval->Context.Config,
4985
0
                                 cmStateEnums::ImportLibraryArtifact);
4986
0
    }
4987
0
    return std::string{};
4988
0
  }
4989
};
4990
4991
template <>
4992
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
4993
{
4994
  static std::string Create(cmGeneratorTarget* target,
4995
                            cm::GenEx::Evaluation* eval,
4996
                            GeneratorExpressionContent const* content)
4997
0
  {
4998
0
    if (target->IsImported()) {
4999
0
      ::reportError(eval, content->GetOriginalExpression(),
5000
0
                    "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
5001
0
      return std::string();
5002
0
    }
5003
0
    if (!target->IsBundleOnApple()) {
5004
0
      ::reportError(eval, content->GetOriginalExpression(),
5005
0
                    "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
5006
0
      return std::string();
5007
0
    }
5008
5009
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
5010
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
5011
0
                                        cmGeneratorTarget::BundleDirLevel);
5012
0
  }
5013
};
5014
5015
template <>
5016
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag>
5017
{
5018
  static std::string Create(cmGeneratorTarget* target,
5019
                            cm::GenEx::Evaluation* eval,
5020
                            GeneratorExpressionContent const* content)
5021
0
  {
5022
0
    if (target->IsImported()) {
5023
0
      ::reportError(
5024
0
        eval, content->GetOriginalExpression(),
5025
0
        "TARGET_BUNDLE_DIR_NAME not allowed for IMPORTED targets.");
5026
0
      return std::string();
5027
0
    }
5028
0
    if (!target->IsBundleOnApple()) {
5029
0
      ::reportError(
5030
0
        eval, content->GetOriginalExpression(),
5031
0
        "TARGET_BUNDLE_DIR_NAME is allowed only for Bundle targets.");
5032
0
      return std::string();
5033
0
    }
5034
5035
0
    auto level = cmGeneratorTarget::BundleDirLevel;
5036
0
    auto config = eval->Context.Config;
5037
0
    if (target->IsAppBundleOnApple()) {
5038
0
      return target->GetAppBundleDirectory(config, level);
5039
0
    }
5040
0
    if (target->IsFrameworkOnApple()) {
5041
0
      return target->GetFrameworkDirectory(config, level);
5042
0
    }
5043
0
    if (target->IsCFBundleOnApple()) {
5044
0
      return target->GetCFBundleDirectory(config, level);
5045
0
    }
5046
0
    return std::string();
5047
0
  }
5048
};
5049
5050
template <>
5051
struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
5052
{
5053
  static std::string Create(cmGeneratorTarget* target,
5054
                            cm::GenEx::Evaluation* eval,
5055
                            GeneratorExpressionContent const* content)
5056
0
  {
5057
0
    if (target->IsImported()) {
5058
0
      ::reportError(
5059
0
        eval, content->GetOriginalExpression(),
5060
0
        "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
5061
0
      return std::string();
5062
0
    }
5063
0
    if (!target->IsBundleOnApple()) {
5064
0
      ::reportError(
5065
0
        eval, content->GetOriginalExpression(),
5066
0
        "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
5067
0
      return std::string();
5068
0
    }
5069
5070
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
5071
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
5072
0
                                        cmGeneratorTarget::ContentLevel);
5073
0
  }
5074
};
5075
5076
template <>
5077
struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
5078
{
5079
  static std::string Create(cmGeneratorTarget* target,
5080
                            cm::GenEx::Evaluation* eval,
5081
                            GeneratorExpressionContent const* /*unused*/)
5082
0
  {
5083
0
    return target->GetFullPath(eval->Context.Config,
5084
0
                               cmStateEnums::RuntimeBinaryArtifact, true);
5085
0
  }
5086
};
5087
5088
template <>
5089
struct TargetFilesystemArtifactResultCreator<ArtifactImportTag>
5090
{
5091
  static std::string Create(cmGeneratorTarget* target,
5092
                            cm::GenEx::Evaluation* eval,
5093
                            GeneratorExpressionContent const* /*unused*/)
5094
0
  {
5095
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5096
0
      return target->GetFullPath(eval->Context.Config,
5097
0
                                 cmStateEnums::ImportLibraryArtifact, true);
5098
0
    }
5099
0
    return std::string{};
5100
0
  }
5101
};
5102
5103
template <typename ArtifactT>
5104
struct TargetFilesystemArtifactResultGetter
5105
{
5106
  static std::string Get(std::string const& result);
5107
};
5108
5109
template <>
5110
struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
5111
{
5112
  static std::string Get(std::string const& result)
5113
0
  {
5114
0
    return cmSystemTools::GetFilenameName(result);
5115
0
  }
5116
};
5117
5118
template <>
5119
struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
5120
{
5121
  static std::string Get(std::string const& result)
5122
0
  {
5123
0
    return cmSystemTools::GetFilenamePath(result);
5124
0
  }
5125
};
5126
5127
template <>
5128
struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
5129
{
5130
0
  static std::string Get(std::string const& result) { return result; }
5131
};
5132
5133
struct TargetArtifactBase : public cmGeneratorExpressionNode
5134
{
5135
172
  TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
5136
5137
protected:
5138
  cmGeneratorTarget* GetTarget(
5139
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5140
    GeneratorExpressionContent const* content,
5141
    cmGeneratorExpressionDAGChecker* dagChecker) const
5142
0
  {
5143
    // Lookup the referenced target.
5144
0
    std::string const& name = parameters.front();
5145
5146
0
    if (!cmGeneratorExpression::IsValidTargetName(name)) {
5147
0
      ::reportError(eval, content->GetOriginalExpression(),
5148
0
                    "Expression syntax not recognized.");
5149
0
      return nullptr;
5150
0
    }
5151
0
    cmGeneratorTarget* target =
5152
0
      eval->Context.LG->FindGeneratorTargetToUse(name);
5153
0
    if (!target) {
5154
0
      ::reportError(eval, content->GetOriginalExpression(),
5155
0
                    cmStrCat("No target \"", name, '"'));
5156
0
      return nullptr;
5157
0
    }
5158
0
    if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
5159
0
        target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
5160
0
      ::reportError(
5161
0
        eval, content->GetOriginalExpression(),
5162
0
        cmStrCat("Target \"", name, "\" is not an executable or library."));
5163
0
      return nullptr;
5164
0
    }
5165
0
    if (dagChecker &&
5166
0
        (dagChecker->EvaluatingLinkLibraries(target) ||
5167
0
         (dagChecker->EvaluatingSources() &&
5168
0
          target == dagChecker->TopTarget()))) {
5169
0
      ::reportError(eval, content->GetOriginalExpression(),
5170
0
                    "Expressions which require the linker language may not "
5171
0
                    "be used while evaluating link libraries");
5172
0
      return nullptr;
5173
0
    }
5174
5175
0
    return target;
5176
0
  }
5177
};
5178
5179
template <typename ArtifactT, typename ComponentT>
5180
struct TargetFilesystemArtifact : public TargetArtifactBase
5181
{
5182
108
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5182
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
5183
5184
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
5185
5186
  std::string Evaluate(
5187
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5188
    GeneratorExpressionContent const* content,
5189
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5190
0
  {
5191
0
    cmGeneratorTarget* target =
5192
0
      this->GetTarget(parameters, eval, content, dagChecker);
5193
0
    if (!target) {
5194
0
      return std::string();
5195
0
    }
5196
    // Not a dependent target if we are querying for ArtifactDirTag,
5197
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5198
    // and ArtifactBundleContentDirTag
5199
0
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5200
0
      target, eval);
5201
5202
0
    std::string result =
5203
0
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5204
0
                                                               content);
5205
0
    if (eval->HadError) {
5206
0
      return std::string();
5207
0
    }
5208
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5209
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
5210
};
5211
5212
template <typename ArtifactT>
5213
struct TargetFilesystemArtifactNodeGroup
5214
{
5215
  TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
5216
32
  {
5217
32
  }
TargetFilesystemArtifactNodeGroup<ArtifactNameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5216
4
  {
5217
4
  }
5218
5219
  TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
5220
  TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
5221
  TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
5222
};
5223
5224
static TargetFilesystemArtifactNodeGroup<ArtifactNameTag> const
5225
  targetNodeGroup;
5226
5227
static TargetFilesystemArtifactNodeGroup<ArtifactImportTag> const
5228
  targetImportNodeGroup;
5229
5230
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag> const
5231
  targetLinkerNodeGroup;
5232
5233
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag> const
5234
  targetLinkerLibraryNodeGroup;
5235
5236
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag> const
5237
  targetLinkerImportNodeGroup;
5238
5239
static TargetFilesystemArtifactNodeGroup<ArtifactSonameTag> const
5240
  targetSoNameNodeGroup;
5241
5242
static TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag> const
5243
  targetSoNameImportNodeGroup;
5244
5245
static TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> const
5246
  targetPdbNodeGroup;
5247
5248
static TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag> const
5249
  targetBundleDirNode;
5250
5251
static TargetFilesystemArtifact<ArtifactBundleDirNameTag,
5252
                                ArtifactNameTag> const targetBundleDirNameNode;
5253
5254
static TargetFilesystemArtifact<ArtifactBundleContentDirTag,
5255
                                ArtifactPathTag> const
5256
  targetBundleContentDirNode;
5257
5258
//
5259
// To retrieve base name for various artifacts
5260
//
5261
enum class Postfix
5262
{
5263
  Unspecified,
5264
  Exclude,
5265
  Include
5266
};
5267
5268
template <typename ArtifactT>
5269
struct TargetOutputNameArtifactResultGetter
5270
{
5271
  static std::string Get(cmGeneratorTarget* target,
5272
                         cm::GenEx::Evaluation* eval,
5273
                         GeneratorExpressionContent const* content,
5274
                         Postfix postfix);
5275
};
5276
5277
template <>
5278
struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
5279
{
5280
  static std::string Get(cmGeneratorTarget* target,
5281
                         cm::GenEx::Evaluation* eval,
5282
                         GeneratorExpressionContent const* /*unused*/,
5283
                         Postfix postfix)
5284
0
  {
5285
0
    auto output = target->GetOutputName(eval->Context.Config,
5286
0
                                        cmStateEnums::RuntimeBinaryArtifact);
5287
0
    return postfix != Postfix::Exclude
5288
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5289
0
      : output;
5290
0
  }
5291
};
5292
5293
template <>
5294
struct TargetOutputNameArtifactResultGetter<ArtifactImportTag>
5295
{
5296
  static std::string Get(cmGeneratorTarget* target,
5297
                         cm::GenEx::Evaluation* eval,
5298
                         GeneratorExpressionContent const* /*unused*/,
5299
                         Postfix postfix)
5300
0
  {
5301
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5302
0
      auto output = target->GetOutputName(eval->Context.Config,
5303
0
                                          cmStateEnums::ImportLibraryArtifact);
5304
0
      return postfix != Postfix::Exclude
5305
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5306
0
        : output;
5307
0
    }
5308
0
    return std::string{};
5309
0
  }
5310
};
5311
5312
template <>
5313
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
5314
{
5315
  static std::string Get(cmGeneratorTarget* target,
5316
                         cm::GenEx::Evaluation* eval,
5317
                         GeneratorExpressionContent const* content,
5318
                         Postfix postfix)
5319
0
  {
5320
    // The library file used to link to the target (.so, .lib, .a) or import
5321
    // file (.lin,  .tbd).
5322
0
    if (!target->IsLinkable()) {
5323
0
      ::reportError(eval, content->GetOriginalExpression(),
5324
0
                    "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
5325
0
                    "libraries and executables with ENABLE_EXPORTS.");
5326
0
      return std::string();
5327
0
    }
5328
0
    cmStateEnums::ArtifactType artifact =
5329
0
      target->HasImportLibrary(eval->Context.Config)
5330
0
      ? cmStateEnums::ImportLibraryArtifact
5331
0
      : cmStateEnums::RuntimeBinaryArtifact;
5332
0
    auto output = target->GetOutputName(eval->Context.Config, artifact);
5333
0
    return postfix != Postfix::Exclude
5334
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5335
0
      : output;
5336
0
  }
5337
};
5338
5339
template <>
5340
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag>
5341
{
5342
  static std::string Get(cmGeneratorTarget* target,
5343
                         cm::GenEx::Evaluation* eval,
5344
                         GeneratorExpressionContent const* content,
5345
                         Postfix postfix)
5346
0
  {
5347
    // The library file used to link to the target (.so, .lib, .a).
5348
0
    if (!target->IsLinkable() ||
5349
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
5350
0
      ::reportError(eval, content->GetOriginalExpression(),
5351
0
                    "TARGET_LINKER_LIBRARY_FILE_BASE_NAME is allowed only for "
5352
0
                    "libraries with ENABLE_EXPORTS.");
5353
0
      return std::string();
5354
0
    }
5355
5356
0
    if (!target->IsDLLPlatform() ||
5357
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5358
0
      auto output = target->GetOutputName(eval->Context.Config,
5359
0
                                          cmStateEnums::ImportLibraryArtifact);
5360
0
      return postfix != Postfix::Exclude
5361
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5362
0
        : output;
5363
0
    }
5364
0
    return std::string{};
5365
0
  }
5366
};
5367
5368
template <>
5369
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag>
5370
{
5371
  static std::string Get(cmGeneratorTarget* target,
5372
                         cm::GenEx::Evaluation* eval,
5373
                         GeneratorExpressionContent const* content,
5374
                         Postfix postfix)
5375
0
  {
5376
    // The import file used to link to the target (.lib, .tbd).
5377
0
    if (!target->IsLinkable()) {
5378
0
      ::reportError(eval, content->GetOriginalExpression(),
5379
0
                    "TARGET_LINKER_IMPORT_FILE_BASE_NAME is allowed only for "
5380
0
                    "libraries and executables with ENABLE_EXPORTS.");
5381
0
      return std::string();
5382
0
    }
5383
5384
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5385
0
      auto output = target->GetOutputName(eval->Context.Config,
5386
0
                                          cmStateEnums::ImportLibraryArtifact);
5387
0
      return postfix != Postfix::Exclude
5388
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5389
0
        : output;
5390
0
    }
5391
0
    return std::string{};
5392
0
  }
5393
};
5394
5395
template <>
5396
struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
5397
{
5398
  static std::string Get(cmGeneratorTarget* target,
5399
                         cm::GenEx::Evaluation* eval,
5400
                         GeneratorExpressionContent const* content,
5401
                         Postfix postfix)
5402
0
  {
5403
0
    if (target->IsImported()) {
5404
0
      ::reportError(
5405
0
        eval, content->GetOriginalExpression(),
5406
0
        "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
5407
0
      return std::string();
5408
0
    }
5409
5410
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
5411
5412
0
    std::string pdbSupportVar =
5413
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
5414
5415
0
    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
5416
0
      ::reportError(
5417
0
        eval, content->GetOriginalExpression(),
5418
0
        "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
5419
0
      return std::string();
5420
0
    }
5421
5422
0
    cmStateEnums::TargetType targetType = target->GetType();
5423
5424
0
    if (targetType != cmStateEnums::SHARED_LIBRARY &&
5425
0
        targetType != cmStateEnums::MODULE_LIBRARY &&
5426
0
        targetType != cmStateEnums::EXECUTABLE) {
5427
0
      ::reportError(eval, content->GetOriginalExpression(),
5428
0
                    "TARGET_PDB_FILE_BASE_NAME is allowed only for "
5429
0
                    "targets with linker created artifacts.");
5430
0
      return std::string();
5431
0
    }
5432
5433
0
    auto output = target->GetPDBOutputName(eval->Context.Config);
5434
5435
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::NEW) {
5436
0
      return postfix != Postfix::Exclude
5437
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5438
0
        : output;
5439
0
    }
5440
5441
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::WARN &&
5442
0
        postfix != Postfix::Unspecified) {
5443
0
      eval->Context.LG->GetCMakeInstance()->IssueMessage(
5444
0
        MessageType::AUTHOR_WARNING,
5445
0
        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0202),
5446
0
                 "\n"
5447
0
                 "\"POSTFIX\" option is recognized only when the policy is "
5448
0
                 "set to NEW. Since the policy is not set, the OLD behavior "
5449
0
                 "will be used."),
5450
0
        eval->Backtrace);
5451
0
    }
5452
5453
0
    return output;
5454
0
  }
5455
};
5456
5457
template <typename ArtifactT>
5458
struct TargetFileBaseNameArtifact : public TargetArtifactBase
5459
{
5460
24
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactNameTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactPdbTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5460
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
5461
5462
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
5463
5464
  std::string Evaluate(
5465
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5466
    GeneratorExpressionContent const* content,
5467
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5468
0
  {
5469
0
    if (parameters.size() > 2) {
5470
0
      ::reportError(eval, content->GetOriginalExpression(),
5471
0
                    "Unexpected parameters, require one or two parameters.");
5472
0
      return std::string{};
5473
0
    }
5474
5475
0
    cmGeneratorTarget* target =
5476
0
      this->GetTarget(parameters, eval, content, dagChecker);
5477
0
    if (!target) {
5478
0
      return std::string();
5479
0
    }
5480
5481
0
    Postfix postfix = Postfix::Unspecified;
5482
0
    if (parameters.size() == 2) {
5483
0
      if (parameters[1] == "POSTFIX:INCLUDE") {
5484
0
        postfix = Postfix::Include;
5485
0
      } else if (parameters[1] == "POSTFIX:EXCLUDE") {
5486
0
        postfix = Postfix::Exclude;
5487
0
      } else {
5488
0
        ::reportError(eval, content->GetOriginalExpression(),
5489
0
                      "Wrong second parameter: \"POSTFIX:INCLUDE\" or "
5490
0
                      "\"POSTFIX:EXCLUDE\" is expected");
5491
0
      }
5492
0
    }
5493
5494
0
    std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
5495
0
      target, eval, content, postfix);
5496
0
    if (eval->HadError) {
5497
0
      return std::string();
5498
0
    }
5499
0
    return result;
5500
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
5501
};
5502
5503
static TargetFileBaseNameArtifact<ArtifactNameTag> const
5504
  targetFileBaseNameNode;
5505
static TargetFileBaseNameArtifact<ArtifactImportTag> const
5506
  targetImportFileBaseNameNode;
5507
static TargetFileBaseNameArtifact<ArtifactLinkerTag> const
5508
  targetLinkerFileBaseNameNode;
5509
static TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag> const
5510
  targetLinkerLibraryFileBaseNameNode;
5511
static TargetFileBaseNameArtifact<ArtifactLinkerImportTag> const
5512
  targetLinkerImportFileBaseNameNode;
5513
static TargetFileBaseNameArtifact<ArtifactPdbTag> const
5514
  targetPdbFileBaseNameNode;
5515
5516
class ArtifactFilePrefixTag;
5517
class ArtifactImportFilePrefixTag;
5518
class ArtifactLinkerFilePrefixTag;
5519
class ArtifactLinkerLibraryFilePrefixTag;
5520
class ArtifactLinkerImportFilePrefixTag;
5521
class ArtifactFileSuffixTag;
5522
class ArtifactImportFileSuffixTag;
5523
class ArtifactLinkerFileSuffixTag;
5524
class ArtifactLinkerLibraryFileSuffixTag;
5525
class ArtifactLinkerImportFileSuffixTag;
5526
5527
template <typename ArtifactT>
5528
struct TargetFileArtifactResultGetter
5529
{
5530
  static std::string Get(cmGeneratorTarget* target,
5531
                         cm::GenEx::Evaluation* eval,
5532
                         GeneratorExpressionContent const* content);
5533
};
5534
5535
template <>
5536
struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
5537
{
5538
  static std::string Get(cmGeneratorTarget* target,
5539
                         cm::GenEx::Evaluation* eval,
5540
                         GeneratorExpressionContent const*)
5541
0
  {
5542
0
    return target->GetFilePrefix(eval->Context.Config);
5543
0
  }
5544
};
5545
template <>
5546
struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag>
5547
{
5548
  static std::string Get(cmGeneratorTarget* target,
5549
                         cm::GenEx::Evaluation* eval,
5550
                         GeneratorExpressionContent const*)
5551
0
  {
5552
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5553
0
      return target->GetFilePrefix(eval->Context.Config,
5554
0
                                   cmStateEnums::ImportLibraryArtifact);
5555
0
    }
5556
0
    return std::string{};
5557
0
  }
5558
};
5559
template <>
5560
struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
5561
{
5562
  static std::string Get(cmGeneratorTarget* target,
5563
                         cm::GenEx::Evaluation* eval,
5564
                         GeneratorExpressionContent const* content)
5565
0
  {
5566
0
    if (!target->IsLinkable()) {
5567
0
      ::reportError(
5568
0
        eval, content->GetOriginalExpression(),
5569
0
        "TARGET_LINKER_FILE_PREFIX is allowed only for libraries and "
5570
0
        "executables with ENABLE_EXPORTS.");
5571
0
      return std::string();
5572
0
    }
5573
5574
0
    cmStateEnums::ArtifactType artifact =
5575
0
      target->HasImportLibrary(eval->Context.Config)
5576
0
      ? cmStateEnums::ImportLibraryArtifact
5577
0
      : cmStateEnums::RuntimeBinaryArtifact;
5578
5579
0
    return target->GetFilePrefix(eval->Context.Config, artifact);
5580
0
  }
5581
};
5582
template <>
5583
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag>
5584
{
5585
  static std::string Get(cmGeneratorTarget* target,
5586
                         cm::GenEx::Evaluation* eval,
5587
                         GeneratorExpressionContent const* content)
5588
0
  {
5589
0
    if (!target->IsLinkable() ||
5590
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
5591
0
      ::reportError(
5592
0
        eval, content->GetOriginalExpression(),
5593
0
        "TARGET_LINKER_LIBRARY_FILE_PREFIX is allowed only for libraries "
5594
0
        "with ENABLE_EXPORTS.");
5595
0
      return std::string();
5596
0
    }
5597
5598
0
    if (!target->IsDLLPlatform() ||
5599
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5600
0
      return target->GetFilePrefix(eval->Context.Config,
5601
0
                                   cmStateEnums::RuntimeBinaryArtifact);
5602
0
    }
5603
0
    return std::string{};
5604
0
  }
5605
};
5606
template <>
5607
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag>
5608
{
5609
  static std::string Get(cmGeneratorTarget* target,
5610
                         cm::GenEx::Evaluation* eval,
5611
                         GeneratorExpressionContent const* content)
5612
0
  {
5613
0
    if (!target->IsLinkable()) {
5614
0
      ::reportError(
5615
0
        eval, content->GetOriginalExpression(),
5616
0
        "TARGET_LINKER_IMPORT_FILE_PREFIX is allowed only for libraries and "
5617
0
        "executables with ENABLE_EXPORTS.");
5618
0
      return std::string();
5619
0
    }
5620
5621
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5622
0
      return target->GetFilePrefix(eval->Context.Config,
5623
0
                                   cmStateEnums::ImportLibraryArtifact);
5624
0
    }
5625
0
    return std::string{};
5626
0
  }
5627
};
5628
template <>
5629
struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
5630
{
5631
  static std::string Get(cmGeneratorTarget* target,
5632
                         cm::GenEx::Evaluation* eval,
5633
                         GeneratorExpressionContent const*)
5634
0
  {
5635
0
    return target->GetFileSuffix(eval->Context.Config);
5636
0
  }
5637
};
5638
template <>
5639
struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag>
5640
{
5641
  static std::string Get(cmGeneratorTarget* target,
5642
                         cm::GenEx::Evaluation* eval,
5643
                         GeneratorExpressionContent const*)
5644
0
  {
5645
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5646
0
      return target->GetFileSuffix(eval->Context.Config,
5647
0
                                   cmStateEnums::ImportLibraryArtifact);
5648
0
    }
5649
0
    return std::string{};
5650
0
  }
5651
};
5652
template <>
5653
struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
5654
{
5655
  static std::string Get(cmGeneratorTarget* target,
5656
                         cm::GenEx::Evaluation* eval,
5657
                         GeneratorExpressionContent const* content)
5658
0
  {
5659
0
    if (!target->IsLinkable()) {
5660
0
      ::reportError(
5661
0
        eval, content->GetOriginalExpression(),
5662
0
        "TARGET_LINKER_FILE_SUFFIX is allowed only for libraries and "
5663
0
        "executables with ENABLE_EXPORTS.");
5664
0
      return std::string();
5665
0
    }
5666
5667
0
    cmStateEnums::ArtifactType artifact =
5668
0
      target->HasImportLibrary(eval->Context.Config)
5669
0
      ? cmStateEnums::ImportLibraryArtifact
5670
0
      : cmStateEnums::RuntimeBinaryArtifact;
5671
5672
0
    return target->GetFileSuffix(eval->Context.Config, artifact);
5673
0
  }
5674
};
5675
template <>
5676
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag>
5677
{
5678
  static std::string Get(cmGeneratorTarget* target,
5679
                         cm::GenEx::Evaluation* eval,
5680
                         GeneratorExpressionContent const* content)
5681
0
  {
5682
0
    if (!target->IsLinkable() ||
5683
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5684
0
      ::reportError(eval, content->GetOriginalExpression(),
5685
0
                    "TARGET_LINKER_LIBRARY_FILE_SUFFIX is allowed only for "
5686
0
                    "libraries with ENABLE_EXPORTS.");
5687
0
      return std::string();
5688
0
    }
5689
5690
0
    if (!target->IsDLLPlatform() ||
5691
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5692
0
      return target->GetFileSuffix(eval->Context.Config,
5693
0
                                   cmStateEnums::RuntimeBinaryArtifact);
5694
0
    }
5695
0
    return std::string{};
5696
0
  }
5697
};
5698
template <>
5699
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag>
5700
{
5701
  static std::string Get(cmGeneratorTarget* target,
5702
                         cm::GenEx::Evaluation* eval,
5703
                         GeneratorExpressionContent const* content)
5704
0
  {
5705
0
    if (!target->IsLinkable()) {
5706
0
      ::reportError(
5707
0
        eval, content->GetOriginalExpression(),
5708
0
        "TARGET_LINKER_IMPORT_FILE_SUFFIX is allowed only for libraries and "
5709
0
        "executables with ENABLE_EXPORTS.");
5710
0
      return std::string();
5711
0
    }
5712
5713
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5714
0
      return target->GetFileSuffix(eval->Context.Config,
5715
0
                                   cmStateEnums::ImportLibraryArtifact);
5716
0
    }
5717
0
    return std::string{};
5718
0
  }
5719
};
5720
5721
template <typename ArtifactT>
5722
struct TargetFileArtifact : public TargetArtifactBase
5723
{
5724
40
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5724
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
5725
5726
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
5727
5728
  std::string Evaluate(
5729
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5730
    GeneratorExpressionContent const* content,
5731
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5732
0
  {
5733
0
    cmGeneratorTarget* target =
5734
0
      this->GetTarget(parameters, eval, content, dagChecker);
5735
0
    if (!target) {
5736
0
      return std::string();
5737
0
    }
5738
5739
0
    std::string result =
5740
0
      TargetFileArtifactResultGetter<ArtifactT>::Get(target, eval, content);
5741
0
    if (eval->HadError) {
5742
0
      return std::string();
5743
0
    }
5744
0
    return result;
5745
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
5746
};
5747
5748
static TargetFileArtifact<ArtifactFilePrefixTag> const targetFilePrefixNode;
5749
static TargetFileArtifact<ArtifactImportFilePrefixTag> const
5750
  targetImportFilePrefixNode;
5751
static TargetFileArtifact<ArtifactLinkerFilePrefixTag> const
5752
  targetLinkerFilePrefixNode;
5753
static TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag> const
5754
  targetLinkerLibraryFilePrefixNode;
5755
static TargetFileArtifact<ArtifactLinkerImportFilePrefixTag> const
5756
  targetLinkerImportFilePrefixNode;
5757
static TargetFileArtifact<ArtifactFileSuffixTag> const targetFileSuffixNode;
5758
static TargetFileArtifact<ArtifactImportFileSuffixTag> const
5759
  targetImportFileSuffixNode;
5760
static TargetFileArtifact<ArtifactLinkerFileSuffixTag> const
5761
  targetLinkerFileSuffixNode;
5762
static TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag> const
5763
  targetLinkerLibraryFileSuffixNode;
5764
static TargetFileArtifact<ArtifactLinkerImportFileSuffixTag> const
5765
  targetLinkerImportFileSuffixNode;
5766
5767
static const struct ShellPathNode : public cmGeneratorExpressionNode
5768
{
5769
4
  ShellPathNode() {} // NOLINT(modernize-use-equals-default)
5770
5771
  std::string Evaluate(
5772
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5773
    GeneratorExpressionContent const* content,
5774
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5775
0
  {
5776
0
    cmList list_in{ parameters.front() };
5777
0
    if (list_in.empty()) {
5778
0
      reportError(eval, content->GetOriginalExpression(),
5779
0
                  "\"\" is not an absolute path.");
5780
0
      return std::string();
5781
0
    }
5782
0
    cmStateSnapshot snapshot = eval->Context.LG->GetStateSnapshot();
5783
0
    cmOutputConverter converter(snapshot);
5784
0
    char const* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
5785
0
    std::vector<std::string> list_out;
5786
0
    list_out.reserve(list_in.size());
5787
0
    for (auto const& in : list_in) {
5788
0
      if (!cmSystemTools::FileIsFullPath(in)) {
5789
0
        reportError(eval, content->GetOriginalExpression(),
5790
0
                    cmStrCat('"', in, "\" is not an absolute path."));
5791
0
        return std::string();
5792
0
      }
5793
0
      list_out.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
5794
0
    }
5795
0
    return cmJoin(list_out, separator);
5796
0
  }
5797
} shellPathNode;
5798
5799
cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
5800
  std::string const& identifier)
5801
0
{
5802
0
  static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
5803
0
    { "0", &zeroNode },
5804
0
    { "1", &oneNode },
5805
0
    { "AND", &andNode },
5806
0
    { "OR", &orNode },
5807
0
    { "NOT", &notNode },
5808
0
    { "C_COMPILER_ID", &cCompilerIdNode },
5809
0
    { "CXX_COMPILER_ID", &cxxCompilerIdNode },
5810
0
    { "OBJC_COMPILER_ID", &objcCompilerIdNode },
5811
0
    { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode },
5812
0
    { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
5813
0
    { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
5814
0
    { "HIP_COMPILER_ID", &hipCompilerIdNode },
5815
0
    { "VERSION_GREATER", &versionGreaterNode },
5816
0
    { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
5817
0
    { "VERSION_LESS", &versionLessNode },
5818
0
    { "VERSION_LESS_EQUAL", &versionLessEqNode },
5819
0
    { "VERSION_EQUAL", &versionEqualNode },
5820
0
    { "C_COMPILER_VERSION", &cCompilerVersionNode },
5821
0
    { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
5822
0
    { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
5823
0
    { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode },
5824
0
    { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode },
5825
0
    { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
5826
0
    { "HIP_COMPILER_VERSION", &hipCompilerVersionNode },
5827
0
    { "C_COMPILER_FRONTEND_VARIANT", &cCompilerFrontendVariantNode },
5828
0
    { "CXX_COMPILER_FRONTEND_VARIANT", &cxxCompilerFrontendVariantNode },
5829
0
    { "CUDA_COMPILER_FRONTEND_VARIANT", &cudaCompilerFrontendVariantNode },
5830
0
    { "OBJC_COMPILER_FRONTEND_VARIANT", &objcCompilerFrontendVariantNode },
5831
0
    { "OBJCXX_COMPILER_FRONTEND_VARIANT", &objcxxCompilerFrontendVariantNode },
5832
0
    { "Fortran_COMPILER_FRONTEND_VARIANT",
5833
0
      &fortranCompilerFrontendVariantNode },
5834
0
    { "HIP_COMPILER_FRONTEND_VARIANT", &hipCompilerFrontendVariantNode },
5835
0
    { "PLATFORM_ID", &platformIdNode },
5836
0
    { "COMPILE_FEATURES", &compileFeaturesNode },
5837
0
    { "CONFIGURATION", &configurationNode },
5838
0
    { "CONFIG", &configurationTestNode },
5839
0
    { "TARGET_FILE", &targetNodeGroup.File },
5840
0
    { "TARGET_IMPORT_FILE", &targetImportNodeGroup.File },
5841
0
    { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
5842
0
    { "TARGET_LINKER_LIBRARY_FILE", &targetLinkerLibraryNodeGroup.File },
5843
0
    { "TARGET_LINKER_IMPORT_FILE", &targetLinkerImportNodeGroup.File },
5844
0
    { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
5845
0
    { "TARGET_SONAME_IMPORT_FILE", &targetSoNameImportNodeGroup.File },
5846
0
    { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
5847
0
    { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
5848
0
    { "TARGET_IMPORT_FILE_BASE_NAME", &targetImportFileBaseNameNode },
5849
0
    { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
5850
0
    { "TARGET_LINKER_LIBRARY_FILE_BASE_NAME",
5851
0
      &targetLinkerLibraryFileBaseNameNode },
5852
0
    { "TARGET_LINKER_IMPORT_FILE_BASE_NAME",
5853
0
      &targetLinkerImportFileBaseNameNode },
5854
0
    { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
5855
0
    { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
5856
0
    { "TARGET_IMPORT_FILE_PREFIX", &targetImportFilePrefixNode },
5857
0
    { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
5858
0
    { "TARGET_LINKER_LIBRARY_FILE_PREFIX",
5859
0
      &targetLinkerLibraryFilePrefixNode },
5860
0
    { "TARGET_LINKER_IMPORT_FILE_PREFIX", &targetLinkerImportFilePrefixNode },
5861
0
    { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
5862
0
    { "TARGET_IMPORT_FILE_SUFFIX", &targetImportFileSuffixNode },
5863
0
    { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
5864
0
    { "TARGET_LINKER_LIBRARY_FILE_SUFFIX",
5865
0
      &targetLinkerLibraryFileSuffixNode },
5866
0
    { "TARGET_LINKER_IMPORT_FILE_SUFFIX", &targetLinkerImportFileSuffixNode },
5867
0
    { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
5868
0
    { "TARGET_IMPORT_FILE_NAME", &targetImportNodeGroup.FileName },
5869
0
    { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
5870
0
    { "TARGET_LINKER_LIBRARY_FILE_NAME",
5871
0
      &targetLinkerLibraryNodeGroup.FileName },
5872
0
    { "TARGET_LINKER_IMPORT_FILE_NAME",
5873
0
      &targetLinkerImportNodeGroup.FileName },
5874
0
    { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
5875
0
    { "TARGET_SONAME_IMPORT_FILE_NAME",
5876
0
      &targetSoNameImportNodeGroup.FileName },
5877
0
    { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
5878
0
    { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
5879
0
    { "TARGET_IMPORT_FILE_DIR", &targetImportNodeGroup.FileDir },
5880
0
    { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
5881
0
    { "TARGET_LINKER_LIBRARY_FILE_DIR",
5882
0
      &targetLinkerLibraryNodeGroup.FileDir },
5883
0
    { "TARGET_LINKER_IMPORT_FILE_DIR", &targetLinkerImportNodeGroup.FileDir },
5884
0
    { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
5885
0
    { "TARGET_SONAME_IMPORT_FILE_DIR", &targetSoNameImportNodeGroup.FileDir },
5886
0
    { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
5887
0
    { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
5888
0
    { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode },
5889
0
    { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
5890
0
    { "STREQUAL", &strEqualNode },
5891
0
    { "STRLESS", &strLessNode },
5892
0
    { "STRLESS_EQUAL", &strLessEqualNode },
5893
0
    { "STRGREATER", &strGreaterNode },
5894
0
    { "STRGREATER_EQUAL", &strGreaterEqualNode },
5895
0
    { "STRING", &stringNode },
5896
0
    { "EQUAL", &equalNode },
5897
0
    { "IN_LIST", &inListNode },
5898
0
    { "FILTER", &filterNode },
5899
0
    { "REMOVE_DUPLICATES", &removeDuplicatesNode },
5900
0
    { "LIST", &listNode },
5901
0
    { "LOWER_CASE", &lowerCaseNode },
5902
0
    { "UPPER_CASE", &upperCaseNode },
5903
0
    { "PATH", &pathNode },
5904
0
    { "PATH_EQUAL", &pathEqualNode },
5905
0
    { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
5906
0
    { "BOOL", &boolNode },
5907
0
    { "IF", &ifNode },
5908
0
    { "ANGLE-R", &angle_rNode },
5909
0
    { "COMMA", &commaNode },
5910
0
    { "SEMICOLON", &semicolonNode },
5911
0
    { "QUOTE", &quoteNode },
5912
0
    { "SOURCE_EXISTS", &sourceExistsNode },
5913
0
    { "SOURCE_PROPERTY", &sourcePropertyNode },
5914
0
    { "FILE_SET_EXISTS", &fileSetExistsNode },
5915
0
    { "FILE_SET_PROPERTY", &fileSetPropertyNode },
5916
0
    { "TARGET_PROPERTY", &targetPropertyNode },
5917
0
    { "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
5918
0
    { "TARGET_NAME", &targetNameNode },
5919
0
    { "TARGET_OBJECTS", &targetObjectsNode },
5920
0
    { "TARGET_POLICY", &targetPolicyNode },
5921
0
    { "TARGET_EXISTS", &targetExistsNode },
5922
0
    { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
5923
0
    { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
5924
0
    { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
5925
0
    { "TARGET_RUNTIME_DLL_DIRS", &targetRuntimeDllDirsNode },
5926
0
    { "GENEX_EVAL", &genexEvalNode },
5927
0
    { "BUILD_INTERFACE", &buildInterfaceNode },
5928
0
    { "INSTALL_INTERFACE", &installInterfaceNode },
5929
0
    { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode },
5930
0
    { "INSTALL_PREFIX", &installPrefixNode },
5931
0
    { "JOIN", &joinNode },
5932
0
    { "COMPILE_ONLY", &compileOnlyNode },
5933
0
    { "LINK_ONLY", &linkOnlyNode },
5934
0
    { "COMPILE_LANG_AND_ID", &languageAndIdNode },
5935
0
    { "COMPILE_LANGUAGE", &languageNode },
5936
0
    { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
5937
0
    { "LINK_LANGUAGE", &linkLanguageNode },
5938
0
    { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
5939
0
    { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
5940
0
    { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
5941
0
    { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
5942
0
    { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
5943
0
    { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
5944
0
    { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
5945
0
    { "C_COMPILER_LINKER_FRONTEND_VARIANT",
5946
0
      &cCompilerLinkerFrontendVariantNode },
5947
0
    { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
5948
0
      &cxxCompilerLinkerFrontendVariantNode },
5949
0
    { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
5950
0
      &cudaCompilerLinkerFrontendVariantNode },
5951
0
    { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
5952
0
      &objcCompilerLinkerFrontendVariantNode },
5953
0
    { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
5954
0
      &objcxxCompilerLinkerFrontendVariantNode },
5955
0
    { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
5956
0
      &fortranCompilerLinkerFrontendVariantNode },
5957
0
    { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
5958
0
      &hipCompilerLinkerFrontendVariantNode },
5959
0
    { "LINK_LIBRARY", &linkLibraryNode },
5960
0
    { "LINK_GROUP", &linkGroupNode },
5961
0
    { "HOST_LINK", &hostLinkNode },
5962
0
    { "DEVICE_LINK", &deviceLinkNode },
5963
0
    { "SHELL_PATH", &shellPathNode }
5964
0
  };
5965
5966
0
  {
5967
0
    auto itr = nodeMap.find(identifier);
5968
0
    if (itr != nodeMap.end()) {
5969
0
      return itr->second;
5970
0
    }
5971
0
  }
5972
0
  return nullptr;
5973
0
}
5974
5975
void reportError(cm::GenEx::Evaluation* eval, std::string const& expr,
5976
                 std::string const& result)
5977
0
{
5978
0
  eval->HadError = true;
5979
0
  if (eval->Quiet) {
5980
0
    return;
5981
0
  }
5982
5983
0
  std::ostringstream e;
5984
  /* clang-format off */
5985
0
  e << "Error evaluating generator expression:\n"
5986
0
    << "  " << expr << "\n"
5987
0
    << result;
5988
  /* clang-format on */
5989
0
  eval->Context.LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
5990
0
                                                     e.str(), eval->Backtrace);
5991
0
}