Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorFileSets.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 "cmGeneratorFileSets.h"
4
5
#include <algorithm>
6
#include <iterator>
7
#include <map>
8
#include <unordered_set>
9
#include <utility>
10
#include <vector>
11
12
#include <cm/memory>
13
#include <cm/optional>
14
#include <cmext/algorithm>
15
#include <cmext/enum_set>
16
17
#include "cmFileSet.h"
18
#include "cmGenExContext.h"
19
#include "cmGenExEvaluation.h"
20
#include "cmGeneratorExpression.h"
21
#include "cmGeneratorExpressionDAGChecker.h"
22
#include "cmGeneratorExpressionNode.h"
23
#include "cmGeneratorFileSet.h"
24
#include "cmGeneratorTarget.h"
25
#include "cmLinkItem.h"
26
#include "cmList.h"
27
#include "cmListFileCache.h"
28
#include "cmLocalGenerator.h"
29
#include "cmMakefile.h"
30
#include "cmMessageType.h"
31
#include "cmSourceFile.h"
32
#include "cmStringAlgorithms.h"
33
#include "cmSystemTools.h"
34
#include "cmTarget.h"
35
#include "cmValue.h"
36
37
cmGeneratorFileSets::cmGeneratorFileSets(cmGeneratorTarget* target,
38
                                         cmLocalGenerator* lg)
39
53.3k
  : Target(target)
40
53.3k
  , LocalGenerator(lg)
41
53.3k
{
42
53.3k
  bool isFramework = target->IsFrameworkOnApple();
43
53.3k
  auto issueMessage = [&target](cmFileSet const* fileSet) {
44
0
    target->Makefile->IssueMessage(
45
0
      MessageType::FATAL_ERROR,
46
0
      cmStrCat(R"(The file set ")", fileSet->GetName(), R"(",  of type ")",
47
0
               fileSet->GetType(),
48
0
               R"(", is incompatible with the "FRAMEWORK" target ")",
49
0
               target->GetName(), R"(".)"));
50
0
  };
51
52
106k
  for (auto domain : cm::FileSetMetadata::AllFileSetDomains) {
53
106k
    for (auto const& name : target->Target->GetAllPrivateFileSets(domain)) {
54
0
      cmFileSet const* fileSet = target->Target->GetFileSet(name);
55
0
      if (isFramework &&
56
0
          !cm::FileSetMetadata::IsFrameworkSupported(fileSet->GetType())) {
57
0
        issueMessage(fileSet);
58
0
        continue;
59
0
      }
60
0
      auto entry = this->FileSets.emplace(
61
0
        name, cm::make_unique<cmGeneratorFileSet>(target, fileSet, domain));
62
0
      auto const* genFileSet = entry.first->second.get();
63
0
      this->AllFileSets.push_back(genFileSet);
64
0
      this->SelfFileSets[genFileSet->GetType()].push_back(genFileSet);
65
0
    }
66
106k
    for (auto const& name : target->Target->GetAllInterfaceFileSets(domain)) {
67
5.92k
      auto it = this->FileSets.find(name);
68
5.92k
      cmGeneratorFileSet const* genFileSet = nullptr;
69
5.92k
      if (it == this->FileSets.end()) {
70
5.92k
        cmFileSet const* fileSet = target->Target->GetFileSet(name);
71
5.92k
        if (isFramework &&
72
0
            !cm::FileSetMetadata::IsFrameworkSupported(fileSet->GetType())) {
73
0
          issueMessage(fileSet);
74
0
          continue;
75
0
        }
76
5.92k
        auto entry = this->FileSets.emplace(
77
5.92k
          name, cm::make_unique<cmGeneratorFileSet>(target, fileSet, domain));
78
5.92k
        genFileSet = entry.first->second.get();
79
5.92k
        this->AllFileSets.push_back(genFileSet);
80
5.92k
      } else {
81
0
        genFileSet = it->second.get();
82
0
      }
83
5.92k
      this->InterfaceFileSets[genFileSet->GetType()].push_back(genFileSet);
84
5.92k
    }
85
106k
  }
86
53.3k
}
87
53.3k
cmGeneratorFileSets::~cmGeneratorFileSets() = default;
88
89
std::vector<cm::string_view> cmGeneratorFileSets::GetFileSetTypes() const
90
0
{
91
0
  return cm::keys(this->SelfFileSets);
92
0
}
93
94
std::vector<cm::string_view> cmGeneratorFileSets::GetInterfaceFileSetTypes()
95
  const
