Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmRule.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 "cmRule.h"
4
5
#include <algorithm>
6
#include <iterator>
7
#include <memory>
8
#include <unordered_map>
9
#include <utility>
10
11
#include <cm/string_view>
12
#include <cmext/algorithm>
13
#include <cmext/string_view>
14
15
#include "cmsys/RegularExpression.hxx"
16
17
#include "cmExecutionStatus.h"
18
#include "cmFileSet.h"
19
#include "cmFileSetMetadata.h"
20
#include "cmGlobalGenerator.h"
21
#include "cmList.h"
22
#include "cmListFileCache.h"
23
#include "cmMakefile.h"
24
#include "cmMessageType.h"
25
#include "cmPlaceholderExpander.h"
26
#include "cmRange.h"
27
#include "cmSourceFile.h"
28
#include "cmStringAlgorithms.h"
29
#include "cmTarget.h"
30
#include "cmValue.h"
31
32
namespace {
33
cm::string_view const NAME = "NAME"_s;
34
cm::string_view const OUTPUT = "OUTPUT"_s;
35
cm::string_view const COMMAND = "COMMAND"_s;
36
cm::string_view const COMMAND_COUNT = "COMMAND_COUNT"_s;
37
cm::string_view const COMMAND_EXPAND_LISTS = "COMMAND_EXPAND_LISTS"_s;
38
cm::string_view const COMMENT = "COMMENT"_s;
39
cm::string_view const COMPILE_DEFINITIONS = "COMPILE_DEFINITIONS"_s;
40
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
41
cm::string_view const DEPENDS = "DEPENDS"_s;
42
cm::string_view const DEPENDS_EXPLICIT_ONLY = "DEPENDS_EXPLICIT_ONLY"_s;
43
cm::string_view const BYPRODUCTS = "BYPRODUCTS"_s;
44
cm::string_view const DEPFILE = "DEPFILE"_s;
45
cm::string_view const GLOBAL = "GLOBAL"_s;
46
cm::string_view const INCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES"_s;
47
cm::string_view const JOB_POOL_COMPILE = "JOB_POOL_COMPILE"_s;
48
cm::string_view const JOB_SERVER_AWARE = "JOB_SERVER_AWARE"_s;
49
cm::string_view const OUTPUT_FILE_SET = "OUTPUT_FILE_SET"_s;
50
cm::string_view const OUTPUT_FILE_SET_BASE_DIRS =
51
  "OUTPUT_FILE_SET_BASE_DIRS"_s;
52
cm::string_view const PARENT_RULE = "PARENT_RULE"_s;
53
cm::string_view const FILE_SET_CONFIGURATORS = "FILE_SET_CONFIGURATORS"_s;
54
cm::string_view const SOURCE_CONFIGURATORS = "SOURCE_CONFIGURATORS"_s;
55
cm::string_view const USES_TERMINAL = "USES_TERMINAL"_s;
56
cm::string_view const VERBATIM = "VERBATIM"_s;
57
cm::string_view const WORKING_DIRECTORY = "WORKING_DIRECTORY"_s;
58
59
cmsys::RegularExpression commandIndex("^COMMAND_[0-9]+$");
60
61
enum class ReadOnlyCondition
62
{
63
  All,
64
  Configuration,
65
  Generation,
66
};
67
68
struct ReadOnlyProperty
69
{
70
  ReadOnlyProperty(ReadOnlyCondition cond)
71
0
    : Condition{ cond }
72
0
  {
73
0
  }
74
75
  ReadOnlyCondition Condition;
76
77
  std::string Message(cm::string_view prop, cmRule const* rule) const
78
0
  {
79
0
    std::string msg;
80
0
    switch (this->Condition) {
81
0
      case ReadOnlyCondition::All:
82
0
        msg = " property is read-only for rules (\"";
83
0
        break;
84
0
      case ReadOnlyCondition::Configuration:
85
0
        msg = " property can't be set during configuration for rules (\"";
86
0
        break;
87
0
      case ReadOnlyCondition::Generation:
88
0
        msg = " property can't be set during generation for rules (\"";
89
0
        break;
90
0
    }
91
0
    return cmStrCat('"', prop, "\" ", msg, rule->GetName(), "\")\n");
92
0
  }
93
94
  bool IsReadOnly(cm::string_view prop, cmRule const* rule) const
95
0
  {
96
0
    if ((rule->InGeneration() &&
97
0
         this->Condition == ReadOnlyCondition::Configuration) ||
98
0
        (!rule->InGeneration() &&
99
0
         this->Condition == ReadOnlyCondition::Generation)) {
100
0
      return false;
101
0
    }
102
103
0
    rule->GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
104
0
                                     this->Message(prop, rule));
105
106
0
    return true;
107
0
  }
108
};
109
110
bool IsSettableProperty(cm::string_view prop, cmRule const* rule)
111
0
{
112
0
  using ROC = ReadOnlyCondition;
113
0
  static std::unordered_map<cm::string_view, ReadOnlyProperty> const
114
0
    readOnlyProps{ { NAME, { ROC::All } },
115
0
                   { OUTPUT, { ROC::All } },
116
0
                   { COMMAND, { ROC::All } },
117
0
                   { COMMAND_COUNT, { ROC::All } },
118
0
                   { COMMAND_EXPAND_LISTS, { ROC::Generation } },
119
0
                   { COMMENT, { ROC::Generation } },
120
0
                   { COMPILE_DEFINITIONS, { ROC::Generation } },
121
0
                   { COMPILE_OPTIONS, { ROC::Generation } },
122
0
                   { DEPENDS, { ROC::All } },
123
0
                   { DEPENDS_EXPLICIT_ONLY, { ROC::Generation } },
124
0
                   { BYPRODUCTS, { ROC::All } },
125
0
                   { DEPFILE, { ROC::All } },
126
0
                   { GLOBAL, { ROC::Generation } },
127
0
                   { INCLUDE_DIRECTORIES, { ROC::Generation } },
128
0
                   { JOB_POOL_COMPILE, { ROC::Generation } },
129
0
                   { JOB_SERVER_AWARE, { ROC::Generation } },
130
0
                   { OUTPUT_FILE_SET, { ROC::Generation } },
131
0
                   { OUTPUT_FILE_SET_BASE_DIRS, { ROC::Generation } },
132
0
                   { PARENT_RULE, { ROC::All } },
133
0
                   { FILE_SET_CONFIGURATORS, { ROC::All } },
134
0
                   { SOURCE_CONFIGURATORS, { ROC::All } },
135
0
                   { USES_TERMINAL, { ROC::Generation } },
136
0
                   { VERBATIM, { ROC::Generation } },
137
0
                   { WORKING_DIRECTORY, { ROC::Generation } } };
138
139
0
  auto it =
140
0
    readOnlyProps.find(commandIndex.find(prop.data()) ? COMMAND : prop);
141
142
0
  if (it != readOnlyProps.end()) {
143
0
    return !(it->second.IsReadOnly(prop, rule));
144
0
  }
145
146
0
  if (rule->InGeneration()) {
147
0
    rule->GetMakefile().IssueMessage(
148
0
      MessageType::FATAL_ERROR,
149
0
      cmStrCat("rule properties cannot be changed during generation (\"",
150
0
               rule->GetName(), "\")\n"));
151
0
    return false;
152
0
  }
153
154
0
  return true;
155
0
}
156
157
class FileSetNamePlaceholderExpander : public cmPlaceholderExpander
158
{
159
public:
160
  using VariableMap = std::unordered_map<std::string, std::string>;
161
  VariableMap Values;
162
163
  bool InError = false;
164
165
private:
166
  std::string ExpandVariable(std::string const& variable) override
167
0
  {
168
0
    if (cm::contains(this->Values, variable)) {
169
0
      return this->Values[variable];
170
0
    }
171
0
    this->InError = true;
172
    // If there is no variable defined, mark unresolved variable by '<' and '>'
173
0
    return cmStrCat('<', variable, '>');
174
0
  }
175
};
176
}
177
178
cmRule::cmRule(cmMakefile& makefile, std::string name, cm::RuleScope scope)
179
0
  : Makefile(&makefile)
