Coverage Report

Created: 2026-02-09 06:05

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 "cmFileSet.h"
33
#include "cmGenExContext.h"
34
#include "cmGenExEvaluation.h"
35
#include "cmGeneratorExpression.h"
36
#include "cmGeneratorExpressionDAGChecker.h"
37
#include "cmGeneratorExpressionEvaluator.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, cmFileSet*& fileSet)
3586
0
{
3587
0
  auto const& fileSetName = parameters[0];
3588
0
  auto targetName = parameters[1];
3589
0
  auto* makefile = eval->Context.LG->GetMakefile();
3590
0
  fileSet = nullptr;
3591
3592
0
  auto const TARGET = "TARGET:"_s;
3593
3594
0
  if (cmHasPrefix(targetName, TARGET)) {
3595
0
    targetName = targetName.substr(TARGET.length());
3596
0
    if (targetName.empty()) {
3597
0
      reportError(eval, content->GetOriginalExpression(),
3598
0
                  cmStrCat("No value provided for the ", TARGET, " option."));
3599
0
      return false;
3600
0
    }
3601
0
    auto* target = makefile->FindTargetToUse(targetName);
3602
0
    if (!target) {
3603
0
      reportError(eval, content->GetOriginalExpression(),
3604
0
                  cmStrCat("Non-existent target: ", targetName));
3605
0
      return false;
3606
0
    }
3607
0
    fileSet = target->GetFileSet(fileSetName);
3608
0
  } else {
3609
0
    reportError(eval, content->GetOriginalExpression(),
3610
0
                cmStrCat("Invalid option. ", TARGET, " expected."));
3611
0
    return false;
3612
0
  }
3613
0
  return true;
3614
0
}
3615
}
3616
3617
static const struct FileSetExistsNode : public cmGeneratorExpressionNode
3618
{
3619
4
  FileSetExistsNode() {} // NOLINT(modernize-use-equals-default)
3620
3621
  // This node handles errors on parameter count itself.
3622
0
  int NumExpectedParameters() const override { return 2; }
3623
3624
  std::string Evaluate(
3625
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3626
    GeneratorExpressionContent const* content,
3627
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3628
0
  {
3629
0
    if (parameters[0].empty()) {
3630
0
      reportError(
3631
0
        eval, content->GetOriginalExpression(),
3632
0
        "$<FILE_SET_EXISTS:fileset,TARGET:tgt> expression requires a "
3633
0
        "non-empty FILE_SET name.");
3634
0
      return std::string{};
3635
0
    }
3636
3637
0
    cmFileSet* fileSet = nullptr;
3638
0
    if (!GetFileSet(parameters, eval, content, fileSet)) {
3639
0
      return std::string{};
3640
0
    }
3641
3642
0
    return fileSet ? "1" : "0";
3643
0
  }
3644
} fileSetExistsNode;
3645
3646
static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
3647
{
3648
4
  FileSetPropertyNode() {} // NOLINT(modernize-use-equals-default)
3649
3650
  // This node handles errors on parameter count itself.
3651
0
  int NumExpectedParameters() const override { return 3; }
3652
3653
  std::string Evaluate(
3654
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3655
    GeneratorExpressionContent const* content,
3656
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3657
0
  {
3658
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3659
3660
0
    std::string const& fileSetName = parameters.front();
3661
0
    std::string const& propertyName = parameters.back();
3662
3663
0
    if (fileSetName.empty() && propertyName.empty()) {
3664
0
      reportError(eval, content->GetOriginalExpression(),
3665
0
                  "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression "
3666
0
                  "requires a non-empty FILE_SET name and property name.");
3667
0
      return std::string{};
3668
0
    }
3669
0
    if (fileSetName.empty()) {
3670
0
      reportError(
3671
0
        eval, content->GetOriginalExpression(),
3672
0
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
3673
0
        "non-empty FILE_SET name.");
3674
0
      return std::string{};
3675
0
    }
3676
0
    if (propertyName.empty()) {
3677
0
      reportError(
3678
0
        eval, content->GetOriginalExpression(),
3679
0
        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
3680
0
        "non-empty property name.");
3681
0
      return std::string{};
3682
0
    }
3683
0
    if (!propertyNameValidator.find(propertyName)) {
3684
0
      reportError(eval, content->GetOriginalExpression(),
3685
0
                  "Property name not supported.");
3686
0
      return std::string{};
3687
0
    }
3688
3689
0
    cmFileSet* fileSet = nullptr;
3690
0
    if (!GetFileSet(parameters, eval, content, fileSet)) {
3691
0
      return std::string{};
3692
0
    }
3693
0
    if (!fileSet) {
3694
0
      reportError(
3695
0
        eval, content->GetOriginalExpression(),
3696
0
        cmStrCat("FILE_SET \"", fileSetName, "\" is not known from CMake."));
3697
0
      return std::string{};
3698
0
    }
3699
3700
0
    return fileSet->GetProperty(propertyName);
3701
0
  }
3702
} fileSetPropertyNode;
3703
3704
namespace {
3705
bool GetSourceFile(
3706
  cmRange<std::vector<std::string>::const_iterator> parameters,
3707
  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
3708
  cmSourceFile*& sourceFile)
3709
0
{
3710
0
  auto sourceName = *parameters.begin();
3711
0
  auto* makefile = eval->Context.LG->GetMakefile();
3712
0
  sourceFile = nullptr;
3713
3714
0
  if (parameters.size() == 2) {
3715
0
    auto const& option = *parameters.advance(1).begin();
3716
0
    auto const DIRECTORY = "DIRECTORY:"_s;
3717
0
    auto const TARGET_DIRECTORY = "TARGET_DIRECTORY:"_s;
3718
0
    if (cmHasPrefix(option, DIRECTORY)) {
3719
0
      auto dir = option.substr(DIRECTORY.length());
3720
0
      if (dir.empty()) {
3721
0
        reportError(
3722
0
          eval, content->GetOriginalExpression(),
3723
0
          cmStrCat("No value provided for the ", DIRECTORY, " option."));
3724
0
        return false;
3725
0
      }
3726
0
      dir = cmSystemTools::CollapseFullPath(
3727
0
        dir, makefile->GetCurrentSourceDirectory());
3728
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(dir);
3729
0
      if (!makefile) {
3730
0
        reportError(
3731
0
          eval, content->GetOriginalExpression(),
3732
0
          cmStrCat("Directory \"", dir, "\" is not known from CMake."));
3733
0
        return false;
3734
0
      }
3735
0
    } else if (cmHasPrefix(option, TARGET_DIRECTORY)) {
3736
0
      auto targetName = option.substr(TARGET_DIRECTORY.length());
3737
0
      if (targetName.empty()) {
3738
0
        reportError(eval, content->GetOriginalExpression(),
3739
0
                    cmStrCat("No value provided for the ", TARGET_DIRECTORY,
3740
0
                             " option."));
3741
0
        return false;
3742
0
      }
3743
0
      auto* target = makefile->FindTargetToUse(targetName);
3744
0
      if (!target) {
3745
0
        reportError(eval, content->GetOriginalExpression(),
3746
0
                    cmStrCat("Non-existent target: ", targetName));
3747
0
        return false;
3748
0
      }
3749
0
      makefile = makefile->GetGlobalGenerator()->FindMakefile(
3750
0
        target->GetProperty("BINARY_DIR"));
3751
0
    } else {
3752
0
      reportError(eval, content->GetOriginalExpression(),
3753
0
                  cmStrCat("Invalid option. ", DIRECTORY, " or ",
3754
0
                           TARGET_DIRECTORY, " expected."));
3755
0
      return false;
3756
0
    }
3757
3758
0
    sourceName = cmSystemTools::CollapseFullPath(
3759
0
      sourceName,
3760
0
      eval->Context.LG->GetMakefile()->GetCurrentSourceDirectory());
3761
0
  }
3762
3763
0
  sourceFile = makefile->GetSource(sourceName);
3764
0
  return true;
3765
0
}
3766
}
3767
3768
static const struct SourceExistsNode : public cmGeneratorExpressionNode
3769
{
3770
4
  SourceExistsNode() {} // NOLINT(modernize-use-equals-default)
3771
3772
  // This node handles errors on parameter count itself.
3773
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3774
3775
  std::string Evaluate(
3776
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3777
    GeneratorExpressionContent const* content,
3778
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3779
0
  {
3780
0
    if (parameters.size() > 2) {
3781
0
      reportError(eval, content->GetOriginalExpression(),
3782
0
                  "$<SOURCE_EXISTS:...> expression requires at most two "
3783
0
                  "parameters.");
3784
0
      return std::string{};
3785
0
    }
3786
3787
0
    if (parameters[0].empty()) {
3788
0
      reportError(eval, content->GetOriginalExpression(),
3789
0
                  "$<SOURCE_EXISTS:src> expression requires a "
3790
0
                  "non-empty source name.");
3791
0
      return std::string{};
3792
0
    }
3793
3794
0
    cmSourceFile* sourceFile = nullptr;
3795
0
    if (!GetSourceFile(cmMakeRange(parameters), eval, content, sourceFile)) {
3796
0
      return std::string{};
3797
0
    }
3798
3799
0
    return sourceFile ? "1" : "0";
3800
0
  }
3801
} sourceExistsNode;
3802
3803
static const struct SourcePropertyNode : public cmGeneratorExpressionNode
3804
{
3805
4
  SourcePropertyNode() {} // NOLINT(modernize-use-equals-default)
3806
3807
  // This node handles errors on parameter count itself.
3808
0
  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
3809
3810
  std::string Evaluate(
3811
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3812
    GeneratorExpressionContent const* content,
3813
    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
3814
0
  {
3815
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3816
3817
0
    if (parameters.size() > 3) {
3818
0
      reportError(eval, content->GetOriginalExpression(),
3819
0
                  "$<SOURCE_PROPERTY:...> expression requires at most three "
3820
0
                  "parameters.");
3821
0
      return std::string{};
3822
0
    }
3823
3824
0
    std::string sourceName = parameters.front();
3825
0
    std::string const& propertyName = parameters.back();
3826
3827
0
    if (sourceName.empty() && propertyName.empty()) {
3828
0
      reportError(eval, content->GetOriginalExpression(),
3829
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3830
0
                  "non-empty source name and property name.");
3831
0
      return std::string{};
3832
0
    }
3833
0
    if (sourceName.empty()) {
3834
0
      reportError(eval, content->GetOriginalExpression(),
3835
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3836
0
                  "non-empty source name.");
3837
0
      return std::string{};
3838
0
    }
3839
0
    if (propertyName.empty()) {
3840
0
      reportError(eval, content->GetOriginalExpression(),
3841
0
                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
3842
0
                  "non-empty property name.");
3843
0
      return std::string{};
3844
0
    }
3845
0
    if (!propertyNameValidator.find(propertyName)) {
3846
0
      reportError(eval, content->GetOriginalExpression(),
3847
0
                  "Property name not supported.");
3848
0
      return std::string{};
3849
0
    }
3850
3851
0
    cmSourceFile* sourceFile = nullptr;
3852
0
    if (!GetSourceFile(cmMakeRange(parameters).retreat(1), eval, content,
3853
0
                       sourceFile)) {
3854
0
      return std::string{};
3855
0
    }
3856
0
    if (!sourceFile) {
3857
0
      reportError(
3858
0
        eval, content->GetOriginalExpression(),
3859
0
        cmStrCat("Source file \"", sourceName, "\" is not known from CMake."));
3860
0
      return std::string{};
3861
0
    }
3862
3863
0
    return sourceFile->GetPropertyForUser(propertyName);
3864
0
  }
3865
} sourcePropertyNode;
3866
3867
static std::string getLinkedTargetsContent(
3868
  cmGeneratorTarget const* target, std::string const& prop,
3869
  cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
3870
  cmGeneratorTarget::UseTo usage)
3871
0
{
3872
0
  std::string result;
3873
0
  if (cmLinkImplementationLibraries const* impl =
3874
0
        target->GetLinkImplementationLibraries(
3875
0
          eval->Context.Config, cmGeneratorTarget::UseTo::Compile)) {
3876
0
    for (cmLinkItem const& lib : impl->Libraries) {
3877
0
      if (lib.Target) {
3878
        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
3879
        // caller's property and hand-evaluate it as if it were compiled.
3880
        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
3881
0
        cm::GenEx::Context libContext(eval->Context);
3882
        // FIXME: Why have we long used the target's local generator
3883
        // instead of that of the evaluation context?
3884
0
        libContext.LG = target->GetLocalGenerator();
3885
0
        cm::GenEx::Evaluation libEval(
3886
0
          std::move(libContext), eval->Quiet, target, target,
3887
0
          eval->EvaluateForBuildsystem, lib.Backtrace);
3888
0
        std::string libResult = lib.Target->EvaluateInterfaceProperty(
3889
0
          prop, &libEval, dagChecker, usage);
3890
0
        if (!libResult.empty()) {
3891
0
          if (result.empty()) {
3892
0
            result = std::move(libResult);
3893
0
          } else {
3894
0
            result.reserve(result.size() + 1 + libResult.size());
3895
0
            result += ";";
3896
0
            result += libResult;
3897
0
          }
3898
0
        }
3899
0
      }
3900
0
    }
3901
0
  }
3902
0
  return result;
3903
0
}
3904
3905
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
3906
{
3907
4
  TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
3908
3909
  // This node handles errors on parameter count itself.
3910
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
3911
3912
  static char const* GetErrorText(std::string const& targetName,
3913
                                  std::string const& propertyName)
3914
0
  {
3915
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3916
0
    if (targetName.empty() && propertyName.empty()) {
3917
0
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
3918
0
             "target name and property name.";
3919
0
    }
3920
0
    if (targetName.empty()) {
3921
0
      return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
3922
0
             "target name.";
3923
0
    }
3924
0
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
3925
0
      if (!propertyNameValidator.find(propertyName)) {
3926
0
        return "Target name and property name not supported.";
3927
0
      }
3928
0
      return "Target name not supported.";
3929
0
    }
3930
0
    return nullptr;
3931
0
  }
3932
3933
  std::string Evaluate(
3934
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
3935
    GeneratorExpressionContent const* content,
3936
    cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
3937
0
  {
3938
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
3939
3940
0
    cmGeneratorTarget const* target = nullptr;
3941
0
    std::string targetName;
3942
0
    std::string propertyName;
3943
3944
0
    if (parameters.size() == 2) {
3945
0
      targetName = parameters[0];
3946
0
      propertyName = parameters[1];
3947
3948
0
      if (char const* e = GetErrorText(targetName, propertyName)) {
3949
0
        reportError(eval, content->GetOriginalExpression(), e);
3950
0
        return std::string();
3951
0
      }
3952
0
      if (propertyName == "ALIASED_TARGET"_s) {
3953
0
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
3954
0
          if (cmGeneratorTarget* tgt =
3955
0
                eval->Context.LG->FindGeneratorTargetToUse(targetName)) {
3956
0
            return tgt->GetName();
3957
0
          }
3958
0
        }
3959
0
        return std::string();
3960
0
      }
3961
0
      if (propertyName == "ALIAS_GLOBAL"_s) {
3962
0
        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
3963
0
          return eval->Context.LG->GetGlobalGenerator()->IsAlias(targetName)
3964
0
            ? "TRUE"
3965
0
            : "FALSE";
3966
0
        }
3967
0
        return std::string();
3968
0
      }
3969
0
      cmLocalGenerator const* lg = eval->CurrentTarget
3970
0
        ? eval->CurrentTarget->GetLocalGenerator()
3971
0
        : eval->Context.LG;
3972
0
      target = lg->FindGeneratorTargetToUse(targetName);
3973
3974
0
      if (!target) {
3975
0
        std::ostringstream e;
3976
0
        e << "Target \"" << targetName << "\" not found.";
3977
0
        reportError(eval, content->GetOriginalExpression(), e.str());
3978
0
        return std::string();
3979
0
      }
3980
0
      eval->AllTargets.insert(target);
3981
3982
0
    } else if (parameters.size() == 1) {
3983
0
      target = eval->HeadTarget;
3984
0
      propertyName = parameters[0];
3985
3986
      // Keep track of the properties seen while processing.
3987
      // The evaluation of the LINK_LIBRARIES generator expressions
3988
      // will check this to ensure that properties have one consistent
3989
      // value for all evaluations.
3990
0
      eval->SeenTargetProperties.insert(propertyName);
3991
3992
0
      eval->HadHeadSensitiveCondition = true;
3993
0
      if (!target) {
3994
0
        reportError(
3995
0
          eval, content->GetOriginalExpression(),
3996
0
          "$<TARGET_PROPERTY:prop>  may only be used with binary targets.  "
3997
0
          "It may not be used with add_custom_command or add_custom_target. "
3998
0
          " "
3999
0
          " "
4000
0
          "Specify the target to read a property from using the "
4001
0
          "$<TARGET_PROPERTY:tgt,prop> signature instead.");
4002
0
        return std::string();
4003
0
      }
4004
0
    } else {
4005
0
      reportError(
4006
0
        eval, content->GetOriginalExpression(),
4007
0
        "$<TARGET_PROPERTY:...> expression requires one or two parameters");
4008
0
      return std::string();
4009
0
    }
4010
4011
0
    if (propertyName == "SOURCES") {
4012
0
      eval->SourceSensitiveTargets.insert(target);
4013
0
    }
4014
4015
0
    if (propertyName.empty()) {
4016
0
      reportError(
4017
0
        eval, content->GetOriginalExpression(),
4018
0
        "$<TARGET_PROPERTY:...> expression requires a non-empty property "
4019
0
        "name.");
4020
0
      return std::string();
4021
0
    }
4022
4023
0
    if (!propertyNameValidator.find(propertyName)) {
4024
0
      ::reportError(eval, content->GetOriginalExpression(),
4025
0
                    "Property name not supported.");
4026
0
      return std::string();
4027
0
    }
4028
4029
0
    assert(target);
4030
4031
0
    if (propertyName == "LINKER_LANGUAGE") {
4032
0
      if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
4033
0
          (dagCheckerParent->EvaluatingLinkLibraries() ||
4034
0
           dagCheckerParent->EvaluatingSources())) {
4035
0
        reportError(
4036
0
          eval, content->GetOriginalExpression(),
4037
0
          "LINKER_LANGUAGE target property can not be used while evaluating "
4038
0
          "link libraries for a static library");
4039
0
        return std::string();
4040
0
      }
4041
0
      return target->GetLinkerLanguage(eval->Context.Config);
4042
0
    }
4043
4044
0
    bool const evaluatingLinkLibraries =
4045
0
      dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries();
4046
4047
0
    std::string interfacePropertyName;
4048
0
    bool isInterfaceProperty = false;
4049
0
    cmGeneratorTarget::UseTo usage = cmGeneratorTarget::UseTo::Compile;
4050
4051
0
    if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
4052
0
          target->IsTransitiveProperty(propertyName, eval->Context,
4053
0
                                       dagCheckerParent)) {
4054
0
      interfacePropertyName = std::string(transitiveProp->InterfaceName);
4055
0
      isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
4056
0
      usage = transitiveProp->Usage;
4057
0
    }
4058
4059
0
    if (dagCheckerParent) {
4060
      // This $<TARGET_PROPERTY:...> node has been reached while evaluating
4061
      // another target property value.  Check that the outermost evaluation
4062
      // expects such nested evaluations.
4063
0
      if (dagCheckerParent->EvaluatingGenexExpression() ||
4064
0
          dagCheckerParent->EvaluatingPICExpression() ||
4065
0
          dagCheckerParent->EvaluatingLinkerLauncher()) {
4066
        // No check required.
4067
0
      } else if (evaluatingLinkLibraries) {
4068
0
        if (!interfacePropertyName.empty() &&
4069
0
            interfacePropertyName != "INTERFACE_LINK_LIBRARIES"_s) {
4070
0
          reportError(
4071
0
            eval, content->GetOriginalExpression(),
4072
0
            "$<TARGET_PROPERTY:...> expression in link libraries "
4073
0
            "evaluation depends on target property which is transitive "
4074
0
            "over the link libraries, creating a recursion.");
4075
0
          return std::string();
4076
0
        }
4077
0
      } else {
4078
0
        assert(dagCheckerParent->EvaluatingTransitiveProperty());
4079
0
      }
4080
0
    }
4081
4082
0
    if (isInterfaceProperty) {
4083
0
      return cmGeneratorExpression::StripEmptyListElements(
4084
0
        target->EvaluateInterfaceProperty(propertyName, eval, dagCheckerParent,
4085
0
                                          usage));
4086
0
    }
4087
4088
0
    cmGeneratorExpressionDAGChecker dagChecker{
4089
0
      target,           propertyName,  content,
4090
0
      dagCheckerParent, eval->Context, eval->Backtrace,
4091
0
    };
4092
4093
0
    switch (dagChecker.Check()) {
4094
0
      case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
4095
0
        dagChecker.ReportError(eval, content->GetOriginalExpression());
4096
0
        return std::string();
4097
0
      case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
4098
        // No error. We just skip cyclic references.
4099
0
        return std::string();
4100
0
      case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
4101
        // We handle transitive properties above.  For non-transitive
4102
        // properties we accept repeats anyway.
4103
0
      case cmGeneratorExpressionDAGChecker::DAG:
4104
0
        break;
4105
0
    }
4106
4107
0
    std::string result;
4108
0
    bool haveProp = false;
4109
0
    if (cmValue p = target->GetProperty(propertyName)) {
4110
0
      result = *p;
4111
0
      haveProp = true;
4112
0
    } else if (evaluatingLinkLibraries) {
4113
0
      return std::string();
4114
0
    }
4115
4116
    // Properties named by COMPATIBLE_INTERFACE_ properties combine over
4117
    // the transitive link closure as a single order-independent value.
4118
    // Imported targets do not themselves have a defined value for these
4119
    // properties, but they can contribute to the value of a non-imported
4120
    // dependent.
4121
    //
4122
    // For COMPATIBLE_INTERFACE_{BOOL,STRING}:
4123
    // * If set on this target, use the value directly.  It is checked
4124
    //   elsewhere for consistency over the transitive link closure.
4125
    // * If not set on this target, compute the value from the closure.
4126
    //
4127
    // For COMPATIBLE_INTERFACE_NUMBER_{MAX,MIN} we always compute the value
4128
    // from this target and the transitive link closure to get the max or min.
4129
0
    if (!haveProp && !target->IsImported()) {
4130
0
      if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
4131
0
                                                       eval->Context.Config)) {
4132
0
        eval->HadContextSensitiveCondition = true;
4133
0
        return target->GetLinkInterfaceDependentBoolProperty(
4134
0
                 propertyName, eval->Context.Config)
4135
0
          ? "1"
4136
0
          : "0";
4137
0
      }
4138
0
      if (target->IsLinkInterfaceDependentStringProperty(
4139
0
            propertyName, eval->Context.Config)) {
4140
0
        eval->HadContextSensitiveCondition = true;
4141
0
        char const* propContent =
4142
0
          target->GetLinkInterfaceDependentStringProperty(
4143
0
            propertyName, eval->Context.Config);
4144
0
        return propContent ? propContent : "";
4145
0
      }
4146
0
    }