96
0
{
97
0
  return cm::keys(this->InterfaceFileSets);
98
0
}
99
100
std::vector<cmGeneratorFileSet const*> const&
101
cmGeneratorFileSets::GetAllFileSets() const
102
0
{
103
0
  return this->AllFileSets;
104
0
}
105
106
namespace {
107
std::vector<cmGeneratorFileSet const*> NoFileSets;
108
}
109
110
std::vector<cmGeneratorFileSet const*> const& cmGeneratorFileSets::GetFileSets(
111
  cm::string_view type) const
112
1.92k
{
113
1.92k
  auto it = this->SelfFileSets.find(type);
114
1.92k
  if (it != this->SelfFileSets.end()) {
115
0
    return it->second;
116
0
  }
117
1.92k
  return NoFileSets;
118
1.92k
}
119
std::vector<cmGeneratorFileSet const*> const&
120
cmGeneratorFileSets::GetInterfaceFileSets(cm::string_view type) const
121
10.6k
{
122
10.6k
  auto it = this->InterfaceFileSets.find(type);
123
10.6k
  if (it != this->InterfaceFileSets.end()) {
124
518
    return it->second;
125
518
  }
126
10.1k
  return NoFileSets;
127
10.6k
}
128
129
cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSet(
130
  std::string const& name) const
131
69
{
132
69
  auto const it = this->FileSets.find(name);
133
69
  if (it != this->FileSets.end()) {
134
43
    return it->second.get();
135
43
  }
136
26
  return nullptr;
137
69
}
138
139
std::unordered_set<cmGeneratorFileSet const*> const&
140
cmGeneratorFileSets::GetAllFileSetsForSource(std::string const& config,
141
                                             std::string const& path) const
142
0
{
143
0
  this->BuildInfoCache(config);
144
145
0
  auto const& info = this->Configs[config];
146
147
0
  auto const it = info.FileSetCache.find(path);
148
0
  if (it != info.FileSetCache.end()) {
149
0
    return it->second;
150
0
  }
151
152
  // search in all the dependents
153
0
  auto const it2 = info.InterfaceFileSetCache.find(path);
154
0
  if (it2 != info.InterfaceFileSetCache.end()) {
155
0
    return it2->second;
156
0
  }
157
158
0
  static std::unordered_set<cmGeneratorFileSet const*> emptySet;
159
0
  return emptySet;
160
0
}
161
std::unordered_set<cmGeneratorFileSet const*> const&
162
cmGeneratorFileSets::GetAllFileSetsForSource(std::string const& config,
163
                                             cmSourceFile const* sf) const
164
0
{
165
0
  return this->GetAllFileSetsForSource(config, sf->GetFullPath());
166
0
}
167
168
cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSetForSource(
169
  std::string const& config, std::string const& file) const
170
1.31k
{
171
1.31k
  this->BuildInfoCache(config);
172
1.31k
  auto const& info = this->Configs[config];
173
174
1.31k
  using FileSetCache =
175
1.31k
    std::map<std::string, std::unordered_set<cmGeneratorFileSet const*>>;
176
5.24k
  auto lookup = [&file](FileSetCache const& cache, bool nonHeaderOnly) {
177
5.24k
    auto const entry = cache.find(file);
178
5.24k
    if (entry == cache.end()) {
179
5.24k
      return static_cast<cmGeneratorFileSet const*>(nullptr);
180
5.24k
    }
181
0
    auto const fileSet =
182
0
      std::find_if(entry->second.begin(), entry->second.end(),
183
0
                   [nonHeaderOnly](cmGeneratorFileSet const* candidate) {
184
0
                     return !nonHeaderOnly ||
185
0
                       candidate->GetType() != cm::FileSetMetadata::HEADERS;
186
0
                   });
187
0
    return fileSet == entry->second.end() ? nullptr : *fileSet;
188
5.24k
  };
189
190
1.31k
  if (auto const* fileSet = lookup(info.FileSetCache, true)) {
191
0
    return fileSet;
192
0
  }
193
1.31k
  if (auto const* fileSet = lookup(info.InterfaceFileSetCache, true)) {
194
0
    return fileSet;
195
0
  }
196
1.31k
  if (auto const* fileSet = lookup(info.FileSetCache, false)) {
197
0
    return fileSet;
198
0
  }
199
1.31k
  return lookup(info.InterfaceFileSetCache, false);
200
1.31k
}
201
cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSetForSource(
202
  std::string const& config, cmSourceFile const* sf) const