180
0
  , Name(std::move(name))
181
0
  , Scope(scope)
182
0
{
183
  // set some useful properties
184
0
  this->SetProperty("VERBATIM", cmValue::True);
185
0
  this->SetProperty("COMMAND_EXPAND_LISTS", cmValue::True);
186
0
  this->SetProperty("OUTPUT_FILE_SET",
187
0
                    "__cmake_rule_<RULE>_<TARGET>_<FILE_SET>_outputs;SOURCES");
188
0
  this->SetProperty("OUTPUT_FILE_SET_BASE_DIRS", "<CURRENT_BINARY_DIR>");
189
0
}
190
191
cmRule::cmRule(cmRule const& parent, cmMakefile& makefile, std::string name,
192
               cm::RuleScope scope)
193
0
  : Makefile(&makefile)
194
0
  , Name(std::move(name))
195
0
  , Scope(scope)
196
0
  , ConfiguratorsChain(parent.ConfiguratorsChain)
197
0
  , Properties(parent.Properties)
198
0
  , IncludeDirectories(parent.IncludeDirectories)
199
0
  , CompileOptions(parent.CompileOptions)
200
0
  , CompileDefinitions(parent.CompileDefinitions)
201
0
  , Generation(parent.Generation)
202
0
{
203
0
}
204
std::string const& cmRule::GetParentName() const
205
0
{
206
0
  static std::string empty;
207
208
0
  return empty;
209
0
}
210
211
void cmRule::SetConfigurator(ConfiguratorType type, std::string configurator,
212
                             ChainConfigurators chain)