4147
0
    if (!evaluatingLinkLibraries && !target->IsImported()) {
4148
0
      if (target->IsLinkInterfaceDependentNumberMinProperty(
4149
0
            propertyName, eval->Context.Config)) {
4150
0
        eval->HadContextSensitiveCondition = true;
4151
0
        char const* propContent =
4152
0
          target->GetLinkInterfaceDependentNumberMinProperty(
4153
0
            propertyName, eval->Context.Config);
4154
0
        return propContent ? propContent : "";
4155
0
      }
4156
0
      if (target->IsLinkInterfaceDependentNumberMaxProperty(
4157
0
            propertyName, eval->Context.Config)) {
4158
0
        eval->HadContextSensitiveCondition = true;
4159
0
        char const* propContent =
4160
0
          target->GetLinkInterfaceDependentNumberMaxProperty(
4161
0
            propertyName, eval->Context.Config);
4162
0
        return propContent ? propContent : "";
4163
0
      }
4164
0
    }
4165
4166
    // Some properties, such as usage requirements, combine over the
4167
    // transitive link closure as an ordered list.
4168
0
    if (!interfacePropertyName.empty()) {
4169
0
      result = cmGeneratorExpression::StripEmptyListElements(
4170
0
        this->EvaluateDependentExpression(result, eval, target, &dagChecker,
4171
0
                                          target));
4172
0
      std::string linkedTargetsContent = getLinkedTargetsContent(
4173
0
        target, interfacePropertyName, eval, &dagChecker, usage);
4174
0
      if (!linkedTargetsContent.empty()) {
4175
0
        result += (result.empty() ? "" : ";") + linkedTargetsContent;
4176
0
      }
4177
0
    }
