/src/CMake/Source/cmGeneratorTarget_Link.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 | | /* clang-format off */ |
4 | | #include "cmGeneratorTarget.h" |
5 | | /* clang-format on */ |
6 | | |
7 | | #include <algorithm> |
8 | | #include <cassert> |
9 | | #include <cstdio> |
10 | | #include <map> |
11 | | #include <set> |
12 | | #include <string> |
13 | | #include <unordered_map> |
14 | | #include <unordered_set> |
15 | | #include <utility> |
16 | | #include <vector> |
17 | | |
18 | | #include <cm/memory> |
19 | | #include <cm/optional> |
20 | | #include <cm/string_view> |
21 | | #include <cmext/algorithm> |
22 | | #include <cmext/string_view> |
23 | | |
24 | | #include "cmAlgorithms.h" |
25 | | #include "cmComputeLinkInformation.h" |
26 | | #include "cmDiagnostics.h" |
27 | | #include "cmGenExContext.h" |
28 | | #include "cmGeneratorExpression.h" |
29 | | #include "cmGeneratorExpressionDAGChecker.h" |
30 | | #include "cmGlobalGenerator.h" |
31 | | #include "cmLinkItem.h" |
32 | | #include "cmList.h" |
33 | | #include "cmListFileCache.h" |
34 | | #include "cmLocalGenerator.h" |
35 | | #include "cmMakefile.h" |
36 | | #include "cmMessageType.h" |
37 | | #include "cmPolicies.h" |
38 | | #include "cmRange.h" |
39 | | #include "cmSourceFile.h" |
40 | | #include "cmSourceFileLocationKind.h" |
41 | | #include "cmStringAlgorithms.h" |
42 | | #include "cmSystemTools.h" |
43 | | #include "cmTarget.h" |
44 | | #include "cmTargetLinkLibraryType.h" |
45 | | #include "cmTargetTypes.h" |
46 | | #include "cmValue.h" |
47 | | #include "cmake.h" |
48 | | |
49 | | namespace { |
50 | | using UseTo = cmGeneratorTarget::UseTo; |
51 | | |
52 | | std::string const kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES"; |
53 | | std::string const kINTERFACE_LINK_LIBRARIES_DIRECT = |
54 | | "INTERFACE_LINK_LIBRARIES_DIRECT"; |
55 | | std::string const kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE = |
56 | | "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"; |
57 | | |
58 | | unsigned int CheckLinkLibrariesSuppressionRAIICount; |
59 | | void MaybeEnableCheckLinkLibraries(cmOptionalLinkImplementation& impl) |
60 | 15.5k | { |
61 | 15.5k | if (CheckLinkLibrariesSuppressionRAIICount == 0) { |
62 | 15.5k | impl.CheckLinkLibraries = true; |
63 | 15.5k | } |
64 | 15.5k | } |
65 | | void MaybeEnableCheckLinkLibraries(cmOptionalLinkInterface& iface) |
66 | 51.0k | { |
67 | 51.0k | if (CheckLinkLibrariesSuppressionRAIICount == 0) { |
68 | 51.0k | iface.CheckLinkLibraries = true; |
69 | 51.0k | } |
70 | 51.0k | } |
71 | | } |
72 | | |
73 | | class cmTargetCollectLinkLanguages |
74 | | { |
75 | | public: |
76 | | cmTargetCollectLinkLanguages(cmGeneratorTarget const* target, |
77 | | std::string config, |
78 | | std::unordered_set<std::string>& languages, |
79 | | cmGeneratorTarget const* head, bool secondPass) |
80 | 567 | : Config(std::move(config)) |
81 | 567 | , Languages(languages) |
82 | 567 | , HeadTarget(head) |
83 | 567 | , SecondPass(secondPass) |
84 | 567 | { |
85 | 567 | this->Visited.insert(target); |
86 | 567 | } |
87 | | |
88 | | void Visit(cmLinkItem const& item) |
89 | 3.65k | { |
90 | 3.65k | if (!item.Target) { |
91 | 492 | return; |
92 | 492 | } |
93 | 3.16k | if (!this->Visited.insert(item.Target).second) { |
94 | 573 | return; |
95 | 573 | } |
96 | 2.59k | cmLinkInterface const* iface = item.Target->GetLinkInterface( |
97 | 2.59k | this->Config, this->HeadTarget, this->SecondPass); |
98 | 2.59k | if (!iface) { |
99 | 0 | return; |
100 | 0 | } |
101 | 2.59k | if (iface->HadLinkLanguageSensitiveCondition) { |
102 | 0 | this->HadLinkLanguageSensitiveCondition = true; |
103 | 0 | } |
104 | | |
105 | 2.59k | for (std::string const& language : iface->Languages) { |
106 | 637 | this->Languages.insert(language); |
107 | 637 | } |
108 | | |
109 | 2.59k | for (cmLinkItem const& lib : iface->Libraries) { |
110 | 2.40k | this->Visit(lib); |
111 | 2.40k | } |
112 | 2.59k | } |
113 | | |
114 | | bool GetHadLinkLanguageSensitiveCondition() const |
115 | 567 | { |
116 | 567 | return this->HadLinkLanguageSensitiveCondition; |
117 | 567 | } |
118 | | |
119 | | private: |
120 | | std::string Config; |
121 | | std::unordered_set<std::string>& Languages; |
122 | | cmGeneratorTarget const* HeadTarget; |
123 | | std::set<cmGeneratorTarget const*> Visited; |
124 | | bool SecondPass; |
125 | | bool HadLinkLanguageSensitiveCondition = false; |
126 | | }; |
127 | | |
128 | | cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( |
129 | | std::string const& config) const |
130 | 567 | { |
131 | | // There is no link implementation for targets that cannot compile sources. |
132 | 567 | if (!this->CanCompileSources()) { |
133 | 0 | static LinkClosure const empty = { {}, {} }; |
134 | 0 | return ∅ |
135 | 0 | } |
136 | | |
137 | 567 | std::string key(cmSystemTools::UpperCase(config)); |
138 | 567 | auto i = this->LinkClosureMap.find(key); |
139 | 567 | if (i == this->LinkClosureMap.end()) { |
140 | 567 | LinkClosure lc; |
141 | 567 | this->ComputeLinkClosure(config, lc); |
142 | 567 | LinkClosureMapType::value_type entry(key, lc); |
143 | 567 | i = this->LinkClosureMap.insert(entry).first; |
144 | 567 | } |
145 | 567 | return &i->second; |
146 | 567 | } |
147 | | |
148 | | class cmTargetSelectLinker |
149 | | { |
150 | | int Preference = 0; |
151 | | cmGeneratorTarget const* Target; |
152 | | cmGlobalGenerator* GG; |
153 | | std::set<std::string> Preferred; |
154 | | |
155 | | public: |
156 | | cmTargetSelectLinker(cmGeneratorTarget const* target) |
157 | 442 | : Target(target) |
158 | 442 | { |
159 | 442 | this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator(); |
160 | 442 | } |
161 | | void Consider(std::string const& lang) |
162 | 576 | { |
163 | 576 | int preference = this->GG->GetLinkerPreference(lang); |
164 | 576 | if (preference > this->Preference) { |
165 | 442 | this->Preference = preference; |
166 | 442 | this->Preferred.clear(); |
167 | 442 | } |
168 | 576 | if (preference == this->Preference) { |
169 | 576 | this->Preferred.insert(lang); |
170 | 576 | } |
171 | 576 | } |
172 | | std::string Choose() |
173 | 442 | { |
174 | 442 | if (this->Preferred.empty()) { |
175 | 0 | return ""; |
176 | 0 | } |
177 | 442 | if (this->Preferred.size() > 1) { |
178 | 0 | cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance(); |
179 | 0 | cm->IssueMessage( |
180 | 0 | MessageType::FATAL_ERROR, |
181 | 0 | cmStrCat( |
182 | 0 | "Target ", this->Target->GetName(), |
183 | 0 | " contains multiple languages with the highest linker preference (", |
184 | 0 | this->Preference, "):\n", cmWrap(" ", this->Preferred, "\n", ""), |
185 | 0 | "Set the LINKER_LANGUAGE property for this target."), |
186 | 0 | this->Target->GetBacktrace()); |
187 | 0 | } |
188 | 442 | return *this->Preferred.begin(); |
189 | 442 | } |
190 | | }; |
191 | | |
192 | | bool cmGeneratorTarget::ComputeLinkClosure(std::string const& config, |
193 | | LinkClosure& lc, |
194 | | bool secondPass) const |
195 | 567 | { |
196 | | // Get languages built in this target. |
197 | 567 | std::unordered_set<std::string> languages; |
198 | 567 | cmLinkImplementation const* impl = |
199 | 567 | this->GetLinkImplementation(config, UseTo::Link, secondPass); |
200 | 567 | assert(impl); |
201 | 567 | languages.insert(impl->Languages.cbegin(), impl->Languages.cend()); |
202 | | |
203 | | // Add interface languages from linked targets. |
204 | | // cmTargetCollectLinkLanguages linkLangs(this, config, languages, this, |
205 | | // secondPass); |
206 | 567 | cmTargetCollectLinkLanguages linkLangs(this, config, languages, this, |
207 | 567 | secondPass); |
208 | 1.25k | for (cmLinkItem const& lib : impl->Libraries) { |
209 | 1.25k | linkLangs.Visit(lib); |
210 | 1.25k | } |
211 | | |
212 | | // Store the transitive closure of languages. |
213 | 567 | cm::append(lc.Languages, languages); |
214 | | |
215 | | // Choose the language whose linker should be used. |
216 | 567 | if (secondPass || lc.LinkerLanguage.empty()) { |
217 | | // Find the language with the highest preference value. |
218 | 442 | cmTargetSelectLinker tsl(this); |
219 | | |
220 | | // First select from the languages compiled directly in this target. |
221 | 442 | for (std::string const& l : impl->Languages) { |
222 | 442 | tsl.Consider(l); |
223 | 442 | } |
224 | | |
225 | | // Now consider languages that propagate from linked targets. |
226 | 543 | for (std::string const& lang : languages) { |
227 | 543 | std::string propagates = |
228 | 543 | cmStrCat("CMAKE_", lang, "_LINKER_PREFERENCE_PROPAGATES"); |
229 | 543 | if (this->Makefile->IsOn(propagates)) { |
230 | 134 | tsl.Consider(lang); |
231 | 134 | } |
232 | 543 | } |
233 | | |
234 | 442 | lc.LinkerLanguage = tsl.Choose(); |
235 | 442 | } |
236 | | |
237 | 567 | return impl->HadLinkLanguageSensitiveCondition || |
238 | 567 | linkLangs.GetHadLinkLanguageSensitiveCondition(); |
239 | 567 | } |
240 | | |
241 | | void cmGeneratorTarget::ComputeLinkClosure(std::string const& config, |
242 | | LinkClosure& lc) const |
243 | 567 | { |
244 | 567 | bool secondPass = false; |
245 | | |
246 | 567 | { |
247 | 567 | LinkClosure linkClosure; |
248 | 567 | linkClosure.LinkerLanguage = this->LinkerLanguage; |
249 | | |
250 | 567 | bool hasHardCodedLinkerLanguage = this->Target->GetProperty("HAS_CXX") || |
251 | 567 | !this->Target->GetSafeProperty("LINKER_LANGUAGE").empty(); |
252 | | |
253 | | // Get languages built in this target. |
254 | 567 | secondPass = this->ComputeLinkClosure(config, linkClosure, false) && |
255 | 0 | !hasHardCodedLinkerLanguage; |
256 | 567 | this->LinkerLanguage = linkClosure.LinkerLanguage; |
257 | 567 | if (!secondPass) { |
258 | 567 | lc = std::move(linkClosure); |
259 | 567 | } |
260 | 567 | } |
261 | | |
262 | 567 | if (secondPass) { |
263 | 0 | LinkClosure linkClosure; |
264 | |
|
265 | 0 | this->ComputeLinkClosure(config, linkClosure, secondPass); |
266 | 0 | lc = std::move(linkClosure); |
267 | | |
268 | | // linker language must not be changed between the two passes |
269 | 0 | if (this->LinkerLanguage != lc.LinkerLanguage) { |
270 | 0 | cmSystemTools::Error(cmStrCat( |
271 | 0 | "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> " |
272 | 0 | "changes\nthe linker language for target \"", |
273 | 0 | this->GetName(), "\" (from '", this->LinkerLanguage, "' to '", |
274 | 0 | lc.LinkerLanguage, "') which is invalid.")); |
275 | 0 | } |
276 | 0 | } |
277 | 567 | } |
278 | | |
279 | | static void processILibs(std::string const& config, |
280 | | cmGeneratorTarget const* headTarget, |
281 | | cmLinkItem const& item, cmGlobalGenerator* gg, |
282 | | std::vector<cmGeneratorTarget const*>& tgts, |
283 | | std::set<cmGeneratorTarget const*>& emitted, |
284 | | UseTo usage) |
285 | 166k | { |
286 | 166k | if (item.Target && emitted.insert(item.Target).second) { |
287 | 10.4k | tgts.push_back(item.Target); |
288 | 10.4k | if (cmLinkInterfaceLibraries const* iface = |
289 | 10.4k | item.Target->GetLinkInterfaceLibraries(config, headTarget, usage)) { |
290 | 26.4k | for (cmLinkItem const& lib : iface->Libraries) { |
291 | 26.4k | processILibs(config, headTarget, lib, gg, tgts, emitted, usage); |
292 | 26.4k | } |
293 | 10.4k | } |
294 | 10.4k | } |
295 | 166k | } |
296 | | |
297 | | std::vector<cmGeneratorTarget const*> |
298 | | cmGeneratorTarget::GetLinkInterfaceClosure(std::string const& config, |
299 | | cmGeneratorTarget const* headTarget, |
300 | | UseTo usage) const |
301 | 2.61k | { |
302 | 2.61k | cmGlobalGenerator* gg = this->GetLocalGenerator()->GetGlobalGenerator(); |
303 | 2.61k | std::vector<cmGeneratorTarget const*> tgts; |
304 | 2.61k | std::set<cmGeneratorTarget const*> emitted; |
305 | 2.61k | if (cmLinkInterfaceLibraries const* iface = |
306 | 2.61k | this->GetLinkInterfaceLibraries(config, headTarget, usage)) { |
307 | 32.7k | for (cmLinkItem const& lib : iface->Libraries) { |
308 | 32.7k | processILibs(config, headTarget, lib, gg, tgts, emitted, usage); |
309 | 32.7k | } |
310 | 2.60k | } |
311 | 2.61k | return tgts; |
312 | 2.61k | } |
313 | | |
314 | | std::vector<cmGeneratorTarget const*> const& |
315 | | cmGeneratorTarget::GetLinkImplementationClosure(std::string const& config, |
316 | | UseTo usage) const |
317 | 11.3k | { |
318 | | // There is no link implementation for targets that cannot compile sources. |
319 | 11.3k | if (!this->CanCompileSources()) { |
320 | 818 | static std::vector<cmGeneratorTarget const*> const empty; |
321 | 818 | return empty; |
322 | 818 | } |
323 | | |
324 | 10.5k | LinkImplClosure& tgts = |
325 | 10.5k | (usage == UseTo::Compile ? this->LinkImplClosureForUsageMap[config] |
326 | 10.5k | : this->LinkImplClosureForLinkMap[config]); |
327 | 10.5k | if (!tgts.Done) { |
328 | 7.08k | tgts.Done = true; |
329 | 7.08k | std::set<cmGeneratorTarget const*> emitted; |
330 | | |
331 | 7.08k | cmLinkImplementationLibraries const* impl = |
332 | 7.08k | this->GetLinkImplementationLibraries(config, usage); |
333 | 7.08k | assert(impl); |
334 | | |
335 | 107k | for (cmLinkItem const& lib : impl->Libraries) { |
336 | 107k | processILibs(config, this, lib, |
337 | 107k | this->LocalGenerator->GetGlobalGenerator(), tgts, emitted, |
338 | 107k | usage); |
339 | 107k | } |
340 | 7.08k | } |
341 | 10.5k | return tgts; |
342 | 11.3k | } |
343 | | |
344 | | cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation( |
345 | | std::string const& config) const |
346 | 0 | { |
347 | | // Lookup any existing information for this configuration. |
348 | 0 | std::string key(cmSystemTools::UpperCase(config)); |
349 | 0 | auto i = this->LinkInformation.find(key); |
350 | 0 | if (i == this->LinkInformation.end()) { |
351 | | // Compute information for this configuration. |
352 | 0 | auto info = cm::make_unique<cmComputeLinkInformation>(this, config); |
353 | 0 | if (info && !info->Compute()) { |
354 | 0 | info.reset(); |
355 | 0 | } |
356 | | |
357 | | // Store the information for this configuration. |
358 | 0 | i = this->LinkInformation.emplace(key, std::move(info)).first; |
359 | |
|
360 | 0 | if (i->second) { |
361 | 0 | this->CheckPropertyCompatibility(*i->second, config); |
362 | 0 | } |
363 | 0 | } |
364 | 0 | return i->second.get(); |
365 | 0 | } |
366 | | |
367 | | void cmGeneratorTarget::CheckLinkLibraries() const |
368 | 0 | { |
369 | 0 | bool linkLibrariesOnlyTargets = |
370 | 0 | this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS"); |
371 | | |
372 | | // Evaluate the link interface of this target if needed for extra checks. |
373 | 0 | if (linkLibrariesOnlyTargets) { |
374 | 0 | std::vector<std::string> const& configs = |
375 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
376 | 0 | for (std::string const& config : configs) { |
377 | 0 | this->GetLinkInterfaceLibraries(config, this, UseTo::Link); |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | | // Check link the implementation for each generated configuration. |
382 | 0 | for (auto const& impl : this->LinkImplMap) { |
383 | 0 | for (cmLinkItem const& item : impl.second.Libraries) { |
384 | 0 | if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) { |
385 | 0 | return; |
386 | 0 | } |
387 | 0 | if (linkLibrariesOnlyTargets && |
388 | 0 | !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) { |
389 | 0 | return; |
390 | 0 | } |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | // Check link the interface for each generated combination of |
395 | | // configuration and consuming head target. We should not need to |
396 | | // consider LinkInterfaceUsageRequirementsOnlyMap because its entries |
397 | | // should be a subset of LinkInterfaceMap (with LINK_ONLY left out). |
398 | 0 | for (auto const& hmp : this->LinkInterfaceMap) { |
399 | 0 | for (auto const& hmi : hmp.second) { |
400 | 0 | if (!hmi.second.LibrariesDone || !hmi.second.CheckLinkLibraries) { |
401 | 0 | continue; |
402 | 0 | } |
403 | 0 | for (cmLinkItem const& item : hmi.second.Libraries) { |
404 | 0 | if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) { |
405 | 0 | return; |
406 | 0 | } |
407 | 0 | if (linkLibrariesOnlyTargets && |
408 | 0 | !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) { |
409 | 0 | return; |
410 | 0 | } |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | cmGeneratorTarget::CheckLinkLibrariesSuppressionRAII:: |
417 | | CheckLinkLibrariesSuppressionRAII() |
418 | 0 | { |
419 | 0 | ++CheckLinkLibrariesSuppressionRAIICount; |
420 | 0 | } |
421 | | |
422 | | cmGeneratorTarget::CheckLinkLibrariesSuppressionRAII:: |
423 | | ~CheckLinkLibrariesSuppressionRAII() |
424 | 0 | { |
425 | 0 | --CheckLinkLibrariesSuppressionRAIICount; |
426 | 0 | } |
427 | | |
428 | | namespace { |
429 | | cm::string_view missingTargetPossibleReasons = |
430 | | "Possible reasons include:\n" |
431 | | " * There is a typo in the target name.\n" |
432 | | " * A find_package call is missing for an IMPORTED target.\n" |
433 | | " * An ALIAS target is missing.\n"_s; |
434 | | } |
435 | | |
436 | | bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role, |
437 | | cmLinkItem const& item) const |
438 | 0 | { |
439 | 0 | if (item.Target || cmHasPrefix(item.AsStr(), "<LINK_GROUP:"_s) || |
440 | 0 | item.AsStr().find("::") == std::string::npos) { |
441 | 0 | return true; |
442 | 0 | } |
443 | 0 | std::string e; |
444 | 0 | if (role == LinkItemRole::Implementation) { |
445 | 0 | e = cmStrCat(std::move(e), "Target \"", this->GetName(), "\" links to"); |
446 | 0 | } else { |
447 | 0 | e = cmStrCat(std::move(e), "The link interface of target \"", |
448 | 0 | this->GetName(), "\" contains"); |
449 | 0 | } |
450 | 0 | e = cmStrCat(std::move(e), ":\n ", item.AsStr(), |
451 | 0 | "\nbut the target was not found. ", |
452 | 0 | missingTargetPossibleReasons); |
453 | 0 | cmListFileBacktrace backtrace = item.Backtrace; |
454 | 0 | if (backtrace.Empty()) { |
455 | 0 | backtrace = this->GetBacktrace(); |
456 | 0 | } |
457 | 0 | this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( |
458 | 0 | MessageType::FATAL_ERROR, e, backtrace); |
459 | 0 | return false; |
460 | 0 | } |
461 | | |
462 | | bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, |
463 | | cmLinkItem const& item) const |
464 | 0 | { |
465 | 0 | if (item.Target) { |
466 | 0 | return true; |
467 | 0 | } |
468 | 0 | std::string const& str = item.AsStr(); |
469 | 0 | if (!str.empty() && |
470 | 0 | (str[0] == '-' || str[0] == '$' || str[0] == '`' || |
471 | 0 | str.find_first_of("/\\") != std::string::npos || |
472 | 0 | cmHasPrefix(str, "<LINK_LIBRARY:"_s) || |
473 | 0 | cmHasPrefix(str, "<LINK_GROUP:"_s))) { |
474 | 0 | return true; |
475 | 0 | } |
476 | | |
477 | 0 | std::string e = cmStrCat("Target \"", this->GetName(), |
478 | 0 | "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ", |
479 | 0 | role == LinkItemRole::Implementation |
480 | 0 | ? "it links to" |
481 | 0 | : "its link interface contains", |
482 | 0 | ":\n ", item.AsStr(), "\nwhich is not a target. ", |
483 | 0 | missingTargetPossibleReasons); |
484 | 0 | cmListFileBacktrace backtrace = item.Backtrace; |
485 | 0 | if (backtrace.Empty()) { |
486 | 0 | backtrace = this->GetBacktrace(); |
487 | 0 | } |
488 | 0 | this->LocalGenerator->GetCMakeInstance()->IssueMessage( |
489 | 0 | MessageType::FATAL_ERROR, e, backtrace); |
490 | 0 | return false; |
491 | 0 | } |
492 | | |
493 | | bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n, |
494 | | cmLocalGenerator const*& lg) const |
495 | 153k | { |
496 | 153k | if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) { |
497 | 893 | cmDirectoryId const dirId = n.substr(cmStrLen(CMAKE_DIRECTORY_ID_SEP)); |
498 | 893 | if (dirId.String.empty()) { |
499 | 24 | lg = this->LocalGenerator; |
500 | 24 | return true; |
501 | 24 | } |
502 | 869 | if (cmLocalGenerator const* otherLG = |
503 | 869 | this->GlobalGenerator->FindLocalGenerator(dirId)) { |
504 | 0 | lg = otherLG; |
505 | 0 | return true; |
506 | 0 | } |
507 | 869 | } |
508 | 153k | return false; |
509 | 153k | } |
510 | | |
511 | | cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( |
512 | | std::string const& n, cmListFileBacktrace const& bt, |
513 | | std::string const& linkFeature, LookupLinkItemScope* scope, |
514 | | LookupSelf lookupSelf) const |
515 | 43.2k | { |
516 | 43.2k | cm::optional<cmLinkItem> maybeItem; |
517 | 43.2k | if (this->IsLinkLookupScope(n, scope->LG)) { |
518 | 8 | return maybeItem; |
519 | 8 | } |
520 | | |
521 | 43.2k | std::string name = this->CheckCMP0004(n); |
522 | 43.2k | if (name.empty() || |
523 | 43.2k | (lookupSelf == LookupSelf::No && name == this->GetName())) { |
524 | 4 | return maybeItem; |
525 | 4 | } |
526 | 43.2k | maybeItem = |
527 | 43.2k | this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG, linkFeature); |
528 | 43.2k | return maybeItem; |
529 | 43.2k | } |
530 | | |
531 | | void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, |
532 | | cmBTStringRange entries, |
533 | | std::string const& config, |
534 | | cmGeneratorTarget const* headTarget, |
535 | | UseTo usage, LinkInterfaceField field, |
536 | | cmLinkInterface& iface) const |
537 | 48.1k | { |
538 | 48.1k | if (entries.empty()) { |
539 | 38.4k | return; |
540 | 38.4k | } |
541 | | // Keep this logic in sync with ComputeLinkImplementationLibraries. |
542 | 9.63k | cm::GenEx::Context context(this->LocalGenerator, config, |
543 | 9.63k | headTarget->LinkerLanguage); |
544 | 9.63k | cmGeneratorExpressionDAGChecker dagChecker{ |
545 | 9.63k | this, |
546 | 9.63k | prop, |
547 | 9.63k | nullptr, |
548 | 9.63k | nullptr, |
549 | 9.63k | context, |
550 | 9.63k | cmListFileBacktrace(), |
551 | 9.63k | cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes, |
552 | 9.63k | }; |
553 | | // The $<LINK_ONLY> expression may be in a link interface to specify |
554 | | // private link dependencies that are otherwise excluded from usage |
555 | | // requirements. |
556 | 9.63k | if (usage == UseTo::Compile) { |
557 | 6.03k | dagChecker.SetTransitivePropertiesOnly(); |
558 | 6.03k | dagChecker.SetTransitivePropertiesOnlyCMP0131(); |
559 | 6.03k | } |
560 | 9.63k | cmMakefile const* mf = this->LocalGenerator->GetMakefile(); |
561 | 9.63k | LookupLinkItemScope scope{ this->LocalGenerator }; |
562 | 20.0k | for (BT<std::string> const& entry : entries) { |
563 | 20.0k | cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(), |
564 | 20.0k | entry.Backtrace); |
565 | 20.0k | std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value); |
566 | 20.0k | cge->SetEvaluateForBuildsystem(true); |
567 | 20.0k | cmList libs{ cge->Evaluate(context, &dagChecker, headTarget, this) }; |
568 | | |
569 | 20.0k | auto linkFeature = cmLinkItem::DEFAULT; |
570 | 43.4k | for (auto const& lib : libs) { |
571 | 43.4k | if (auto maybeLinkFeature = ParseLinkFeature(lib)) { |
572 | 140 | linkFeature = std::move(*maybeLinkFeature); |
573 | 140 | continue; |
574 | 140 | } |
575 | | |
576 | 43.2k | if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( |
577 | 43.2k | lib, cge->GetBacktrace(), linkFeature, &scope, |
578 | 43.2k | field == LinkInterfaceField::Libraries ? LookupSelf::No |
579 | 43.2k | : LookupSelf::Yes)) { |
580 | 43.2k | cmLinkItem item = std::move(*maybeItem); |
581 | | |
582 | 43.2k | if (field == LinkInterfaceField::HeadInclude) { |
583 | 0 | item.InterfaceDirectFrom = this; |
584 | 0 | iface.HeadInclude.emplace_back(std::move(item)); |
585 | 0 | continue; |
586 | 0 | } |
587 | 43.2k | if (field == LinkInterfaceField::HeadExclude) { |
588 | 0 | iface.HeadExclude.emplace_back(std::move(item)); |
589 | 0 | continue; |
590 | 0 | } |
591 | 43.2k | if (!item.Target) { |
592 | | // Report explicitly linked object files separately. |
593 | 33.2k | std::string const& maybeObj = item.AsStr(); |
594 | 33.2k | if (cmSystemTools::FileIsFullPath(maybeObj)) { |
595 | 10.9k | cmSourceFile const* sf = |
596 | 10.9k | mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); |
597 | 10.9k | if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { |
598 | 0 | item.ObjectSource = sf; |
599 | 0 | iface.Objects.emplace_back(std::move(item)); |
600 | 0 | continue; |
601 | 0 | } |
602 | 10.9k | } |
603 | 33.2k | } |
604 | | |
605 | 43.2k | iface.Libraries.emplace_back(std::move(item)); |
606 | 43.2k | } |
607 | 43.2k | } |
608 | 20.0k | if (cge->GetHadHeadSensitiveCondition()) { |
609 | 440 | iface.HadHeadSensitiveCondition = true; |
610 | 440 | } |
611 | 20.0k | if (cge->GetHadContextSensitiveCondition()) { |
612 | 2.50k | iface.HadContextSensitiveCondition = true; |
613 | 2.50k | } |
614 | 20.0k | if (cge->GetHadLinkLanguageSensitiveCondition()) { |
615 | 0 | iface.HadLinkLanguageSensitiveCondition = true; |
616 | 0 | } |
617 | 20.0k | } |
618 | 9.63k | } |
619 | | |
620 | | cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( |
621 | | std::string const& config, cmGeneratorTarget const* head) const |
622 | 0 | { |
623 | 0 | return this->GetLinkInterface(config, head, false); |
624 | 0 | } |
625 | | |
626 | | cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( |
627 | | std::string const& config, cmGeneratorTarget const* head, |
628 | | bool secondPass) const |
629 | 2.59k | { |
630 | | // Imported targets have their own link interface. |
631 | 2.59k | if (this->IsImported()) { |
632 | 1.01k | return this->GetImportLinkInterface(config, head, UseTo::Link, secondPass); |
633 | 1.01k | } |
634 | | |
635 | | // Link interfaces are not supported for executables that do not |
636 | | // export symbols. |
637 | 1.58k | if (this->GetType() == cm::TargetType::EXECUTABLE && |
638 | 0 | !this->IsExecutableWithExports()) { |
639 | 0 | return nullptr; |
640 | 0 | } |
641 | | |
642 | | // Lookup any existing link interface for this configuration. |
643 | 1.58k | cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); |
644 | | |
645 | | // If the link interface does not depend on the head target |
646 | | // then reuse the one from the head we computed first. |
647 | 1.58k | if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { |
648 | 1.58k | head = hm.begin()->first; |
649 | 1.58k | } |
650 | | |
651 | 1.58k | cmOptionalLinkInterface& iface = hm[head]; |
652 | 1.58k | if (secondPass) { |
653 | 0 | iface = cmOptionalLinkInterface(); |
654 | 0 | } |
655 | 1.58k | MaybeEnableCheckLinkLibraries(iface); |
656 | 1.58k | if (!iface.LibrariesDone) { |
657 | 0 | iface.LibrariesDone = true; |
658 | 0 | this->ComputeLinkInterfaceLibraries(config, iface, head, UseTo::Link); |
659 | 0 | } |
660 | 1.58k | if (!iface.AllDone) { |
661 | 1.48k | iface.AllDone = true; |
662 | 1.48k | if (iface.Exists) { |
663 | 1.48k | this->ComputeLinkInterface(config, iface, secondPass); |
664 | 1.48k | this->ComputeLinkInterfaceRuntimeLibraries(config, iface); |
665 | 1.48k | } |
666 | 1.48k | } |
667 | | |
668 | 1.58k | return iface.Exists ? &iface : nullptr; |
669 | 1.58k | } |
670 | | |
671 | | void cmGeneratorTarget::ComputeLinkInterface(std::string const& config, |
672 | | cmOptionalLinkInterface& iface, |
673 | | bool secondPass) const |
674 | 1.48k | { |
675 | 1.48k | if (this->GetType() == cm::TargetType::SHARED_LIBRARY || |
676 | 1.48k | this->GetType() == cm::TargetType::STATIC_LIBRARY || |
677 | 1.35k | this->GetType() == cm::TargetType::INTERFACE_LIBRARY) { |
678 | | // Shared libraries may have runtime implementation dependencies |
679 | | // on other shared libraries that are not in the interface. |
680 | 1.01k | std::set<cmLinkItem> emitted; |
681 | 1.82k | for (cmLinkItem const& lib : iface.Libraries) { |
682 | 1.82k | emitted.insert(lib); |
683 | 1.82k | } |
684 | 1.01k | if (this->GetType() != cm::TargetType::INTERFACE_LIBRARY) { |
685 | 132 | cmLinkImplementation const* impl = |
686 | 132 | this->GetLinkImplementation(config, UseTo::Link, secondPass); |
687 | 393 | for (cmLinkItem const& lib : impl->Libraries) { |
688 | 393 | if (emitted.insert(lib).second) { |
689 | 0 | if (lib.Target) { |
690 | | // This is a runtime dependency on another shared library. |
691 | 0 | if (lib.Target->GetType() == cm::TargetType::SHARED_LIBRARY) { |
692 | 0 | iface.SharedDeps.push_back(lib); |
693 | 0 | } |
694 | 0 | } else { |
695 | | // TODO: Recognize shared library file names. Perhaps this |
696 | | // should be moved to cmComputeLinkInformation, but that |
697 | | // creates a chicken-and-egg problem since this list is needed |
698 | | // for its construction. |
699 | 0 | } |
700 | 0 | } |
701 | 393 | } |
702 | 132 | } |
703 | 1.01k | } |
704 | | |
705 | 1.48k | if (this->LinkLanguagePropagatesToDependents()) { |
706 | | // Targets using this archive need its language runtime libraries. |
707 | 132 | if (cmLinkImplementation const* impl = |
708 | 132 | this->GetLinkImplementation(config, UseTo::Link, secondPass)) { |
709 | 132 | iface.Languages = impl->Languages; |
710 | 132 | } |
711 | 132 | } |
712 | | |
713 | 1.48k | if (this->GetType() == cm::TargetType::STATIC_LIBRARY) { |
714 | | // Construct the property name suffix for this configuration. |
715 | 132 | std::string suffix = "_"; |
716 | 132 | if (!config.empty()) { |
717 | 126 | suffix += cmSystemTools::UpperCase(config); |
718 | 126 | } else { |
719 | 6 | suffix += "NOCONFIG"; |
720 | 6 | } |
721 | | |
722 | | // How many repetitions are needed if this library has cyclic |
723 | | // dependencies? |
724 | 132 | std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix); |
725 | 132 | if (cmValue config_reps = this->GetProperty(propName)) { |
726 | 0 | sscanf(config_reps->c_str(), "%u", &iface.Multiplicity); |
727 | 132 | } else if (cmValue reps = |
728 | 132 | this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { |
729 | 0 | sscanf(reps->c_str(), "%u", &iface.Multiplicity); |
730 | 0 | } |
731 | 132 | } |
732 | 1.48k | } |
733 | | |
734 | | cmLinkInterfaceLibraries const* cmGeneratorTarget::GetLinkInterfaceLibraries( |
735 | | std::string const& config, cmGeneratorTarget const* head, UseTo usage) const |
736 | 48.4k | { |
737 | | // Imported targets have their own link interface. |
738 | 48.4k | if (this->IsImported()) { |
739 | 12.0k | return this->GetImportLinkInterface(config, head, usage); |
740 | 12.0k | } |
741 | | |
742 | | // Link interfaces are not supported for executables that do not |
743 | | // export symbols. |
744 | 36.3k | if (this->GetType() == cm::TargetType::EXECUTABLE && |
745 | 8 | !this->IsExecutableWithExports()) { |
746 | 8 | return nullptr; |
747 | 8 | } |
748 | | |
749 | | // Lookup any existing link interface for this configuration. |
750 | 36.3k | cmHeadToLinkInterfaceMap& hm = |
751 | 36.3k | (usage == UseTo::Compile |
752 | 36.3k | ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) |
753 | 36.3k | : this->GetHeadToLinkInterfaceMap(config)); |
754 | | |
755 | | // If the link interface does not depend on the head target |
756 | | // then reuse the one from the head we computed first. |
757 | 36.3k | if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { |
758 | 23.9k | head = hm.begin()->first; |
759 | 23.9k | } |
760 | | |
761 | 36.3k | cmOptionalLinkInterface& iface = hm[head]; |
762 | 36.3k | MaybeEnableCheckLinkLibraries(iface); |
763 | 36.3k | if (!iface.LibrariesDone) { |
764 | 12.0k | iface.LibrariesDone = true; |
765 | 12.0k | this->ComputeLinkInterfaceLibraries(config, iface, head, usage); |
766 | 12.0k | } |
767 | | |
768 | 36.3k | return iface.Exists ? &iface : nullptr; |
769 | 36.3k | } |
770 | | |
771 | | void cmGeneratorTarget::ComputeLinkInterfaceLibraries( |
772 | | std::string const& config, cmOptionalLinkInterface& iface, |
773 | | cmGeneratorTarget const* headTarget, UseTo usage) const |
774 | 12.0k | { |
775 | | // Construct the property name suffix for this configuration. |
776 | 12.0k | std::string suffix = "_"; |
777 | 12.0k | if (!config.empty()) { |
778 | 10.4k | suffix += cmSystemTools::UpperCase(config); |
779 | 10.4k | } else { |
780 | 1.54k | suffix += "NOCONFIG"; |
781 | 1.54k | } |
782 | | |
783 | | // An explicit list of interface libraries may be set for shared |
784 | | // libraries and executables that export symbols. |
785 | 12.0k | bool const haveExplicitLibraries = |
786 | 12.0k | !this->Target->GetLinkInterfaceEntries().empty() || |
787 | 4.32k | !this->Target->GetLinkInterfaceDirectEntries().empty() || |
788 | 4.32k | !this->Target->GetLinkInterfaceDirectExcludeEntries().empty(); |
789 | | |
790 | | // There is no implicit link interface for executables or modules |
791 | | // so if none was explicitly set then there is no link interface. |
792 | 12.0k | if (!haveExplicitLibraries && |
793 | 4.32k | (this->GetType() == cm::TargetType::EXECUTABLE || |
794 | 4.32k | (this->GetType() == cm::TargetType::MODULE_LIBRARY))) { |
795 | 0 | return; |
796 | 0 | } |
797 | 12.0k | iface.Exists = true; |
798 | | |
799 | | // The interface libraries are specified by INTERFACE_LINK_LIBRARIES. |
800 | | // Use its special representation directly to get backtraces. |
801 | 12.0k | this->ExpandLinkItems( |
802 | 12.0k | kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(), config, |
803 | 12.0k | headTarget, usage, LinkInterfaceField::Libraries, iface); |
804 | 12.0k | this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, |
805 | 12.0k | this->Target->GetLinkInterfaceDirectEntries(), config, |
806 | 12.0k | headTarget, usage, LinkInterfaceField::HeadInclude, |
807 | 12.0k | iface); |
808 | 12.0k | this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, |
809 | 12.0k | this->Target->GetLinkInterfaceDirectExcludeEntries(), |
810 | 12.0k | config, headTarget, usage, |
811 | 12.0k | LinkInterfaceField::HeadExclude, iface); |
812 | 12.0k | } |
813 | | |
814 | | std::vector<cmLinkItem> cmGeneratorTarget::ComputeImplicitLanguageTargets( |
815 | | std::string const& lang, std::string const& config) const |
816 | 0 | { |
817 | 0 | cmListFileBacktrace bt; |
818 | 0 | std::vector<cmLinkItem> result; |
819 | 0 | cmLocalGenerator* lg = this->GetLocalGenerator(); |
820 | |
|
821 | 0 | std::string const& runtimeLibrary = |
822 | 0 | this->GetRuntimeLinkLibrary(lang, config); |
823 | 0 | if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition( |
824 | 0 | cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARIES_", runtimeLibrary))) { |
825 | 0 | cmList libsList{ *runtimeLinkOptions }; |
826 | 0 | result.reserve(libsList.size()); |
827 | |
|
828 | 0 | for (auto const& i : libsList) { |
829 | 0 | cmGeneratorTarget::TargetOrString resolved = |
830 | 0 | this->ResolveTargetReference(i, lg); |
831 | 0 | if (resolved.Target) { |
832 | 0 | result.emplace_back(resolved.Target, false, bt); |
833 | 0 | } |
834 | 0 | } |
835 | 0 | } |
836 | |
|
837 | 0 | return result; |
838 | 0 | } |
839 | | |
840 | | void cmGeneratorTarget::ComputeLinkInterfaceRuntimeLibraries( |
841 | | std::string const& config, cmOptionalLinkInterface& iface) const |
842 | 1.48k | { |
843 | 1.48k | for (std::string const& lang : iface.Languages) { |
844 | 132 | if ((lang == "CUDA" || lang == "HIP") && |
845 | 0 | iface.LanguageRuntimeLibraries.find(lang) == |
846 | 0 | iface.LanguageRuntimeLibraries.end()) { |
847 | 0 | iface.LanguageRuntimeLibraries[lang] = |
848 | 0 | this->ComputeImplicitLanguageTargets(lang, config); |
849 | 0 | } |
850 | 132 | } |
851 | 1.48k | } |
852 | | |
853 | | void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries( |
854 | | std::string const& config, cmOptionalLinkImplementation& impl) const |
855 | 603 | { |
856 | 603 | for (std::string const& lang : impl.Languages) { |
857 | 603 | if ((lang == "CUDA" || lang == "HIP") && |
858 | 0 | impl.LanguageRuntimeLibraries.find(lang) == |
859 | 0 | impl.LanguageRuntimeLibraries.end()) { |
860 | 0 | impl.LanguageRuntimeLibraries[lang] = |
861 | 0 | this->ComputeImplicitLanguageTargets(lang, config); |
862 | 0 | } |
863 | 603 | } |
864 | 603 | } |
865 | | |
866 | | cmLinkInterface const* cmGeneratorTarget::GetImportLinkInterface( |
867 | | std::string const& config, cmGeneratorTarget const* headTarget, UseTo usage, |
868 | | bool secondPass) const |
869 | 13.0k | { |
870 | 13.0k | cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); |
871 | 13.0k | if (!info) { |
872 | 0 | return nullptr; |
873 | 0 | } |
874 | | |
875 | 13.0k | cmHeadToLinkInterfaceMap& hm = |
876 | 13.0k | (usage == UseTo::Compile |
877 | 13.0k | ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) |
878 | 13.0k | : this->GetHeadToLinkInterfaceMap(config)); |
879 | | |
880 | | // If the link interface does not depend on the head target |
881 | | // then reuse the one from the head we computed first. |
882 | 13.0k | if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { |
883 | 9.06k | headTarget = hm.begin()->first; |
884 | 9.06k | } |
885 | | |
886 | 13.0k | cmOptionalLinkInterface& iface = hm[headTarget]; |
887 | 13.0k | if (secondPass) { |
888 | 0 | iface = cmOptionalLinkInterface(); |
889 | 0 | } |
890 | 13.0k | MaybeEnableCheckLinkLibraries(iface); |
891 | 13.0k | if (!iface.AllDone) { |
892 | 4.02k | iface.AllDone = true; |
893 | 4.02k | iface.LibrariesDone = true; |
894 | 4.02k | iface.Multiplicity = info->Multiplicity; |
895 | 4.02k | cmExpandList(info->Languages, iface.Languages); |
896 | 4.02k | this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, |
897 | 4.02k | cmMakeRange(info->LibrariesHeadInclude), config, |
898 | 4.02k | headTarget, usage, LinkInterfaceField::HeadInclude, |
899 | 4.02k | iface); |
900 | 4.02k | this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, |
901 | 4.02k | cmMakeRange(info->LibrariesHeadExclude), config, |
902 | 4.02k | headTarget, usage, LinkInterfaceField::HeadExclude, |
903 | 4.02k | iface); |
904 | 4.02k | this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries), |
905 | 4.02k | config, headTarget, usage, |
906 | 4.02k | LinkInterfaceField::Libraries, iface); |
907 | 4.02k | cmList deps{ info->SharedDeps }; |
908 | 4.02k | LookupLinkItemScope scope{ this->LocalGenerator }; |
909 | | |
910 | 4.02k | auto linkFeature = cmLinkItem::DEFAULT; |
911 | 4.02k | for (auto const& dep : deps) { |
912 | 0 | if (auto maybeLinkFeature = ParseLinkFeature(dep)) { |
913 | 0 | linkFeature = std::move(*maybeLinkFeature); |
914 | 0 | continue; |
915 | 0 | } |
916 | | |
917 | 0 | if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( |
918 | 0 | dep, cmListFileBacktrace(), linkFeature, &scope, LookupSelf::No)) { |
919 | 0 | iface.SharedDeps.emplace_back(std::move(*maybeItem)); |
920 | 0 | } |
921 | 0 | } |
922 | 4.02k | } |
923 | | |
924 | 13.0k | return &iface; |
925 | 13.0k | } |
926 | | |
927 | | cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap( |
928 | | std::string const& config) const |
929 | 14.1k | { |
930 | 14.1k | return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)]; |
931 | 14.1k | } |
932 | | |
933 | | cmHeadToLinkInterfaceMap& |
934 | | cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( |
935 | | std::string const& config) const |
936 | 36.9k | { |
937 | 36.9k | return this |
938 | 36.9k | ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)]; |
939 | 36.9k | } |
940 | | |
941 | | cmLinkImplementation const* cmGeneratorTarget::GetLinkImplementation( |
942 | | std::string const& config, UseTo usage) const |
943 | 0 | { |
944 | 0 | return this->GetLinkImplementation(config, usage, false); |
945 | 0 | } |
946 | | |
947 | | cmLinkImplementation const* cmGeneratorTarget::GetLinkImplementation( |
948 | | std::string const& config, UseTo usage, bool secondPass) const |
949 | 831 | { |
950 | | // There is no link implementation for targets that cannot compile sources. |
951 | 831 | if (!this->CanCompileSources()) { |
952 | 0 | return nullptr; |
953 | 0 | } |
954 | | |
955 | 831 | cmOptionalLinkImplementation& impl = |
956 | 831 | (usage == UseTo::Compile |
957 | 831 | ? this |
958 | 0 | ->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)] |
959 | 831 | : this->LinkImplMap[cmSystemTools::UpperCase(config)]); |
960 | 831 | if (secondPass) { |
961 | 0 | impl = cmOptionalLinkImplementation(); |
962 | 0 | } |
963 | 831 | MaybeEnableCheckLinkLibraries(impl); |
964 | 831 | if (!impl.LibrariesDone) { |
965 | 597 | impl.LibrariesDone = true; |
966 | 597 | this->ComputeLinkImplementationLibraries(config, impl, usage); |
967 | 597 | } |
968 | 831 | if (!impl.LanguagesDone) { |
969 | 603 | impl.LanguagesDone = true; |
970 | 603 | this->ComputeLinkImplementationLanguages(config, impl); |
971 | 603 | this->ComputeLinkImplementationRuntimeLibraries(config, impl); |
972 | 603 | } |
973 | 831 | return &impl; |
974 | 831 | } |
975 | | |
976 | | cmLinkImplementationLibraries const* |
977 | | cmGeneratorTarget::GetLinkImplementationLibraries(std::string const& config, |
978 | | UseTo usage) const |
979 | 14.7k | { |
980 | | // There is no link implementation for targets that cannot compile sources. |
981 | 14.7k | if (!this->CanCompileSources()) { |
982 | 37 | return nullptr; |
983 | 37 | } |
984 | | |
985 | | // Populate the link implementation libraries for this configuration. |
986 | 14.6k | cmOptionalLinkImplementation& impl = |
987 | 14.6k | (usage == UseTo::Compile |
988 | 14.6k | ? this |
989 | 11.4k | ->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)] |
990 | 14.6k | : this->LinkImplMap[cmSystemTools::UpperCase(config)]); |
991 | 14.6k | MaybeEnableCheckLinkLibraries(impl); |
992 | 14.6k | if (!impl.LibrariesDone) { |
993 | 7.99k | impl.LibrariesDone = true; |
994 | 7.99k | this->ComputeLinkImplementationLibraries(config, impl, usage); |
995 | 7.99k | } |
996 | 14.6k | return &impl; |
997 | 14.7k | } |
998 | | |
999 | | namespace { |
1000 | | class TransitiveLinkImpl |
1001 | | { |
1002 | | cmGeneratorTarget const* Self; |
1003 | | std::string const& Config; |
1004 | | UseTo ImplFor; |
1005 | | cmLinkImplementation& Impl; |
1006 | | |
1007 | | std::set<cmLinkItem> Emitted; |
1008 | | std::set<cmLinkItem> Excluded; |
1009 | | std::unordered_set<cmGeneratorTarget const*> Followed; |
1010 | | |
1011 | | void Follow(cmGeneratorTarget const* target); |
1012 | | |
1013 | | public: |
1014 | | TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config, |
1015 | | UseTo usage, cmLinkImplementation& impl) |
1016 | 8.58k | : Self(self) |
1017 | 8.58k | , Config(config) |
1018 | 8.58k | , ImplFor(usage) |
1019 | 8.58k | , Impl(impl) |
1020 | 8.58k | { |
1021 | 8.58k | } |
1022 | | |
1023 | | void Compute(); |
1024 | | }; |
1025 | | |
1026 | | void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target) |
1027 | 137k | { |
1028 | 137k | if (!target || !this->Followed.insert(target).second) { |
1029 | 121k | return; |
1030 | 121k | } |
1031 | | |
1032 | | // Get this target's usage requirements. |
1033 | 15.6k | cmLinkInterfaceLibraries const* iface = |
1034 | 15.6k | target->GetLinkInterfaceLibraries(this->Config, this->Self, this->ImplFor); |
1035 | 15.6k | if (!iface) { |
1036 | 0 | return; |
1037 | 0 | } |
1038 | 15.6k | if (iface->HadContextSensitiveCondition) { |
1039 | 2.74k | this->Impl.HadContextSensitiveCondition = true; |
1040 | 2.74k | } |
1041 | | |
1042 | | // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements. |
1043 | 15.6k | for (cmLinkItem const& item : iface->HeadInclude) { |
1044 | | // Inject direct dependencies from the item's usage requirements |
1045 | | // before the item itself. |
1046 | 0 | this->Follow(item.Target); |
1047 | | |
1048 | | // Add the item itself, but at most once. |
1049 | 0 | if (this->Emitted.insert(item).second) { |
1050 | 0 | this->Impl.Libraries.emplace_back(item); |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | | // Follow transitive dependencies. |
1055 | 27.1k | for (cmLinkItem const& item : iface->Libraries) { |
1056 | 27.1k | this->Follow(item.Target); |
1057 | 27.1k | } |
1058 | | |
1059 | | // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' |
1060 | | // usage requirements. |
1061 | 15.6k | for (cmLinkItem const& item : iface->HeadExclude) { |
1062 | 0 | this->Excluded.insert(item); |
1063 | 0 | } |
1064 | 15.6k | } |
1065 | | |
1066 | | void TransitiveLinkImpl::Compute() |
1067 | 8.58k | { |
1068 | | // Save the original items and start with an empty list. |
1069 | 8.58k | std::vector<cmLinkItem> original = std::move(this->Impl.Libraries); |
1070 | | |
1071 | | // Avoid injecting any original items as usage requirements. |
1072 | | // This gives LINK_LIBRARIES final control over the order |
1073 | | // if it explicitly lists everything. |
1074 | 8.58k | this->Emitted.insert(original.cbegin(), original.cend()); |
1075 | | |
1076 | | // Process each original item. |
1077 | 110k | for (cmLinkItem& item : original) { |
1078 | | // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT' |
1079 | | // usage requirements before the item itself. |
1080 | 110k | this->Follow(item.Target); |
1081 | | |
1082 | | // Add the item itself. |
1083 | 110k | this->Impl.Libraries.emplace_back(std::move(item)); |
1084 | 110k | } |
1085 | | |
1086 | | // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' |
1087 | | // usage requirements found through any dependency above. |
1088 | 8.58k | this->Impl.Libraries.erase( |
1089 | 8.58k | std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(), |
1090 | 110k | [this](cmLinkItem const& item) { |
1091 | 110k | return this->Excluded.find(item) != this->Excluded.end(); |
1092 | 110k | }), |
1093 | 8.58k | this->Impl.Libraries.end()); |
1094 | 8.58k | } |
1095 | | |
1096 | | void ComputeLinkImplTransitive(cmGeneratorTarget const* self, |
1097 | | std::string const& config, UseTo usage, |
1098 | | cmLinkImplementation& impl) |
1099 | 8.58k | { |
1100 | 8.58k | TransitiveLinkImpl transitiveLinkImpl(self, config, usage, impl); |
1101 | 8.58k | transitiveLinkImpl.Compute(); |
1102 | 8.58k | } |
1103 | | } |
1104 | | |
1105 | | void cmGeneratorTarget::ComputeLinkImplementationLibraries( |
1106 | | std::string const& config, cmOptionalLinkImplementation& impl, |
1107 | | UseTo usage) const |
1108 | 8.59k | { |
1109 | 8.59k | cm::GenEx::Context context(this->LocalGenerator, config, |
1110 | 8.59k | this->LinkerLanguage); |
1111 | 8.59k | cmLocalGenerator const* lg = this->LocalGenerator; |
1112 | 8.59k | cmMakefile const* mf = lg->GetMakefile(); |
1113 | 8.59k | cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries(); |
1114 | 8.59k | auto const& synthTargetsForConfig = this->Configs[config].SyntheticDeps; |
1115 | | // Collect libraries directly linked in this configuration. |
1116 | 10.8k | for (auto const& entry : entryRange) { |
1117 | | // Keep this logic in sync with ExpandLinkItems. |
1118 | 10.8k | cmGeneratorExpressionDAGChecker dagChecker{ |
1119 | 10.8k | this, |
1120 | 10.8k | "LINK_LIBRARIES", |
1121 | 10.8k | nullptr, |
1122 | 10.8k | nullptr, |
1123 | 10.8k | context, |
1124 | 10.8k | cmListFileBacktrace(), |
1125 | 10.8k | cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes, |
1126 | 10.8k | }; |
1127 | | // The $<LINK_ONLY> expression may be used to specify link dependencies |
1128 | | // that are otherwise excluded from usage requirements. |
1129 | 10.8k | if (usage == UseTo::Compile) { |
1130 | 6.31k | dagChecker.SetTransitivePropertiesOnly(); |
1131 | 6.31k | switch (this->GetPolicyStatusCMP0131()) { |
1132 | 0 | case cmPolicies::WARN: |
1133 | 0 | case cmPolicies::OLD: |
1134 | 0 | break; |
1135 | 6.31k | case cmPolicies::NEW: |
1136 | 6.31k | dagChecker.SetTransitivePropertiesOnlyCMP0131(); |
1137 | 6.31k | break; |
1138 | 6.31k | } |
1139 | 6.31k | } |
1140 | 10.8k | cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(), |
1141 | 10.8k | entry.Backtrace); |
1142 | 10.8k | std::unique_ptr<cmCompiledGeneratorExpression> const cge = |
1143 | 10.8k | ge.Parse(entry.Value); |
1144 | 10.8k | cge->SetEvaluateForBuildsystem(true); |
1145 | 10.8k | std::string const& evaluated = cge->Evaluate(context, &dagChecker, this); |
1146 | 10.8k | cmList llibs(evaluated); |
1147 | 10.8k | if (cge->GetHadHeadSensitiveCondition()) { |
1148 | 77 | impl.HadHeadSensitiveCondition = true; |
1149 | 77 | } |
1150 | 10.8k | if (cge->GetHadContextSensitiveCondition()) { |
1151 | 68 | impl.HadContextSensitiveCondition = true; |
1152 | 68 | } |
1153 | 10.8k | if (cge->GetHadLinkLanguageSensitiveCondition()) { |
1154 | 0 | impl.HadLinkLanguageSensitiveCondition = true; |
1155 | 0 | } |
1156 | | |
1157 | 10.8k | auto linkFeature = cmLinkItem::DEFAULT; |
1158 | 113k | for (auto const& lib : llibs) { |
1159 | 113k | if (auto maybeLinkFeature = ParseLinkFeature(lib)) { |
1160 | 2.49k | linkFeature = std::move(*maybeLinkFeature); |
1161 | 2.49k | continue; |
1162 | 2.49k | } |
1163 | | |
1164 | 110k | if (this->IsLinkLookupScope(lib, lg)) { |
1165 | 16 | continue; |
1166 | 16 | } |
1167 | | |
1168 | | // Skip entries that resolve to the target itself or are empty. |
1169 | 110k | std::string name = this->CheckCMP0004(lib); |
1170 | 110k | if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) { |
1171 | | // resolve alias name |
1172 | 110k | auto* target = |
1173 | 110k | this->Makefile->FindTargetToUse(name, cm::AllTargetDomains); |
1174 | 110k | if (target) { |
1175 | 9.28k | name = target->GetName(); |
1176 | 9.28k | } |
1177 | 110k | } |
1178 | 110k | if (name == this->GetName() || name.empty()) { |
1179 | 8 | if (name == this->GetName()) { |
1180 | 8 | this->LocalGenerator->GetCMakeInstance()->IssueMessage( |
1181 | 8 | MessageType::FATAL_ERROR, |
1182 | 8 | cmStrCat("Target \"", this->GetName(), "\" links to itself."), |
1183 | 8 | this->GetBacktrace()); |
1184 | 8 | return; |
1185 | 8 | } |
1186 | 0 | continue; |
1187 | 8 | } |
1188 | | |
1189 | | // The entry is meant for this configuration. |
1190 | 110k | cmLinkItem item = this->ResolveLinkItem( |
1191 | 110k | BT<std::string>(name, entry.Backtrace), lg, linkFeature); |
1192 | 110k | if (item.Target) { |
1193 | 9.26k | auto depsForTarget = synthTargetsForConfig.find(item.Target); |
1194 | 9.26k | if (depsForTarget != synthTargetsForConfig.end()) { |
1195 | 0 | for (auto const* depForTarget : depsForTarget->second) { |
1196 | 0 | cmLinkItem synthItem(depForTarget, item.Cross, item.Backtrace); |
1197 | 0 | impl.Libraries.emplace_back(std::move(synthItem)); |
1198 | 0 | } |
1199 | 0 | } |
1200 | 101k | } else { |
1201 | | // Report explicitly linked object files separately. |
1202 | 101k | std::string const& maybeObj = item.AsStr(); |
1203 | 101k | if (cmSystemTools::FileIsFullPath(maybeObj)) { |
1204 | 43.1k | cmSourceFile const* sf = |
1205 | 43.1k | mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); |
1206 | 43.1k | if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { |
1207 | 0 | item.ObjectSource = sf; |
1208 | 0 | impl.Objects.emplace_back(std::move(item)); |
1209 | 0 | continue; |
1210 | 0 | } |
1211 | 43.1k | } |
1212 | 101k | } |
1213 | | |
1214 | 110k | impl.Libraries.emplace_back(std::move(item)); |
1215 | 110k | } |
1216 | | |
1217 | 10.8k | std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); |
1218 | 10.8k | for (std::string const& sp : seenProps) { |
1219 | 396 | if (!this->GetProperty(sp)) { |
1220 | 264 | this->LinkImplicitNullProperties.insert(sp); |
1221 | 264 | } |
1222 | 396 | } |
1223 | 10.8k | cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); |
1224 | 10.8k | } |
1225 | | |
1226 | | // Update the list of direct link dependencies from usage requirements. |
1227 | 8.58k | ComputeLinkImplTransitive(this, config, usage, impl); |
1228 | | |
1229 | | // Get the list of configurations considered to be DEBUG. |
1230 | 8.58k | std::vector<std::string> debugConfigs = |
1231 | 8.58k | this->Makefile->GetCMakeInstance()->GetDebugConfigs(); |
1232 | | |
1233 | 8.58k | cmTargetLinkLibraryType linkType = ComputeLinkType(config, debugConfigs); |
1234 | 8.58k | cmTarget::LinkLibraryVectorType const& oldllibs = |
1235 | 8.58k | this->Target->GetOriginalLinkLibraries(); |
1236 | | |
1237 | 8.58k | auto linkFeature = cmLinkItem::DEFAULT; |
1238 | 8.58k | for (cmTarget::LibraryID const& oldllib : oldllibs) { |
1239 | 8.17k | if (auto maybeLinkFeature = ParseLinkFeature(oldllib.first)) { |
1240 | 0 | linkFeature = std::move(*maybeLinkFeature); |
1241 | 0 | continue; |
1242 | 0 | } |
1243 | | |
1244 | 8.17k | if (oldllib.second != GENERAL_LibraryType && oldllib.second != linkType) { |
1245 | 0 | std::string name = this->CheckCMP0004(oldllib.first); |
1246 | 0 | if (name == this->GetName() || name.empty()) { |
1247 | 0 | continue; |
1248 | 0 | } |
1249 | 0 | } |
1250 | 8.17k | } |
1251 | 8.58k | } |
1252 | | |
1253 | | cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( |
1254 | | std::string const& name) const |
1255 | 0 | { |
1256 | 0 | return this->ResolveTargetReference(name, this->LocalGenerator); |
1257 | 0 | } |
1258 | | |
1259 | | cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( |
1260 | | std::string const& name, cmLocalGenerator const* lg) const |
1261 | 153k | { |
1262 | 153k | TargetOrString resolved; |
1263 | | |
1264 | 153k | if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) { |
1265 | 19.2k | resolved.Target = tgt; |
1266 | 134k | } else { |
1267 | 134k | resolved.String = name; |
1268 | 134k | } |
1269 | | |
1270 | 153k | return resolved; |
1271 | 153k | } |
1272 | | |
1273 | | cmLinkItem cmGeneratorTarget::ResolveLinkItem( |
1274 | | BT<std::string> const& name, std::string const& linkFeature) const |
1275 | 0 | { |
1276 | 0 | return this->ResolveLinkItem(name, this->LocalGenerator, linkFeature); |
1277 | 0 | } |
1278 | | |
1279 | | cmLinkItem cmGeneratorTarget::ResolveLinkItem( |
1280 | | BT<std::string> const& name, cmLocalGenerator const* lg, |
1281 | | std::string const& linkFeature) const |
1282 | 153k | { |
1283 | 153k | auto bt = name.Backtrace; |
1284 | 153k | TargetOrString resolved = this->ResolveTargetReference(name.Value, lg); |
1285 | | |
1286 | 153k | if (!resolved.Target) { |
1287 | 134k | return cmLinkItem(resolved.String, false, bt, linkFeature); |
1288 | 134k | } |
1289 | | |
1290 | | // Check deprecation, issue message with `bt` backtrace. |
1291 | 19.2k | if (resolved.Target->IsDeprecated()) { |
1292 | 0 | this->LocalGenerator->IssueDiagnostic( |
1293 | 0 | cmDiagnostics::CMD_AUTHOR, |
1294 | 0 | cmStrCat("The library that is being linked to, ", |
1295 | 0 | resolved.Target->GetName(), |
1296 | 0 | ", is marked as being deprecated by the owner. The message " |
1297 | 0 | "provided by the developer is: \n", |
1298 | 0 | resolved.Target->GetDeprecation(), '\n'), |
1299 | 0 | bt); |
1300 | 0 | } |
1301 | | |
1302 | | // Skip targets that will not really be linked. This is probably a |
1303 | | // name conflict between an external library and an executable |
1304 | | // within the project. |
1305 | 19.2k | if (resolved.Target->GetType() == cm::TargetType::EXECUTABLE && |
1306 | 26 | !resolved.Target->IsExecutableWithExports()) { |
1307 | 26 | return cmLinkItem(resolved.Target->GetName(), false, bt, linkFeature); |
1308 | 26 | } |
1309 | | |
1310 | 19.2k | return cmLinkItem(resolved.Target, false, bt, linkFeature); |
1311 | 19.2k | } |