213
0
{
214
0
  this->Configurators[type] = std::move(configurator);
215
0
  if (chain == ChainConfigurators::Yes) {
216
0
    this->ConfiguratorsChain[type].emplace_back(&this->GetName(),
217
0
                                                &this->Configurators[type]);
218
0
  } else {
219
0
    this->ConfiguratorsChain[type].assign(
220
0
      1,
221
0
      ConfiguratorSet::value_type{ &this->GetName(),
222
0
                                   &this->Configurators[type] });
223
0
  }
224
0
}
225
cmRule::ConfiguratorSet const& cmRule::GetConfigurators(
226
  ConfiguratorType type) const
227
0
{
228
0
  static ConfiguratorSet emptySet;
229
230
0
  if (this->HasConfigurators(type)) {
231
0
    return this->ConfiguratorsChain.at(type);
232
0
  }
233
0
  return emptySet;
234
0
}
235
236
bool cmRule::HasConfigurators(ConfiguratorType type) const
237
0
{
238
0
  return cm::contains(this->ConfiguratorsChain, type);
239
0
}
240
241
cmFileSet* cmRule::GetOutputFileSet(cmTarget* target,
242
                                    cmFileSet const* fileSet) const
243
0
{
244
0
  cmList outputFileSet{ this->GetProperty(std::string{ OUTPUT_FILE_SET }) };
245
0
  FileSetNamePlaceholderExpander expander;
246
0
  expander.Values["RULE"] = this->GetName();
247
0
  expander.Values["TARGET"] = target->GetName();
248
0
  expander.Values["FILE_SET"] = fileSet->GetName();
249
250
0
  std::string fsName{ outputFileSet[0] };
251
0
  expander.ExpandVariables(fsName);
252
0
  if (expander.InError) {
253
0
    this->GetMakefile().IssueMessage(
254
0
      MessageType::FATAL_ERROR,
255
0
      cmStrCat("Output File Set name, for rule \"", this->GetName(),
256
0
               "\", did not expand correctly:\n  \"", fsName, "\"."));
257
0
    return nullptr;
258
0
  }
259
260
0
  auto result = target->GetOrCreateFileSet(fsName, outputFileSet[1],
261
0
                                           fileSet->GetVisibility());
262
0
  if (!result.second && result.first->GetType() != outputFileSet[1]) {
263
0
    this->GetMakefile().IssueMessage(
264
0
      MessageType::FATAL_ERROR,
265
0
      cmStrCat("The output file set \"", fsName, "\", for the target \"",
266
0
               target->GetName(), "\", has the type \"",
267
0
               result.first->GetType(), "\" instead of \"", outputFileSet[1],
268
0
               "\", as specified by the rule \"", this->GetName(), "\"."));
269
0
    return nullptr;
270
0
  }
271
272
0
  if (result.first->GetDirectoryEntries().empty()) {
273
0
    if (cmValue baseDirs =
274
0
          this->GetProperty(std::string{ OUTPUT_FILE_SET_BASE_DIRS })) {
275
0
      expander.Values["CURRENT_SOURCE_DIR"] =
276
0
        fileSet->GetMakefile()->GetCurrentSourceDirectory();
277
0
      expander.Values["CURRENT_BINARY_DIR"] =
278
0
        fileSet->GetMakefile()->GetCurrentBinaryDirectory();
279
0
      expander.Values["OUTPUT_CURRENT_SOURCE_DIR"] =
280
0
        result.first->GetMakefile()->GetCurrentSourceDirectory();
281
0
      expander.Values["OUTPUT_CURRENT_BINARY_DIR"] =
282
0
        result.first->GetMakefile()->GetCurrentBinaryDirectory();
283
0
      std::string dirs{ baseDirs };
284
0
      expander.ExpandVariables(dirs);
285
0
      result.first->AddDirectoryEntry(BT<std::string>{ dirs });
286
0
    } else {
287
      // Add default base directory if none are specified
288
0
      result.first->AddDirectoryEntry(BT<std::string>{
289
0
        fileSet->GetMakefile()->GetCurrentBinaryDirectory() });
290
0
    }
291
0
  }
292
293
0
  return result.first;
294
0
}
295
296
cmBTStringRange cmRule::GetIncludeDirectories() const
297
0
{
298
0
  return cmMakeRange(this->IncludeDirectories);
299
0
}
300
301
cmBTStringRange cmRule::GetCompileOptions() const
302
0
{
303
0
  return cmMakeRange(this->CompileOptions);
304
0
}
305
306
cmBTStringRange cmRule::GetCompileDefinitions() const
307
0
{
308
0
  return cmMakeRange(this->CompileDefinitions);
309
0
}
310
311
void cmRule::SetProperty(std::string const& prop, cmValue value)
312
0
{
313
0
  if (!IsSettableProperty(prop, this)) {
314
0
    return;
315
0
  }
316
317
0
  if (prop == GLOBAL) {
318
0
    if (!value.IsOn()) {
319
0
      this->GetMakefile().IssueMessage(
320
0
        MessageType::FATAL_ERROR,
321
0
        cmStrCat("GLOBAL property can't be set to FALSE on rules (\"",
322
0
                 this->GetName(), "\")"));
323
0
      return;
324
0
    }
325
    /* no need to change anything if value does not change */
326
0
    if (!this->IsGloballyVisible()) {
327
0
      this->Scope = cm::RuleScope::Global;
328
0
      this->GetMakefile().GetGlobalGenerator()->IndexRule(this);
329
0
    }
330
0
  } else if (prop == OUTPUT_FILE_SET) {
331
0
    cmList fileSet{ value };
332
0
    if (fileSet.size() != 2) {
333
0
      this->GetMakefile().IssueMessage(
334
0
        MessageType::FATAL_ERROR,
335
0
        "OUTPUT_FILE_SET property require a list of 2 elements:\n  "
336
0
        "\"name;type\"");
337
0
      return;
338
0
    }
339
0
    if (!cm::FileSetMetadata::IsKnownType(fileSet[1])) {
340
0
      this->GetMakefile().IssueMessage(
341
0
        MessageType::FATAL_ERROR,
342
0
        cmStrCat(
343
0
          "specified file set type is erroneous. The supported types are: ",
344
0
          cmJoin(cm::FileSetMetadata::GetKnownTypes(), ", "), '.'));
345
0
      return;
346
0
    }
347
0
    this->Properties.SetProperty(prop, value);
348
0
  } else if (prop == INCLUDE_DIRECTORIES) {
349
0
    this->IncludeDirectories.clear();
350
0
    if (value) {
351
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
352
0
      this->IncludeDirectories.emplace_back(value, lfbt);
353
0
    }
354
0
  } else if (prop == COMPILE_OPTIONS) {
355
0
    this->CompileOptions.clear();
356
0
    if (value) {
357
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
358
0
      this->CompileOptions.emplace_back(value, lfbt);
359
0
    }
360
0
  } else if (prop == COMPILE_DEFINITIONS) {
361
0
    this->CompileDefinitions.clear();
362
0
    if (value) {
363
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
364
0
      this->CompileDefinitions.emplace_back(value, lfbt);
365
0
    }
366
0
  } else {
367
0
    this->Properties.SetProperty(prop, value);
368
0
  }
369
0
}
370
371
void cmRule::AppendProperty(std::string const& prop, std::string const& value,
372
                            bool asString)