4178
0
    return result;
4179
0
  }
4180
} targetPropertyNode;
4181
4182
static const struct targetIntermediateDirNode
4183
  : public cmGeneratorExpressionNode
4184
{
4185
4
  targetIntermediateDirNode() {} // NOLINT(modernize-use-equals-default)
4186
4187
  static char const* GetErrorText(std::string const& targetName)
4188
0
  {
4189
0
    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
4190
0
    if (targetName.empty()) {
4191
0
      return "$<TARGET_INTERMEDIATE_DIR:tgt> expression requires a non-empty "
4192
0
             "target name.";
4193
0
    }
4194
0
    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
4195
0
      return "Target name not supported.";
4196
0
    }
4197
0
    return nullptr;
4198
0
  }
4199
4200
  std::string Evaluate(
4201
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4202
    GeneratorExpressionContent const* content,
4203
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4204
0
  {
4205
0
    cmGeneratorTarget const* target = nullptr;
4206
0
    std::string targetName;
4207
4208
0
    if (parameters.size() == 1) {
4209
0
      targetName = parameters[0];
4210
4211
0
      if (char const* e = GetErrorText(targetName)) {
4212
0
        reportError(eval, content->GetOriginalExpression(), e);
4213
0
        return std::string();
4214
0
      }
4215
0
      cmLocalGenerator const* lg = eval->CurrentTarget
4216
0
        ? eval->CurrentTarget->GetLocalGenerator()
4217
0
        : eval->Context.LG;
4218
0
      target = lg->FindGeneratorTargetToUse(targetName);
4219
4220
0
      if (!target) {
4221
0
        std::ostringstream e;
4222
0
        e << "Target \"" << targetName << "\" not found.";
4223
0
        reportError(eval, content->GetOriginalExpression(), e.str());
4224
0
        return std::string();
4225
0
      }
4226
0
      eval->AllTargets.insert(target);
4227
4228
0
    } else {
4229
0
      reportError(
4230
0
        eval, content->GetOriginalExpression(),
4231
0
        "$<TARGET_INTERMEDIATE_DIR:...> expression requires one parameter");
4232
0
      return std::string();
4233
0
    }
4234
4235
0
    assert(target);
4236
4237
0
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_INTERMEDIATE_DIR",
4238
0
                                    target)) {
4239
0
      return std::string();
4240
0
    }
4241
4242
0
    return cmSystemTools::CollapseFullPath(
4243
0
      target->GetObjectDirectory(eval->Context.Config));
4244
0
  }
