/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 | } |