373
0
{
374
0
  if (!IsSettableProperty(prop, this)) {
375
0
    return;
376
0
  }
377
378
0
  if (prop == GLOBAL) {
379
0
    this->GetMakefile().IssueMessage(
380
0
      MessageType::FATAL_ERROR,
381
0
      cmStrCat("GLOBAL property can't be appended, only set on rules (\"",
382
0
               this->GetName(), "\")\n"));
383
0
    return;
384
0
  }
385
386
0
  if (prop == INCLUDE_DIRECTORIES) {
387
0
    if (!value.empty()) {
388
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
389
0
      this->IncludeDirectories.emplace_back(value, lfbt);
390
0
    }
391
0
  } else if (prop == COMPILE_OPTIONS) {
392
0
    if (!value.empty()) {
393
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
394
0
      this->CompileOptions.emplace_back(value, lfbt);
395
0
    }
396
0
  } else if (prop == COMPILE_DEFINITIONS) {
397
0
    if (!value.empty()) {
398
0
      cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
399
0
      this->CompileDefinitions.emplace_back(value, lfbt);
400
0
    }
401
0
  } else {
402
0
    this->Properties.AppendProperty(prop, value, asString);
403
0
  }
404
0
}
405
406
cmValue cmRule::GetProperty(std::string const& prop) const
407
0
{
408
0
  static std::string value;
409
410
0
  if (prop == NAME) {
411
0
    return cmValue{ this->GetName() };
412
0
  }
413
0
  if (prop == OUTPUT) {
414
0
    value = cmList::to_string(this->GetOutputs());
415
0
    return cmValue{ value };
416
0
  }
417
0
  if (prop == COMMAND) {
418
0
    value = cmList::to_string(this->GetCommands()[0]);
419
0
    return cmValue{ value };
420
0
  }
421
0
  if (prop == COMMAND_COUNT) {
422
0
    value = std::to_string(this->GetCommands().size());
423
0
    return cmValue{ value };
424
0
  }
425
0
  if (commandIndex.find(prop)) {
426
0
    auto index = std::stoul(prop.substr(8));
427
0
    value = index >= this->GetCommands().size()
428
0
      ? "NOTFOUND"
429
0
      : cmList::to_string(this->GetCommands()[index]);
430
0
    return cmValue{ value };
431
0
  }
432
0
  if (prop == DEPENDS) {
433
0
    value = cmList::to_string(this->GetDepends());
434
0
    return cmValue{ value };
435
0
  }
436
0
  if (prop == BYPRODUCTS) {
437
0
    value = cmList::to_string(this->GetByproducts());
438
0
    return cmValue{ value };
439
0
  }
440
0
  if (prop == DEPFILE) {
441
0
    return cmValue{ this->GetDepfile() };
442
0
  }
443
0
  if (prop == GLOBAL) {
444
0
    return this->IsGloballyVisible() ? cmValue::True : cmValue::False;
445
0
  }
446
0
  if (prop == PARENT_RULE) {
447
0
    return cmValue{ this->GetParentName() };
448
0
  }
449
0
  if (prop == FILE_SET_CONFIGURATORS || prop == SOURCE_CONFIGURATORS) {
450
0
    ConfiguratorType type = prop == FILE_SET_CONFIGURATORS
451
0
      ? ConfiguratorType::FileSet
452
0
      : ConfiguratorType::Source;
453
454
0
    if (this->HasConfigurators(type)) {
455
0
      auto cfgs_set = this->GetConfigurators(type);
456
0
      std::vector<std::string> cfgs;
457
0
      cfgs.reserve(cfgs_set.size());
458
459
0
      std::transform(cfgs_set.cbegin(), cfgs_set.cend(),
460
0
                     std::back_inserter(cfgs),
461
0
                     [](ConfiguratorSet::value_type cfg) -> std::string {
462
0
                       return *cfg.second;
463
0
                     });
464
465
0
      value = cmList::to_string(cfgs);
466
0
      return cmValue{ value };
467
0
    }
468
469
0
    return nullptr;
470
0
  }
471
472
  // Check for the properties with backtraces.
473
0
  if (prop == INCLUDE_DIRECTORIES) {
474
0
    if (this->IncludeDirectories.empty()) {
475
0
      return nullptr;
476
0
    }
477
478
0
    value = cmList::to_string(this->IncludeDirectories);
479
0
    return cmValue{ value };
480
0
  }
481
482
0
  if (prop == COMPILE_OPTIONS) {
483
0
    if (this->CompileOptions.empty()) {
484
0
      return nullptr;
485
0
    }
486
487
0
    value = cmList::to_string(this->CompileOptions);
488
0
    return cmValue{ value };
489
0
  }
490
491
0
  if (prop == COMPILE_DEFINITIONS) {
492
0
    if (this->CompileDefinitions.empty()) {
493
0
      return nullptr;
494
0
    }
495
496
0
    value = cmList::to_string(this->CompileDefinitions);
497
0
    return cmValue{ value };
498
0
  }
499
500
0
  return this->Properties.GetPropertyValue(prop);
501
0
}
502
503
void cmRule::CheckProperty(std::string const& prop, cmMakefile& context) const
504
0
{
505
  // Certain properties need checking.
506
0
  if (prop == GLOBAL) {
507
0
    auto const& rules = context.GetOwnedRules();
508
0
    auto it = std::find_if(rules.begin(), rules.end(),
509
0
                           [&](std::unique_ptr<cmRule> const& rule) -> bool {
510
0
                             return this == rule.get();
511
0
                           });
512
0
    if (it == rules.end()) {
513
0
      context.IssueMessage(
514
0
        MessageType::FATAL_ERROR,
515
0
        cmStrCat("Attempt to promote rule \"", this->GetName(),
516
0
                 "\" to global scope (by setting GLOBAL) "
517
0
                 "which is not created in this directory."));
518
0
    }
519
0
  }
520
0
}
521
522
namespace {
523
cmsys::RegularExpression PatternRegex{ "(^[A-Z][A-Z0-9_]+)=(.*)$" };
524
525
void UpdatePatterns(cmRule::PatternSet& patterns, cmList const& newPatterns)
526
0
{
527
0
  for (auto const& pattern : newPatterns) {
528
0
    if (PatternRegex.find(pattern)) {
529
0
      auto it = std::find_if(patterns.begin(), patterns.end(),
530
0
                             [](cmRule::Pattern const& item) {
531
0
                               return item.Name == PatternRegex.match(1);
532
0
                             });
533
0
      if (it == patterns.end()) {
534
0
        patterns.emplace_back(PatternRegex.match(1), PatternRegex.match(2));
535
0
      } else {
536
0
        it->Value = PatternRegex.match(2);
537
0
      }
538
0
    }
539
0
  }
540
0
}
541
542
bool ConfigureRule(cmRule::ConfiguratorSet const& configurators,
543
                   cmMakefile* mf, cmRule::PatternSet& patterns,
544
                   std::string const& rule, std::string const& target,
545
                   std::string const& fileSet,
546
                   std::string const& outputFileSet,
547
                   std::string const& source = {})
548
0
{
549
0
  cm::string_view patternsVariable{ "_CMAKE_RULE_PATTERNS"_s };
550
551
0
  for (auto const& item : configurators) {
552
    // The validator command will be executed in an isolated scope.
553
0
    cmMakefile::ScopePushPop varScope(mf);
554
0
    cmMakefile::PolicyPushPop polScope(mf);
555
0
    static_cast<void>(varScope);
556
0
    static_cast<void>(polScope);
557
558
0
    std::vector<cmListFileArgument> args{
559
0
      cmListFileArgument{ rule, cmListFileArgument::Unquoted, 0 },
560
0
      cmListFileArgument{ target, cmListFileArgument::Unquoted, 0 },
561
0
      cmListFileArgument{ fileSet, cmListFileArgument::Unquoted, 0 },
562
0
      cmListFileArgument{ outputFileSet, cmListFileArgument::Unquoted, 0 }
563
0
    };
564
0
    if (!source.empty()) {
565
0
      args.emplace_back(source, cmListFileArgument::Quoted, 0);
566
0
    }
567
0
    args.emplace_back(patternsVariable, cmListFileArgument::Unquoted, 0);
568
569
0
    cmListFileFunction command(*item.second, 0, 0, args);
570
0
    cmExecutionStatus status(*mf);
571
0
    if (!mf->ExecuteCommand(command, status)) {
572
0
      mf->IssueMessage(MessageType::FATAL_ERROR,
573
0
                       cmStrCat("Erroneous execution of the CONFIGURATOR \"",
574
0
                                *item.second, "\", from the RULE \"",
575
0
                                *item.first, "\", for the FILE_SET \"",
576
0
                                fileSet, "\" of TARGET \"", target, "\"."));
577
0
      return false;
578
0
    }
579
0
    UpdatePatterns(
580
0
      patterns, cmList{ mf->GetDefinition(std::string{ patternsVariable }) });
581
0
  }
582
583
0
  return true;
584
0
}
585
}
586
587
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
588
                         cmFileSet const* outputFileSet,