4245
} targetIntermediateDirNode;
4246
4247
static const struct TargetNameNode : public cmGeneratorExpressionNode
4248
{
4249
4
  TargetNameNode() {} // NOLINT(modernize-use-equals-default)
4250
4251
0
  bool GeneratesContent() const override { return true; }
4252
4253
0
  bool AcceptsArbitraryContentParameter() const override { return true; }
4254
0
  bool RequiresLiteralInput() const override { return true; }
4255
4256
  std::string Evaluate(
4257
    std::vector<std::string> const& parameters,
4258
    cm::GenEx::Evaluation* /*eval*/,
4259
    GeneratorExpressionContent const* /*content*/,
4260
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4261
0
  {
4262
0
    return parameters.front();
4263
0
  }
4264
4265
0
  int NumExpectedParameters() const override { return 1; }
4266
4267
} targetNameNode;
4268
4269
static const struct TargetObjectsNode : public cmGeneratorExpressionNode
4270
{
4271
4
  TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
4272
4273
  std::string Evaluate(
4274
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4275
    GeneratorExpressionContent const* content,
4276
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4277
0
  {
4278
0
    std::string const& tgtName = parameters.front();
4279
0
    cmGeneratorTarget* gt =
4280
0
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
4281
0
    if (!gt) {
4282
0
      std::ostringstream e;
4283
0
      e << "Objects of target \"" << tgtName
4284
0
        << "\" referenced but no such target exists.";
4285
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4286
0
      return std::string();
4287
0
    }
4288
0
    cmStateEnums::TargetType type = gt->GetType();
4289
0
    if (type != cmStateEnums::EXECUTABLE &&
4290
0
        type != cmStateEnums::STATIC_LIBRARY &&
4291
0
        type != cmStateEnums::SHARED_LIBRARY &&
4292
0
        type != cmStateEnums::MODULE_LIBRARY &&
4293
0
        type != cmStateEnums::OBJECT_LIBRARY) {
4294
0
      std::ostringstream e;
4295
0
      e << "Objects of target \"" << tgtName
4296
0
        << "\" referenced but is not one of the allowed target types "
4297
0
        << "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT).";
4298
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4299
0
      return std::string();
4300
0
    }
4301
0
    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
4302
0
    if (!HasKnownObjectFileLocation(eval, content, "TARGET_OBJECTS", gt)) {
4303
0
      return std::string();
4304
0
    }
4305
4306
0
    cmList objects;
4307
4308
0
    if (gt->IsImported()) {
4309
0
      cmValue loc = nullptr;
4310
0
      cmValue imp = nullptr;
4311
0
      std::string suffix;
4312
0
      if (gt->Target->GetMappedConfig(eval->Context.Config, loc, imp,
4313
0
                                      suffix)) {
4314
0
        objects.assign(*loc);
4315
0
      }
4316
0
      eval->HadContextSensitiveCondition = true;
4317
0
    } else {
4318
0
      gt->GetTargetObjectNames(eval->Context.Config, objects);
4319
4320
0
      std::string obj_dir;
4321
0
      if (eval->EvaluateForBuildsystem && !gg->SupportsCrossConfigs()) {
4322
        // Use object file directory with buildsystem placeholder.
4323
0
        obj_dir = gt->ObjectDirectory;
4324
0
        eval->HadContextSensitiveCondition = gt->HasContextDependentSources();
4325
0
      } else {
4326
        // Use object file directory with per-config location.
4327
0
        obj_dir = gt->GetObjectDirectory(eval->Context.Config);
4328
0
        eval->HadContextSensitiveCondition = true;
4329
0
      }
4330
4331
0
      for (auto& o : objects) {
4332
0
        o = cmStrCat(obj_dir, o);
4333
0
      }
4334
0
    }
4335
4336
    // Create the cmSourceFile instances in the referencing directory.
4337
0
    cmMakefile* mf = eval->Context.LG->GetMakefile();
4338
0
    for (std::string const& o : objects) {
4339
0
      mf->AddTargetObject(tgtName, o);
4340
0
    }
4341
4342
0
    return objects.to_string();
4343
0
  }
4344
} targetObjectsNode;
4345
4346
struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
4347
{
4348
  std::vector<std::string> CollectDlls(
4349
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4350
    GeneratorExpressionContent const* content) const
4351
0
  {
4352
0
    std::string const& tgtName = parameters.front();
4353
0
    cmGeneratorTarget* gt =
4354
0
      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
4355
0
    if (!gt) {
4356
0
      std::ostringstream e;
4357
0
      e << "Objects of target \"" << tgtName
4358
0
        << "\" referenced but no such target exists.";
4359
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4360
0
      return std::vector<std::string>();
4361
0
    }
4362
0
    cmStateEnums::TargetType type = gt->GetType();
4363
0
    if (type != cmStateEnums::EXECUTABLE &&
4364
0
        type != cmStateEnums::SHARED_LIBRARY &&
4365
0
        type != cmStateEnums::MODULE_LIBRARY) {
4366
0
      std::ostringstream e;
4367
0
      e << "Objects of target \"" << tgtName
4368
0
        << "\" referenced but is not one of the allowed target types "
4369
0
        << "(EXECUTABLE, SHARED, MODULE).";
4370
0
      reportError(eval, content->GetOriginalExpression(), e.str());
4371
0
      return std::vector<std::string>();
4372
0
    }
4373
4374
0
    if (auto* cli = gt->GetLinkInformation(eval->Context.Config)) {
4375
0
      std::vector<std::string> dllPaths;
4376
0
      auto const& dlls = cli->GetRuntimeDLLs();
4377
4378
0
      for (auto const& dll : dlls) {
4379
0
        if (auto loc = dll->MaybeGetLocation(eval->Context.Config)) {
4380
0
          dllPaths.emplace_back(*loc);
4381
0
        }
4382
0
      }
4383
4384
0
      return dllPaths;
4385
0
    }
4386
4387
0
    return std::vector<std::string>();
4388
0
  }
4389
};
4390
4391
static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode
4392
{
4393
4
  TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
4394
4395
  std::string Evaluate(
4396
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4397
    GeneratorExpressionContent const* content,
4398
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4399
0
  {
4400
0
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
4401
0
    return cmList::to_string(dlls);
4402
0
  }
4403
} targetRuntimeDllsNode;
4404
4405
static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode
4406
{
4407
4
  TargetRuntimeDllDirsNode() {} // NOLINT(modernize-use-equals-default)
4408
4409
  std::string Evaluate(
4410
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4411
    GeneratorExpressionContent const* content,
4412
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4413
0
  {
4414
0
    std::vector<std::string> dlls = CollectDlls(parameters, eval, content);
4415
0
    std::vector<std::string> dllDirs;
4416
0
    for (std::string const& dll : dlls) {
4417
0
      std::string directory = cmSystemTools::GetFilenamePath(dll);
4418
0
      if (std::find(dllDirs.begin(), dllDirs.end(), directory) ==
4419
0
          dllDirs.end()) {
4420
0
        dllDirs.push_back(directory);
4421
0
      }
4422
0
    }
4423
0
    return cmList::to_string(dllDirs);
4424
0
  }
4425
} targetRuntimeDllDirsNode;
4426
4427
static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
4428
{
4429
4
  CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
4430
4431
0
  int NumExpectedParameters() const override { return OneOrMoreParameters; }
4432
4433
  std::string Evaluate(
4434
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4435
    GeneratorExpressionContent const* content,
4436
    cmGeneratorExpressionDAGChecker* dagChecker) const override
4437
0
  {
4438
0
    cmGeneratorTarget const* target = eval->HeadTarget;
4439
0
    if (!target) {
4440
0
      reportError(
4441
0
        eval, content->GetOriginalExpression(),
4442
0
        "$<COMPILE_FEATURE> may only be used with binary targets.  It may "
4443
0
        "not be used with add_custom_command or add_custom_target.");
4444
0
      return std::string();
4445
0
    }
4446
0
    eval->HadHeadSensitiveCondition = true;
4447
4448
0
    using LangMap = std::map<std::string, cmList>;
4449
0
    static LangMap availableFeatures;
4450
4451
0
    LangMap testedFeatures;
4452
0
    cmStandardLevelResolver standardResolver(eval->Context.LG->GetMakefile());
4453
0
    for (std::string const& p : parameters) {
4454
0
      std::string error;
4455
0
      std::string lang;
4456
0
      if (!standardResolver.CompileFeatureKnown(
4457
0
            eval->HeadTarget->Target->GetName(), p, lang, &error)) {
4458
0
        reportError(eval, content->GetOriginalExpression(), error);
4459
0
        return std::string();
4460
0
      }
4461
0
      testedFeatures[lang].push_back(p);
4462
4463
0
      if (availableFeatures.find(lang) == availableFeatures.end()) {
4464
0
        cmValue featuresKnown =
4465
0
          standardResolver.CompileFeaturesAvailable(lang, &error);
4466
0
        if (!featuresKnown) {
4467
0
          reportError(eval, content->GetOriginalExpression(), error);
4468
0
          return std::string();
4469
0
        }
4470
0
        availableFeatures[lang].assign(featuresKnown);
4471
0
      }
4472
0
    }
4473
4474
0
    bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
4475
4476
0
    for (auto const& lit : testedFeatures) {
4477
0
      std::vector<std::string> const& langAvailable =
4478
0
        availableFeatures[lit.first];
4479
0
      cmValue standardDefault = eval->Context.LG->GetMakefile()->GetDefinition(
4480
0
        cmStrCat("CMAKE_", lit.first, "_STANDARD_DEFAULT"));
4481
0
      for (std::string const& it : lit.second) {
4482
0
        if (!cm::contains(langAvailable, it)) {
4483
0
          return "0";
4484
0
        }
4485
0
        if (standardDefault && standardDefault->empty()) {
4486
          // This compiler has no notion of language standard levels.
4487
          // All features known for the language are always available.
4488
0
          continue;
4489
0
        }
4490
0
        if (!standardResolver.HaveStandardAvailable(
4491
0
              target, lit.first, eval->Context.Config, it)) {
4492
0
          if (evalLL) {
4493
0
            cmValue l =
4494
0
              target->GetLanguageStandard(lit.first, eval->Context.Config);
4495
0
            if (!l) {
4496
0
              l = standardDefault;
4497
0
            }
4498
0
            assert(l);
4499
0
            eval->MaxLanguageStandard[target][lit.first] = *l;
4500
0
          } else {
4501
0
            return "0";
4502
0
          }
4503
0
        }
4504
0
      }
4505
0
    }
4506
0
    return "1";
4507
0
  }
4508
} compileFeaturesNode;
4509
4510
static char const* targetPolicyWhitelist[] = {
4511
  nullptr
4512
#define TARGET_POLICY_STRING(POLICY) , #POLICY
4513
4514
  CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
4515
4516
#undef TARGET_POLICY_STRING
4517
};
4518
4519
static cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
4520
                                                char const* policy)
4521
0
{
4522
0
#define RETURN_POLICY(POLICY)                                                 \
4523
0
  if (strcmp(policy, #POLICY) == 0) {                                         \
4524
0
    return tgt->GetPolicyStatus##POLICY();                                    \
4525
0
  }
4526
4527
0
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
4528
4529
0
#undef RETURN_POLICY
4530
4531
0
  assert(false && "Unreachable code. Not a valid policy");
4532
0
  return cmPolicies::WARN;
4533
0
}
4534
4535
static cmPolicies::PolicyID policyForString(char const* policy_id)
4536
0
{
4537
0
#define RETURN_POLICY_ID(POLICY_ID)                                           \
4538
0
  if (strcmp(policy_id, #POLICY_ID) == 0) {                                   \
4539
0
    return cmPolicies::POLICY_ID;                                             \
4540
0
  }
4541
4542
0
  CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
4543
4544
0
#undef RETURN_POLICY_ID
4545
4546
0
  assert(false && "Unreachable code. Not a valid policy");
4547
0
  return cmPolicies::CMPCOUNT;
4548
0
}
4549
4550
static const struct TargetPolicyNode : public cmGeneratorExpressionNode
4551
{
4552
4
  TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
4553
4554
0
  int NumExpectedParameters() const override { return 1; }
4555
4556
  std::string Evaluate(
4557
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
4558
    GeneratorExpressionContent const* content,
4559
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4560
0
  {
4561
0
    if (!eval->HeadTarget) {
4562
0
      reportError(
4563
0
        eval, content->GetOriginalExpression(),
4564
0
        "$<TARGET_POLICY:prop> may only be used with binary targets.  It "
4565
0
        "may not be used with add_custom_command or add_custom_target.");
4566
0
      return std::string();
4567
0
    }
4568
4569
0
    eval->HadContextSensitiveCondition = true;
4570
0
    eval->HadHeadSensitiveCondition = true;
4571
4572
0
    for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
4573
0
      char const* policy = targetPolicyWhitelist[i];
4574
0
      if (parameters.front() == policy) {
4575
0
        cmLocalGenerator* lg = eval->HeadTarget->GetLocalGenerator();
4576
0
        switch (statusForTarget(eval->HeadTarget, policy)) {
4577
0
          case cmPolicies::WARN:
4578
0
            lg->IssueMessage(
4579
0
              MessageType::AUTHOR_WARNING,
4580
0
              cmPolicies::GetPolicyWarning(policyForString(policy)));
4581
0
            CM_FALLTHROUGH;
4582
0
          case cmPolicies::OLD:
4583
0
            return "0";
4584
0
          case cmPolicies::NEW:
4585
0
            return "1";
4586
0
        }
4587
0
      }
4588
0
    }
4589
0
    reportError(
4590
0
      eval, content->GetOriginalExpression(),
4591
0
      "$<TARGET_POLICY:prop> may only be used with a limited number of "
4592
0
      "policies.  Currently it may be used with the following policies:\n"
4593
4594
0
#define STRINGIFY_HELPER(X) #X
4595
0
#define STRINGIFY(X) STRINGIFY_HELPER(X)
4596
4597
0
#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
4598
4599
0
      CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
4600
4601
0
#undef TARGET_POLICY_LIST_ITEM
4602
0
    );
4603
0
    return std::string();
4604
0
  }
4605
4606
} targetPolicyNode;
4607
4608
static const struct InstallPrefixNode : public cmGeneratorExpressionNode
4609
{
4610
4
  InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
4611
4612
0
  bool GeneratesContent() const override { return true; }
4613
0
  int NumExpectedParameters() const override { return 0; }
4614
4615
  std::string Evaluate(
4616
    std::vector<std::string> const& /*parameters*/,
4617
    cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
4618
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
4619
0
  {
4620
0
    reportError(eval, content->GetOriginalExpression(),
4621
0
                "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
4622
0
                "should never be evaluated.");
4623
0
    return std::string();
4624
0
  }
4625
4626
} installPrefixNode;
4627
4628
class ArtifactDirTag;
4629
class ArtifactLinkerTag;
4630
class ArtifactLinkerLibraryTag;
4631
class ArtifactLinkerImportTag;
4632
class ArtifactNameTag;
4633
class ArtifactImportTag;
4634
class ArtifactPathTag;
4635
class ArtifactPdbTag;
4636
class ArtifactSonameTag;
4637
class ArtifactSonameImportTag;
4638
class ArtifactBundleDirTag;
4639
class ArtifactBundleDirNameTag;
4640
class ArtifactBundleContentDirTag;
4641
4642
template <typename ArtifactT, typename ComponentT>
4643
struct TargetFilesystemArtifactDependency
4644
{
4645
  static void AddDependency(cmGeneratorTarget* target,
4646
                            cm::GenEx::Evaluation* eval)
4647
0
  {
4648
0
    eval->DependTargets.insert(target);
4649
0
    eval->AllTargets.insert(target);
4650
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*)
4651
};
4652
4653
struct TargetFilesystemArtifactDependencyCMP0112
4654
{
4655
  static void AddDependency(cmGeneratorTarget* target,
4656
                            cm::GenEx::Evaluation* eval)
4657
0
  {
4658
0
    eval->AllTargets.insert(target);
4659
0
    cmLocalGenerator const* lg = eval->Context.LG;
4660
0
    switch (target->GetPolicyStatusCMP0112()) {
4661
0
      case cmPolicies::WARN:
4662
0
        if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
4663
0
              "CMAKE_POLICY_WARNING_CMP0112")) {
4664
0
          std::string err =
4665
0
            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0112),
4666
0
                     "\nDependency being added to target:\n  \"",
4667
0
                     target->GetName(), "\"\n");
4668
0
          lg->GetCMakeInstance()->IssueMessage(MessageType ::AUTHOR_WARNING,
4669
0
                                               err, eval->Backtrace);
4670
0
        }
4671
0
        CM_FALLTHROUGH;
4672
0
      case cmPolicies::OLD:
4673
0
        eval->DependTargets.insert(target);
4674
0
        break;
4675
0
      case cmPolicies::NEW:
4676
0
        break;
4677
0
    }
4678
0
  }
4679
};
4680
4681
template <typename ArtifactT>
4682
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactNameTag>
4683
  : TargetFilesystemArtifactDependencyCMP0112
4684
{
4685
};
4686
template <typename ArtifactT>
4687
struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactDirTag>
4688
  : TargetFilesystemArtifactDependencyCMP0112
4689
{
4690
};
4691
template <>
4692
struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag,
4693
                                          ArtifactPathTag>
4694
  : TargetFilesystemArtifactDependencyCMP0112
4695
{
4696
};
4697
template <>
4698
struct TargetFilesystemArtifactDependency<ArtifactBundleDirNameTag,
4699
                                          ArtifactPathTag>
4700
  : TargetFilesystemArtifactDependencyCMP0112
4701
{
4702
};
4703
template <>
4704
struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag,
4705
                                          ArtifactPathTag>
4706
  : TargetFilesystemArtifactDependencyCMP0112
4707
{
4708
};
4709
4710
template <typename ArtifactT>
4711
struct TargetFilesystemArtifactResultCreator
4712
{
4713
  static std::string Create(cmGeneratorTarget* target,
4714
                            cm::GenEx::Evaluation* eval,
4715
                            GeneratorExpressionContent const* content);
4716
};
4717
4718
template <>
4719
struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
4720
{
4721
  static std::string Create(cmGeneratorTarget* target,
4722
                            cm::GenEx::Evaluation* eval,
4723
                            GeneratorExpressionContent const* content)
4724
0
  {
4725
    // The target soname file (.so.1).
4726
0
    if (target->IsDLLPlatform()) {
4727
0
      ::reportError(eval, content->GetOriginalExpression(),
4728
0
                    "TARGET_SONAME_FILE is not allowed "
4729
0
                    "for DLL target platforms.");
4730
0
      return std::string();
4731
0
    }
4732
0
    if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
4733
0
      ::reportError(eval, content->GetOriginalExpression(),
4734
0
                    "TARGET_SONAME_FILE is allowed only for "
4735
0
                    "SHARED libraries.");
4736
0
      return std::string();
4737
0
    }
4738
0
    if (target->IsArchivedAIXSharedLibrary()) {
4739
0
      ::reportError(eval, content->GetOriginalExpression(),
4740
0
                    "TARGET_SONAME_FILE is not allowed for "
4741
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
4742
0
      return std::string();
4743
0
    }
4744
0
    std::string result =
4745
0
      cmStrCat(target->GetDirectory(eval->Context.Config), '/',
4746
0
               target->GetSOName(eval->Context.Config));
4747
0
    return result;
4748
0
  }
4749
};
4750
4751
template <>
4752
struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag>
4753
{
4754
  static std::string Create(cmGeneratorTarget* target,
4755
                            cm::GenEx::Evaluation* eval,
4756
                            GeneratorExpressionContent const* content)
4757
0
  {
4758
    // The target soname file (.so.1).
4759
0
    if (target->IsDLLPlatform()) {
4760
0
      ::reportError(eval, content->GetOriginalExpression(),
4761
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed "
4762
0
                    "for DLL target platforms.");
4763
0
      return std::string();
4764
0
    }
4765
0
    if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
4766
0
      ::reportError(eval, content->GetOriginalExpression(),
4767
0
                    "TARGET_SONAME_IMPORT_FILE is allowed only for "
4768
0
                    "SHARED libraries.");
4769
0
      return std::string();
4770
0
    }
4771
0
    if (target->IsArchivedAIXSharedLibrary()) {
4772
0
      ::reportError(eval, content->GetOriginalExpression(),
4773
0
                    "TARGET_SONAME_IMPORT_FILE is not allowed for "
4774
0
                    "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
4775
0
      return std::string();
4776
0
    }
4777
4778
0
    if (target->HasImportLibrary(eval->Context.Config)) {
4779
0
      return cmStrCat(
4780
0
        target->GetDirectory(eval->Context.Config,
4781
0
                             cmStateEnums::ImportLibraryArtifact),
4782
0
        '/',
4783
0
        target->GetSOName(eval->Context.Config,
4784
0
                          cmStateEnums::ImportLibraryArtifact));
4785
0
    }
4786
0
    return std::string{};
4787
0
  }
4788
};
4789
4790
template <>
4791
struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
4792
{
4793
  static std::string Create(cmGeneratorTarget* target,
4794
                            cm::GenEx::Evaluation* eval,
4795
                            GeneratorExpressionContent const* content)
4796
0
  {
4797
0
    if (target->IsImported()) {
4798
0
      ::reportError(eval, content->GetOriginalExpression(),
4799
0
                    "TARGET_PDB_FILE not allowed for IMPORTED targets.");
4800
0
      return std::string();
4801
0
    }
4802
4803
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
4804
4805
0
    std::string pdbSupportVar =
4806
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
4807
4808
0
    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
4809
0
      ::reportError(eval, content->GetOriginalExpression(),
4810
0
                    "TARGET_PDB_FILE is not supported by the target linker.");
4811
0
      return std::string();
4812
0
    }
4813
4814
0
    cmStateEnums::TargetType targetType = target->GetType();
4815
4816
0
    if (targetType != cmStateEnums::SHARED_LIBRARY &&
4817
0
        targetType != cmStateEnums::MODULE_LIBRARY &&
4818
0
        targetType != cmStateEnums::EXECUTABLE) {
4819
0
      ::reportError(eval, content->GetOriginalExpression(),
4820
0
                    "TARGET_PDB_FILE is allowed only for "
4821
0
                    "targets with linker created artifacts.");
4822
0
      return std::string();
4823
0
    }
4824
4825
0
    std::string result =
4826
0
      cmStrCat(target->GetPDBDirectory(eval->Context.Config), '/',
4827
0
               target->GetPDBName(eval->Context.Config));
4828
0
    return result;
4829
0
  }
4830
};
4831
4832
template <>
4833
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
4834
{
4835
  static std::string Create(cmGeneratorTarget* target,
4836
                            cm::GenEx::Evaluation* eval,
4837
                            GeneratorExpressionContent const* content)
4838
0
  {
4839
    // The file used to link to the target (.so, .lib, .a) or import file
4840
    // (.lib,  .tbd).
4841
0
    if (!target->IsLinkable()) {
4842
0
      ::reportError(eval, content->GetOriginalExpression(),
4843
0
                    "TARGET_LINKER_FILE is allowed only for libraries and "
4844
0
                    "executables with ENABLE_EXPORTS.");
4845
0
      return std::string();
4846
0
    }
4847
0
    cmStateEnums::ArtifactType artifact =
4848
0
      target->HasImportLibrary(eval->Context.Config)
4849
0
      ? cmStateEnums::ImportLibraryArtifact
4850
0
      : cmStateEnums::RuntimeBinaryArtifact;
4851
0
    return target->GetFullPath(eval->Context.Config, artifact);
4852
0
  }
4853
};
4854
4855
template <>
4856
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag>
4857
{
4858
  static std::string Create(cmGeneratorTarget* target,
4859
                            cm::GenEx::Evaluation* eval,
4860
                            GeneratorExpressionContent const* content)
4861
0
  {
4862
    // The file used to link to the target (.dylib, .so, .a).
4863
0
    if (!target->IsLinkable() ||
4864
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
4865
0
      ::reportError(eval, content->GetOriginalExpression(),
4866
0
                    "TARGET_LINKER_LIBRARY_FILE is allowed only for libraries "
4867
0
                    "with ENABLE_EXPORTS.");
4868
0
      return std::string();
4869
0
    }
4870
4871
0
    if (!target->IsDLLPlatform() ||
4872
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
4873
0
      return target->GetFullPath(eval->Context.Config,
4874
0
                                 cmStateEnums::RuntimeBinaryArtifact);
4875
0
    }
4876
0
    return std::string{};
4877
0
  }
4878
};
4879
4880
template <>
4881
struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag>
4882
{
4883
  static std::string Create(cmGeneratorTarget* target,
4884
                            cm::GenEx::Evaluation* eval,
4885
                            GeneratorExpressionContent const* content)
4886
0
  {
4887
    // The file used to link to the target (.lib, .tbd).
4888
0
    if (!target->IsLinkable()) {
4889
0
      ::reportError(
4890
0
        eval, content->GetOriginalExpression(),
4891
0
        "TARGET_LINKER_IMPORT_FILE is allowed only for libraries and "
4892
0
        "executables with ENABLE_EXPORTS.");
4893
0
      return std::string();
4894
0
    }
4895
4896
0
    if (target->HasImportLibrary(eval->Context.Config)) {
4897
0
      return target->GetFullPath(eval->Context.Config,
4898
0
                                 cmStateEnums::ImportLibraryArtifact);
4899
0
    }
4900
0
    return std::string{};
4901
0
  }
4902
};
4903
4904
template <>
4905
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
4906
{
4907
  static std::string Create(cmGeneratorTarget* target,
4908
                            cm::GenEx::Evaluation* eval,
4909
                            GeneratorExpressionContent const* content)
4910
0
  {
4911
0
    if (target->IsImported()) {
4912
0
      ::reportError(eval, content->GetOriginalExpression(),
4913
0
                    "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
4914
0
      return std::string();
4915
0
    }
4916
0
    if (!target->IsBundleOnApple()) {
4917
0
      ::reportError(eval, content->GetOriginalExpression(),
4918
0
                    "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
4919
0
      return std::string();
4920
0
    }
4921
4922
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
4923
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
4924
0
                                        cmGeneratorTarget::BundleDirLevel);
4925
0
  }
4926
};
4927
4928
template <>
4929
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag>
4930
{
4931
  static std::string Create(cmGeneratorTarget* target,
4932
                            cm::GenEx::Evaluation* eval,
4933
                            GeneratorExpressionContent const* content)
4934
0
  {
4935
0
    if (target->IsImported()) {
4936
0
      ::reportError(
4937
0
        eval, content->GetOriginalExpression(),
4938
0
        "TARGET_BUNDLE_DIR_NAME not allowed for IMPORTED targets.");
4939
0
      return std::string();
4940
0
    }
4941
0
    if (!target->IsBundleOnApple()) {
4942
0
      ::reportError(
4943
0
        eval, content->GetOriginalExpression(),
4944
0
        "TARGET_BUNDLE_DIR_NAME is allowed only for Bundle targets.");
4945
0
      return std::string();
4946
0
    }
4947
4948
0
    auto level = cmGeneratorTarget::BundleDirLevel;
4949
0
    auto config = eval->Context.Config;
4950
0
    if (target->IsAppBundleOnApple()) {
4951
0
      return target->GetAppBundleDirectory(config, level);
4952
0
    }
4953
0
    if (target->IsFrameworkOnApple()) {
4954
0
      return target->GetFrameworkDirectory(config, level);
4955
0
    }
4956
0
    if (target->IsCFBundleOnApple()) {
4957
0
      return target->GetCFBundleDirectory(config, level);
4958
0
    }
4959
0
    return std::string();
4960
0
  }
4961
};
4962
4963
template <>
4964
struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
4965
{
4966
  static std::string Create(cmGeneratorTarget* target,
4967
                            cm::GenEx::Evaluation* eval,
4968
                            GeneratorExpressionContent const* content)
4969
0
  {
4970
0
    if (target->IsImported()) {
4971
0
      ::reportError(
4972
0
        eval, content->GetOriginalExpression(),
4973
0
        "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
4974
0
      return std::string();
4975
0
    }
4976
0
    if (!target->IsBundleOnApple()) {
4977
0
      ::reportError(
4978
0
        eval, content->GetOriginalExpression(),
4979
0
        "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
4980
0
      return std::string();
4981
0
    }
4982
4983
0
    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
4984
0
    return target->BuildBundleDirectory(outpath, eval->Context.Config,
4985
0
                                        cmGeneratorTarget::ContentLevel);
4986
0
  }
4987
};
4988
4989
template <>
4990
struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
4991
{
4992
  static std::string Create(cmGeneratorTarget* target,
4993
                            cm::GenEx::Evaluation* eval,
4994
                            GeneratorExpressionContent const* /*unused*/)
4995
0
  {
4996
0
    return target->GetFullPath(eval->Context.Config,
4997
0
                               cmStateEnums::RuntimeBinaryArtifact, true);
4998
0
  }
4999
};
5000
5001
template <>
5002
struct TargetFilesystemArtifactResultCreator<ArtifactImportTag>
5003
{
5004
  static std::string Create(cmGeneratorTarget* target,
5005
                            cm::GenEx::Evaluation* eval,
5006
                            GeneratorExpressionContent const* /*unused*/)
5007
0
  {
5008
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5009
0
      return target->GetFullPath(eval->Context.Config,
5010
0
                                 cmStateEnums::ImportLibraryArtifact, true);
5011
0
    }
5012
0
    return std::string{};
5013
0
  }
5014
};
5015
5016
template <typename ArtifactT>
5017
struct TargetFilesystemArtifactResultGetter
5018
{
5019
  static std::string Get(std::string const& result);
5020
};
5021
5022
template <>
5023
struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
5024
{
5025
  static std::string Get(std::string const& result)
5026
0
  {
5027
0
    return cmSystemTools::GetFilenameName(result);
5028
0
  }
5029
};
5030
5031
template <>
5032
struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
5033
{
5034
  static std::string Get(std::string const& result)
5035
0
  {
5036
0
    return cmSystemTools::GetFilenamePath(result);
5037
0
  }
5038
};
5039
5040
template <>
5041
struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
5042
{
5043
0
  static std::string Get(std::string const& result) { return result; }
5044
};
5045
5046
struct TargetArtifactBase : public cmGeneratorExpressionNode
5047
{
5048
172
  TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
5049
5050
protected:
5051
  cmGeneratorTarget* GetTarget(
5052
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5053
    GeneratorExpressionContent const* content,
5054
    cmGeneratorExpressionDAGChecker* dagChecker) const
5055
0
  {
5056
    // Lookup the referenced target.
5057
0
    std::string const& name = parameters.front();
5058
5059
0
    if (!cmGeneratorExpression::IsValidTargetName(name)) {
5060
0
      ::reportError(eval, content->GetOriginalExpression(),
5061
0
                    "Expression syntax not recognized.");
5062
0
      return nullptr;
5063
0
    }
5064
0
    cmGeneratorTarget* target =
5065
0
      eval->Context.LG->FindGeneratorTargetToUse(name);
5066
0
    if (!target) {
5067
0
      ::reportError(eval, content->GetOriginalExpression(),
5068
0
                    cmStrCat("No target \"", name, '"'));
5069
0
      return nullptr;
5070
0
    }
5071
0
    if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
5072
0
        target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
5073
0
      ::reportError(
5074
0
        eval, content->GetOriginalExpression(),
5075
0
        cmStrCat("Target \"", name, "\" is not an executable or library."));
5076
0
      return nullptr;
5077
0
    }
5078
0
    if (dagChecker &&
5079
0
        (dagChecker->EvaluatingLinkLibraries(target) ||
5080
0
         (dagChecker->EvaluatingSources() &&
5081
0
          target == dagChecker->TopTarget()))) {
5082
0
      ::reportError(eval, content->GetOriginalExpression(),
5083
0
                    "Expressions which require the linker language may not "
5084
0
                    "be used while evaluating link libraries");
5085
0
      return nullptr;
5086
0
    }
5087
5088
0
    return target;
5089
0
  }
5090
};
5091
5092
template <typename ArtifactT, typename ComponentT>
5093
struct TargetFilesystemArtifact : public TargetArtifactBase
5094
{
5095
108
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactNameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerLibraryTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactLinkerImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactSonameImportTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactPdbTag, ArtifactDirTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleDirNameTag, ArtifactNameTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag>::TargetFilesystemArtifact()
Line
Count
Source
5095
4
  TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
5096
5097
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
5098
5099
  std::string Evaluate(
5100
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5101
    GeneratorExpressionContent const* content,
5102
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5103
0
  {
5104
0
    cmGeneratorTarget* target =
5105
0
      this->GetTarget(parameters, eval, content, dagChecker);
5106
0
    if (!target) {
5107
0
      return std::string();
5108
0
    }
5109
    // Not a dependent target if we are querying for ArtifactDirTag,
5110
    // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag,
5111
    // and ArtifactBundleContentDirTag
5112
0
    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
5113
0
      target, eval);
5114
5115
0
    std::string result =
5116
0
      TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, eval,
5117
0
                                                               content);
5118
0
    if (eval->HadError) {
5119
0
      return std::string();
5120
0
    }
5121
0
    return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
5122
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
5123
};
5124
5125
template <typename ArtifactT>
5126
struct TargetFilesystemArtifactNodeGroup
5127
{
5128
  TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
5129
32
  {
5130
32
  }
TargetFilesystemArtifactNodeGroup<ArtifactNameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>::TargetFilesystemArtifactNodeGroup()
Line
Count
Source
5129
4
  {
5130
4
  }
5131
5132
  TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
5133
  TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
5134
  TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
5135
};
5136
5137
static TargetFilesystemArtifactNodeGroup<ArtifactNameTag> const
5138
  targetNodeGroup;
5139
5140
static TargetFilesystemArtifactNodeGroup<ArtifactImportTag> const
5141
  targetImportNodeGroup;
5142
5143
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag> const
5144
  targetLinkerNodeGroup;
5145
5146
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag> const
5147
  targetLinkerLibraryNodeGroup;
5148
5149
static TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag> const
5150
  targetLinkerImportNodeGroup;
5151
5152
static TargetFilesystemArtifactNodeGroup<ArtifactSonameTag> const
5153
  targetSoNameNodeGroup;
5154
5155
static TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag> const
5156
  targetSoNameImportNodeGroup;
5157
5158
static TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> const
5159
  targetPdbNodeGroup;
5160
5161
static TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag> const
5162
  targetBundleDirNode;
5163
5164
static TargetFilesystemArtifact<ArtifactBundleDirNameTag,
5165
                                ArtifactNameTag> const targetBundleDirNameNode;
5166
5167
static TargetFilesystemArtifact<ArtifactBundleContentDirTag,
5168
                                ArtifactPathTag> const
5169
  targetBundleContentDirNode;
5170
5171
//
5172
// To retrieve base name for various artifacts
5173
//
5174
enum class Postfix
5175
{
5176
  Unspecified,
5177
  Exclude,
5178
  Include
5179
};
5180
5181
template <typename ArtifactT>
5182
struct TargetOutputNameArtifactResultGetter
5183
{
5184
  static std::string Get(cmGeneratorTarget* target,
5185
                         cm::GenEx::Evaluation* eval,
5186
                         GeneratorExpressionContent const* content,
5187
                         Postfix postfix);
5188
};
5189
5190
template <>
5191
struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
5192
{
5193
  static std::string Get(cmGeneratorTarget* target,
5194
                         cm::GenEx::Evaluation* eval,
5195
                         GeneratorExpressionContent const* /*unused*/,
5196
                         Postfix postfix)
5197
0
  {
5198
0
    auto output = target->GetOutputName(eval->Context.Config,
5199
0
                                        cmStateEnums::RuntimeBinaryArtifact);
5200
0
    return postfix != Postfix::Exclude
5201
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5202
0
      : output;
5203
0
  }
5204
};
5205
5206
template <>
5207
struct TargetOutputNameArtifactResultGetter<ArtifactImportTag>
5208
{
5209
  static std::string Get(cmGeneratorTarget* target,
5210
                         cm::GenEx::Evaluation* eval,
5211
                         GeneratorExpressionContent const* /*unused*/,
5212
                         Postfix postfix)
5213
0
  {
5214
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5215
0
      auto output = target->GetOutputName(eval->Context.Config,
5216
0
                                          cmStateEnums::ImportLibraryArtifact);
5217
0
      return postfix != Postfix::Exclude
5218
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5219
0
        : output;
5220
0
    }
5221
0
    return std::string{};
5222
0
  }
5223
};
5224
5225
template <>
5226
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
5227
{
5228
  static std::string Get(cmGeneratorTarget* target,
5229
                         cm::GenEx::Evaluation* eval,
5230
                         GeneratorExpressionContent const* content,
5231
                         Postfix postfix)
5232
0
  {
5233
    // The library file used to link to the target (.so, .lib, .a) or import
5234
    // file (.lin,  .tbd).
5235
0
    if (!target->IsLinkable()) {
5236
0
      ::reportError(eval, content->GetOriginalExpression(),
5237
0
                    "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
5238
0
                    "libraries and executables with ENABLE_EXPORTS.");
5239
0
      return std::string();
5240
0
    }
5241
0
    cmStateEnums::ArtifactType artifact =
5242
0
      target->HasImportLibrary(eval->Context.Config)
5243
0
      ? cmStateEnums::ImportLibraryArtifact
5244
0
      : cmStateEnums::RuntimeBinaryArtifact;
5245
0
    auto output = target->GetOutputName(eval->Context.Config, artifact);
5246
0
    return postfix != Postfix::Exclude
5247
0
      ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5248
0
      : output;
5249
0
  }
5250
};
5251
5252
template <>
5253
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag>
5254
{
5255
  static std::string Get(cmGeneratorTarget* target,
5256
                         cm::GenEx::Evaluation* eval,
5257
                         GeneratorExpressionContent const* content,
5258
                         Postfix postfix)
5259
0
  {
5260
    // The library file used to link to the target (.so, .lib, .a).
5261
0
    if (!target->IsLinkable() ||
5262
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
5263
0
      ::reportError(eval, content->GetOriginalExpression(),
5264
0
                    "TARGET_LINKER_LIBRARY_FILE_BASE_NAME is allowed only for "
5265
0
                    "libraries with ENABLE_EXPORTS.");
5266
0
      return std::string();
5267
0
    }
5268
5269
0
    if (!target->IsDLLPlatform() ||
5270
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5271
0
      auto output = target->GetOutputName(eval->Context.Config,
5272
0
                                          cmStateEnums::ImportLibraryArtifact);
5273
0
      return postfix != Postfix::Exclude
5274
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5275
0
        : output;
5276
0
    }
5277
0
    return std::string{};
5278
0
  }
5279
};
5280
5281
template <>
5282
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag>
5283
{
5284
  static std::string Get(cmGeneratorTarget* target,
5285
                         cm::GenEx::Evaluation* eval,
5286
                         GeneratorExpressionContent const* content,
5287
                         Postfix postfix)
5288
0
  {
5289
    // The import file used to link to the target (.lib, .tbd).
5290
0
    if (!target->IsLinkable()) {
5291
0
      ::reportError(eval, content->GetOriginalExpression(),
5292
0
                    "TARGET_LINKER_IMPORT_FILE_BASE_NAME is allowed only for "
5293
0
                    "libraries and executables with ENABLE_EXPORTS.");
5294
0
      return std::string();
5295
0
    }
5296
5297
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5298
0
      auto output = target->GetOutputName(eval->Context.Config,
5299
0
                                          cmStateEnums::ImportLibraryArtifact);
5300
0
      return postfix != Postfix::Exclude
5301
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5302
0
        : output;
5303
0
    }
5304
0
    return std::string{};
5305
0
  }
5306
};
5307
5308
template <>
5309
struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
5310
{
5311
  static std::string Get(cmGeneratorTarget* target,
5312
                         cm::GenEx::Evaluation* eval,
5313
                         GeneratorExpressionContent const* content,
5314
                         Postfix postfix)
5315
0
  {
5316
0
    if (target->IsImported()) {
5317
0
      ::reportError(
5318
0
        eval, content->GetOriginalExpression(),
5319
0
        "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
5320
0
      return std::string();
5321
0
    }
5322
5323
0
    std::string language = target->GetLinkerLanguage(eval->Context.Config);
5324
5325
0
    std::string pdbSupportVar =
5326
0
      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
5327
5328
0
    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
5329
0
      ::reportError(
5330
0
        eval, content->GetOriginalExpression(),
5331
0
        "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
5332
0
      return std::string();
5333
0
    }
5334
5335
0
    cmStateEnums::TargetType targetType = target->GetType();
5336
5337
0
    if (targetType != cmStateEnums::SHARED_LIBRARY &&
5338
0
        targetType != cmStateEnums::MODULE_LIBRARY &&
5339
0
        targetType != cmStateEnums::EXECUTABLE) {
5340
0
      ::reportError(eval, content->GetOriginalExpression(),
5341
0
                    "TARGET_PDB_FILE_BASE_NAME is allowed only for "
5342
0
                    "targets with linker created artifacts.");
5343
0
      return std::string();
5344
0
    }
5345
5346
0
    auto output = target->GetPDBOutputName(eval->Context.Config);
5347
5348
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::NEW) {
5349
0
      return postfix != Postfix::Exclude
5350
0
        ? cmStrCat(output, target->GetFilePostfix(eval->Context.Config))
5351
0
        : output;
5352
0
    }
5353
5354
0
    if (target->GetPolicyStatusCMP0202() == cmPolicies::WARN &&
5355
0
        postfix != Postfix::Unspecified) {
5356
0
      eval->Context.LG->GetCMakeInstance()->IssueMessage(
5357
0
        MessageType::AUTHOR_WARNING,
5358
0
        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0202),
5359
0
                 "\n"
5360
0
                 "\"POSTFIX\" option is recognized only when the policy is "
5361
0
                 "set to NEW. Since the policy is not set, the OLD behavior "
5362
0
                 "will be used."),
5363
0
        eval->Backtrace);
5364
0
    }