203
1.31k
{
204
1.31k
  return this->GetFileSetForSource(config, sf->GetFullPath());
205
1.31k
}
206
207
cm::optional<std::string> cmGeneratorFileSets::GetLanguageForSource(
208
  std::string const& config, cmSourceFile const* sf) const
209
1.91k
{
210
1.91k
  this->BuildInfoCache(config);
211
1.91k
  auto const& languages = this->Configs[config].LanguageCache;
212
1.91k
  auto const language = languages.find(sf->GetFullPath());
213
1.91k
  if (language == languages.end()) {
214
1.91k
    return cm::nullopt;
215
1.91k
  }
216
0
  return language->second;
217
1.91k
}
218
219
bool cmGeneratorFileSets::HasSyclHeaders(std::string const& config) const
220
612
{
221
612
  this->BuildInfoCache(config);
222
612
  return this->Configs[config].HasSyclHeaders;
223
612
}
224
225
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
226
cmGeneratorFileSets::GetSources(
227
  std::function<bool(cmGeneratorFileSet const*)> include,
228
  cm::GenEx::Context const& context, cmGeneratorTarget const* target,
229
  cmGeneratorExpressionDAGChecker* dagChecker) const
230
974
{
231
974
  std::vector<std::unique_ptr<TargetPropertyEntry>> entries;
232
233
974
  for (auto const& entry : this->FileSets) {
234
0
    auto const* fileSet = entry.second.get();
235
0
    if (include(fileSet)) {
236
0
      auto sources = fileSet->GetSources(context, target, dagChecker);
237
0
      std::move(sources.begin(), sources.end(), std::back_inserter(entries));
238
0
    }
239
0
  }
240
241
974
  return entries;
242
974
}
243
244
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
245
cmGeneratorFileSets::GetSources(
246
  cm::GenEx::Context const& context, cmGeneratorTarget const* target,
247
  cm::FileSetMetadata::FileSetDomainSet domains,
248
  cmGeneratorExpressionDAGChecker* dagChecker) const
249
974
{
250
974
  return this->GetSources(
251
974
    [&domains](cmGeneratorFileSet const* fileSet) -> bool {
252
0
      return fileSet->IsForSelf() && domains.contains(fileSet->GetDomain());
253
0
    },
254
974
    context, target, dagChecker);
255
974
}
256
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
257
cmGeneratorFileSets::GetSources(
258
  std::string type, cm::GenEx::Context const& context,
259
  cmGeneratorTarget const* target,
260
  cmGeneratorExpressionDAGChecker* dagChecker) const
261
0
{
262
0
  return this->GetSources(
263
0
    [&type](cmGeneratorFileSet const* fileSet) -> bool {
264
0
      return fileSet->IsForSelf() && fileSet->GetType() == type;
265
0
    },
266
0
    context, target, dagChecker);
267
0
}
268
269
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
270
cmGeneratorFileSets::GetInterfaceSources(
271
  cm::GenEx::Context const& context, cmGeneratorTarget const* target,
272
  cm::FileSetMetadata::FileSetDomainSet domains,
273
  cmGeneratorExpressionDAGChecker* dagChecker) const
274
0
{
275
0
  return this->GetSources(
276
0
    [&domains](cmGeneratorFileSet const* fileSet) -> bool {
277
0
      return fileSet->IsForInterface() &&
278
0
        domains.contains(fileSet->GetDomain());
279
0
    },
280
0
    context, target, dagChecker);
281
0
}
282
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
283
cmGeneratorFileSets::GetInterfaceSources(
284
  std::string type, cm::GenEx::Context const& context,
285
  cmGeneratorTarget const* target,
286
  cmGeneratorExpressionDAGChecker* dagChecker) const
287
0
{
288
0
  return this->GetSources(
289
0
    [&type](cmGeneratorFileSet const* fileSet) -> bool {
290
0
      return fileSet->IsForInterface() && fileSet->GetType() == type;
291
0
    },
292
0
    context, target, dagChecker);
293
0
}
294
295
bool cmGeneratorFileSets::MaybeHaveInterfaceProperty(
296
  cm::string_view type, std::string const& prop,
297
  cm::GenEx::Evaluation* eval) const