589
                         PatternSet& patterns) const
590
0
{
591
0
  this->SwitchMode();
592
593
  // First, take patterns from RULE_PATTERNS file set property, if any
594
0
  if (cmValue fsPatterns = fileSet->GetProperty("RULE_PATTERNS")) {
595
0
    UpdatePatterns(patterns, cmList{ fsPatterns, cmList::EmptyElements::No });
596
0
  }
597
598
0
  if (this->HasConfigurators(ConfiguratorType::FileSet)) {
599
    // Finalize file set level configuration by calling user's commands
600
0
    return ConfigureRule(this->GetConfigurators(ConfiguratorType::FileSet),
601
0
                         fileSet->GetMakefile(), patterns, this->GetName(),
602
0
                         target->GetName(), fileSet->GetName(),
603
0
                         outputFileSet->GetName());
604
0
  }
605
606
0
  return true;
607
0
}
608
609
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
610
                         cmFileSet const* outputFileSet, cmSourceFile* source,
611
                         PatternSet& patterns) const
612
0
{
613
  // First, take patterns from <RULE>_PATTERNS source file property, if any
614
0
  if (cmValue sfPatterns =
615
0
        source->GetProperty(cmStrCat(this->GetName(), "_PATTERNS"))) {
616
0
    UpdatePatterns(patterns, cmList{ sfPatterns, cmList::EmptyElements::No });
617
0
  }
618
619
0
  if (this->HasConfigurators(ConfiguratorType::Source)) {
620
    // Before custom commands generation, finalize source level
621
    // configuration by calling user's commands
622
0
    return ConfigureRule(this->GetConfigurators(ConfiguratorType::Source),
623
0
                         fileSet->GetMakefile(), patterns, this->GetName(),
624
0
                         target->GetName(), fileSet->GetName(),
625
0
                         outputFileSet->GetName(), source->GetFullPath());
626
0
  }
627
628
0
  return true;
629
0
}