5365
5366
0
    return output;
5367
0
  }
5368
};
5369
5370
template <typename ArtifactT>
5371
struct TargetFileBaseNameArtifact : public TargetArtifactBase
5372
{
5373
24
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactNameTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactLinkerImportTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileBaseNameArtifact<ArtifactPdbTag>::TargetFileBaseNameArtifact()
Line
Count
Source
5373
4
  TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
5374
5375
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
5376
5377
  std::string Evaluate(
5378
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5379
    GeneratorExpressionContent const* content,
5380
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5381
0
  {
5382
0
    if (parameters.size() > 2) {
5383
0
      ::reportError(eval, content->GetOriginalExpression(),
5384
0
                    "Unexpected parameters, require one or two parameters.");
5385
0
      return std::string{};
5386
0
    }
5387
5388
0
    cmGeneratorTarget* target =
5389
0
      this->GetTarget(parameters, eval, content, dagChecker);
5390
0
    if (!target) {
5391
0
      return std::string();
5392
0
    }
5393
5394
0
    Postfix postfix = Postfix::Unspecified;
5395
0
    if (parameters.size() == 2) {
5396
0
      if (parameters[1] == "POSTFIX:INCLUDE") {
5397
0
        postfix = Postfix::Include;
5398
0
      } else if (parameters[1] == "POSTFIX:EXCLUDE") {
5399
0
        postfix = Postfix::Exclude;
5400
0
      } else {
5401
0
        ::reportError(eval, content->GetOriginalExpression(),
5402
0
                      "Wrong second parameter: \"POSTFIX:INCLUDE\" or "
5403
0
                      "\"POSTFIX:EXCLUDE\" is expected");
5404
0
      }
5405
0
    }
5406
5407
0
    std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
5408
0
      target, eval, content, postfix);
5409
0
    if (eval->HadError) {
5410
0
      return std::string();
5411
0
    }
5412
0
    return result;
5413
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
5414
};
5415
5416
static TargetFileBaseNameArtifact<ArtifactNameTag> const
5417
  targetFileBaseNameNode;
5418
static TargetFileBaseNameArtifact<ArtifactImportTag> const
5419
  targetImportFileBaseNameNode;
5420
static TargetFileBaseNameArtifact<ArtifactLinkerTag> const
5421
  targetLinkerFileBaseNameNode;
5422
static TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag> const
5423
  targetLinkerLibraryFileBaseNameNode;
5424
static TargetFileBaseNameArtifact<ArtifactLinkerImportTag> const
5425
  targetLinkerImportFileBaseNameNode;
5426
static TargetFileBaseNameArtifact<ArtifactPdbTag> const
5427
  targetPdbFileBaseNameNode;
5428
5429
class ArtifactFilePrefixTag;
5430
class ArtifactImportFilePrefixTag;
5431
class ArtifactLinkerFilePrefixTag;
5432
class ArtifactLinkerLibraryFilePrefixTag;
5433
class ArtifactLinkerImportFilePrefixTag;
5434
class ArtifactFileSuffixTag;
5435
class ArtifactImportFileSuffixTag;
5436
class ArtifactLinkerFileSuffixTag;
5437
class ArtifactLinkerLibraryFileSuffixTag;
5438
class ArtifactLinkerImportFileSuffixTag;
5439
5440
template <typename ArtifactT>
5441
struct TargetFileArtifactResultGetter
5442
{
5443
  static std::string Get(cmGeneratorTarget* target,
5444
                         cm::GenEx::Evaluation* eval,
5445
                         GeneratorExpressionContent const* content);
5446
};
5447
5448
template <>
5449
struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
5450
{
5451
  static std::string Get(cmGeneratorTarget* target,
5452
                         cm::GenEx::Evaluation* eval,
5453
                         GeneratorExpressionContent const*)
5454
0
  {
5455
0
    return target->GetFilePrefix(eval->Context.Config);
5456
0
  }
5457
};
5458
template <>
5459
struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag>
5460
{
5461
  static std::string Get(cmGeneratorTarget* target,
5462
                         cm::GenEx::Evaluation* eval,
5463
                         GeneratorExpressionContent const*)
5464
0
  {
5465
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5466
0
      return target->GetFilePrefix(eval->Context.Config,
5467
0
                                   cmStateEnums::ImportLibraryArtifact);
5468
0
    }
5469
0
    return std::string{};
5470
0
  }
5471
};
5472
template <>
5473
struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
5474
{
5475
  static std::string Get(cmGeneratorTarget* target,
5476
                         cm::GenEx::Evaluation* eval,
5477
                         GeneratorExpressionContent const* content)
5478
0
  {
5479
0
    if (!target->IsLinkable()) {
5480
0
      ::reportError(
5481
0
        eval, content->GetOriginalExpression(),
5482
0
        "TARGET_LINKER_FILE_PREFIX is allowed only for libraries and "
5483
0
        "executables with ENABLE_EXPORTS.");
5484
0
      return std::string();
5485
0
    }
5486
5487
0
    cmStateEnums::ArtifactType artifact =
5488
0
      target->HasImportLibrary(eval->Context.Config)
5489
0
      ? cmStateEnums::ImportLibraryArtifact
5490
0
      : cmStateEnums::RuntimeBinaryArtifact;
5491
5492
0
    return target->GetFilePrefix(eval->Context.Config, artifact);
5493
0
  }
5494
};
5495
template <>
5496
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag>
5497
{
5498
  static std::string Get(cmGeneratorTarget* target,
5499
                         cm::GenEx::Evaluation* eval,
5500
                         GeneratorExpressionContent const* content)
5501
0
  {
5502
0
    if (!target->IsLinkable() ||
5503
0
        target->GetType() == cmStateEnums::EXECUTABLE) {
5504
0
      ::reportError(
5505
0
        eval, content->GetOriginalExpression(),
5506
0
        "TARGET_LINKER_LIBRARY_FILE_PREFIX is allowed only for libraries "
5507
0
        "with ENABLE_EXPORTS.");
5508
0
      return std::string();
5509
0
    }
5510
5511
0
    if (!target->IsDLLPlatform() ||
5512
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5513
0
      return target->GetFilePrefix(eval->Context.Config,
5514
0
                                   cmStateEnums::RuntimeBinaryArtifact);
5515
0
    }
5516
0
    return std::string{};
5517
0
  }
5518
};
5519
template <>
5520
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag>
5521
{
5522
  static std::string Get(cmGeneratorTarget* target,
5523
                         cm::GenEx::Evaluation* eval,
5524
                         GeneratorExpressionContent const* content)
5525
0
  {
5526
0
    if (!target->IsLinkable()) {
5527
0
      ::reportError(
5528
0
        eval, content->GetOriginalExpression(),
5529
0
        "TARGET_LINKER_IMPORT_FILE_PREFIX is allowed only for libraries and "
5530
0
        "executables with ENABLE_EXPORTS.");
5531
0
      return std::string();
5532
0
    }
5533
5534
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5535
0
      return target->GetFilePrefix(eval->Context.Config,
5536
0
                                   cmStateEnums::ImportLibraryArtifact);
5537
0
    }
5538
0
    return std::string{};
5539
0
  }
