Coverage Report

Created: 2026-04-29 07:01

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