298
2.67k
{
299
2.67k
  std::string const key =
300
2.67k
    cmStrCat(type, "::", prop, '@', eval->Context.Config);
301
2.67k
  auto i = this->MaybeInterfacePropertyExists.find(key);
302
2.67k
  if (i == this->MaybeInterfacePropertyExists.end()) {
303
    // Insert an entry now in case there is a cycle.
304
2.45k
    i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
305
2.45k
    bool& maybeInterfaceProp = i->second;
306
307
2.45k
    for (auto const* fileSet : this->GetInterfaceFileSets(type)) {
308
      // If this file set itself has a non-empty property value, we are done.
309
0
      maybeInterfaceProp = !fileSet->GetProperty(prop).IsEmpty();
310
0
      if (maybeInterfaceProp) {
311
0
        break;
312
0
      }
313
0
    }
314
315
    // Otherwise, recurse to interface dependencies.
316
2.45k
    if (!maybeInterfaceProp) {
317
2.45k
      cmGeneratorTarget const* headTarget =
318
2.45k
        eval->HeadTarget ? eval->HeadTarget : this->Target;
319
2.45k
      if (cmLinkInterfaceLibraries const* iface =
320
2.45k
            this->Target->GetLinkInterfaceLibraries(
321
2.45k
              eval->Context.Config, headTarget,
322
2.45k
              cmGeneratorTarget::UseTo::Compile)) {
323
2.45k
        if (iface->HadHeadSensitiveCondition) {
324
          // With a different head target we may get to a library with
325
          // this interface property.
326
0
          maybeInterfaceProp = true;
327
2.45k
        } else {
328
          // The transitive interface libraries do not depend on the
329
          // head target, so we can follow them.
330
2.45k
          for (cmLinkItem const& lib : iface->Libraries) {
331
1.12k
            if (lib.Target &&
332
1.12k
                lib.Target->GetGeneratorFileSets()->MaybeHaveInterfaceProperty(
333
1.12k
                  type, prop, eval)) {
334
0
              maybeInterfaceProp = true;
335
0
              break;
336
0
            }
337
1.12k
          }
338
2.45k
        }
339
2.45k
      }
340
2.45k
    }
341
2.45k
  }
342
2.67k
  return i->second;
343
2.67k
}
344
345
std::string cmGeneratorFileSets::EvaluateInterfaceProperty(
346
  cm::string_view type, std::string const& prop, cm::GenEx::Evaluation* eval,
347
  cmGeneratorExpressionDAGChecker* dagCheckerParent) const