5540
};
5541
template <>
5542
struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
5543
{
5544
  static std::string Get(cmGeneratorTarget* target,
5545
                         cm::GenEx::Evaluation* eval,
5546
                         GeneratorExpressionContent const*)
5547
0
  {
5548
0
    return target->GetFileSuffix(eval->Context.Config);
5549
0
  }
5550
};
5551
template <>
5552
struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag>
5553
{
5554
  static std::string Get(cmGeneratorTarget* target,
5555
                         cm::GenEx::Evaluation* eval,
5556
                         GeneratorExpressionContent const*)
5557
0
  {
5558
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5559
0
      return target->GetFileSuffix(eval->Context.Config,
5560
0
                                   cmStateEnums::ImportLibraryArtifact);
5561
0
    }
5562
0
    return std::string{};
5563
0
  }
5564
};
5565
template <>
5566
struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
5567
{
5568
  static std::string Get(cmGeneratorTarget* target,
5569
                         cm::GenEx::Evaluation* eval,
5570
                         GeneratorExpressionContent const* content)
5571
0
  {
5572
0
    if (!target->IsLinkable()) {
5573
0
      ::reportError(
5574
0
        eval, content->GetOriginalExpression(),
5575
0
        "TARGET_LINKER_FILE_SUFFIX is allowed only for libraries and "
5576
0
        "executables with ENABLE_EXPORTS.");
5577
0
      return std::string();
5578
0
    }
5579
5580
0
    cmStateEnums::ArtifactType artifact =
5581
0
      target->HasImportLibrary(eval->Context.Config)
5582
0
      ? cmStateEnums::ImportLibraryArtifact
5583
0
      : cmStateEnums::RuntimeBinaryArtifact;
5584
5585
0
    return target->GetFileSuffix(eval->Context.Config, artifact);
5586
0
  }
5587
};
5588
template <>
5589
struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag>
5590
{
5591
  static std::string Get(cmGeneratorTarget* target,
5592
                         cm::GenEx::Evaluation* eval,
5593
                         GeneratorExpressionContent const* content)
5594
0
  {
5595
0
    if (!target->IsLinkable() ||
5596
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5597
0
      ::reportError(eval, content->GetOriginalExpression(),
5598
0
                    "TARGET_LINKER_LIBRARY_FILE_SUFFIX is allowed only for "
5599
0
                    "libraries with ENABLE_EXPORTS.");
5600
0
      return std::string();
5601
0
    }
5602
5603
0
    if (!target->IsDLLPlatform() ||
5604
0
        target->GetType() == cmStateEnums::STATIC_LIBRARY) {
5605
0
      return target->GetFileSuffix(eval->Context.Config,
5606
0
                                   cmStateEnums::RuntimeBinaryArtifact);
5607
0
    }
5608
0
    return std::string{};
5609
0
  }
5610
};
5611
template <>
5612
struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag>
5613
{
5614
  static std::string Get(cmGeneratorTarget* target,
5615
                         cm::GenEx::Evaluation* eval,
5616
                         GeneratorExpressionContent const* content)
5617
0
  {
5618
0
    if (!target->IsLinkable()) {
5619
0
      ::reportError(
5620
0
        eval, content->GetOriginalExpression(),
5621
0
        "TARGET_LINKER_IMPORT_FILE_SUFFIX is allowed only for libraries and "
5622
0
        "executables with ENABLE_EXPORTS.");
5623
0
      return std::string();
5624
0
    }
5625
5626
0
    if (target->HasImportLibrary(eval->Context.Config)) {
5627
0
      return target->GetFileSuffix(eval->Context.Config,
5628
0
                                   cmStateEnums::ImportLibraryArtifact);
5629
0
    }
5630
0
    return std::string{};
5631
0
  }
5632
};
5633
5634
template <typename ArtifactT>
5635
struct TargetFileArtifact : public TargetArtifactBase
5636
{
5637
40
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>::TargetFileArtifact()
Line
Count
Source
5637
4
  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
5638
5639
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
5640
5641
  std::string Evaluate(
5642
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5643
    GeneratorExpressionContent const* content,
5644
    cmGeneratorExpressionDAGChecker* dagChecker) const override
5645
0
  {
5646
0
    cmGeneratorTarget* target =
5647
0
      this->GetTarget(parameters, eval, content, dagChecker);
5648
0
    if (!target) {
5649
0
      return std::string();
5650
0
    }
5651
5652
0
    std::string result =
5653
0
      TargetFileArtifactResultGetter<ArtifactT>::Get(target, eval, content);
5654
0
    if (eval->HadError) {
5655
0
      return std::string();
5656
0
    }
5657
0
    return result;
5658
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
5659
};
5660
5661
static TargetFileArtifact<ArtifactFilePrefixTag> const targetFilePrefixNode;
5662
static TargetFileArtifact<ArtifactImportFilePrefixTag> const
5663
  targetImportFilePrefixNode;
5664
static TargetFileArtifact<ArtifactLinkerFilePrefixTag> const
5665
  targetLinkerFilePrefixNode;
5666
static TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag> const
5667
  targetLinkerLibraryFilePrefixNode;
5668
static TargetFileArtifact<ArtifactLinkerImportFilePrefixTag> const
5669
  targetLinkerImportFilePrefixNode;
5670
static TargetFileArtifact<ArtifactFileSuffixTag> const targetFileSuffixNode;
5671
static TargetFileArtifact<ArtifactImportFileSuffixTag> const
5672
  targetImportFileSuffixNode;
5673
static TargetFileArtifact<ArtifactLinkerFileSuffixTag> const
5674
  targetLinkerFileSuffixNode;
5675
static TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag> const
5676
  targetLinkerLibraryFileSuffixNode;
5677
static TargetFileArtifact<ArtifactLinkerImportFileSuffixTag> const
5678
  targetLinkerImportFileSuffixNode;
5679
5680
static const struct ShellPathNode : public cmGeneratorExpressionNode
5681
{
5682
4
  ShellPathNode() {} // NOLINT(modernize-use-equals-default)
5683
5684
  std::string Evaluate(
5685
    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
5686
    GeneratorExpressionContent const* content,
5687
    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
5688
0
  {
5689
0
    cmList list_in{ parameters.front() };
5690
0
    if (list_in.empty()) {
5691
0
      reportError(eval, content->GetOriginalExpression(),
5692
0
                  "\"\" is not an absolute path.");
5693
0
      return std::string();
5694
0
    }
5695
0
    cmStateSnapshot snapshot = eval->Context.LG->GetStateSnapshot();
5696
0
    cmOutputConverter converter(snapshot);
5697
0
    char const* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
5698
0
    std::vector<std::string> list_out;
5699
0
    list_out.reserve(list_in.size());
5700
0
    for (auto const& in : list_in) {
5701
0
      if (!cmSystemTools::FileIsFullPath(in)) {
5702
0
        reportError(eval, content->GetOriginalExpression(),
5703
0
                    cmStrCat('"', in, "\" is not an absolute path."));
5704
0
        return std::string();
5705
0
      }
5706
0
      list_out.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
5707
0
    }
5708
0
    return cmJoin(list_out, separator);
5709
0
  }
5710
} shellPathNode;
5711
5712
cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
5713
  std::string const& identifier)
5714
0
{
5715
0
  static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
5716
0
    { "0", &zeroNode },
5717
0
    { "1", &oneNode },
5718
0
    { "AND", &andNode },
5719
0
    { "OR", &orNode },
5720
0
    { "NOT", &notNode },
5721
0
    { "C_COMPILER_ID", &cCompilerIdNode },
5722
0
    { "CXX_COMPILER_ID", &cxxCompilerIdNode },
5723
0
    { "OBJC_COMPILER_ID", &objcCompilerIdNode },
5724
0
    { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode },
5725
0
    { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
5726
0
    { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
5727
0
    { "HIP_COMPILER_ID", &hipCompilerIdNode },
5728
0
    { "VERSION_GREATER", &versionGreaterNode },
5729
0
    { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
5730
0
    { "VERSION_LESS", &versionLessNode },
5731
0
    { "VERSION_LESS_EQUAL", &versionLessEqNode },
5732
0
    { "VERSION_EQUAL", &versionEqualNode },
5733
0
    { "C_COMPILER_VERSION", &cCompilerVersionNode },
5734
0
    { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
5735
0
    { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
5736
0
    { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode },
5737
0
    { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode },
5738
0
    { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
5739
0
    { "HIP_COMPILER_VERSION", &hipCompilerVersionNode },
5740
0
    { "C_COMPILER_FRONTEND_VARIANT", &cCompilerFrontendVariantNode },
5741
0
    { "CXX_COMPILER_FRONTEND_VARIANT", &cxxCompilerFrontendVariantNode },
5742
0
    { "CUDA_COMPILER_FRONTEND_VARIANT", &cudaCompilerFrontendVariantNode },
5743
0
    { "OBJC_COMPILER_FRONTEND_VARIANT", &objcCompilerFrontendVariantNode },
5744
0
    { "OBJCXX_COMPILER_FRONTEND_VARIANT", &objcxxCompilerFrontendVariantNode },
5745
0
    { "Fortran_COMPILER_FRONTEND_VARIANT",
5746
0
      &fortranCompilerFrontendVariantNode },
5747
0
    { "HIP_COMPILER_FRONTEND_VARIANT", &hipCompilerFrontendVariantNode },
5748
0
    { "PLATFORM_ID", &platformIdNode },
5749
0
    { "COMPILE_FEATURES", &compileFeaturesNode },
5750
0
    { "CONFIGURATION", &configurationNode },
5751
0
    { "CONFIG", &configurationTestNode },
5752
0
    { "TARGET_FILE", &targetNodeGroup.File },
5753
0
    { "TARGET_IMPORT_FILE", &targetImportNodeGroup.File },
5754
0
    { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
5755
0
    { "TARGET_LINKER_LIBRARY_FILE", &targetLinkerLibraryNodeGroup.File },
5756
0
    { "TARGET_LINKER_IMPORT_FILE", &targetLinkerImportNodeGroup.File },
5757
0
    { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
5758
0
    { "TARGET_SONAME_IMPORT_FILE", &targetSoNameImportNodeGroup.File },
5759
0
    { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
5760
0
    { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
5761
0
    { "TARGET_IMPORT_FILE_BASE_NAME", &targetImportFileBaseNameNode },
5762
0
    { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
5763
0
    { "TARGET_LINKER_LIBRARY_FILE_BASE_NAME",
5764
0
      &targetLinkerLibraryFileBaseNameNode },
5765
0
    { "TARGET_LINKER_IMPORT_FILE_BASE_NAME",
5766
0
      &targetLinkerImportFileBaseNameNode },
5767
0
    { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
5768
0
    { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
5769
0
    { "TARGET_IMPORT_FILE_PREFIX", &targetImportFilePrefixNode },
5770
0
    { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
5771
0
    { "TARGET_LINKER_LIBRARY_FILE_PREFIX",
5772
0
      &targetLinkerLibraryFilePrefixNode },
5773
0
    { "TARGET_LINKER_IMPORT_FILE_PREFIX", &targetLinkerImportFilePrefixNode },
5774
0
    { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
5775
0
    { "TARGET_IMPORT_FILE_SUFFIX", &targetImportFileSuffixNode },
5776
0
    { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
5777
0
    { "TARGET_LINKER_LIBRARY_FILE_SUFFIX",
5778
0
      &targetLinkerLibraryFileSuffixNode },
5779
0
    { "TARGET_LINKER_IMPORT_FILE_SUFFIX", &targetLinkerImportFileSuffixNode },
5780
0
    { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
5781
0
    { "TARGET_IMPORT_FILE_NAME", &targetImportNodeGroup.FileName },
5782
0
    { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
5783
0
    { "TARGET_LINKER_LIBRARY_FILE_NAME",
5784
0
      &targetLinkerLibraryNodeGroup.FileName },
5785
0
    { "TARGET_LINKER_IMPORT_FILE_NAME",
5786
0
      &targetLinkerImportNodeGroup.FileName },
5787
0
    { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
5788
0
    { "TARGET_SONAME_IMPORT_FILE_NAME",
5789
0
      &targetSoNameImportNodeGroup.FileName },
5790
0
    { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
5791
0
    { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
5792
0
    { "TARGET_IMPORT_FILE_DIR", &targetImportNodeGroup.FileDir },
5793
0
    { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
5794
0
    { "TARGET_LINKER_LIBRARY_FILE_DIR",
5795
0
      &targetLinkerLibraryNodeGroup.FileDir },
5796
0
    { "TARGET_LINKER_IMPORT_FILE_DIR", &targetLinkerImportNodeGroup.FileDir },
5797
0
    { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
5798
0
    { "TARGET_SONAME_IMPORT_FILE_DIR", &targetSoNameImportNodeGroup.FileDir },
5799
0
    { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
5800
0
    { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
5801
0
    { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode },
5802
0
    { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
5803
0
    { "STREQUAL", &strEqualNode },
5804
0
    { "STRLESS", &strLessNode },
5805
0
    { "STRLESS_EQUAL", &strLessEqualNode },
5806
0
    { "STRGREATER", &strGreaterNode },
5807
0
    { "STRGREATER_EQUAL", &strGreaterEqualNode },
5808
0
    { "STRING", &stringNode },
5809
0
    { "EQUAL", &equalNode },
5810
0
    { "IN_LIST", &inListNode },
5811
0
    { "FILTER", &filterNode },
5812
0
    { "REMOVE_DUPLICATES", &removeDuplicatesNode },
5813
0
    { "LIST", &listNode },
5814
0
    { "LOWER_CASE", &lowerCaseNode },
5815
0
    { "UPPER_CASE", &upperCaseNode },
5816
0
    { "PATH", &pathNode },
5817
0
    { "PATH_EQUAL", &pathEqualNode },
5818
0
    { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
5819
0
    { "BOOL", &boolNode },
5820
0
    { "IF", &ifNode },
5821
0
    { "ANGLE-R", &angle_rNode },
5822
0
    { "COMMA", &commaNode },
5823
0
    { "SEMICOLON", &semicolonNode },
5824
0
    { "QUOTE", &quoteNode },
5825
0
    { "SOURCE_EXISTS", &sourceExistsNode },
5826
0
    { "SOURCE_PROPERTY", &sourcePropertyNode },
5827
0
    { "FILE_SET_EXISTS", &fileSetExistsNode },
5828
0
    { "FILE_SET_PROPERTY", &fileSetPropertyNode },
5829
0
    { "TARGET_PROPERTY", &targetPropertyNode },
5830
0
    { "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
5831
0
    { "TARGET_NAME", &targetNameNode },
5832
0
    { "TARGET_OBJECTS", &targetObjectsNode },
5833
0
    { "TARGET_POLICY", &targetPolicyNode },
5834
0
    { "TARGET_EXISTS", &targetExistsNode },
5835
0
    { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
5836
0
    { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
5837
0
    { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
5838
0
    { "TARGET_RUNTIME_DLL_DIRS", &targetRuntimeDllDirsNode },
5839
0
    { "GENEX_EVAL", &genexEvalNode },
5840
0
    { "BUILD_INTERFACE", &buildInterfaceNode },
5841
0
    { "INSTALL_INTERFACE", &installInterfaceNode },
5842
0
    { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode },
5843
0
    { "INSTALL_PREFIX", &installPrefixNode },
5844
0
    { "JOIN", &joinNode },
5845
0
    { "COMPILE_ONLY", &compileOnlyNode },
5846
0
    { "LINK_ONLY", &linkOnlyNode },
5847
0
    { "COMPILE_LANG_AND_ID", &languageAndIdNode },
5848
0
    { "COMPILE_LANGUAGE", &languageNode },
5849
0
    { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
5850
0
    { "LINK_LANGUAGE", &linkLanguageNode },
5851
0
    { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
5852
0
    { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
5853
0
    { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
5854
0
    { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
5855
0
    { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
5856
0
    { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
5857
0
    { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
5858
0
    { "C_COMPILER_LINKER_FRONTEND_VARIANT",
5859
0
      &cCompilerLinkerFrontendVariantNode },
5860
0
    { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
5861
0
      &cxxCompilerLinkerFrontendVariantNode },
5862
0
    { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
5863
0
      &cudaCompilerLinkerFrontendVariantNode },
5864
0
    { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
5865
0
      &objcCompilerLinkerFrontendVariantNode },
5866
0
    { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
5867
0
      &objcxxCompilerLinkerFrontendVariantNode },
5868
0
    { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
5869
0
      &fortranCompilerLinkerFrontendVariantNode },
5870
0
    { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
5871
0
      &hipCompilerLinkerFrontendVariantNode },
5872
0
    { "LINK_LIBRARY", &linkLibraryNode },
5873
0
    { "LINK_GROUP", &linkGroupNode },
5874
0
    { "HOST_LINK", &hostLinkNode },
5875
0
    { "DEVICE_LINK", &deviceLinkNode },
5876
0
    { "SHELL_PATH", &shellPathNode }
5877
0
  };
5878
5879
0
  {
5880
0
    auto itr = nodeMap.find(identifier);
5881
0
    if (itr != nodeMap.end()) {
5882
0
      return itr->second;
5883
0
    }
5884
0
  }
5885
0
  return nullptr;
5886
0
}
5887
5888
void reportError(cm::GenEx::Evaluation* eval, std::string const& expr,
5889
                 std::string const& result)
5890
0
{
5891
0
  eval->HadError = true;
5892
0
  if (eval->Quiet) {
5893
0
    return;
5894
0
  }
5895
5896
0
  std::ostringstream e;
5897
  /* clang-format off */
5898
0
  e << "Error evaluating generator expression:\n"
5899
0
    << "  " << expr << "\n"
5900
0
    << result;
5901
  /* clang-format on */
5902
0
  eval->Context.LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
5903
0
                                                     e.str(), eval->Backtrace);
5904
0
}