348
1.55k
{
349
  // If the property does not appear transitively at all, we are done.
350
1.55k
  if (!this->MaybeHaveInterfaceProperty(type, prop, eval)) {
351
1.55k
    return std::string{};
352
1.55k
  }
353
354
0
  cmList result;
355
0
  cmGeneratorExpressionDAGChecker dagChecker{
356
0
    this->Target,     prop,          nullptr,
357
0
    dagCheckerParent, eval->Context, eval->Backtrace,
358
0
  };
359
0
  switch (dagChecker.Check()) {
360
0
    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
361
0
      dagChecker.ReportError(
362
0
        eval,
363
0
        cmStrCat("$<FILE_SET_PROPERTY:*,TARGET:", this->Target->GetName(), ',',
364
0
                 prop, '>'));
365
0
      return std::string{};
366
0
    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
367
      // No error. We just skip cyclic references.
368
0
    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
369
      // No error. We have already seen this transitive property.
370
0
      return std::string{};
371
0
    case cmGeneratorExpressionDAGChecker::DAG:
372
0
      break;
373
0
  }
374
375
0
  cmGeneratorTarget const* headTarget =
376
0
    eval->HeadTarget ? eval->HeadTarget : this->Target;
377
378
0
  for (auto const* fileSet : this->GetInterfaceFileSets(type)) {
379
0
    if (cmValue p = fileSet->GetProperty(prop)) {
380
0
      result.append(cmGeneratorExpressionNode::EvaluateDependentExpression(
381
0
        *p, eval, headTarget, &dagChecker, this->Target));
382
0
    }
383
0
  }
384
385
0
  if (cmLinkInterfaceLibraries const* iface =
386
0
        this->Target->GetLinkInterfaceLibraries(
387
0
          eval->Context.Config, headTarget,
388
0
          cmGeneratorTarget::UseTo::Compile)) {
389
0
    eval->HadContextSensitiveCondition = eval->HadContextSensitiveCondition ||
390
0
      iface->HadContextSensitiveCondition;
391
0
    for (cmLinkItem const& lib : iface->Libraries) {
392
      // Broken code can have a target in its own link interface.
393
      // Don't follow such link interface entries so as not to create a
394
      // self-referencing loop.
395
0
      if (lib.Target && lib.Target != this->Target) {
396
        // Pretend $<FILE_SET__PROPERTY:fileSet,TARGET:lib.Target,prop>
397
        // appeared in the above property and hand-evaluate it as if it were
398
        // compiled.
399
        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
400
0
        cm::GenEx::Evaluation libEval(
401
0
          eval->Context, eval->Quiet, headTarget, this->Target,
402
0
          eval->EvaluateForBuildsystem, eval->Backtrace);
403
0
        std::string libResult = cmGeneratorExpression::StripEmptyListElements(
404
0
          lib.Target->GetGeneratorFileSets()->EvaluateInterfaceProperty(
405
0
            type, prop, &libEval, &dagChecker));
406
0
        if (!libResult.empty()) {
407
0
          result.append(libResult);
408
0
        }
409
0
        eval->HadContextSensitiveCondition =
410
0
          eval->HadContextSensitiveCondition ||
411
0
          libEval.HadContextSensitiveCondition;
412
0
        eval->HadHeadSensitiveCondition =
413
0
          eval->HadHeadSensitiveCondition || libEval.HadHeadSensitiveCondition;
414
0
      }
415
0
    }
416
0
  }
417
418
0
  return result.to_string();
419
0
}
420
421
namespace {
422
void GetInterfaceFiles(
423
  cmGeneratorTarget const* target, cmGeneratorTarget const* headTarget,
424
  cm::GenEx::Context const& context,
425
  std::unordered_set<cmGeneratorTarget const*>& targets,
426
  std::map<std::string, std::unordered_set<cmGeneratorFileSet const*>>& cache)
427
2.74k
{
428
2.74k
  namespace Metadata = cm::FileSetMetadata;
429
430
13.7k
  for (auto const& type : Metadata::GetKnownTypes()) {
431
13.7k
    auto fileSetDescriptor = Metadata::GetFileSetDescriptor(type);
432
13.7k
    if (fileSetDescriptor &&
433
13.7k
        fileSetDescriptor->Lookup == Metadata::FileSetLookup::Dependencies) {
434
5.48k
      for (auto const* fileSet : target->GetInterfaceFileSets(type)) {
435
0
        auto files = fileSet->GetFiles(context, headTarget);
436
437
0
        for (auto const& it : files.first) {
438
0
          for (auto const& filename : it.second) {
439
0
            auto collapsedFile = cmSystemTools::CollapseFullPath(filename);
440
0
            cache[collapsedFile].insert(fileSet);
441
0
          }
442
0
        }
443
0
      }
444
5.48k
    }
445
13.7k
  }
446
447
2.74k
  if (cmLinkInterfaceLibraries const* iface =
448
2.74k
        target->GetLinkInterfaceLibraries(context.Config, headTarget,
449
2.74k
                                          cmGeneratorTarget::UseTo::Compile)) {
450
2.74k
    for (cmLinkItem const& lib : iface->Libraries) {
451
1.31k
      if (lib.Target && lib.Target != target &&
452
1.31k
          targets.insert(lib.Target).second) {
453
1.31k
        GetInterfaceFiles(lib.Target, headTarget, context, targets, cache);
454
1.31k
      }
455
1.31k
    }
456
2.74k
  }
457
2.74k
}
458
459
bool HasInterfaceSyclHeaders(
460
  cmGeneratorTarget const* target, cmGeneratorTarget const* headTarget,
461
  std::string const& config,
462
  std::unordered_set<cmGeneratorTarget const*>& targets)
463
2.74k
{
464
2.74k
  for (auto const* fileSet :
465
2.74k
       target->GetInterfaceFileSets(cm::FileSetMetadata::HEADERS)) {
466
518
    if (fileSet->GetProperty("LANGUAGE") == cm::FileSetMetadata::SYCL) {
467
0
      return true;
468
0
    }
469
518
  }
470
471
2.74k
  if (cmLinkInterfaceLibraries const* iface =
472
2.74k
        target->GetLinkInterfaceLibraries(config, headTarget,
473
2.74k
                                          cmGeneratorTarget::UseTo::Compile)) {
474
2.74k
    for (cmLinkItem const& lib : iface->Libraries) {
475
1.31k
      if (lib.Target && lib.Target != target &&
476
1.31k
          targets.insert(lib.Target).second &&
477
1.31k
          HasInterfaceSyclHeaders(lib.Target, headTarget, config, targets)) {
478
0
        return true;
479
0
      }
480
1.31k
    }
481
2.74k
  }
482
2.74k
  return false;
483
2.74k
}
484
}
485
486
void cmGeneratorFileSets::BuildInfoCache(std::string const& config) const
487
3.83k
{
488
3.83k
  auto& info = this->Configs[config];
489
490
3.83k
  if (info.BuiltCache) {
491
2.87k
    return;
492
2.87k
  }
493
494
964
  cm::GenEx::Context context(this->LocalGenerator, config);
495
496
964
  info.HasSyclHeaders = std::any_of(
497
964
    this->GetFileSets(cm::FileSetMetadata::HEADERS).begin(),
498
964
    this->GetFileSets(cm::FileSetMetadata::HEADERS).end(),
499
964
    [](cmGeneratorFileSet const* fileSet) {
500
0
      return fileSet->GetProperty("LANGUAGE") == cm::FileSetMetadata::SYCL;
501
0
    });
502
503
964
  for (auto const& item : this->FileSets) {
504
0
    auto const* fileSet = item.second.get();
505
0
    if (!fileSet->IsForSelf()) {
506
0
      continue;
507
0
    }
508
509
0
    auto files = fileSet->GetFiles(context, this->Target);
510
511
0
    for (auto const& it : files.first) {
512
0
      for (auto const& filename : it.second) {
513
0
        auto collapsedFile = cmSystemTools::CollapseFullPath(filename);
514
0
        info.FileSetCache[collapsedFile].insert(fileSet);
515
0
      }
516
0
    }
517
0
  }
518
519
  // retrieve all files inherited from dependent targets
520
964
  std::unordered_set<cmGeneratorTarget const*> targets;
521
964
  std::unordered_set<cmGeneratorTarget const*> syclHeaderTargets;
522
523
964
  if (cmLinkImplementationLibraries const* impl =
524
964
        this->Target->GetLinkImplementationLibraries(
525
964
          config, cmGeneratorTarget::UseTo::Compile)) {
526
1.55k
    for (cmLinkItem const& lib : impl->Libraries) {
527
1.55k
      if (!info.HasSyclHeaders && lib.Target &&
528
1.55k
          syclHeaderTargets.insert(lib.Target).second) {
529
1.43k
        info.HasSyclHeaders = HasInterfaceSyclHeaders(
530
1.43k
          lib.Target, this->Target, config, syclHeaderTargets);
531
1.43k
      }
532
1.55k
      if (lib.Target && targets.insert(lib.Target).second) {
533
1.43k
        GetInterfaceFiles(lib.Target, this->Target, context, targets,
534
1.43k
                          info.InterfaceFileSetCache);
535
1.43k
      }
536
1.55k
    }
537
964
  }
538
539
964
  auto indexLanguages =
540
964
    [this,
541
964
     &info](std::map<std::string,
542
964
                     std::unordered_set<cmGeneratorFileSet const*>> const&
543
1.92k
              fileSets) {
544
1.92k
      for (auto const& file : fileSets) {
545
0
        for (auto const* fileSet : file.second) {
546
0
          if (fileSet->GetType() != cm::FileSetMetadata::SOURCES) {
547
0
            continue;
548
0
          }
549
0
          cmValue const language = fileSet->GetProperty("LANGUAGE");
550
0
          if (language.IsEmpty()) {
551
0
            continue;
552
0
          }
553
0
          auto const inserted =
554
0
            info.LanguageCache.emplace(file.first, *language);
555
0
          if (!inserted.second && inserted.first->second != *language) {
556
0
            this->LocalGenerator->IssueMessage(
557
0
              MessageType::FATAL_ERROR,
558
0
              cmStrCat("Source file\n  ", file.first,
559
0
                       "\nbelongs to multiple SOURCES file sets with "
560
0
                       "conflicting LANGUAGE properties."));
561
0
          }
562
0
        }
563
0
      }
564
1.92k
    };
565
964
  indexLanguages(info.FileSetCache);
566
964
  indexLanguages(info.InterfaceFileSetCache);
567
568
964
  info.BuiltCache = true;
569
964
}