resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmGeneratorTarget.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmGeneratorTarget.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cerrno>
8 #include <cstddef>
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <iterator>
13 #include <queue>
14 #include <sstream>
15 #include <unordered_set>
16 #include <utility>
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 "cmsys/RegularExpression.hxx"
25
26 #include "cmAlgorithms.h"
27 #include "cmComputeLinkInformation.h"
28 #include "cmCustomCommandGenerator.h"
29 #include "cmFileSet.h"
30 #include "cmFileTimes.h"
31 #include "cmGeneratedFileStream.h"
32 #include "cmGeneratorExpression.h"
33 #include "cmGeneratorExpressionContext.h"
34 #include "cmGeneratorExpressionDAGChecker.h"
35 #include "cmGeneratorExpressionNode.h"
36 #include "cmGlobalGenerator.h"
37 #include "cmLocalGenerator.h"
38 #include "cmMakefile.h"
39 #include "cmMessageType.h"
40 #include "cmOutputConverter.h"
41 #include "cmPropertyMap.h"
42 #include "cmRange.h"
43 #include "cmSourceFile.h"
44 #include "cmSourceFileLocation.h"
45 #include "cmSourceFileLocationKind.h"
46 #include "cmSourceGroup.h"
47 #include "cmStandardLevelResolver.h"
48 #include "cmState.h"
49 #include "cmStringAlgorithms.h"
50 #include "cmSystemTools.h"
51 #include "cmTarget.h"
52 #include "cmTargetLinkLibraryType.h"
53 #include "cmTargetPropertyComputer.h"
54 #include "cmake.h"
55
56 namespace {
57 using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor;
58
59 const cmsys::RegularExpression FrameworkRegularExpression(
60   "^(.*/)?([^/]*)\\.framework/(.*)$");
61 const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES";
62 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT =
63   "INTERFACE_LINK_LIBRARIES_DIRECT";
64 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
65   "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
66 }
67
68 template <>
69 cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
70   cmGeneratorTarget const* tgt, cmMakefile const& /* mf */)
71 {
72   return tgt->GetSourcesProperty();
73 }
74
75 template <>
76 const std::string&
77 cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
78   cmGeneratorTarget const* tgt)
79 {
80   return tgt->GetLocation("");
81 }
82
83 template <>
84 const std::string&
85 cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
86   cmGeneratorTarget const* tgt, const std::string& config)
87 {
88   return tgt->GetLocation(config);
89 }
90
91 class cmGeneratorTarget::TargetPropertyEntry
92 {
93 protected:
94   static cmLinkImplItem NoLinkImplItem;
95
96 public:
97   TargetPropertyEntry(cmLinkImplItem const& item)
98     : LinkImplItem(item)
99   {
100   }
101   virtual ~TargetPropertyEntry() = default;
102
103   virtual const std::string& Evaluate(
104     cmLocalGenerator* lg, const std::string& config,
105     cmGeneratorTarget const* headTarget,
106     cmGeneratorExpressionDAGChecker* dagChecker,
107     std::string const& language) const = 0;
108
109   virtual cmListFileBacktrace GetBacktrace() const = 0;
110   virtual std::string const& GetInput() const = 0;
111   virtual bool GetHadContextSensitiveCondition() const { return false; }
112
113   cmLinkImplItem const& LinkImplItem;
114 };
115 cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
116
117 class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
118 {
119 public:
120   TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
121                            cmLinkImplItem const& item = NoLinkImplItem)
122     : cmGeneratorTarget::TargetPropertyEntry(item)
123     , ge(std::move(cge))
124   {
125   }
126
127   const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
128                               cmGeneratorTarget const* headTarget,
129                               cmGeneratorExpressionDAGChecker* dagChecker,
130                               std::string const& language) const override
131   {
132     return this->ge->Evaluate(lg, config, headTarget, dagChecker, nullptr,
133                               language);
134   }
135
136   cmListFileBacktrace GetBacktrace() const override
137   {
138     return this->ge->GetBacktrace();
139   }
140
141   std::string const& GetInput() const override { return this->ge->GetInput(); }
142
143   bool GetHadContextSensitiveCondition() const override
144   {
145     return this->ge->GetHadContextSensitiveCondition();
146   }
147
148 private:
149   const std::unique_ptr<cmCompiledGeneratorExpression> ge;
150 };
151
152 class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
153 {
154 public:
155   TargetPropertyEntryString(BT<std::string> propertyValue,
156                             cmLinkImplItem const& item = NoLinkImplItem)
157     : cmGeneratorTarget::TargetPropertyEntry(item)
158     , PropertyValue(std::move(propertyValue))
159   {
160   }
161
162   const std::string& Evaluate(cmLocalGenerator*, const std::string&,
163                               cmGeneratorTarget const*,
164                               cmGeneratorExpressionDAGChecker*,
165                               std::string const&) const override
166   {
167     return this->PropertyValue.Value;
168   }
169
170   cmListFileBacktrace GetBacktrace() const override
171   {
172     return this->PropertyValue.Backtrace;
173   }
174   std::string const& GetInput() const override
175   {
176     return this->PropertyValue.Value;
177   }
178
179 private:
180   BT<std::string> PropertyValue;
181 };
182
183 class TargetPropertyEntryFileSet
184   : public cmGeneratorTarget::TargetPropertyEntry
185 {
186 public:
187   TargetPropertyEntryFileSet(
188     std::vector<std::string> dirs, bool contextSensitiveDirs,
189     std::unique_ptr<cmCompiledGeneratorExpression> entryCge,
190     const cmFileSet* fileSet, cmLinkImplItem const& item = NoLinkImplItem)
191     : cmGeneratorTarget::TargetPropertyEntry(item)
192     , BaseDirs(std::move(dirs))
193     , ContextSensitiveDirs(contextSensitiveDirs)
194     , EntryCge(std::move(entryCge))
195     , FileSet(fileSet)
196   {
197   }
198
199   const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
200                               cmGeneratorTarget const* headTarget,
201                               cmGeneratorExpressionDAGChecker* dagChecker,
202                               std::string const& /*lang*/) const override
203   {
204     std::map<std::string, std::vector<std::string>> filesPerDir;
205     this->FileSet->EvaluateFileEntry(this->BaseDirs, filesPerDir,
206                                      this->EntryCge, lg, config, headTarget,
207                                      dagChecker);
208
209     std::vector<std::string> files;
210     for (auto const& it : filesPerDir) {
211       files.insert(files.end(), it.second.begin(), it.second.end());
212     }
213
214     static std::string filesStr;
215     filesStr = cmJoin(files, ";");
216     return filesStr;
217   }
218
219   cmListFileBacktrace GetBacktrace() const override
220   {
221     return this->EntryCge->GetBacktrace();
222   }
223
224   std::string const& GetInput() const override
225   {
226     return this->EntryCge->GetInput();
227   }
228
229   bool GetHadContextSensitiveCondition() const override
230   {
231     return this->ContextSensitiveDirs ||
232       this->EntryCge->GetHadContextSensitiveCondition();
233   }
234
235 private:
236   const std::vector<std::string> BaseDirs;
237   const bool ContextSensitiveDirs;
238   const std::unique_ptr<cmCompiledGeneratorExpression> EntryCge;
239   const cmFileSet* FileSet;
240 };
241
242 std::unique_ptr<
243   cmGeneratorTarget::
244     TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std::
245                                                                      string>&
246                                                             propertyValue,
247                                                           bool
248                                                             evaluateForBuildsystem =
249                                                               false)
250 {
251   if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) {
252     cmGeneratorExpression ge(propertyValue.Backtrace);
253     std::unique_ptr<cmCompiledGeneratorExpression> cge =
254       ge.Parse(propertyValue.Value);
255     cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
256     return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
257       cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
258   }
259
260   return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
261     cm::make_unique<TargetPropertyEntryString>(propertyValue));
262 }
263
264 static void CreatePropertyGeneratorExpressions(
265   cmBTStringRange entries,
266   std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
267   bool evaluateForBuildsystem = false)
268 {
269   for (auto const& entry : entries) {
270     items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem));
271   }
272 }
273
274 namespace {
275 // Represent a target property entry after evaluating generator expressions
276 // and splitting up lists.
277 struct EvaluatedTargetPropertyEntry
278 {
279   EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
280                                cmListFileBacktrace bt)
281     : LinkImplItem(item)
282     , Backtrace(std::move(bt))
283   {
284   }
285
286   // Move-only.
287   EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
288   EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
289   EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
290     delete;
291   EvaluatedTargetPropertyEntry& operator=(
292     EvaluatedTargetPropertyEntry const&) = delete;
293
294   cmLinkImplItem const& LinkImplItem;
295   cmListFileBacktrace Backtrace;
296   std::vector<std::string> Values;
297   bool ContextDependent = false;
298 };
299
300 EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
301   cmGeneratorTarget const* thisTarget, std::string const& config,
302   std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
303   cmGeneratorTarget::TargetPropertyEntry& entry)
304 {
305   EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
306   cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
307                               thisTarget, dagChecker, lang),
308                ee.Values);
309   if (entry.GetHadContextSensitiveCondition()) {
310     ee.ContextDependent = true;
311   }
312   return ee;
313 }
314
315 struct EvaluatedTargetPropertyEntries
316 {
317   std::vector<EvaluatedTargetPropertyEntry> Entries;
318   bool HadContextSensitiveCondition = false;
319 };
320
321 EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
322   cmGeneratorTarget const* thisTarget, std::string const& config,
323   std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
324   std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
325     in)
326 {
327   EvaluatedTargetPropertyEntries out;
328   out.Entries.reserve(in.size());
329   for (auto const& entry : in) {
330     out.Entries.emplace_back(EvaluateTargetPropertyEntry(
331       thisTarget, config, lang, dagChecker, *entry));
332   }
333   return out;
334 }
335 }
336
337 cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
338   : Target(t)
339 {
340   this->Makefile = this->Target->GetMakefile();
341   this->LocalGenerator = lg;
342   this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
343
344   this->GlobalGenerator->ComputeTargetObjectDirectory(this);
345
346   CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
347                                      this->IncludeDirectoriesEntries);
348
349   CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
350                                      this->CompileOptionsEntries);
351
352   CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
353                                      this->CompileFeaturesEntries);
354
355   CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
356                                      this->CompileDefinitionsEntries);
357
358   CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
359                                      this->LinkOptionsEntries);
360
361   CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
362                                      this->LinkDirectoriesEntries);
363
364   CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
365                                      this->PrecompileHeadersEntries);
366
367   CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
368                                      this->SourceEntries, true);
369
370   this->PolicyMap = t->GetPolicyMap();
371
372   // Get hard-coded linker language
373   if (this->Target->GetProperty("HAS_CXX")) {
374     this->LinkerLanguage = "CXX";
375   } else {
376     this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
377   }
378 }
379
380 cmGeneratorTarget::~cmGeneratorTarget() = default;
381
382 cmValue cmGeneratorTarget::GetSourcesProperty() const
383 {
384   std::vector<std::string> values;
385   for (auto const& se : this->SourceEntries) {
386     values.push_back(se->GetInput());
387   }
388   static std::string value;
389   value.clear();
390   value = cmJoin(values, ";");
391   return cmValue(value);
392 }
393
394 cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
395 {
396   return this->GetLocalGenerator()->GetGlobalGenerator();
397 }
398
399 cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
400 {
401   return this->LocalGenerator;
402 }
403
404 cmStateEnums::TargetType cmGeneratorTarget::GetType() const
405 {
406   return this->Target->GetType();
407 }
408
409 const std::string& cmGeneratorTarget::GetName() const
410 {
411   return this->Target->GetName();
412 }
413
414 std::string cmGeneratorTarget::GetExportName() const
415 {
416   cmValue exportName = this->GetProperty("EXPORT_NAME");
417
418   if (cmNonempty(exportName)) {
419     if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
420       std::ostringstream e;
421       e << "EXPORT_NAME property \"" << *exportName << "\" for \""
422         << this->GetName() << "\": is not valid.";
423       cmSystemTools::Error(e.str());
424       return "";
425     }
426     return *exportName;
427   }
428   return this->GetName();
429 }
430
431 cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const
432 {
433   if (cmValue result =
434         cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) {
435     return result;
436   }
437   if (cmSystemTools::GetFatalErrorOccurred()) {
438     return nullptr;
439   }
440   return this->Target->GetProperty(prop);
441 }
442
443 std::string const& cmGeneratorTarget::GetSafeProperty(
444   std::string const& prop) const
445 {
446   return this->GetProperty(prop);
447 }
448
449 const char* cmGeneratorTarget::GetOutputTargetType(
450   cmStateEnums::ArtifactType artifact) const
451 {
452   switch (this->GetType()) {
453     case cmStateEnums::SHARED_LIBRARY:
454       if (this->IsDLLPlatform()) {
455         switch (artifact) {
456           case cmStateEnums::RuntimeBinaryArtifact:
457             // A DLL shared library is treated as a runtime target.
458             return "RUNTIME";
459           case cmStateEnums::ImportLibraryArtifact:
460             // A DLL import library is treated as an archive target.
461             return "ARCHIVE";
462         }
463       } else {
464         // For non-DLL platforms shared libraries are treated as
465         // library targets.
466         return "LIBRARY";
467       }
468       break;
469     case cmStateEnums::STATIC_LIBRARY:
470       // Static libraries are always treated as archive targets.
471       return "ARCHIVE";
472     case cmStateEnums::MODULE_LIBRARY:
473       switch (artifact) {
474         case cmStateEnums::RuntimeBinaryArtifact:
475           // Module libraries are always treated as library targets.
476           return "LIBRARY";
477         case cmStateEnums::ImportLibraryArtifact:
478           // Module import libraries are treated as archive targets.
479           return "ARCHIVE";
480       }
481       break;
482     case cmStateEnums::OBJECT_LIBRARY:
483       // Object libraries are always treated as object targets.
484       return "OBJECT";
485     case cmStateEnums::EXECUTABLE:
486       switch (artifact) {
487         case cmStateEnums::RuntimeBinaryArtifact:
488           // Executables are always treated as runtime targets.
489           return "RUNTIME";
490         case cmStateEnums::ImportLibraryArtifact:
491           // Executable import libraries are treated as archive targets.
492           return "ARCHIVE";
493       }
494       break;
495     default:
496       break;
497   }
498   return "";
499 }
500
501 std::string cmGeneratorTarget::GetOutputName(
502   const std::string& config, cmStateEnums::ArtifactType artifact) const
503 {
504   // Lookup/compute/cache the output name for this configuration.
505   OutputNameKey key(config, artifact);
506   auto i = this->OutputNameMap.find(key);
507   if (i == this->OutputNameMap.end()) {
508     // Add empty name in map to detect potential recursion.
509     OutputNameMapType::value_type entry(key, "");
510     i = this->OutputNameMap.insert(entry).first;
511
512     // Compute output name.
513     std::vector<std::string> props;
514     std::string type = this->GetOutputTargetType(artifact);
515     std::string configUpper = cmSystemTools::UpperCase(config);
516     if (!type.empty() && !configUpper.empty()) {
517       // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
518       props.push_back(type + "_OUTPUT_NAME_" + configUpper);
519     }
520     if (!type.empty()) {
521       // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
522       props.push_back(type + "_OUTPUT_NAME");
523     }
524     if (!configUpper.empty()) {
525       // OUTPUT_NAME_<CONFIG>
526       props.push_back("OUTPUT_NAME_" + configUpper);
527       // <CONFIG>_OUTPUT_NAME
528       props.push_back(configUpper + "_OUTPUT_NAME");
529     }
530     // OUTPUT_NAME
531     props.emplace_back("OUTPUT_NAME");
532
533     std::string outName;
534     for (std::string const& p : props) {
535       if (cmValue outNameProp = this->GetProperty(p)) {
536         outName = *outNameProp;
537         break;
538       }
539     }
540
541     if (outName.empty()) {
542       outName = this->GetName();
543     }
544
545     // Now evaluate genex and update the previously-prepared map entry.
546     i->second =
547       cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
548   } else if (i->second.empty()) {
549     // An empty map entry indicates we have been called recursively
550     // from the above block.
551     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
552       MessageType::FATAL_ERROR,
553       "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
554       this->GetBacktrace());
555   }
556   return i->second;
557 }
558
559 std::string cmGeneratorTarget::GetFilePrefix(
560   const std::string& config, cmStateEnums::ArtifactType artifact) const
561 {
562   if (this->IsImported()) {
563     cmValue prefix = this->GetFilePrefixInternal(config, artifact);
564     return prefix ? *prefix : std::string();
565   }
566
567   std::string prefix;
568   std::string suffix;
569   std::string base;
570   this->GetFullNameInternal(config, artifact, prefix, base, suffix);
571   return prefix;
572 }
573 std::string cmGeneratorTarget::GetFileSuffix(
574   const std::string& config, cmStateEnums::ArtifactType artifact) const
575 {
576   if (this->IsImported()) {
577     cmValue suffix = this->GetFileSuffixInternal(config, artifact);
578     return suffix ? *suffix : std::string();
579   }
580
581   std::string prefix;
582   std::string suffix;
583   std::string base;
584   this->GetFullNameInternal(config, artifact, prefix, base, suffix);
585   return suffix;
586 }
587
588 std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
589 {
590   cmValue postfix = nullptr;
591   std::string frameworkPostfix;
592   if (!config.empty()) {
593     std::string configProp =
594       cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
595     postfix = this->GetProperty(configProp);
596
597     // Mac application bundles and frameworks have no regular postfix like
598     // libraries do.
599     if (!this->IsImported() && postfix &&
600         (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
601       postfix = nullptr;
602     }
603
604     // Frameworks created by multi config generators can have a special
605     // framework postfix.
606     frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
607     if (!frameworkPostfix.empty()) {
608       postfix = cmValue(frameworkPostfix);
609     }
610   }
611   return postfix ? *postfix : std::string();
612 }
613
614 std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
615   const std::string& config) const
616 {
617   cmValue postfix = nullptr;
618   if (!config.empty()) {
619     std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
620                                       cmSystemTools::UpperCase(config));
621     postfix = this->GetProperty(configProp);
622
623     if (!this->IsImported() && postfix &&
624         (this->IsFrameworkOnApple() &&
625          !this->GetGlobalGenerator()->IsMultiConfig())) {
626       postfix = nullptr;
627     }
628   }
629   return postfix ? *postfix : std::string();
630 }
631
632 cmValue cmGeneratorTarget::GetFilePrefixInternal(
633   std::string const& config, cmStateEnums::ArtifactType artifact,
634   const std::string& language) const
635 {
636   // no prefix for non-main target types.
637   if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
638       this->GetType() != cmStateEnums::SHARED_LIBRARY &&
639       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
640       this->GetType() != cmStateEnums::EXECUTABLE) {
641     return nullptr;
642   }
643
644   const bool isImportedLibraryArtifact =
645     (artifact == cmStateEnums::ImportLibraryArtifact);
646
647   // Return an empty prefix for the import library if this platform
648   // does not support import libraries.
649   if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
650     return nullptr;
651   }
652
653   // The implib option is only allowed for shared libraries, module
654   // libraries, and executables.
655   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
656       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
657       this->GetType() != cmStateEnums::EXECUTABLE) {
658     artifact = cmStateEnums::RuntimeBinaryArtifact;
659   }
660
661   // Compute prefix value.
662   cmValue targetPrefix =
663     (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
664                                : this->GetProperty("PREFIX"));
665
666   if (!targetPrefix) {
667     const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
668     if (!language.empty() && cmNonempty(prefixVar)) {
669       std::string langPrefix = cmStrCat(prefixVar, "_", language);
670       targetPrefix = this->Makefile->GetDefinition(langPrefix);
671     }
672
673     // if there is no prefix on the target nor specific language
674     // use the cmake definition.
675     if (!targetPrefix && prefixVar) {
676       targetPrefix = this->Makefile->GetDefinition(prefixVar);
677     }
678   }
679
680   return targetPrefix;
681 }
682
683 cmValue cmGeneratorTarget::GetFileSuffixInternal(
684   std::string const& config, cmStateEnums::ArtifactType artifact,
685   const std::string& language) const
686 {
687   // no suffix for non-main target types.
688   if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
689       this->GetType() != cmStateEnums::SHARED_LIBRARY &&
690       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
691       this->GetType() != cmStateEnums::EXECUTABLE) {
692     return nullptr;
693   }
694
695   const bool isImportedLibraryArtifact =
696     (artifact == cmStateEnums::ImportLibraryArtifact);
697
698   // Return an empty suffix for the import library if this platform
699   // does not support import libraries.
700   if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
701     return nullptr;
702   }
703
704   // The implib option is only allowed for shared libraries, module
705   // libraries, and executables.
706   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
707       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
708       this->GetType() != cmStateEnums::EXECUTABLE) {
709     artifact = cmStateEnums::RuntimeBinaryArtifact;
710   }
711
712   // Compute suffix value.
713   cmValue targetSuffix =
714     (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
715                                : this->GetProperty("SUFFIX"));
716
717   if (!targetSuffix) {
718     const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
719     if (!language.empty() && cmNonempty(suffixVar)) {
720       std::string langSuffix = cmStrCat(suffixVar, "_", language);
721       targetSuffix = this->Makefile->GetDefinition(langSuffix);
722     }
723
724     // if there is no suffix on the target nor specific language
725     // use the cmake definition.
726     if (!targetSuffix && suffixVar) {
727       targetSuffix = this->Makefile->GetDefinition(suffixVar);
728     }
729   }
730
731   return targetSuffix;
732 }
733
734 void cmGeneratorTarget::ClearSourcesCache()
735 {
736   this->AllConfigSources.clear();
737   this->KindedSourcesMap.clear();
738   this->SourcesAreContextDependent = Tribool::Indeterminate;
739   this->Objects.clear();
740   this->VisitedConfigsForObjects.clear();
741   this->LinkImplMap.clear();
742   this->LinkImplUsageRequirementsOnlyMap.clear();
743 }
744
745 void cmGeneratorTarget::ClearLinkInterfaceCache()
746 {
747   this->LinkInterfaceMap.clear();
748   this->LinkInterfaceUsageRequirementsOnlyMap.clear();
749 }
750
751 void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
752 {
753   this->SourceEntries.insert(
754     before ? this->SourceEntries.begin() : this->SourceEntries.end(),
755     CreateTargetPropertyEntry(
756       BT<std::string>(src, this->Makefile->GetBacktrace()), true));
757   this->ClearSourcesCache();
758 }
759
760 void cmGeneratorTarget::AddSource(const std::string& src, bool before)
761 {
762   this->Target->AddSource(src, before);
763   this->AddSourceCommon(src, before);
764 }
765
766 void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
767 {
768   this->Target->AddTracedSources(srcs);
769   if (!srcs.empty()) {
770     this->AddSourceCommon(cmJoin(srcs, ";"));
771   }
772 }
773
774 void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
775                                             bool before)
776 {
777   this->Target->InsertInclude(
778     BT<std::string>(src, this->Makefile->GetBacktrace()), before);
779   this->IncludeDirectoriesEntries.insert(
780     before ? this->IncludeDirectoriesEntries.begin()
781            : this->IncludeDirectoriesEntries.end(),
782     CreateTargetPropertyEntry(
783       BT<std::string>(src, this->Makefile->GetBacktrace()), true));
784 }
785
786 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
787   cmSourceFile const* sf) const
788 {
789   auto i = this->SourceDepends.find(sf);
790   if (i != this->SourceDepends.end()) {
791     return &i->second.Depends;
792   }
793   return nullptr;
794 }
795
796 namespace {
797 void handleSystemIncludesDep(cmLocalGenerator* lg,
798                              cmGeneratorTarget const* depTgt,
799                              const std::string& config,
800                              cmGeneratorTarget const* headTarget,
801                              cmGeneratorExpressionDAGChecker* dagChecker,
802                              std::vector<std::string>& result,
803                              bool excludeImported, std::string const& language)
804 {
805   if (cmValue dirs =
806         depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
807     cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
808                                                  dagChecker, depTgt, language),
809                  result);
810   }
811   if (!depTgt->GetPropertyAsBool("SYSTEM")) {
812     return;
813   }
814   if (depTgt->IsImported()) {
815     if (excludeImported) {
816       return;
817     }
818     if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
819       return;
820     }
821   }
822
823   if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
824     cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
825                                                  dagChecker, depTgt, language),
826                  result);
827   }
828 }
829 }
830
831 /* clang-format off */
832 #define IMPLEMENT_VISIT(KIND)                                                 \
833   do {                                                                        \
834     KindedSources const& kinded = this->GetKindedSources(config);             \
835     for (SourceAndKind const& s : kinded.Sources) {                           \
836       if (s.Kind == KIND) {                                                   \
837         data.push_back(s.Source.Value);                                       \
838       }                                                                       \
839     }                                                                         \
840   } while (false)
841 /* clang-format on */
842
843 void cmGeneratorTarget::GetObjectSources(
844   std::vector<cmSourceFile const*>& data, const std::string& config) const
845 {
846   IMPLEMENT_VISIT(SourceKindObjectSource);
847
848   if (this->VisitedConfigsForObjects.count(config)) {
849     return;
850   }
851
852   for (cmSourceFile const* it : data) {
853     this->Objects[it];
854   }
855
856   this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
857   this->VisitedConfigsForObjects.insert(config);
858 }
859
860 void cmGeneratorTarget::ComputeObjectMapping()
861 {
862   auto const& configs =
863     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
864   std::set<std::string> configSet(configs.begin(), configs.end());
865   if (configSet == this->VisitedConfigsForObjects) {
866     return;
867   }
868
869   for (std::string const& c : configs) {
870     std::vector<cmSourceFile const*> sourceFiles;
871     this->GetObjectSources(sourceFiles, c);
872   }
873 }
874
875 cmValue cmGeneratorTarget::GetFeature(const std::string& feature,
876                                       const std::string& config) const
877 {
878   if (!config.empty()) {
879     std::string featureConfig =
880       cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
881     if (cmValue value = this->GetProperty(featureConfig)) {
882       return value;
883     }
884   }
885   if (cmValue value = this->GetProperty(feature)) {
886     return value;
887   }
888   return this->LocalGenerator->GetFeature(feature, config);
889 }
890
891 const char* cmGeneratorTarget::GetLinkPIEProperty(
892   const std::string& config) const
893 {
894   static std::string PICValue;
895
896   PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
897     "POSITION_INDEPENDENT_CODE", config);
898
899   if (PICValue == "(unset)") {
900     // POSITION_INDEPENDENT_CODE is not set
901     return nullptr;
902   }
903
904   auto status = this->GetPolicyStatusCMP0083();
905   return (status != cmPolicies::WARN && status != cmPolicies::OLD)
906     ? PICValue.c_str()
907     : nullptr;
908 }
909
910 bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
911                                      std::string const& config) const
912 {
913   cmValue feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
914
915   if (!cmIsOn(feature)) {
916     // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
917     return false;
918   }
919
920   if (lang != "C" && lang != "CXX" && lang != "CUDA" && lang != "Fortran") {
921     // We do not define IPO behavior for other languages.
922     return false;
923   }
924
925   if (lang == "CUDA") {
926     // CUDA IPO requires both CUDA_ARCHITECTURES and CUDA_SEPARABLE_COMPILATION
927     if (cmIsOff(this->GetSafeProperty("CUDA_ARCHITECTURES")) ||
928         cmIsOff(this->GetSafeProperty("CUDA_SEPARABLE_COMPILATION"))) {
929       return false;
930     }
931   }
932
933   cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
934
935   if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
936     if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
937       return true;
938     }
939     if (this->PolicyReportedCMP0069) {
940       // problem is already reported, no need to issue a message
941       return false;
942     }
943     const bool in_try_compile =
944       this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
945     if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
946       std::ostringstream w;
947       w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
948       w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
949         << "'" << this->GetName() << "'.";
950       this->LocalGenerator->GetCMakeInstance()->IssueMessage(
951         MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
952
953       this->PolicyReportedCMP0069 = true;
954     }
955     return false;
956   }
957
958   // Note: check consistency with messages from CheckIPOSupported
959   const char* message = nullptr;
960   if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
961     message = "CMake doesn't support IPO for current compiler";
962   } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
963                                    "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
964     message = "Compiler doesn't support IPO";
965   } else if (!this->GlobalGenerator->IsIPOSupported()) {
966     message = "CMake doesn't support IPO for current generator";
967   }
968
969   if (!message) {
970     // No error/warning messages
971     return true;
972   }
973
974   if (this->PolicyReportedCMP0069) {
975     // problem is already reported, no need to issue a message
976     return false;
977   }
978
979   this->PolicyReportedCMP0069 = true;
980
981   this->LocalGenerator->GetCMakeInstance()->IssueMessage(
982     MessageType::FATAL_ERROR, message, this->GetBacktrace());
983   return false;
984 }
985
986 const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
987 {
988   this->ComputeObjectMapping();
989   return this->Objects[file];
990 }
991
992 const char* cmGeneratorTarget::GetCustomObjectExtension() const
993 {
994   static std::string extension;
995   const bool has_ptx_extension =
996     this->GetPropertyAsBool("CUDA_PTX_COMPILATION");
997   if (has_ptx_extension) {
998     extension = ".ptx";
999     return extension.c_str();
1000   }
1001   return nullptr;
1002 }
1003
1004 void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
1005 {
1006   this->ExplicitObjectName.insert(sf);
1007 }
1008
1009 bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
1010 {
1011   const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
1012   auto it = this->ExplicitObjectName.find(file);
1013   return it != this->ExplicitObjectName.end();
1014 }
1015
1016 BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
1017   std::string const& lang, std::string const& config) const
1018 {
1019   std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
1020   auto langStandardIter = this->LanguageStandardMap.find(key);
1021   if (langStandardIter != this->LanguageStandardMap.end()) {
1022     return &langStandardIter->second;
1023   }
1024
1025   return this->Target->GetLanguageStandardProperty(
1026     cmStrCat(lang, "_STANDARD"));
1027 }
1028
1029 cmValue cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
1030                                                std::string const& config) const
1031 {
1032   BTs<std::string> const* languageStandard =
1033     this->GetLanguageStandardProperty(lang, config);
1034
1035   if (languageStandard) {
1036     return cmValue(languageStandard->Value);
1037   }
1038
1039   return nullptr;
1040 }
1041
1042 cmValue cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
1043   std::string const& lang, const char* suffix) const
1044 {
1045   cmValue propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
1046   if (!propertyValue) {
1047     // Check if we should use the value set by another language.
1048     if (lang == "OBJC") {
1049       propertyValue = this->GetPropertyWithPairedLanguageSupport("C", suffix);
1050     } else if (lang == "OBJCXX" || lang == "CUDA" || lang == "HIP") {
1051       propertyValue =
1052         this->GetPropertyWithPairedLanguageSupport("CXX", suffix);
1053     }
1054   }
1055   return propertyValue;
1056 }
1057
1058 cmValue cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
1059 {
1060   return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS");
1061 }
1062
1063 bool cmGeneratorTarget::GetLanguageStandardRequired(
1064   std::string const& lang) const
1065 {
1066   return cmIsOn(
1067     this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"));
1068 }
1069
1070 void cmGeneratorTarget::GetModuleDefinitionSources(
1071   std::vector<cmSourceFile const*>& data, const std::string& config) const
1072 {
1073   IMPLEMENT_VISIT(SourceKindModuleDefinition);
1074 }
1075
1076 void cmGeneratorTarget::GetHeaderSources(
1077   std::vector<cmSourceFile const*>& data, const std::string& config) const
1078 {
1079   IMPLEMENT_VISIT(SourceKindHeader);
1080 }
1081
1082 void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
1083                                         const std::string& config) const
1084 {
1085   IMPLEMENT_VISIT(SourceKindExtra);
1086 }
1087
1088 void cmGeneratorTarget::GetCustomCommands(
1089   std::vector<cmSourceFile const*>& data, const std::string& config) const
1090 {
1091   IMPLEMENT_VISIT(SourceKindCustomCommand);
1092 }
1093
1094 void cmGeneratorTarget::GetExternalObjects(
1095   std::vector<cmSourceFile const*>& data, const std::string& config) const
1096 {
1097   IMPLEMENT_VISIT(SourceKindExternalObject);
1098 }
1099
1100 void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
1101                                      const std::string& config) const
1102 {
1103   IMPLEMENT_VISIT(SourceKindManifest);
1104 }
1105
1106 std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
1107 {
1108   if (!this->UtilityItemsDone) {
1109     this->UtilityItemsDone = true;
1110     std::set<BT<std::pair<std::string, bool>>> const& utilities =
1111       this->GetUtilities();
1112     for (BT<std::pair<std::string, bool>> const& i : utilities) {
1113       if (cmGeneratorTarget* gt =
1114             this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
1115         this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
1116       } else {
1117         this->UtilityItems.insert(
1118           cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
1119       }
1120     }
1121   }
1122   return this->UtilityItems;
1123 }
1124
1125 const std::string& cmGeneratorTarget::GetLocation(
1126   const std::string& config) const
1127 {
1128   static std::string location;
1129   if (this->IsImported()) {
1130     location = this->Target->ImportedGetFullPath(
1131       config, cmStateEnums::RuntimeBinaryArtifact);
1132   } else {
1133     location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1134   }
1135   return location;
1136 }
1137
1138 cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
1139   std::string const& config) const
1140 {
1141   cm::optional<std::string> location;
1142   if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
1143     if (!imp->Location.empty()) {
1144       location = imp->Location;
1145     }
1146   } else {
1147     location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1148   }
1149   return location;
1150 }
1151
1152 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
1153   const
1154 {
1155   return this->Target->GetPreBuildCommands();
1156 }
1157
1158 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
1159   const
1160 {
1161   return this->Target->GetPreLinkCommands();
1162 }
1163
1164 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
1165   const
1166 {
1167   return this->Target->GetPostBuildCommands();
1168 }
1169
1170 void cmGeneratorTarget::AppendCustomCommandSideEffects(
1171   std::set<cmGeneratorTarget const*>& sideEffects) const
1172 {
1173   if (!this->GetPreBuildCommands().empty() ||
1174       !this->GetPreLinkCommands().empty() ||
1175       !this->GetPostBuildCommands().empty()) {
1176     sideEffects.insert(this);
1177   } else {
1178     for (auto const& source : this->GetAllConfigSources()) {
1179       if (source.Source->GetCustomCommand() != nullptr) {
1180         sideEffects.insert(this);
1181         break;
1182       }
1183     }
1184   }
1185 }
1186
1187 void cmGeneratorTarget::AppendLanguageSideEffects(
1188   std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const
1189 {
1190   static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = {
1191     "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, "HIP"_s
1192   };
1193
1194   for (auto const& lang : this->GetAllConfigCompileLanguages()) {
1195     if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) {
1196       sideEffects[lang].insert(this);
1197     }
1198   }
1199 }
1200
1201 bool cmGeneratorTarget::IsInBuildSystem() const
1202 {
1203   if (this->IsImported()) {
1204     return false;
1205   }
1206   switch (this->Target->GetType()) {
1207     case cmStateEnums::EXECUTABLE:
1208     case cmStateEnums::STATIC_LIBRARY:
1209     case cmStateEnums::SHARED_LIBRARY:
1210     case cmStateEnums::MODULE_LIBRARY:
1211     case cmStateEnums::OBJECT_LIBRARY:
1212     case cmStateEnums::UTILITY:
1213     case cmStateEnums::GLOBAL_TARGET:
1214       return true;
1215     case cmStateEnums::INTERFACE_LIBRARY:
1216       // An INTERFACE library is in the build system if it has SOURCES or
1217       // HEADER_SETS.
1218       if (!this->SourceEntries.empty() ||
1219           !this->Target->GetHeaderSetsEntries().empty()) {
1220         return true;
1221       }
1222       break;
1223     case cmStateEnums::UNKNOWN_LIBRARY:
1224       break;
1225   }
1226   return false;
1227 }
1228
1229 bool cmGeneratorTarget::IsImported() const
1230 {
1231   return this->Target->IsImported();
1232 }
1233
1234 bool cmGeneratorTarget::IsImportedGloballyVisible() const
1235 {
1236   return this->Target->IsImportedGloballyVisible();
1237 }
1238
1239 bool cmGeneratorTarget::CanCompileSources() const
1240 {
1241   return this->Target->CanCompileSources();
1242 }
1243
1244 const std::string& cmGeneratorTarget::GetLocationForBuild() const
1245 {
1246   static std::string location;
1247   if (this->IsImported()) {
1248     location = this->Target->ImportedGetFullPath(
1249       "", cmStateEnums::RuntimeBinaryArtifact);
1250     return location;
1251   }
1252
1253   // Now handle the deprecated build-time configuration location.
1254   std::string const noConfig;
1255   location = this->GetDirectory(noConfig);
1256   cmValue cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
1257   if (cfgid && (*cfgid != ".")) {
1258     location += "/";
1259     location += *cfgid;
1260   }
1261
1262   if (this->IsAppBundleOnApple()) {
1263     std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
1264     if (!macdir.empty()) {
1265       location += "/";
1266       location += macdir;
1267     }
1268   }
1269   location += "/";
1270   location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
1271   return location;
1272 }
1273
1274 bool cmGeneratorTarget::IsSystemIncludeDirectory(
1275   const std::string& dir, const std::string& config,
1276   const std::string& language) const
1277 {
1278   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
1279   std::string config_upper;
1280   if (!config.empty()) {
1281     config_upper = cmSystemTools::UpperCase(config);
1282   }
1283
1284   std::string key = cmStrCat(config_upper, "/", language);
1285   auto iter = this->SystemIncludesCache.find(key);
1286
1287   if (iter == this->SystemIncludesCache.end()) {
1288     cmGeneratorExpressionDAGChecker dagChecker(
1289       this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
1290
1291     bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
1292
1293     std::vector<std::string> result;
1294     for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
1295       cmExpandList(cmGeneratorExpression::Evaluate(it, this->LocalGenerator,
1296                                                    config, this, &dagChecker,
1297                                                    nullptr, language),
1298                    result);
1299     }
1300
1301     std::vector<cmGeneratorTarget const*> const& deps =
1302       this->GetLinkImplementationClosure(config);
1303     for (cmGeneratorTarget const* dep : deps) {
1304       handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
1305                               &dagChecker, result, excludeImported, language);
1306     }
1307
1308     cmLinkImplementation const* impl =
1309       this->GetLinkImplementation(config, LinkInterfaceFor::Usage);
1310     if (impl != nullptr) {
1311       auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language);
1312       if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) {
1313         for (auto const& lib : runtimeEntries->second) {
1314           if (lib.Target) {
1315             handleSystemIncludesDep(this->LocalGenerator, lib.Target, config,
1316                                     this, &dagChecker, result, excludeImported,
1317                                     language);
1318           }
1319         }
1320       }
1321     }
1322
1323     std::for_each(result.begin(), result.end(),
1324                   cmSystemTools::ConvertToUnixSlashes);
1325     std::sort(result.begin(), result.end());
1326     result.erase(std::unique(result.begin(), result.end()), result.end());
1327
1328     iter = this->SystemIncludesCache.emplace(key, result).first;
1329   }
1330
1331   return std::binary_search(iter->second.begin(), iter->second.end(), dir);
1332 }
1333
1334 bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
1335 {
1336   return this->Target->GetPropertyAsBool(prop);
1337 }
1338
1339 bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
1340   std::string const& prop, cmGeneratorExpressionContext* context,
1341   LinkInterfaceFor interfaceFor) const
1342 {
1343   std::string const key = prop + '@' + context->Config;
1344   auto i = this->MaybeInterfacePropertyExists.find(key);
1345   if (i == this->MaybeInterfacePropertyExists.end()) {
1346     // Insert an entry now in case there is a cycle.
1347     i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
1348     bool& maybeInterfaceProp = i->second;
1349
1350     // If this target itself has a non-empty property value, we are done.
1351     maybeInterfaceProp = cmNonempty(this->GetProperty(prop));
1352
1353     // Otherwise, recurse to interface dependencies.
1354     if (!maybeInterfaceProp) {
1355       cmGeneratorTarget const* headTarget =
1356         context->HeadTarget ? context->HeadTarget : this;
1357       if (cmLinkInterfaceLibraries const* iface =
1358             this->GetLinkInterfaceLibraries(context->Config, headTarget,
1359                                             interfaceFor)) {
1360         if (iface->HadHeadSensitiveCondition) {
1361           // With a different head target we may get to a library with
1362           // this interface property.
1363           maybeInterfaceProp = true;
1364         } else {
1365           // The transitive interface libraries do not depend on the
1366           // head target, so we can follow them.
1367           for (cmLinkItem const& lib : iface->Libraries) {
1368             if (lib.Target &&
1369                 lib.Target->MaybeHaveInterfaceProperty(prop, context,
1370                                                        interfaceFor)) {
1371               maybeInterfaceProp = true;
1372               break;
1373             }
1374           }
1375         }
1376       }
1377     }
1378   }
1379   return i->second;
1380 }
1381
1382 std::string cmGeneratorTarget::EvaluateInterfaceProperty(
1383   std::string const& prop, cmGeneratorExpressionContext* context,
1384   cmGeneratorExpressionDAGChecker* dagCheckerParent,
1385   LinkInterfaceFor interfaceFor) const
1386 {
1387   std::string result;
1388
1389   // If the property does not appear transitively at all, we are done.
1390   if (!this->MaybeHaveInterfaceProperty(prop, context, interfaceFor)) {
1391     return result;
1392   }
1393
1394   // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled.  This is
1395   // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
1396   // but sufficient for transitive interface properties.
1397   cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
1398                                              nullptr, dagCheckerParent);
1399   switch (dagChecker.Check()) {
1400     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1401       dagChecker.ReportError(
1402         context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
1403       return result;
1404     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1405       // No error. We just skip cyclic references.
1406     case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1407       // No error. We have already seen this transitive property.
1408       return result;
1409     case cmGeneratorExpressionDAGChecker::DAG:
1410       break;
1411   }
1412
1413   cmGeneratorTarget const* headTarget =
1414     context->HeadTarget ? context->HeadTarget : this;
1415
1416   if (cmValue p = this->GetProperty(prop)) {
1417     result = cmGeneratorExpressionNode::EvaluateDependentExpression(
1418       *p, context->LG, context, headTarget, &dagChecker, this);
1419   }
1420
1421   if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
1422         context->Config, headTarget, interfaceFor)) {
1423     context->HadContextSensitiveCondition =
1424       context->HadContextSensitiveCondition ||
1425       iface->HadContextSensitiveCondition;
1426     for (cmLinkItem const& lib : iface->Libraries) {
1427       // Broken code can have a target in its own link interface.
1428       // Don't follow such link interface entries so as not to create a
1429       // self-referencing loop.
1430       if (lib.Target && lib.Target != this) {
1431         // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
1432         // above property and hand-evaluate it as if it were compiled.
1433         // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1434         cmGeneratorExpressionContext libContext(
1435           context->LG, context->Config, context->Quiet, headTarget, this,
1436           context->EvaluateForBuildsystem, context->Backtrace,
1437           context->Language);
1438         std::string libResult = cmGeneratorExpression::StripEmptyListElements(
1439           lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker,
1440                                                 interfaceFor));
1441         if (!libResult.empty()) {
1442           if (result.empty()) {
1443             result = std::move(libResult);
1444           } else {
1445             result.reserve(result.size() + 1 + libResult.size());
1446             result += ";";
1447             result += libResult;
1448           }
1449         }
1450         context->HadContextSensitiveCondition =
1451           context->HadContextSensitiveCondition ||
1452           libContext.HadContextSensitiveCondition;
1453         context->HadHeadSensitiveCondition =
1454           context->HadHeadSensitiveCondition ||
1455           libContext.HadHeadSensitiveCondition;
1456       }
1457     }
1458   }
1459
1460   return result;
1461 }
1462
1463 namespace {
1464
1465 enum class IncludeDirectoryFallBack
1466 {
1467   BINARY,
1468   OBJECT
1469 };
1470
1471 std::string AddLangSpecificInterfaceIncludeDirectories(
1472   const cmGeneratorTarget* root, const cmGeneratorTarget* target,
1473   const std::string& lang, const std::string& config,
1474   const std::string& propertyName, IncludeDirectoryFallBack mode,
1475   cmGeneratorExpressionDAGChecker* context)
1476 {
1477   cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1478                                        propertyName, nullptr, context };
1479   switch (dag.Check()) {
1480     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1481       dag.ReportError(
1482         nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
1483       CM_FALLTHROUGH;
1484     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1485       // No error. We just skip cyclic references.
1486     case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1487       // No error. We have already seen this transitive property.
1488       return "";
1489     case cmGeneratorExpressionDAGChecker::DAG:
1490       break;
1491   }
1492
1493   std::string directories;
1494   if (const auto* interface = target->GetLinkInterfaceLibraries(
1495         config, root, LinkInterfaceFor::Usage)) {
1496     for (const cmLinkItem& library : interface->Libraries) {
1497       if (const cmGeneratorTarget* dependency = library.Target) {
1498         if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
1499           auto* lg = dependency->GetLocalGenerator();
1500           std::string value = dependency->GetSafeProperty(propertyName);
1501           if (value.empty()) {
1502             if (mode == IncludeDirectoryFallBack::BINARY) {
1503               value = lg->GetCurrentBinaryDirectory();
1504             } else if (mode == IncludeDirectoryFallBack::OBJECT) {
1505               value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
1506                                lg->GetTargetDirectory(dependency));
1507             }
1508           }
1509
1510           if (!directories.empty()) {
1511             directories += ";";
1512           }
1513           directories += value;
1514         }
1515       }
1516     }
1517   }
1518   return directories;
1519 }
1520
1521 void AddLangSpecificImplicitIncludeDirectories(
1522   const cmGeneratorTarget* target, const std::string& lang,
1523   const std::string& config, const std::string& propertyName,
1524   IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
1525 {
1526   if (const auto* libraries = target->GetLinkImplementationLibraries(
1527         config, LinkInterfaceFor::Usage)) {
1528     cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1529                                          propertyName, nullptr, nullptr };
1530
1531     for (const cmLinkImplItem& library : libraries->Libraries) {
1532       if (const cmGeneratorTarget* dependency = library.Target) {
1533         if (!dependency->IsInBuildSystem()) {
1534           continue;
1535         }
1536         if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
1537           auto* lg = dependency->GetLocalGenerator();
1538           EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
1539
1540           if (cmValue val = dependency->GetProperty(propertyName)) {
1541             entry.Values.emplace_back(*val);
1542           } else {
1543             if (mode == IncludeDirectoryFallBack::BINARY) {
1544               entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
1545             } else if (mode == IncludeDirectoryFallBack::OBJECT) {
1546               entry.Values.emplace_back(
1547                 dependency->GetObjectDirectory(config));
1548             }
1549           }
1550
1551           cmExpandList(
1552             AddLangSpecificInterfaceIncludeDirectories(
1553               target, dependency, lang, config, propertyName, mode, &dag),
1554             entry.Values);
1555           entries.Entries.emplace_back(std::move(entry));
1556         }
1557       }
1558     }
1559   }
1560 }
1561
1562 void addInterfaceEntry(cmGeneratorTarget const* headTarget,
1563                        std::string const& config, std::string const& prop,
1564                        std::string const& lang,
1565                        cmGeneratorExpressionDAGChecker* dagChecker,
1566                        EvaluatedTargetPropertyEntries& entries,
1567                        LinkInterfaceFor interfaceFor,
1568                        std::vector<cmLinkImplItem> const& libraries)
1569 {
1570   for (cmLinkImplItem const& lib : libraries) {
1571     if (lib.Target) {
1572       EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1573       // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
1574       // caller's property and hand-evaluate it as if it were compiled.
1575       // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1576       cmGeneratorExpressionContext context(
1577         headTarget->GetLocalGenerator(), config, false, headTarget, headTarget,
1578         true, lib.Backtrace, lang);
1579       cmExpandList(lib.Target->EvaluateInterfaceProperty(
1580                      prop, &context, dagChecker, interfaceFor),
1581                    ee.Values);
1582       ee.ContextDependent = context.HadContextSensitiveCondition;
1583       entries.Entries.emplace_back(std::move(ee));
1584     }
1585   }
1586 }
1587
1588 // IncludeRuntimeInterface is used to break the cycle in computing
1589 // the necessary transitive dependencies of targets that can occur
1590 // now that we have implicit language runtime targets.
1591 //
1592 // To determine the set of languages that a target has we need to iterate
1593 // all the sources which includes transitive INTERFACE sources.
1594 // Therefore we can't determine what language runtimes are needed
1595 // for a target until after all sources are computed.
1596 //
1597 // Therefore while computing the applicable INTERFACE_SOURCES we
1598 // must ignore anything in LanguageRuntimeLibraries or we would
1599 // create a cycle ( INTERFACE_SOURCES requires LanguageRuntimeLibraries,
1600 // LanguageRuntimeLibraries requires INTERFACE_SOURCES).
1601 //
1602 enum class IncludeRuntimeInterface
1603 {
1604   Yes,
1605   No
1606 };
1607 void AddInterfaceEntries(
1608   cmGeneratorTarget const* headTarget, std::string const& config,
1609   std::string const& prop, std::string const& lang,
1610   cmGeneratorExpressionDAGChecker* dagChecker,
1611   EvaluatedTargetPropertyEntries& entries,
1612   IncludeRuntimeInterface searchRuntime,
1613   LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage)
1614 {
1615   if (searchRuntime == IncludeRuntimeInterface::Yes) {
1616     if (cmLinkImplementation const* impl =
1617           headTarget->GetLinkImplementation(config, interfaceFor)) {
1618       entries.HadContextSensitiveCondition =
1619         impl->HadContextSensitiveCondition;
1620
1621       auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang);
1622       if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) {
1623         addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1624                           interfaceFor, runtimeLibIt->second);
1625       }
1626       addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1627                         interfaceFor, impl->Libraries);
1628     }
1629   } else {
1630     if (cmLinkImplementationLibraries const* impl =
1631           headTarget->GetLinkImplementationLibraries(config, interfaceFor)) {
1632       entries.HadContextSensitiveCondition =
1633         impl->HadContextSensitiveCondition;
1634       addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1635                         interfaceFor, impl->Libraries);
1636     }
1637   }
1638 }
1639
1640 void AddObjectEntries(cmGeneratorTarget const* headTarget,
1641                       std::string const& config,
1642                       cmGeneratorExpressionDAGChecker* dagChecker,
1643                       EvaluatedTargetPropertyEntries& entries)
1644 {
1645   if (cmLinkImplementationLibraries const* impl =
1646         headTarget->GetLinkImplementationLibraries(config,
1647                                                    LinkInterfaceFor::Usage)) {
1648     entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
1649     for (cmLinkImplItem const& lib : impl->Libraries) {
1650       if (lib.Target &&
1651           lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1652         std::string uniqueName =
1653           headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
1654             lib.Target);
1655         std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
1656         cmGeneratorExpression ge(lib.Backtrace);
1657         std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
1658         cge->SetEvaluateForBuildsystem(true);
1659
1660         EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1661         cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config,
1662                                    headTarget, dagChecker),
1663                      ee.Values);
1664         if (cge->GetHadContextSensitiveCondition()) {
1665           ee.ContextDependent = true;
1666         }
1667         entries.Entries.emplace_back(std::move(ee));
1668       }
1669     }
1670   }
1671 }
1672
1673 void addFileSetEntry(cmGeneratorTarget const* headTarget,
1674                      std::string const& config,
1675                      cmGeneratorExpressionDAGChecker* dagChecker,
1676                      cmFileSet const* fileSet,
1677                      EvaluatedTargetPropertyEntries& entries)
1678 {
1679   auto dirCges = fileSet->CompileDirectoryEntries();
1680   auto dirs = fileSet->EvaluateDirectoryEntries(
1681     dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker);
1682   bool contextSensitiveDirs = false;
1683   for (auto const& dirCge : dirCges) {
1684     if (dirCge->GetHadContextSensitiveCondition()) {
1685       contextSensitiveDirs = true;
1686       break;
1687     }
1688   }
1689   cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance();
1690   for (auto& entryCge : fileSet->CompileFileEntries()) {
1691     TargetPropertyEntryFileSet tpe(dirs, contextSensitiveDirs,
1692                                    std::move(entryCge), fileSet);
1693     entries.Entries.emplace_back(
1694       EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, tpe));
1695     for (auto const& file : entries.Entries.back().Values) {
1696       auto* sf = headTarget->Makefile->GetOrCreateSource(file);
1697       if (fileSet->GetType() == "HEADERS"_s) {
1698         sf->SetProperty("HEADER_FILE_ONLY", "TRUE");
1699       }
1700
1701 #ifndef CMAKE_BOOTSTRAP
1702       std::string e;
1703       std::string w;
1704       auto path = sf->ResolveFullPath(&e, &w);
1705       if (!w.empty()) {
1706         cm->IssueMessage(MessageType::AUTHOR_WARNING, w,
1707                          headTarget->GetBacktrace());
1708       }
1709       if (path.empty()) {
1710         if (!e.empty()) {
1711           cm->IssueMessage(MessageType::FATAL_ERROR, e,
1712                            headTarget->GetBacktrace());
1713         }
1714         return;
1715       }
1716       bool found = false;
1717       for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
1718         if (sg.MatchChildrenFiles(path)) {
1719           found = true;
1720           break;
1721         }
1722       }
1723       if (!found) {
1724         if (fileSet->GetType() == "HEADERS"_s ||
1725             fileSet->GetType() == "CXX_MODULE_HEADER_UNITS"_s) {
1726           headTarget->Makefile->GetOrCreateSourceGroup("Header Files")
1727             ->AddGroupFile(path);
1728         }
1729       }
1730 #endif
1731     }
1732   }
1733 }
1734
1735 void AddFileSetEntries(cmGeneratorTarget const* headTarget,
1736                        std::string const& config,
1737                        cmGeneratorExpressionDAGChecker* dagChecker,
1738                        EvaluatedTargetPropertyEntries& entries)
1739 {
1740   for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) {
1741     for (auto const& name : cmExpandedList(entry.Value)) {
1742       auto const* headerSet = headTarget->Target->GetFileSet(name);
1743       addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
1744     }
1745   }
1746   for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) {
1747     for (auto const& name : cmExpandedList(entry.Value)) {
1748       auto const* cxxModuleSet = headTarget->Target->GetFileSet(name);
1749       addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries);
1750     }
1751   }
1752   for (auto const& entry :
1753        headTarget->Target->GetCxxModuleHeaderSetsEntries()) {
1754     for (auto const& name : cmExpandedList(entry.Value)) {
1755       auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name);
1756       addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet,
1757                       entries);
1758     }
1759   }
1760 }
1761
1762 bool processSources(cmGeneratorTarget const* tgt,
1763                     EvaluatedTargetPropertyEntries& entries,
1764                     std::vector<BT<std::string>>& srcs,
1765                     std::unordered_set<std::string>& uniqueSrcs,
1766                     bool debugSources)
1767 {
1768   cmMakefile* mf = tgt->Target->GetMakefile();
1769
1770   bool contextDependent = entries.HadContextSensitiveCondition;
1771
1772   for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
1773     if (entry.ContextDependent) {
1774       contextDependent = true;
1775     }
1776
1777     cmLinkImplItem const& item = entry.LinkImplItem;
1778     std::string const& targetName = item.AsStr();
1779
1780     for (std::string& src : entry.Values) {
1781       cmSourceFile* sf = mf->GetOrCreateSource(src);
1782       std::string e;
1783       std::string w;
1784       std::string fullPath = sf->ResolveFullPath(&e, &w);
1785       cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
1786       if (!w.empty()) {
1787         cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
1788       }
1789       if (fullPath.empty()) {
1790         if (!e.empty()) {
1791           cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
1792         }
1793         return contextDependent;
1794       }
1795
1796       if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
1797         std::ostringstream err;
1798         if (!targetName.empty()) {
1799           err << "Target \"" << targetName
1800               << "\" contains relative path in its INTERFACE_SOURCES:\n  \""
1801               << src << "\"";
1802         } else {
1803           err << "Found relative path while evaluating sources of \""
1804               << tgt->GetName() << "\":\n  \"" << src << "\"\n";
1805         }
1806         tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
1807                                                err.str());
1808         return contextDependent;
1809       }
1810       src = fullPath;
1811     }
1812     std::string usedSources;
1813     for (std::string const& src : entry.Values) {
1814       if (uniqueSrcs.insert(src).second) {
1815         srcs.emplace_back(src, entry.Backtrace);
1816         if (debugSources) {
1817           usedSources += " * " + src + "\n";
1818         }
1819       }
1820     }
1821     if (!usedSources.empty()) {
1822       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
1823         MessageType::LOG,
1824         std::string("Used sources for target ") + tgt->GetName() + ":\n" +
1825           usedSources,
1826         entry.Backtrace);
1827     }
1828   }
1829   return contextDependent;
1830 }
1831 }
1832
1833 std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
1834   std::string const& config) const
1835 {
1836   std::vector<BT<std::string>> files;
1837
1838   if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1839     // At configure-time, this method can be called as part of getting the
1840     // LOCATION property or to export() a file to be include()d.  However
1841     // there is no cmGeneratorTarget at configure-time, so search the SOURCES
1842     // for TARGET_OBJECTS instead for backwards compatibility with OLD
1843     // behavior of CMP0024 and CMP0026 only.
1844
1845     cmBTStringRange sourceEntries = this->Target->GetSourceEntries();
1846     for (auto const& entry : sourceEntries) {
1847       std::vector<std::string> items = cmExpandedList(entry.Value);
1848       for (std::string const& item : items) {
1849         if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
1850             item.back() == '>') {
1851           continue;
1852         }
1853         files.emplace_back(item);
1854       }
1855     }
1856     return files;
1857   }
1858
1859   std::vector<std::string> debugProperties;
1860   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
1861                                    debugProperties);
1862
1863   bool debugSources =
1864     !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES");
1865
1866   if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1867     this->DebugSourcesDone = true;
1868   }
1869
1870   cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
1871                                              nullptr);
1872
1873   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
1874     this, config, std::string(), &dagChecker, this->SourceEntries);
1875
1876   std::unordered_set<std::string> uniqueSrcs;
1877   bool contextDependentDirectSources =
1878     processSources(this, entries, files, uniqueSrcs, debugSources);
1879
1880   // Collect INTERFACE_SOURCES of all direct link-dependencies.
1881   EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries;
1882   AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(),
1883                       &dagChecker, linkInterfaceSourcesEntries,
1884                       IncludeRuntimeInterface::No, LinkInterfaceFor::Usage);
1885   std::vector<std::string>::size_type numFilesBefore = files.size();
1886   bool contextDependentInterfaceSources = processSources(
1887     this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources);
1888
1889   // Collect TARGET_OBJECTS of direct object link-dependencies.
1890   bool contextDependentObjects = false;
1891   std::vector<std::string>::size_type numFilesBefore2 = files.size();
1892   if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
1893     EvaluatedTargetPropertyEntries linkObjectsEntries;
1894     AddObjectEntries(this, config, &dagChecker, linkObjectsEntries);
1895     contextDependentObjects = processSources(this, linkObjectsEntries, files,
1896                                              uniqueSrcs, debugSources);
1897   }
1898
1899   // Collect this target's file sets.
1900   std::vector<std::string>::size_type numFilesBefore3 = files.size();
1901   EvaluatedTargetPropertyEntries fileSetEntries;
1902   AddFileSetEntries(this, config, &dagChecker, fileSetEntries);
1903   bool contextDependentFileSets =
1904     processSources(this, fileSetEntries, files, uniqueSrcs, debugSources);
1905
1906   // Determine if sources are context-dependent or not.
1907   if (!contextDependentDirectSources &&
1908       !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
1909       !(contextDependentObjects && numFilesBefore2 < files.size()) &&
1910       !(contextDependentFileSets && numFilesBefore3 < files.size())) {
1911     this->SourcesAreContextDependent = Tribool::False;
1912   } else {
1913     this->SourcesAreContextDependent = Tribool::True;
1914   }
1915
1916   return files;
1917 }
1918
1919 void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
1920                                        const std::string& config) const
1921 {
1922   std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config);
1923   files.reserve(tmp.size());
1924   for (BT<cmSourceFile*>& v : tmp) {
1925     files.push_back(v.Value);
1926   }
1927 }
1928
1929 std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles(
1930   std::string const& config) const
1931 {
1932   std::vector<BT<cmSourceFile*>> files;
1933   if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
1934     // Since we are still configuring not all sources may exist yet,
1935     // so we need to avoid full source classification because that
1936     // requires the absolute paths to all sources to be determined.
1937     // Since this is only for compatibility with old policies that
1938     // projects should not depend on anymore, just compute the files
1939     // without memoizing them.
1940     std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
1941     std::set<cmSourceFile*> emitted;
1942     for (BT<std::string> const& s : srcs) {
1943       cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
1944       if (emitted.insert(sf).second) {
1945         files.emplace_back(sf, s.Backtrace);
1946       }
1947     }
1948     return files;
1949   }
1950
1951   KindedSources const& kinded = this->GetKindedSources(config);
1952   files.reserve(kinded.Sources.size());
1953   for (SourceAndKind const& si : kinded.Sources) {
1954     files.push_back(si.Source);
1955   }
1956   return files;
1957 }
1958
1959 void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1960   std::vector<cmSourceFile*>& files, const std::string& config) const
1961 {
1962   std::vector<BT<cmSourceFile*>> tmp =
1963     this->GetSourceFilesWithoutObjectLibraries(config);
1964   files.reserve(tmp.size());
1965   for (BT<cmSourceFile*>& v : tmp) {
1966     files.push_back(v.Value);
1967   }
1968 }
1969
1970 std::vector<BT<cmSourceFile*>>
1971 cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1972   std::string const& config) const
1973 {
1974   std::vector<BT<cmSourceFile*>> files;
1975   KindedSources const& kinded = this->GetKindedSources(config);
1976   files.reserve(kinded.Sources.size());
1977   for (SourceAndKind const& si : kinded.Sources) {
1978     if (si.Source.Value->GetObjectLibrary().empty()) {
1979       files.push_back(si.Source);
1980     }
1981   }
1982   return files;
1983 }
1984
1985 cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
1986   std::string const& config) const
1987 {
1988   // If we already processed one configuration and found no dependency
1989   // on configuration then always use the one result.
1990   if (this->SourcesAreContextDependent == Tribool::False) {
1991     return this->KindedSourcesMap.begin()->second;
1992   }
1993
1994   // Lookup any existing link implementation for this configuration.
1995   std::string const key = cmSystemTools::UpperCase(config);
1996   auto it = this->KindedSourcesMap.find(key);
1997   if (it != this->KindedSourcesMap.end()) {
1998     if (!it->second.Initialized) {
1999       std::ostringstream e;
2000       e << "The SOURCES of \"" << this->GetName()
2001         << "\" use a generator expression that depends on the "
2002            "SOURCES themselves.";
2003       this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
2004         MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
2005       static KindedSources empty;
2006       return empty;
2007     }
2008     return it->second;
2009   }
2010
2011   // Add an entry to the map for this configuration.
2012   KindedSources& files = this->KindedSourcesMap[key];
2013   this->ComputeKindedSources(files, config);
2014   files.Initialized = true;
2015   return files;
2016 }
2017
2018 void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
2019                                              std::string const& config) const
2020 {
2021   // Get the source file paths by string.
2022   std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
2023
2024   cmsys::RegularExpression header_regex(CM_HEADER_REGEX);
2025   std::vector<cmSourceFile*> badObjLib;
2026
2027   std::set<cmSourceFile*> emitted;
2028   for (BT<std::string> const& s : srcs) {
2029     // Create each source at most once.
2030     cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
2031     if (!emitted.insert(sf).second) {
2032       continue;
2033     }
2034
2035     // Compute the kind (classification) of this source file.
2036     SourceKind kind;
2037     std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
2038     if (sf->GetCustomCommand()) {
2039       kind = SourceKindCustomCommand;
2040     } else if (this->Target->GetType() == cmStateEnums::UTILITY ||
2041                this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY
2042                // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2043                // NOLINTNEXTLINE(bugprone-branch-clone)
2044     ) {
2045       kind = SourceKindExtra;
2046     } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) {
2047       kind = SourceKindUnityBatched;
2048       // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2049       // NOLINTNEXTLINE(bugprone-branch-clone)
2050     } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) {
2051       kind = SourceKindHeader;
2052     } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
2053       kind = SourceKindExternalObject;
2054     } else if (!sf->GetOrDetermineLanguage().empty()) {
2055       kind = SourceKindObjectSource;
2056     } else if (ext == "def") {
2057       kind = SourceKindModuleDefinition;
2058       if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2059         badObjLib.push_back(sf);
2060       }
2061     } else if (ext == "idl") {
2062       kind = SourceKindIDL;
2063       if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2064         badObjLib.push_back(sf);
2065       }
2066     } else if (ext == "resx") {
2067       kind = SourceKindResx;
2068     } else if (ext == "appxmanifest") {
2069       kind = SourceKindAppManifest;
2070     } else if (ext == "manifest") {
2071       if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) {
2072         kind = SourceKindExtra;
2073       } else {
2074         kind = SourceKindManifest;
2075       }
2076     } else if (ext == "pfx") {
2077       kind = SourceKindCertificate;
2078     } else if (ext == "xaml") {
2079       kind = SourceKindXaml;
2080     } else if (header_regex.find(sf->ResolveFullPath())) {
2081       kind = SourceKindHeader;
2082     } else {
2083       kind = SourceKindExtra;
2084     }
2085
2086     // Save this classified source file in the result vector.
2087     files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind });
2088   }
2089
2090   if (!badObjLib.empty()) {
2091     std::ostringstream e;
2092     e << "OBJECT library \"" << this->GetName() << "\" contains:\n";
2093     for (cmSourceFile* i : badObjLib) {
2094       e << "  " << i->GetLocation().GetName() << "\n";
2095     }
2096     e << "but may contain only sources that compile, header files, and "
2097          "other files that would not affect linking of a normal library.";
2098     this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
2099       MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
2100   }
2101 }
2102
2103 std::vector<cmGeneratorTarget::AllConfigSource> const&
2104 cmGeneratorTarget::GetAllConfigSources() const
2105 {
2106   if (this->AllConfigSources.empty()) {
2107     this->ComputeAllConfigSources();
2108   }
2109   return this->AllConfigSources;
2110 }
2111
2112 void cmGeneratorTarget::ComputeAllConfigSources() const
2113 {
2114   std::vector<std::string> configs =
2115     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2116
2117   std::map<cmSourceFile const*, size_t> index;
2118
2119   for (size_t ci = 0; ci < configs.size(); ++ci) {
2120     KindedSources const& sources = this->GetKindedSources(configs[ci]);
2121     for (SourceAndKind const& src : sources.Sources) {
2122       auto mi = index.find(src.Source.Value);
2123       if (mi == index.end()) {
2124         AllConfigSource acs;
2125         acs.Source = src.Source.Value;
2126         acs.Kind = src.Kind;
2127         this->AllConfigSources.push_back(std::move(acs));
2128         std::map<cmSourceFile const*, size_t>::value_type entry(
2129           src.Source.Value, this->AllConfigSources.size() - 1);
2130         mi = index.insert(entry).first;
2131       }
2132       this->AllConfigSources[mi->second].Configs.push_back(ci);
2133     }
2134   }
2135 }
2136
2137 std::vector<cmGeneratorTarget::AllConfigSource>
2138 cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
2139 {
2140   std::vector<AllConfigSource> result;
2141   for (AllConfigSource const& source : this->GetAllConfigSources()) {
2142     if (source.Kind == kind) {
2143       result.push_back(source);
2144     }
2145   }
2146   return result;
2147 }
2148
2149 std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
2150 {
2151   std::set<std::string> languages;
2152   std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
2153   for (AllConfigSource const& si : sources) {
2154     std::string const& lang = si.Source->GetOrDetermineLanguage();
2155     if (!lang.empty()) {
2156       languages.emplace(lang);
2157     }
2158   }
2159   return languages;
2160 }
2161
2162 std::string cmGeneratorTarget::GetCompilePDBName(
2163   const std::string& config) const
2164 {
2165   std::string prefix;
2166   std::string base;
2167   std::string suffix;
2168   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
2169                             prefix, base, suffix);
2170
2171   // Check for a per-configuration output directory target property.
2172   std::string configUpper = cmSystemTools::UpperCase(config);
2173   std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
2174   cmValue config_name = this->GetProperty(configProp);
2175   if (cmNonempty(config_name)) {
2176     return prefix + *config_name + ".pdb";
2177   }
2178
2179   cmValue name = this->GetProperty("COMPILE_PDB_NAME");
2180   if (cmNonempty(name)) {
2181     return prefix + *name + ".pdb";
2182   }
2183
2184   return "";
2185 }
2186
2187 std::string cmGeneratorTarget::GetCompilePDBPath(
2188   const std::string& config) const
2189 {
2190   std::string dir = this->GetCompilePDBDirectory(config);
2191   std::string name = this->GetCompilePDBName(config);
2192   if (dir.empty() && !name.empty() && this->HaveWellDefinedOutputFiles()) {
2193     dir = this->GetPDBDirectory(config);
2194   }
2195   if (!dir.empty()) {
2196     dir += "/";
2197   }
2198   return dir + name;
2199 }
2200
2201 bool cmGeneratorTarget::HasSOName(const std::string& config) const
2202 {
2203   // soname is supported only for shared libraries and modules,
2204   // and then only when the platform supports an soname flag.
2205   return ((this->GetType() == cmStateEnums::SHARED_LIBRARY) &&
2206           !this->GetPropertyAsBool("NO_SONAME") &&
2207           this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
2208 }
2209
2210 bool cmGeneratorTarget::NeedRelinkBeforeInstall(
2211   const std::string& config) const
2212 {
2213   // Only executables and shared libraries can have an rpath and may
2214   // need relinking.
2215   if (this->GetType() != cmStateEnums::EXECUTABLE &&
2216       this->GetType() != cmStateEnums::SHARED_LIBRARY &&
2217       this->GetType() != cmStateEnums::MODULE_LIBRARY) {
2218     return false;
2219   }
2220
2221   // If there is no install location this target will not be installed
2222   // and therefore does not need relinking.
2223   if (!this->Target->GetHaveInstallRule()) {
2224     return false;
2225   }
2226
2227   // If skipping all rpaths completely then no relinking is needed.
2228   if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
2229     return false;
2230   }
2231
2232   // If building with the install-tree rpath no relinking is needed.
2233   if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2234     return false;
2235   }
2236
2237   // If chrpath is going to be used no relinking is needed.
2238   if (this->IsChrpathUsed(config)) {
2239     return false;
2240   }
2241
2242   // Check for rpath support on this platform.
2243   std::string ll = this->GetLinkerLanguage(config);
2244   if (!ll.empty()) {
2245     std::string flagVar =
2246       cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG");
2247     if (!this->Makefile->IsSet(flagVar)) {
2248       // There is no rpath support on this platform so nothing needs
2249       // relinking.
2250       return false;
2251     }
2252   } else {
2253     // No linker language is known.  This error will be reported by
2254     // other code.
2255     return false;
2256   }
2257
2258   // If either a build or install tree rpath is set then the rpath
2259   // will likely change between the build tree and install tree and
2260   // this target must be relinked.
2261   bool have_rpath =
2262     this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
2263   bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja();
2264
2265   if (have_rpath && is_ninja) {
2266     std::ostringstream w;
2267     /* clang-format off */
2268     w <<
2269       "The install of the " << this->GetName() << " target requires changing "
2270       "an RPATH from the build tree, but this is not supported with the Ninja "
2271       "generator unless on an ELF-based or XCOFF-based platform.  "
2272       "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
2273       "relinking step."
2274       ;
2275     /* clang-format on */
2276
2277     cmake* cm = this->LocalGenerator->GetCMakeInstance();
2278     cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
2279   }
2280
2281   return have_rpath;
2282 }
2283
2284 bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
2285 {
2286   // Only certain target types have an rpath.
2287   if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2288         this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2289         this->GetType() == cmStateEnums::EXECUTABLE)) {
2290     return false;
2291   }
2292
2293   // If the target will not be installed we do not need to change its
2294   // rpath.
2295   if (!this->Target->GetHaveInstallRule()) {
2296     return false;
2297   }
2298
2299   // Skip chrpath if skipping rpath altogether.
2300   if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
2301     return false;
2302   }
2303
2304   // Skip chrpath if it does not need to be changed at install time.
2305   if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2306     return false;
2307   }
2308
2309   // Allow the user to disable builtin chrpath explicitly.
2310   if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
2311     return false;
2312   }
2313
2314   if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2315     return true;
2316   }
2317
2318   // Enable if the rpath flag uses a separator and the target uses
2319   // binaries we know how to edit.
2320   std::string ll = this->GetLinkerLanguage(config);
2321   if (!ll.empty()) {
2322     std::string sepVar =
2323       cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
2324     cmValue sep = this->Makefile->GetDefinition(sepVar);
2325     if (cmNonempty(sep)) {
2326       // TODO: Add binary format check to ABI detection and get rid of
2327       // CMAKE_EXECUTABLE_FORMAT.
2328       if (cmValue fmt =
2329             this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
2330         if (*fmt == "ELF") {
2331           return true;
2332         }
2333 #if defined(CMake_USE_XCOFF_PARSER)
2334         if (*fmt == "XCOFF") {
2335           return true;
2336         }
2337 #endif
2338       }
2339     }
2340   }
2341   return false;
2342 }
2343
2344 bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
2345   const std::string& config) const
2346 {
2347   if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY) {
2348     if (cmGeneratorTarget::ImportInfo const* info =
2349           this->GetImportInfo(config)) {
2350       return info->NoSOName;
2351     }
2352   }
2353   return false;
2354 }
2355
2356 bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
2357   const std::string& config) const
2358 {
2359   TargetPtrToBoolMap& cache = this->MacOSXRpathInstallNameDirCache[config];
2360   const auto lookup = cache.find(this->Target);
2361
2362   if (lookup != cache.cend()) {
2363     return lookup->second;
2364   }
2365
2366   const bool result = this->DetermineHasMacOSXRpathInstallNameDir(config);
2367   cache[this->Target] = result;
2368   return result;
2369 }
2370
2371 bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir(
2372   const std::string& config) const
2373 {
2374   bool install_name_is_rpath = false;
2375   bool macosx_rpath = false;
2376
2377   if (!this->IsImported()) {
2378     if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
2379       return false;
2380     }
2381     cmValue install_name = this->GetProperty("INSTALL_NAME_DIR");
2382     bool use_install_name = this->MacOSXUseInstallNameDir();
2383     if (install_name && use_install_name && *install_name == "@rpath") {
2384       install_name_is_rpath = true;
2385     } else if (install_name && use_install_name) {
2386       return false;
2387     }
2388     if (!install_name_is_rpath) {
2389       macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
2390     }
2391   } else {
2392     // Lookup the imported soname.
2393     if (cmGeneratorTarget::ImportInfo const* info =
2394           this->GetImportInfo(config)) {
2395       if (!info->NoSOName && !info->SOName.empty()) {
2396         if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
2397           install_name_is_rpath = true;
2398         }
2399       } else {
2400         std::string install_name;
2401         cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
2402         if (install_name.find("@rpath") != std::string::npos) {
2403           install_name_is_rpath = true;
2404         }
2405       }
2406     }
2407   }
2408
2409   if (!install_name_is_rpath && !macosx_rpath) {
2410     return false;
2411   }
2412
2413   if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2414     std::ostringstream w;
2415     w << "Attempting to use ";
2416     if (macosx_rpath) {
2417       w << "MACOSX_RPATH";
2418     } else {
2419       w << "@rpath";
2420     }
2421     w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
2422     w << "  This could be because you are using a Mac OS X version";
2423     w << " less than 10.5 or because CMake's platform configuration is";
2424     w << " corrupt.";
2425     cmake* cm = this->LocalGenerator->GetCMakeInstance();
2426     cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
2427   }
2428
2429   return true;
2430 }
2431
2432 bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
2433 {
2434   // we can't do rpaths when unsupported
2435   if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2436     return false;
2437   }
2438
2439   cmValue macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
2440   if (macosx_rpath_str) {
2441     return this->GetPropertyAsBool("MACOSX_RPATH");
2442   }
2443
2444   cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
2445
2446   if (cmp0042 == cmPolicies::WARN) {
2447     this->LocalGenerator->GetGlobalGenerator()->AddCMP0042WarnTarget(
2448       this->GetName());
2449   }
2450
2451   return cmp0042 == cmPolicies::NEW;
2452 }
2453
2454 bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
2455 {
2456   cmValue build_with_install_name =
2457     this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
2458   if (build_with_install_name) {
2459     return cmIsOn(*build_with_install_name);
2460   }
2461
2462   cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2463   if (cmp0068 == cmPolicies::NEW) {
2464     return false;
2465   }
2466
2467   bool use_install_name = this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
2468
2469   if (use_install_name && cmp0068 == cmPolicies::WARN) {
2470     this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2471       this->GetName());
2472   }
2473
2474   return use_install_name;
2475 }
2476
2477 bool cmGeneratorTarget::CanGenerateInstallNameDir(
2478   InstallNameType name_type) const
2479 {
2480   cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2481
2482   if (cmp0068 == cmPolicies::NEW) {
2483     return true;
2484   }
2485
2486   bool skip = this->Makefile->IsOn("CMAKE_SKIP_RPATH");
2487   if (name_type == INSTALL_NAME_FOR_INSTALL) {
2488     skip |= this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
2489   } else {
2490     skip |= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
2491   }
2492
2493   if (skip && cmp0068 == cmPolicies::WARN) {
2494     this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2495       this->GetName());
2496   }
2497
2498   return !skip;
2499 }
2500
2501 std::string cmGeneratorTarget::GetSOName(const std::string& config) const
2502 {
2503   if (this->IsImported()) {
2504     // Lookup the imported soname.
2505     if (cmGeneratorTarget::ImportInfo const* info =
2506           this->GetImportInfo(config)) {
2507       if (info->NoSOName) {
2508         // The imported library has no builtin soname so the name
2509         // searched at runtime will be just the filename.
2510         return cmSystemTools::GetFilenameName(info->Location);
2511       }
2512       // Use the soname given if any.
2513       if (this->IsFrameworkOnApple()) {
2514         cmsys::RegularExpressionMatch match;
2515         if (FrameworkRegularExpression.find(info->SOName.c_str(), match)) {
2516           auto frameworkName = match.match(2);
2517           auto fileName = match.match(3);
2518           return cmStrCat(frameworkName, ".framework/", fileName);
2519         }
2520       }
2521       if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
2522         return info->SOName.substr(cmStrLen("@rpath/"));
2523       }
2524       return info->SOName;
2525     }
2526     return "";
2527   }
2528   // Compute the soname that will be built.
2529   return this->GetLibraryNames(config).SharedObject;
2530 }
2531
2532 namespace {
2533 bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2534 {
2535   return level == cmGeneratorTarget::FullLevel;
2536 }
2537
2538 bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2539 {
2540   return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
2541 }
2542 }
2543
2544 std::string cmGeneratorTarget::GetAppBundleDirectory(
2545   const std::string& config, BundleDirectoryLevel level) const
2546 {
2547   std::string fpath = cmStrCat(
2548     this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2549   cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
2550   fpath += (ext ? *ext : "app");
2551   if (shouldAddContentLevel(level) &&
2552       !this->Makefile->PlatformIsAppleEmbedded()) {
2553     fpath += "/Contents";
2554     if (shouldAddFullLevel(level)) {
2555       fpath += "/MacOS";
2556     }
2557   }
2558   return fpath;
2559 }
2560
2561 bool cmGeneratorTarget::IsBundleOnApple() const
2562 {
2563   return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
2564     this->IsCFBundleOnApple();
2565 }
2566
2567 bool cmGeneratorTarget::IsWin32Executable(const std::string& config) const
2568 {
2569   return cmIsOn(cmGeneratorExpression::Evaluate(
2570     this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator, config));
2571 }
2572
2573 std::string cmGeneratorTarget::GetCFBundleDirectory(
2574   const std::string& config, BundleDirectoryLevel level) const
2575 {
2576   std::string fpath = cmStrCat(
2577     this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2578   std::string ext;
2579   if (cmValue p = this->GetProperty("BUNDLE_EXTENSION")) {
2580     ext = *p;
2581   } else {
2582     if (this->IsXCTestOnApple()) {
2583       ext = "xctest";
2584     } else {
2585       ext = "bundle";
2586     }
2587   }
2588   fpath += ext;
2589   if (shouldAddContentLevel(level) &&
2590       !this->Makefile->PlatformIsAppleEmbedded()) {
2591     fpath += "/Contents";
2592     if (shouldAddFullLevel(level)) {
2593       fpath += "/MacOS";
2594     }
2595   }
2596   return fpath;
2597 }
2598
2599 std::string cmGeneratorTarget::GetFrameworkDirectory(
2600   const std::string& config, BundleDirectoryLevel level) const
2601 {
2602   std::string fpath = cmStrCat(
2603     this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2604   cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
2605   fpath += (ext ? *ext : "framework");
2606   if (shouldAddFullLevel(level) &&
2607       !this->Makefile->PlatformIsAppleEmbedded()) {
2608     fpath += "/Versions/";
2609     fpath += this->GetFrameworkVersion();
2610   }
2611   return fpath;
2612 }
2613
2614 std::string cmGeneratorTarget::GetFullName(
2615   const std::string& config, cmStateEnums::ArtifactType artifact) const
2616 {
2617   if (this->IsImported()) {
2618     return this->GetFullNameImported(config, artifact);
2619   }
2620   return this->GetFullNameInternal(config, artifact);
2621 }
2622
2623 std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
2624   const std::string& config) const
2625 {
2626   if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2627
2628     // If building directly for installation then the build tree install_name
2629     // is the same as the install tree.
2630     if (this->MacOSXUseInstallNameDir()) {
2631       std::string installPrefix =
2632         this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2633       return this->GetInstallNameDirForInstallTree(config, installPrefix);
2634     }
2635
2636     // Use the build tree directory for the target.
2637     if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD)) {
2638       std::string dir;
2639       if (this->MacOSXRpathInstallNameDirDefault()) {
2640         dir = "@rpath";
2641       } else {
2642         dir = this->GetDirectory(config);
2643       }
2644       dir += "/";
2645       return dir;
2646     }
2647   }
2648   return "";
2649 }
2650
2651 std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
2652   const std::string& config, const std::string& installPrefix) const
2653 {
2654   if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2655     std::string dir;
2656     cmValue install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
2657
2658     if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
2659       if (cmNonempty(install_name_dir)) {
2660         dir = *install_name_dir;
2661         cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
2662         dir =
2663           cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
2664         if (!dir.empty()) {
2665           dir = cmStrCat(dir, '/');
2666         }
2667       }
2668     }
2669     if (!install_name_dir) {
2670       if (this->MacOSXRpathInstallNameDirDefault()) {
2671         dir = "@rpath/";
2672       }
2673     }
2674     return dir;
2675   }
2676   return "";
2677 }
2678
2679 cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
2680 {
2681   return this->Target->GetBacktrace();
2682 }
2683
2684 const std::set<BT<std::pair<std::string, bool>>>&
2685 cmGeneratorTarget::GetUtilities() const
2686 {
2687   return this->Target->GetUtilities();
2688 }
2689
2690 bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
2691 {
2692   return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
2693     this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2694     this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2695     this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
2696     this->GetType() == cmStateEnums::EXECUTABLE;
2697 }
2698
2699 const std::string* cmGeneratorTarget::GetExportMacro() const
2700 {
2701   // Define the symbol for targets that export symbols.
2702   if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2703       this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2704       this->IsExecutableWithExports()) {
2705     if (cmValue custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
2706       this->ExportMacro = *custom_export_name;
2707     } else {
2708       std::string in = cmStrCat(this->GetName(), "_EXPORTS");
2709       this->ExportMacro = cmSystemTools::MakeCidentifier(in);
2710     }
2711     return &this->ExportMacro;
2712   }
2713   return nullptr;
2714 }
2715
2716 class cmTargetCollectLinkLanguages
2717 {
2718 public:
2719   cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
2720                                std::string config,
2721                                std::unordered_set<std::string>& languages,
2722                                cmGeneratorTarget const* head, bool secondPass)
2723     : Config(std::move(config))
2724     , Languages(languages)
2725     , HeadTarget(head)
2726     , SecondPass(secondPass)
2727   {
2728     this->Visited.insert(target);
2729   }
2730
2731   void Visit(cmLinkItem const& item)
2732   {
2733     if (!item.Target) {
2734       return;
2735     }
2736     if (!this->Visited.insert(item.Target).second) {
2737       return;
2738     }
2739     cmLinkInterface const* iface = item.Target->GetLinkInterface(
2740       this->Config, this->HeadTarget, this->SecondPass);
2741     if (!iface) {
2742       return;
2743     }
2744     if (iface->HadLinkLanguageSensitiveCondition) {
2745       this->HadLinkLanguageSensitiveCondition = true;
2746     }
2747
2748     for (std::string const& language : iface->Languages) {
2749       this->Languages.insert(language);
2750     }
2751
2752     for (cmLinkItem const& lib : iface->Libraries) {
2753       this->Visit(lib);
2754     }
2755   }
2756
2757   bool GetHadLinkLanguageSensitiveCondition() const
2758   {
2759     return this->HadLinkLanguageSensitiveCondition;
2760   }
2761
2762 private:
2763   std::string Config;
2764   std::unordered_set<std::string>& Languages;
2765   cmGeneratorTarget const* HeadTarget;
2766   std::set<cmGeneratorTarget const*> Visited;
2767   bool SecondPass;
2768   bool HadLinkLanguageSensitiveCondition = false;
2769 };
2770
2771 cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure(
2772   const std::string& config) const
2773 {
2774   // There is no link implementation for targets that cannot compile sources.
2775   if (!this->CanCompileSources()) {
2776     static LinkClosure const empty = { {}, {} };
2777     return &empty;
2778   }
2779
2780   std::string key(cmSystemTools::UpperCase(config));
2781   auto i = this->LinkClosureMap.find(key);
2782   if (i == this->LinkClosureMap.end()) {
2783     LinkClosure lc;
2784     this->ComputeLinkClosure(config, lc);
2785     LinkClosureMapType::value_type entry(key, lc);
2786     i = this->LinkClosureMap.insert(entry).first;
2787   }
2788   return &i->second;
2789 }
2790
2791 class cmTargetSelectLinker
2792 {
2793   int Preference = 0;
2794   cmGeneratorTarget const* Target;
2795   cmGlobalGenerator* GG;
2796   std::set<std::string> Preferred;
2797
2798 public:
2799   cmTargetSelectLinker(cmGeneratorTarget const* target)
2800     : Target(target)
2801   {
2802     this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator();
2803   }
2804   void Consider(const std::string& lang)
2805   {
2806     int preference = this->GG->GetLinkerPreference(lang);
2807     if (preference > this->Preference) {
2808       this->Preference = preference;
2809       this->Preferred.clear();
2810     }
2811     if (preference == this->Preference) {
2812       this->Preferred.insert(lang);
2813     }
2814   }
2815   std::string Choose()
2816   {
2817     if (this->Preferred.empty()) {
2818       return "";
2819     }
2820     if (this->Preferred.size() > 1) {
2821       std::ostringstream e;
2822       e << "Target " << this->Target->GetName()
2823         << " contains multiple languages with the highest linker preference"
2824         << " (" << this->Preference << "):\n";
2825       for (std::string const& li : this->Preferred) {
2826         e << "  " << li << "\n";
2827       }
2828       e << "Set the LINKER_LANGUAGE property for this target.";
2829       cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance();
2830       cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2831                        this->Target->GetBacktrace());
2832     }
2833     return *this->Preferred.begin();
2834   }
2835 };
2836
2837 bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2838                                            LinkClosure& lc,
2839                                            bool secondPass) const
2840 {
2841   // Get languages built in this target.
2842   std::unordered_set<std::string> languages;
2843   cmLinkImplementation const* impl =
2844     this->GetLinkImplementation(config, LinkInterfaceFor::Link, secondPass);
2845   assert(impl);
2846   languages.insert(impl->Languages.cbegin(), impl->Languages.cend());
2847
2848   // Add interface languages from linked targets.
2849   // cmTargetCollectLinkLanguages cll(this, config, languages, this,
2850   // secondPass);
2851   cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass);
2852   for (cmLinkImplItem const& lib : impl->Libraries) {
2853     cll.Visit(lib);
2854   }
2855
2856   // Store the transitive closure of languages.
2857   cm::append(lc.Languages, languages);
2858
2859   // Choose the language whose linker should be used.
2860   if (secondPass || lc.LinkerLanguage.empty()) {
2861     // Find the language with the highest preference value.
2862     cmTargetSelectLinker tsl(this);
2863
2864     // First select from the languages compiled directly in this target.
2865     for (std::string const& l : impl->Languages) {
2866       tsl.Consider(l);
2867     }
2868
2869     // Now consider languages that propagate from linked targets.
2870     for (std::string const& lang : languages) {
2871       std::string propagates =
2872         "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES";
2873       if (this->Makefile->IsOn(propagates)) {
2874         tsl.Consider(lang);
2875       }
2876     }
2877
2878     lc.LinkerLanguage = tsl.Choose();
2879   }
2880
2881   return impl->HadLinkLanguageSensitiveCondition ||
2882     cll.GetHadLinkLanguageSensitiveCondition();
2883 }
2884
2885 void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2886                                            LinkClosure& lc) const
2887 {
2888   bool secondPass = false;
2889
2890   {
2891     LinkClosure linkClosure;
2892     linkClosure.LinkerLanguage = this->LinkerLanguage;
2893
2894     bool hasHardCodedLinkerLanguage = this->Target->GetProperty("HAS_CXX") ||
2895       !this->Target->GetSafeProperty("LINKER_LANGUAGE").empty();
2896
2897     // Get languages built in this target.
2898     secondPass = this->ComputeLinkClosure(config, linkClosure, false) &&
2899       !hasHardCodedLinkerLanguage;
2900     this->LinkerLanguage = linkClosure.LinkerLanguage;
2901     if (!secondPass) {
2902       lc = std::move(linkClosure);
2903     }
2904   }
2905
2906   if (secondPass) {
2907     LinkClosure linkClosure;
2908
2909     this->ComputeLinkClosure(config, linkClosure, secondPass);
2910     lc = std::move(linkClosure);
2911
2912     // linker language must not be changed between the two passes
2913     if (this->LinkerLanguage != lc.LinkerLanguage) {
2914       std::ostringstream e;
2915       e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> "
2916            "changes\nthe linker language for target \""
2917         << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '"
2918         << lc.LinkerLanguage << "') which is invalid.";
2919       cmSystemTools::Error(e.str());
2920     }
2921   }
2922 }
2923
2924 void cmGeneratorTarget::GetFullNameComponents(
2925   std::string& prefix, std::string& base, std::string& suffix,
2926   const std::string& config, cmStateEnums::ArtifactType artifact) const
2927 {
2928   this->GetFullNameInternal(config, artifact, prefix, base, suffix);
2929 }
2930
2931 std::string cmGeneratorTarget::BuildBundleDirectory(
2932   const std::string& base, const std::string& config,
2933   BundleDirectoryLevel level) const
2934 {
2935   std::string fpath = base;
2936   if (this->IsAppBundleOnApple()) {
2937     fpath += this->GetAppBundleDirectory(config, level);
2938   }
2939   if (this->IsFrameworkOnApple()) {
2940     fpath += this->GetFrameworkDirectory(config, level);
2941   }
2942   if (this->IsCFBundleOnApple()) {
2943     fpath += this->GetCFBundleDirectory(config, level);
2944   }
2945   return fpath;
2946 }
2947
2948 std::string cmGeneratorTarget::GetMacContentDirectory(
2949   const std::string& config, cmStateEnums::ArtifactType artifact) const
2950 {
2951   // Start with the output directory for the target.
2952   std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
2953   BundleDirectoryLevel level = ContentLevel;
2954   if (this->IsFrameworkOnApple()) {
2955     // additional files with a framework go into the version specific
2956     // directory
2957     level = FullLevel;
2958   }
2959   fpath = this->BuildBundleDirectory(fpath, config, level);
2960   return fpath;
2961 }
2962
2963 std::string cmGeneratorTarget::GetEffectiveFolderName() const
2964 {
2965   std::string effectiveFolder;
2966
2967   if (!this->GlobalGenerator->UseFolderProperty()) {
2968     return effectiveFolder;
2969   }
2970
2971   cmValue targetFolder = this->GetProperty("FOLDER");
2972   if (targetFolder) {
2973     effectiveFolder += *targetFolder;
2974   }
2975
2976   return effectiveFolder;
2977 }
2978
2979 cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
2980   const std::string& config) const
2981 {
2982   // There is no compile information for imported targets.
2983   if (this->IsImported()) {
2984     return nullptr;
2985   }
2986
2987   if (this->GetType() > cmStateEnums::OBJECT_LIBRARY) {
2988     std::string msg = cmStrCat("cmTarget::GetCompileInfo called for ",
2989                                this->GetName(), " which has type ",
2990                                cmState::GetTargetTypeName(this->GetType()));
2991     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
2992     return nullptr;
2993   }
2994
2995   // Lookup/compute/cache the compile information for this configuration.
2996   std::string config_upper;
2997   if (!config.empty()) {
2998     config_upper = cmSystemTools::UpperCase(config);
2999   }
3000   auto i = this->CompileInfoMap.find(config_upper);
3001   if (i == this->CompileInfoMap.end()) {
3002     CompileInfo info;
3003     this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
3004     CompileInfoMapType::value_type entry(config_upper, info);
3005     i = this->CompileInfoMap.insert(entry).first;
3006   }
3007   return &i->second;
3008 }
3009
3010 cmGeneratorTarget::ModuleDefinitionInfo const*
3011 cmGeneratorTarget::GetModuleDefinitionInfo(std::string const& config) const
3012 {
3013   // A module definition file only makes sense on certain target types.
3014   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
3015       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
3016       !this->IsExecutableWithExports()) {
3017     return nullptr;
3018   }
3019
3020   // Lookup/compute/cache the compile information for this configuration.
3021   std::string config_upper;
3022   if (!config.empty()) {
3023     config_upper = cmSystemTools::UpperCase(config);
3024   }
3025   auto i = this->ModuleDefinitionInfoMap.find(config_upper);
3026   if (i == this->ModuleDefinitionInfoMap.end()) {
3027     ModuleDefinitionInfo info;
3028     this->ComputeModuleDefinitionInfo(config, info);
3029     ModuleDefinitionInfoMapType::value_type entry(config_upper, info);
3030     i = this->ModuleDefinitionInfoMap.insert(entry).first;
3031   }
3032   return &i->second;
3033 }
3034
3035 void cmGeneratorTarget::ComputeModuleDefinitionInfo(
3036   std::string const& config, ModuleDefinitionInfo& info) const
3037 {
3038   this->GetModuleDefinitionSources(info.Sources, config);
3039   info.WindowsExportAllSymbols =
3040     this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
3041     this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
3042 #if !defined(CMAKE_BOOTSTRAP)
3043   info.DefFileGenerated =
3044     info.WindowsExportAllSymbols || info.Sources.size() > 1;
3045 #else
3046   // Our __create_def helper is not available during CMake bootstrap.
3047   info.DefFileGenerated = false;
3048 #endif
3049   if (info.DefFileGenerated) {
3050     info.DefFile =
3051       this->GetObjectDirectory(config) /* has slash */ + "exports.def";
3052   } else if (!info.Sources.empty()) {
3053     info.DefFile = info.Sources.front()->GetFullPath();
3054   }
3055 }
3056
3057 bool cmGeneratorTarget::IsDLLPlatform() const
3058 {
3059   return this->Target->IsDLLPlatform();
3060 }
3061
3062 void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
3063                                           const std::string& config) const
3064 {
3065   const char* prop =
3066     this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
3067   if (!prop) {
3068     return;
3069   }
3070
3071   cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
3072                                              nullptr);
3073   cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
3074                                                config, this, &dagChecker),
3075                result);
3076 }
3077
3078 static void processILibs(const std::string& config,
3079                          cmGeneratorTarget const* headTarget,
3080                          cmLinkItem const& item, cmGlobalGenerator* gg,
3081                          std::vector<cmGeneratorTarget const*>& tgts,
3082                          std::set<cmGeneratorTarget const*>& emitted)
3083 {
3084   if (item.Target && emitted.insert(item.Target).second) {
3085     tgts.push_back(item.Target);
3086     if (cmLinkInterfaceLibraries const* iface =
3087           item.Target->GetLinkInterfaceLibraries(config, headTarget,
3088                                                  LinkInterfaceFor::Usage)) {
3089       for (cmLinkItem const& lib : iface->Libraries) {
3090         processILibs(config, headTarget, lib, gg, tgts, emitted);
3091       }
3092     }
3093   }
3094 }
3095
3096 const std::vector<const cmGeneratorTarget*>&
3097 cmGeneratorTarget::GetLinkImplementationClosure(
3098   const std::string& config) const
3099 {
3100   // There is no link implementation for targets that cannot compile sources.
3101   if (!this->CanCompileSources()) {
3102     static std::vector<const cmGeneratorTarget*> const empty;
3103     return empty;
3104   }
3105
3106   LinkImplClosure& tgts = this->LinkImplClosureMap[config];
3107   if (!tgts.Done) {
3108     tgts.Done = true;
3109     std::set<cmGeneratorTarget const*> emitted;
3110
3111     cmLinkImplementationLibraries const* impl =
3112       this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Usage);
3113     assert(impl);
3114
3115     for (cmLinkImplItem const& lib : impl->Libraries) {
3116       processILibs(config, this, lib,
3117                    this->LocalGenerator->GetGlobalGenerator(), tgts, emitted);
3118     }
3119   }
3120   return tgts;
3121 }
3122
3123 class cmTargetTraceDependencies
3124 {
3125 public:
3126   cmTargetTraceDependencies(cmGeneratorTarget* target);
3127   void Trace();
3128
3129 private:
3130   cmGeneratorTarget* GeneratorTarget;
3131   cmMakefile* Makefile;
3132   cmLocalGenerator* LocalGenerator;
3133   cmGlobalGenerator const* GlobalGenerator;
3134   using SourceEntry = cmGeneratorTarget::SourceEntry;
3135   SourceEntry* CurrentEntry;
3136   std::queue<cmSourceFile*> SourceQueue;
3137   std::set<cmSourceFile*> SourcesQueued;
3138   using NameMapType = std::map<std::string, cmSourcesWithOutput>;
3139   NameMapType NameMap;
3140   std::vector<std::string> NewSources;
3141
3142   void QueueSource(cmSourceFile* sf);
3143   void FollowName(std::string const& name);
3144   void FollowNames(std::vector<std::string> const& names);
3145   bool IsUtility(std::string const& dep);
3146   void CheckCustomCommand(cmCustomCommand const& cc);
3147   void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
3148 };
3149
3150 cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
3151   : GeneratorTarget(target)
3152 {
3153   // Convenience.
3154   this->Makefile = target->Target->GetMakefile();
3155   this->LocalGenerator = target->GetLocalGenerator();
3156   this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
3157   this->CurrentEntry = nullptr;
3158
3159   // Queue all the source files already specified for the target.
3160   std::set<cmSourceFile*> emitted;
3161   std::vector<std::string> const& configs =
3162     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
3163   for (std::string const& c : configs) {
3164     std::vector<cmSourceFile*> sources;
3165     this->GeneratorTarget->GetSourceFiles(sources, c);
3166     for (cmSourceFile* sf : sources) {
3167       const std::set<cmGeneratorTarget const*> tgts =
3168         this->GlobalGenerator->GetFilenameTargetDepends(sf);
3169       if (cm::contains(tgts, this->GeneratorTarget)) {
3170         std::ostringstream e;
3171         e << "Evaluation output file\n  \"" << sf->ResolveFullPath()
3172           << "\"\ndepends on the sources of a target it is used in.  This "
3173              "is a dependency loop and is not allowed.";
3174         this->GeneratorTarget->LocalGenerator->IssueMessage(
3175           MessageType::FATAL_ERROR, e.str());
3176         return;
3177       }
3178       if (emitted.insert(sf).second && this->SourcesQueued.insert(sf).second) {
3179         this->SourceQueue.push(sf);
3180       }
3181     }
3182   }
3183
3184   // Queue pre-build, pre-link, and post-build rule dependencies.
3185   this->CheckCustomCommands(this->GeneratorTarget->GetPreBuildCommands());
3186   this->CheckCustomCommands(this->GeneratorTarget->GetPreLinkCommands());
3187   this->CheckCustomCommands(this->GeneratorTarget->GetPostBuildCommands());
3188 }
3189
3190 void cmTargetTraceDependencies::Trace()
3191 {
3192   // Process one dependency at a time until the queue is empty.
3193   while (!this->SourceQueue.empty()) {
3194     // Get the next source from the queue.
3195     cmSourceFile* sf = this->SourceQueue.front();
3196     this->SourceQueue.pop();
3197     this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
3198
3199     // Queue dependencies added explicitly by the user.
3200     if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
3201       std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
3202       for (std::string& objDep : objDeps) {
3203         if (cmSystemTools::FileIsFullPath(objDep)) {
3204           objDep = cmSystemTools::CollapseFullPath(objDep);
3205         }
3206       }
3207       this->FollowNames(objDeps);
3208     }
3209
3210     // Queue the source needed to generate this file, if any.
3211     this->FollowName(sf->ResolveFullPath());
3212
3213     // Queue dependencies added programmatically by commands.
3214     this->FollowNames(sf->GetDepends());
3215
3216     // Queue custom command dependencies.
3217     if (cmCustomCommand const* cc = sf->GetCustomCommand()) {
3218       this->CheckCustomCommand(*cc);
3219     }
3220   }
3221   this->CurrentEntry = nullptr;
3222
3223   this->GeneratorTarget->AddTracedSources(this->NewSources);
3224 }
3225
3226 void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
3227 {
3228   if (this->SourcesQueued.insert(sf).second) {
3229     this->SourceQueue.push(sf);
3230
3231     // Make sure this file is in the target at the end.
3232     this->NewSources.push_back(sf->ResolveFullPath());
3233   }
3234 }
3235
3236 void cmTargetTraceDependencies::FollowName(std::string const& name)
3237 {
3238   // Use lower bound with key comparison to not repeat the search for the
3239   // insert position if the name could not be found (which is the common case).
3240   auto i = this->NameMap.lower_bound(name);
3241   if (i == this->NameMap.end() || i->first != name) {
3242     // Check if we know how to generate this file.
3243     cmSourcesWithOutput sources =
3244       this->LocalGenerator->GetSourcesWithOutput(name);
3245     // If we failed to find a target or source and we have a relative path, it
3246     // might be a valid source if made relative to the current binary
3247     // directory.
3248     if (!sources.Target && !sources.Source &&
3249         !cmSystemTools::FileIsFullPath(name)) {
3250       auto fullname =
3251         cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
3252       fullname = cmSystemTools::CollapseFullPath(
3253         fullname, this->Makefile->GetHomeOutputDirectory());
3254       sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
3255     }
3256     i = this->NameMap.emplace_hint(i, name, sources);
3257   }
3258   if (cmTarget* t = i->second.Target) {
3259     // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
3260     // POST_BUILD command.
3261     this->GeneratorTarget->Target->AddUtility(t->GetName(), false);
3262   }
3263   if (cmSourceFile* sf = i->second.Source) {
3264     // For now only follow the dependency if the source file is not a
3265     // byproduct.  Semantics of byproducts in a non-Ninja context will have to
3266     // be defined first.
3267     if (!i->second.SourceIsByproduct) {
3268       // Record the dependency we just followed.
3269       if (this->CurrentEntry) {
3270         this->CurrentEntry->Depends.push_back(sf);
3271       }
3272       this->QueueSource(sf);
3273     }
3274   }
3275 }
3276
3277 void cmTargetTraceDependencies::FollowNames(
3278   std::vector<std::string> const& names)
3279 {
3280   for (std::string const& name : names) {
3281     this->FollowName(name);
3282   }
3283 }
3284
3285 bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
3286 {
3287   // Dependencies on targets (utilities) are supposed to be named by
3288   // just the target name.  However for compatibility we support
3289   // naming the output file generated by the target (assuming there is
3290   // no output-name property which old code would not have set).  In
3291   // that case the target name will be the file basename of the
3292   // dependency.
3293   std::string util = cmSystemTools::GetFilenameName(dep);
3294   if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
3295     util = cmSystemTools::GetFilenameWithoutLastExtension(util);
3296   }
3297
3298   // Check for a target with this name.
3299   if (cmGeneratorTarget* t =
3300         this->GeneratorTarget->GetLocalGenerator()->FindGeneratorTargetToUse(
3301           util)) {
3302     // If we find the target and the dep was given as a full path,
3303     // then make sure it was not a full path to something else, and
3304     // the fact that the name matched a target was just a coincidence.
3305     if (cmSystemTools::FileIsFullPath(dep)) {
3306       if (t->GetType() >= cmStateEnums::EXECUTABLE &&
3307           t->GetType() <= cmStateEnums::MODULE_LIBRARY) {
3308         // This is really only for compatibility so we do not need to
3309         // worry about configuration names and output names.
3310         std::string tLocation = t->GetLocationForBuild();
3311         tLocation = cmSystemTools::GetFilenamePath(tLocation);
3312         std::string depLocation = cmSystemTools::GetFilenamePath(dep);
3313         depLocation = cmSystemTools::CollapseFullPath(depLocation);
3314         tLocation = cmSystemTools::CollapseFullPath(tLocation);
3315         if (depLocation == tLocation) {
3316           this->GeneratorTarget->Target->AddUtility(util, false);
3317           return true;
3318         }
3319       }
3320     } else {
3321       // The original name of the dependency was not a full path.  It
3322       // must name a target, so add the target-level dependency.
3323       this->GeneratorTarget->Target->AddUtility(util, true);
3324       return true;
3325     }
3326   }
3327
3328   // The dependency does not name a target built in this project.
3329   return false;
3330 }
3331
3332 void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
3333 {
3334   // Collect dependencies referenced by all configurations.
3335   std::set<std::string> depends;
3336   for (std::string const& config :
3337        this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
3338     for (cmCustomCommandGenerator const& ccg :
3339          this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) {
3340       // Collect target-level dependencies referenced in command lines.
3341       for (auto const& util : ccg.GetUtilities()) {
3342         this->GeneratorTarget->Target->AddUtility(util);
3343       }
3344
3345       // Collect file-level dependencies referenced in DEPENDS.
3346       depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
3347     }
3348   }
3349
3350   // Queue file-level dependencies.
3351   for (std::string const& dep : depends) {
3352     if (!this->IsUtility(dep)) {
3353       // The dependency does not name a target and may be a file we
3354       // know how to generate.  Queue it.
3355       this->FollowName(dep);
3356     }
3357   }
3358 }
3359
3360 void cmTargetTraceDependencies::CheckCustomCommands(
3361   const std::vector<cmCustomCommand>& commands)
3362 {
3363   for (cmCustomCommand const& command : commands) {
3364     this->CheckCustomCommand(command);
3365   }
3366 }
3367
3368 void cmGeneratorTarget::TraceDependencies()
3369 {
3370   // CMake-generated targets have no dependencies to trace.  Normally tracing
3371   // would find nothing anyway, but when building CMake itself the "install"
3372   // target command ends up referencing the "cmake" target but we do not
3373   // really want the dependency because "install" depend on "all" anyway.
3374   if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
3375     return;
3376   }
3377
3378   // Use a helper object to trace the dependencies.
3379   cmTargetTraceDependencies tracer(this);
3380   tracer.Trace();
3381 }
3382
3383 std::string cmGeneratorTarget::GetCompilePDBDirectory(
3384   const std::string& config) const
3385 {
3386   if (CompileInfo const* info = this->GetCompileInfo(config)) {
3387     return info->CompilePdbDir;
3388   }
3389   return "";
3390 }
3391
3392 void cmGeneratorTarget::GetAppleArchs(const std::string& config,
3393                                       std::vector<std::string>& archVec) const
3394 {
3395   if (!this->Makefile->IsOn("APPLE")) {
3396     return;
3397   }
3398   cmValue archs = nullptr;
3399   if (!config.empty()) {
3400     std::string defVarName =
3401       cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
3402     archs = this->GetProperty(defVarName);
3403   }
3404   if (!archs) {
3405     archs = this->GetProperty("OSX_ARCHITECTURES");
3406   }
3407   if (archs) {
3408     cmExpandList(*archs, archVec);
3409   }
3410   if (archVec.empty()) {
3411     this->Makefile->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", archVec);
3412   }
3413 }
3414
3415 void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
3416                                                  cmSourceFile const& sf) const
3417 {
3418   cmValue lang = sf.GetProperty("LANGUAGE");
3419   if (!lang) {
3420     return;
3421   }
3422
3423   switch (this->GetPolicyStatusCMP0119()) {
3424     case cmPolicies::WARN:
3425       CM_FALLTHROUGH;
3426     case cmPolicies::OLD:
3427       // The OLD behavior is to not add explicit language flags.
3428       return;
3429     case cmPolicies::REQUIRED_ALWAYS:
3430     case cmPolicies::REQUIRED_IF_USED:
3431     case cmPolicies::NEW:
3432       // The NEW behavior is to add explicit language flags.
3433       break;
3434   }
3435
3436   this->LocalGenerator->AppendFeatureOptions(flags, *lang,
3437                                              "EXPLICIT_LANGUAGE");
3438 }
3439
3440 void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
3441                                                  const std::string& config,
3442                                                  std::string& flags) const
3443 {
3444   std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES");
3445
3446   if (property.empty()) {
3447     switch (this->GetPolicyStatusCMP0104()) {
3448       case cmPolicies::WARN:
3449         if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
3450           this->Makefile->IssueMessage(
3451             MessageType::AUTHOR_WARNING,
3452             cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
3453               "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3454               "\".");
3455         }
3456         CM_FALLTHROUGH;
3457       case cmPolicies::OLD:
3458         break;
3459       default:
3460         this->Makefile->IssueMessage(
3461           MessageType::FATAL_ERROR,
3462           "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3463             "\".");
3464     }
3465   }
3466
3467   // If CUDA_ARCHITECTURES is false we don't add any architectures.
3468   if (cmIsOff(property)) {
3469     return;
3470   }
3471
3472   std::string const& compiler =
3473     this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3474   const bool ipoEnabled = this->IsIPOEnabled("CUDA", config);
3475
3476   // Check for special modes: `all`, `all-major`.
3477   if (property == "all" || property == "all-major") {
3478     if (compiler == "NVIDIA" &&
3479         cmSystemTools::VersionCompare(
3480           cmSystemTools::OP_GREATER_EQUAL,
3481           this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"),
3482           "11.5")) {
3483       flags = cmStrCat(flags, " -arch=", property);
3484       return;
3485     }
3486     if (property == "all") {
3487       property =
3488         *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL");
3489     } else if (property == "all-major") {
3490       property =
3491         *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR");
3492     }
3493   } else if (property == "native") {
3494     cmValue native =
3495       this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_NATIVE");
3496     if (native.IsEmpty()) {
3497       this->Makefile->IssueMessage(
3498         MessageType::FATAL_ERROR,
3499         "CUDA_ARCHITECTURES is set to \"native\", but no GPU was detected.");
3500     }
3501     if (compiler == "NVIDIA" &&
3502         cmSystemTools::VersionCompare(
3503           cmSystemTools::OP_GREATER_EQUAL,
3504           this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"),
3505           "11.6")) {
3506       flags = cmStrCat(flags, " -arch=", property);
3507       return;
3508     }
3509     property = *native;
3510   }
3511
3512   struct CudaArchitecture
3513   {
3514     std::string name;
3515     bool real{ true };
3516     bool virtual_{ true };
3517   };
3518   std::vector<CudaArchitecture> architectures;
3519
3520   {
3521     std::vector<std::string> options;
3522     cmExpandList(property, options);
3523
3524     for (std::string& option : options) {
3525       CudaArchitecture architecture;
3526
3527       // Architecture name is up to the first specifier.
3528       std::size_t pos = option.find_first_of('-');
3529       architecture.name = option.substr(0, pos);
3530
3531       if (pos != std::string::npos) {
3532         cm::string_view specifier{ option.c_str() + pos + 1,
3533                                    option.length() - pos - 1 };
3534
3535         if (specifier == "real") {
3536           architecture.real = true;
3537           architecture.virtual_ = false;
3538         } else if (specifier == "virtual") {
3539           architecture.real = false;
3540           architecture.virtual_ = true;
3541         } else {
3542           this->Makefile->IssueMessage(
3543             MessageType::FATAL_ERROR,
3544             "Unknown CUDA architecture specifier \"" + std::string(specifier) +
3545               "\".");
3546         }
3547       }
3548
3549       architectures.emplace_back(architecture);
3550     }
3551   }
3552
3553   if (compiler == "NVIDIA") {
3554     if (ipoEnabled && compileOrLink == cmBuildStep::Link) {
3555       if (cmValue cudaIPOFlags =
3556             this->Makefile->GetDefinition("CMAKE_CUDA_LINK_OPTIONS_IPO")) {
3557         flags += cudaIPOFlags;
3558       }
3559     }
3560
3561     for (CudaArchitecture& architecture : architectures) {
3562       flags +=
3563         " --generate-code=arch=compute_" + architecture.name + ",code=[";
3564
3565       if (architecture.virtual_) {
3566         flags += "compute_" + architecture.name;
3567
3568         if (architecture.real) {
3569           flags += ",";
3570         }
3571       }
3572
3573       if (ipoEnabled) {
3574         if (compileOrLink == cmBuildStep::Compile) {
3575           flags += "lto_" + architecture.name;
3576         } else if (compileOrLink == cmBuildStep::Link) {
3577           flags += "sm_" + architecture.name;
3578         }
3579       } else if (architecture.real) {
3580         flags += "sm_" + architecture.name;
3581       }
3582
3583       flags += "]";
3584     }
3585   } else if (compiler == "Clang") {
3586     for (CudaArchitecture& architecture : architectures) {
3587       flags += " --cuda-gpu-arch=sm_" + architecture.name;
3588
3589       if (!architecture.real) {
3590         this->Makefile->IssueMessage(
3591           MessageType::WARNING,
3592           "Clang doesn't support disabling CUDA real code generation.");
3593       }
3594
3595       if (!architecture.virtual_) {
3596         flags += " --no-cuda-include-ptx=sm_" + architecture.name;
3597       }
3598     }
3599   }
3600 }
3601
3602 void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const
3603 {
3604   const std::string& property = this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
3605
3606   // If ISPC_TARGET is false we don't add any architectures.
3607   if (cmIsOff(property)) {
3608     return;
3609   }
3610
3611   std::string const& compiler =
3612     this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
3613
3614   if (compiler == "Intel") {
3615     std::vector<std::string> targets;
3616     cmExpandList(property, targets);
3617     if (!targets.empty()) {
3618       flags += cmStrCat(" --target=", cmWrap("", targets, "", ","));
3619     }
3620   }
3621 }
3622
3623 void cmGeneratorTarget::AddHIPArchitectureFlags(std::string& flags) const
3624 {
3625   const std::string& property = this->GetSafeProperty("HIP_ARCHITECTURES");
3626
3627   if (property.empty()) {
3628     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
3629                                  "HIP_ARCHITECTURES is empty for target \"" +
3630                                    this->GetName() + "\".");
3631   }
3632
3633   // If HIP_ARCHITECTURES is false we don't add any architectures.
3634   if (cmIsOff(property)) {
3635     return;
3636   }
3637
3638   std::vector<std::string> options;
3639   cmExpandList(property, options);
3640
3641   for (std::string& option : options) {
3642     flags += " --offload-arch=" + option;
3643   }
3644 }
3645
3646 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
3647 {
3648   std::string const& compiler =
3649     this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3650
3651   if (compiler == "Clang") {
3652     // Pass CUDA toolkit explicitly to Clang.
3653     // Clang's searching for the system CUDA toolkit isn't very good and it's
3654     // expected the user will explicitly pass the toolkit path.
3655     // This also avoids Clang having to search for the toolkit on every
3656     // invocation.
3657     std::string toolkitRoot =
3658       this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
3659
3660     if (!toolkitRoot.empty()) {
3661       flags += " --cuda-path=" +
3662         this->LocalGenerator->ConvertToOutputFormat(toolkitRoot,
3663                                                     cmOutputConverter::SHELL);
3664     }
3665   }
3666 }
3667
3668 //----------------------------------------------------------------------------
3669 std::string cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
3670   std::string const& var, std::string const& lang,
3671   std::string const& config) const
3672 {
3673   if (this->IsIPOEnabled(lang, config)) {
3674     std::string varIPO = var + "_IPO";
3675     if (this->Makefile->IsDefinitionSet(varIPO)) {
3676       return varIPO;
3677     }
3678   }
3679
3680   return var;
3681 }
3682
3683 //----------------------------------------------------------------------------
3684 std::string cmGeneratorTarget::GetCreateRuleVariable(
3685   std::string const& lang, std::string const& config) const
3686 {
3687   switch (this->GetType()) {
3688     case cmStateEnums::STATIC_LIBRARY: {
3689       std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
3690       return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
3691     }
3692     case cmStateEnums::SHARED_LIBRARY:
3693       return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
3694     case cmStateEnums::MODULE_LIBRARY:
3695       return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
3696     case cmStateEnums::EXECUTABLE:
3697       if (this->IsExecutableWithExports()) {
3698         std::string linkExeWithExports =
3699           "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
3700         if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
3701           return linkExeWithExports;
3702         }
3703       }
3704       return "CMAKE_" + lang + "_LINK_EXECUTABLE";
3705     default:
3706       break;
3707   }
3708   return "";
3709 }
3710
3711 namespace {
3712 void processIncludeDirectories(cmGeneratorTarget const* tgt,
3713                                EvaluatedTargetPropertyEntries& entries,
3714                                std::vector<BT<std::string>>& includes,
3715                                std::unordered_set<std::string>& uniqueIncludes,
3716                                bool debugIncludes)
3717 {
3718   for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
3719     cmLinkImplItem const& item = entry.LinkImplItem;
3720     std::string const& targetName = item.AsStr();
3721     bool const fromImported = item.Target && item.Target->IsImported();
3722     bool const checkCMP0027 = item.CheckCMP0027;
3723
3724     std::string usedIncludes;
3725     for (std::string& entryInclude : entry.Values) {
3726       if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
3727         std::ostringstream e;
3728         MessageType messageType = MessageType::FATAL_ERROR;
3729         if (checkCMP0027) {
3730           switch (tgt->GetPolicyStatusCMP0027()) {
3731             case cmPolicies::WARN:
3732               e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
3733               CM_FALLTHROUGH;
3734             case cmPolicies::OLD:
3735               messageType = MessageType::AUTHOR_WARNING;
3736               break;
3737             case cmPolicies::REQUIRED_ALWAYS:
3738             case cmPolicies::REQUIRED_IF_USED:
3739             case cmPolicies::NEW:
3740               break;
3741           }
3742         }
3743         /* clang-format off */
3744         e << "Imported target \"" << targetName << "\" includes "
3745              "non-existent path\n  \"" << entryInclude << "\"\nin its "
3746              "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
3747              "* The path was deleted, renamed, or moved to another "
3748              "location.\n"
3749              "* An install or uninstall procedure did not complete "
3750              "successfully.\n"
3751              "* The installation package was faulty and references files it "
3752              "does not provide.\n";
3753         /* clang-format on */
3754         tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3755         return;
3756       }
3757
3758       if (!cmSystemTools::FileIsFullPath(entryInclude)) {
3759         std::ostringstream e;
3760         bool noMessage = false;
3761         MessageType messageType = MessageType::FATAL_ERROR;
3762         if (!targetName.empty()) {
3763           /* clang-format off */
3764           e << "Target \"" << targetName << "\" contains relative "
3765             "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
3766             "  \"" << entryInclude << "\"";
3767           /* clang-format on */
3768         } else {
3769           switch (tgt->GetPolicyStatusCMP0021()) {
3770             case cmPolicies::WARN: {
3771               e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
3772               messageType = MessageType::AUTHOR_WARNING;
3773             } break;
3774             case cmPolicies::OLD:
3775               noMessage = true;
3776               break;
3777             case cmPolicies::REQUIRED_IF_USED:
3778             case cmPolicies::REQUIRED_ALWAYS:
3779             case cmPolicies::NEW:
3780               // Issue the fatal message.
3781               break;
3782           }
3783           e << "Found relative path while evaluating include directories of "
3784                "\""
3785             << tgt->GetName() << "\":\n  \"" << entryInclude << "\"\n";
3786         }
3787         if (!noMessage) {
3788           tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3789           if (messageType == MessageType::FATAL_ERROR) {
3790             return;
3791           }
3792         }
3793       }
3794
3795       if (!cmIsOff(entryInclude)) {
3796         cmSystemTools::ConvertToUnixSlashes(entryInclude);
3797       }
3798
3799       if (uniqueIncludes.insert(entryInclude).second) {
3800         includes.emplace_back(entryInclude, entry.Backtrace);
3801         if (debugIncludes) {
3802           usedIncludes += " * " + entryInclude + "\n";
3803         }
3804       }
3805     }
3806     if (!usedIncludes.empty()) {
3807       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3808         MessageType::LOG,
3809         std::string("Used includes for target ") + tgt->GetName() + ":\n" +
3810           usedIncludes,
3811         entry.Backtrace);
3812     }
3813   }
3814 }
3815 }
3816
3817 std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
3818   const std::string& config, const std::string& lang) const
3819 {
3820   std::vector<BT<std::string>> includes;
3821   std::unordered_set<std::string> uniqueIncludes;
3822
3823   cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
3824                                              nullptr, nullptr);
3825
3826   std::vector<std::string> debugProperties;
3827   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3828                                    debugProperties);
3829
3830   bool debugIncludes = !this->DebugIncludesDone &&
3831     cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
3832
3833   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3834     this->DebugIncludesDone = true;
3835   }
3836
3837   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3838     this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
3839
3840   if (lang == "Swift") {
3841     AddLangSpecificImplicitIncludeDirectories(
3842       this, lang, config, "Swift_MODULE_DIRECTORY",
3843       IncludeDirectoryFallBack::BINARY, entries);
3844   }
3845
3846   if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
3847
3848     const std::string propertyName = "ISPC_HEADER_DIRECTORY";
3849
3850     // If this target has ISPC sources make sure to add the header
3851     // directory to other compilation units
3852     if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
3853       if (cmValue val = this->GetProperty(propertyName)) {
3854         includes.emplace_back(*val);
3855       } else {
3856         includes.emplace_back(this->GetObjectDirectory(config));
3857       }
3858     }
3859
3860     AddLangSpecificImplicitIncludeDirectories(
3861       this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
3862       entries);
3863   }
3864
3865   AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
3866                       &dagChecker, entries, IncludeRuntimeInterface::Yes);
3867
3868   if (this->Makefile->IsOn("APPLE")) {
3869     if (cmLinkImplementationLibraries const* impl =
3870           this->GetLinkImplementationLibraries(config,
3871                                                LinkInterfaceFor::Usage)) {
3872       for (cmLinkImplItem const& lib : impl->Libraries) {
3873         std::string libDir = cmSystemTools::CollapseFullPath(
3874           lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
3875
3876         static cmsys::RegularExpression frameworkCheck(
3877           "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
3878         if (!frameworkCheck.find(libDir)) {
3879           continue;
3880         }
3881
3882         libDir = frameworkCheck.match(1);
3883
3884         EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace());
3885         ee.Values.emplace_back(std::move(libDir));
3886         entries.Entries.emplace_back(std::move(ee));
3887       }
3888     }
3889   }
3890
3891   processIncludeDirectories(this, entries, includes, uniqueIncludes,
3892                             debugIncludes);
3893
3894   return includes;
3895 }
3896
3897 enum class OptionsParse
3898 {
3899   None,
3900   Shell
3901 };
3902
3903 namespace {
3904 const auto DL_BEGIN = "<DEVICE_LINK>"_s;
3905 const auto DL_END = "</DEVICE_LINK>"_s;
3906
3907 void processOptions(cmGeneratorTarget const* tgt,
3908                     EvaluatedTargetPropertyEntries const& entries,
3909                     std::vector<BT<std::string>>& options,
3910                     std::unordered_set<std::string>& uniqueOptions,
3911                     bool debugOptions, const char* logName, OptionsParse parse,
3912                     bool processDeviceOptions = false)
3913 {
3914   bool splitOption = !processDeviceOptions;
3915   for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
3916     std::string usedOptions;
3917     for (std::string const& opt : entry.Values) {
3918       if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
3919         options.emplace_back(opt, entry.Backtrace);
3920         splitOption = opt == DL_BEGIN;
3921         continue;
3922       }
3923
3924       if (uniqueOptions.insert(opt).second) {
3925         if (parse == OptionsParse::Shell &&
3926             cmHasLiteralPrefix(opt, "SHELL:")) {
3927           if (splitOption) {
3928             std::vector<std::string> tmp;
3929             cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
3930             for (std::string& o : tmp) {
3931               options.emplace_back(std::move(o), entry.Backtrace);
3932             }
3933           } else {
3934             options.emplace_back(std::string(opt.c_str() + 6),
3935                                  entry.Backtrace);
3936           }
3937         } else {
3938           options.emplace_back(opt, entry.Backtrace);
3939         }
3940         if (debugOptions) {
3941           usedOptions += " * " + opt + "\n";
3942         }
3943       }
3944     }
3945     if (!usedOptions.empty()) {
3946       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3947         MessageType::LOG,
3948         std::string("Used ") + logName + std::string(" for target ") +
3949           tgt->GetName() + ":\n" + usedOptions,
3950         entry.Backtrace);
3951     }
3952   }
3953 }
3954
3955 std::vector<BT<std::string>> wrapOptions(
3956   std::vector<std::string>& options, const cmListFileBacktrace& bt,
3957   const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
3958   bool concatFlagAndArgs)
3959 {
3960   std::vector<BT<std::string>> result;
3961
3962   if (options.empty()) {
3963     return result;
3964   }
3965
3966   if (wrapperFlag.empty()) {
3967     // nothing specified, insert elements as is
3968     result.reserve(options.size());
3969     for (std::string& o : options) {
3970       result.emplace_back(std::move(o), bt);
3971     }
3972     return result;
3973   }
3974
3975   for (std::vector<std::string>::size_type index = 0; index < options.size();
3976        index++) {
3977     if (cmHasLiteralPrefix(options[index], "LINKER:")) {
3978       // LINKER wrapper specified, insert elements as is
3979       result.emplace_back(std::move(options[index]), bt);
3980       continue;
3981     }
3982     if (cmHasLiteralPrefix(options[index], "-Wl,")) {
3983       // replace option by LINKER wrapper
3984       result.emplace_back(options[index].replace(0, 4, "LINKER:"), bt);
3985       continue;
3986     }
3987     if (cmHasLiteralPrefix(options[index], "-Xlinker=")) {
3988       // replace option by LINKER wrapper
3989       result.emplace_back(options[index].replace(0, 9, "LINKER:"), bt);
3990       continue;
3991     }
3992     if (options[index] == "-Xlinker") {
3993       // replace option by LINKER wrapper
3994       if (index + 1 < options.size()) {
3995         result.emplace_back("LINKER:" + options[++index], bt);
3996       } else {
3997         result.emplace_back(std::move(options[index]), bt);
3998       }
3999       continue;
4000     }
4001
4002     // collect all options which must be transformed
4003     std::vector<std::string> opts;
4004     while (index < options.size()) {
4005       if (!cmHasLiteralPrefix(options[index], "LINKER:") &&
4006           !cmHasLiteralPrefix(options[index], "-Wl,") &&
4007           !cmHasLiteralPrefix(options[index], "-Xlinker")) {
4008         opts.emplace_back(std::move(options[index++]));
4009       } else {
4010         --index;
4011         break;
4012       }
4013     }
4014     if (opts.empty()) {
4015       continue;
4016     }
4017
4018     if (!wrapperSep.empty()) {
4019       if (concatFlagAndArgs) {
4020         // insert flag elements except last one
4021         for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
4022           result.emplace_back(*i, bt);
4023         }
4024         // concatenate last flag element and all list values
4025         // in one option
4026         result.emplace_back(wrapperFlag.back() + cmJoin(opts, wrapperSep), bt);
4027       } else {
4028         for (std::string const& i : wrapperFlag) {
4029           result.emplace_back(i, bt);
4030         }
4031         // concatenate all list values in one option
4032         result.emplace_back(cmJoin(opts, wrapperSep), bt);
4033       }
4034     } else {
4035       // prefix each element of list with wrapper
4036       if (concatFlagAndArgs) {
4037         std::transform(opts.begin(), opts.end(), opts.begin(),
4038                        [&wrapperFlag](std::string const& o) -> std::string {
4039                          return wrapperFlag.back() + o;
4040                        });
4041       }
4042       for (std::string& o : opts) {
4043         for (auto i = wrapperFlag.begin(),
4044                   e = concatFlagAndArgs ? wrapperFlag.end() - 1
4045                                         : wrapperFlag.end();
4046              i != e; ++i) {
4047           result.emplace_back(*i, bt);
4048         }
4049         result.emplace_back(std::move(o), bt);
4050       }
4051     }
4052   }
4053   return result;
4054 }
4055 }
4056
4057 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
4058                                           const std::string& config,
4059                                           const std::string& language) const
4060 {
4061   std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language);
4062   result.reserve(tmp.size());
4063   for (BT<std::string>& v : tmp) {
4064     result.emplace_back(std::move(v.Value));
4065   }
4066 }
4067
4068 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
4069   std::string const& config, std::string const& language) const
4070 {
4071   std::vector<BT<std::string>> result;
4072   std::unordered_set<std::string> uniqueOptions;
4073
4074   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
4075                                              nullptr);
4076
4077   std::vector<std::string> debugProperties;
4078   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4079                                    debugProperties);
4080
4081   bool debugOptions = !this->DebugCompileOptionsDone &&
4082     cm::contains(debugProperties, "COMPILE_OPTIONS");
4083
4084   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4085     this->DebugCompileOptionsDone = true;
4086   }
4087
4088   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4089     this, config, language, &dagChecker, this->CompileOptionsEntries);
4090
4091   AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language,
4092                       &dagChecker, entries, IncludeRuntimeInterface::Yes);
4093
4094   processOptions(this, entries, result, uniqueOptions, debugOptions,
4095                  "compile options", OptionsParse::Shell);
4096
4097   return result;
4098 }
4099
4100 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
4101                                            const std::string& config) const
4102 {
4103   std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config);
4104   result.reserve(tmp.size());
4105   for (BT<std::string>& v : tmp) {
4106     result.emplace_back(std::move(v.Value));
4107   }
4108 }
4109
4110 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
4111   std::string const& config) const
4112 {
4113   std::vector<BT<std::string>> result;
4114   std::unordered_set<std::string> uniqueFeatures;
4115
4116   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
4117                                              nullptr);
4118
4119   std::vector<std::string> debugProperties;
4120   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4121                                    debugProperties);
4122
4123   bool debugFeatures = !this->DebugCompileFeaturesDone &&
4124     cm::contains(debugProperties, "COMPILE_FEATURES");
4125
4126   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4127     this->DebugCompileFeaturesDone = true;
4128   }
4129
4130   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4131     this, config, std::string(), &dagChecker, this->CompileFeaturesEntries);
4132
4133   AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES",
4134                       std::string(), &dagChecker, entries,
4135                       IncludeRuntimeInterface::Yes);
4136
4137   processOptions(this, entries, result, uniqueFeatures, debugFeatures,
4138                  "compile features", OptionsParse::None);
4139
4140   return result;
4141 }
4142
4143 void cmGeneratorTarget::GetCompileDefinitions(
4144   std::vector<std::string>& result, const std::string& config,
4145   const std::string& language) const
4146 {
4147   std::vector<BT<std::string>> tmp =
4148     this->GetCompileDefinitions(config, language);
4149   result.reserve(tmp.size());
4150   for (BT<std::string>& v : tmp) {
4151     result.emplace_back(std::move(v.Value));
4152   }
4153 }
4154
4155 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
4156   std::string const& config, std::string const& language) const
4157 {
4158   std::vector<BT<std::string>> list;
4159   std::unordered_set<std::string> uniqueOptions;
4160
4161   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
4162                                              nullptr, nullptr);
4163
4164   std::vector<std::string> debugProperties;
4165   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4166                                    debugProperties);
4167
4168   bool debugDefines = !this->DebugCompileDefinitionsDone &&
4169     cm::contains(debugProperties, "COMPILE_DEFINITIONS");
4170
4171   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4172     this->DebugCompileDefinitionsDone = true;
4173   }
4174
4175   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4176     this, config, language, &dagChecker, this->CompileDefinitionsEntries);
4177
4178   AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language,
4179                       &dagChecker, entries, IncludeRuntimeInterface::Yes);
4180
4181   if (!config.empty()) {
4182     std::string configPropName =
4183       "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
4184     cmValue configProp = this->GetProperty(configPropName);
4185     if (configProp) {
4186       switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
4187         case cmPolicies::WARN: {
4188           this->LocalGenerator->IssueMessage(
4189             MessageType::AUTHOR_WARNING,
4190             cmPolicies::GetPolicyWarning(cmPolicies::CMP0043));
4191           CM_FALLTHROUGH;
4192         }
4193         case cmPolicies::OLD: {
4194           std::unique_ptr<TargetPropertyEntry> entry =
4195             CreateTargetPropertyEntry(*configProp);
4196           entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4197             this, config, language, &dagChecker, *entry));
4198         } break;
4199         case cmPolicies::NEW:
4200         case cmPolicies::REQUIRED_ALWAYS:
4201         case cmPolicies::REQUIRED_IF_USED:
4202           break;
4203       }
4204     }
4205   }
4206
4207   processOptions(this, entries, list, uniqueOptions, debugDefines,
4208                  "compile definitions", OptionsParse::None);
4209
4210   return list;
4211 }
4212
4213 std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
4214   const std::string& config, const std::string& language) const
4215 {
4216   std::unordered_set<std::string> uniqueOptions;
4217
4218   cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
4219                                              nullptr, nullptr);
4220
4221   std::vector<std::string> debugProperties;
4222   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4223                                    debugProperties);
4224
4225   bool debugDefines = !this->DebugPrecompileHeadersDone &&
4226     std::find(debugProperties.begin(), debugProperties.end(),
4227               "PRECOMPILE_HEADERS") != debugProperties.end();
4228
4229   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4230     this->DebugPrecompileHeadersDone = true;
4231   }
4232
4233   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4234     this, config, language, &dagChecker, this->PrecompileHeadersEntries);
4235
4236   AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language,
4237                       &dagChecker, entries, IncludeRuntimeInterface::Yes);
4238
4239   std::vector<BT<std::string>> list;
4240   processOptions(this, entries, list, uniqueOptions, debugDefines,
4241                  "precompile headers", OptionsParse::None);
4242
4243   return list;
4244 }
4245
4246 std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
4247                                             const std::string& language,
4248                                             const std::string& arch) const
4249 {
4250   if (language != "C" && language != "CXX" && language != "OBJC" &&
4251       language != "OBJCXX") {
4252     return std::string();
4253   }
4254
4255   if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
4256     return std::string();
4257   }
4258   const cmGeneratorTarget* generatorTarget = this;
4259   cmValue pchReuseFrom =
4260     generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4261
4262   const auto inserted =
4263     this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
4264   if (inserted.second) {
4265     const std::vector<BT<std::string>> headers =
4266       this->GetPrecompileHeaders(config, language);
4267     if (headers.empty() && !pchReuseFrom) {
4268       return std::string();
4269     }
4270     std::string& filename = inserted.first->second;
4271
4272     if (pchReuseFrom) {
4273       generatorTarget =
4274         this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4275     }
4276
4277     filename = cmStrCat(
4278       generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
4279
4280     const std::map<std::string, std::string> languageToExtension = {
4281       { "C", ".h" },
4282       { "CXX", ".hxx" },
4283       { "OBJC", ".objc.h" },
4284       { "OBJCXX", ".objcxx.hxx" }
4285     };
4286
4287     filename =
4288       cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
4289
4290     if (this->GetGlobalGenerator()->IsMultiConfig()) {
4291       filename = cmStrCat(filename, "/", config);
4292     }
4293
4294     filename =
4295       cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch),
4296                languageToExtension.at(language));
4297
4298     const std::string filename_tmp = cmStrCat(filename, ".tmp");
4299     if (!pchReuseFrom) {
4300       cmValue pchPrologue =
4301         this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
4302       cmValue pchEpilogue =
4303         this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
4304
4305       std::string firstHeaderOnDisk;
4306       {
4307         cmGeneratedFileStream file(
4308           filename_tmp, false,
4309           this->GetGlobalGenerator()->GetMakefileEncoding());
4310         file << "/* generated by CMake */\n\n";
4311         if (pchPrologue) {
4312           file << *pchPrologue << "\n";
4313         }
4314         if (this->GetGlobalGenerator()->IsXcode()) {
4315           file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4316         }
4317         if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4318           file << "#ifdef __cplusplus\n";
4319         }
4320         for (auto const& header_bt : headers) {
4321           if (header_bt.Value.empty()) {
4322             continue;
4323           }
4324           if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
4325             file << "#include " << header_bt.Value << "\n";
4326           } else {
4327             file << "#include \"" << header_bt.Value << "\"\n";
4328           }
4329
4330           if (cmSystemTools::FileExists(header_bt.Value) &&
4331               firstHeaderOnDisk.empty()) {
4332             firstHeaderOnDisk = header_bt.Value;
4333           }
4334         }
4335         if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4336           file << "#endif // __cplusplus\n";
4337         }
4338         if (this->GetGlobalGenerator()->IsXcode()) {
4339           file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4340         }
4341         if (pchEpilogue) {
4342           file << *pchEpilogue << "\n";
4343         }
4344       }
4345
4346       if (!firstHeaderOnDisk.empty()) {
4347         cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
4348       }
4349
4350       cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
4351     }
4352   }
4353   return inserted.first->second;
4354 }
4355
4356 std::string cmGeneratorTarget::GetPchSource(const std::string& config,
4357                                             const std::string& language,
4358                                             const std::string& arch) const
4359 {
4360   if (language != "C" && language != "CXX" && language != "OBJC" &&
4361       language != "OBJCXX") {
4362     return std::string();
4363   }
4364   const auto inserted =
4365     this->PchSources.insert(std::make_pair(language + config + arch, ""));
4366   if (inserted.second) {
4367     const std::string pchHeader = this->GetPchHeader(config, language, arch);
4368     if (pchHeader.empty()) {
4369       return std::string();
4370     }
4371     std::string& filename = inserted.first->second;
4372
4373     const cmGeneratorTarget* generatorTarget = this;
4374     cmValue pchReuseFrom =
4375       generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4376     if (pchReuseFrom) {
4377       generatorTarget =
4378         this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4379     }
4380
4381     filename =
4382       cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(),
4383                "/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch");
4384
4385     // For GCC the source extension will be transformed into .h[xx].gch
4386     if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
4387       const std::map<std::string, std::string> languageToExtension = {
4388         { "C", ".h.c" },
4389         { "CXX", ".hxx.cxx" },
4390         { "OBJC", ".objc.h.m" },
4391         { "OBJCXX", ".objcxx.hxx.mm" }
4392       };
4393
4394       filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
4395                           languageToExtension.at(language));
4396     } else {
4397       const std::map<std::string, std::string> languageToExtension = {
4398         { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
4399       };
4400
4401       filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
4402                           languageToExtension.at(language));
4403     }
4404
4405     const std::string filename_tmp = cmStrCat(filename, ".tmp");
4406     if (!pchReuseFrom) {
4407       {
4408         cmGeneratedFileStream file(filename_tmp);
4409         file << "/* generated by CMake */\n";
4410       }
4411       cmFileTimes::Copy(pchHeader, filename_tmp);
4412       cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
4413     }
4414   }
4415   return inserted.first->second;
4416 }
4417
4418 std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
4419                                                 const std::string& language,
4420                                                 const std::string& arch)
4421 {
4422   if (language != "C" && language != "CXX" && language != "OBJC" &&
4423       language != "OBJCXX") {
4424     return std::string();
4425   }
4426   const auto inserted =
4427     this->PchObjectFiles.insert(std::make_pair(language + config + arch, ""));
4428   if (inserted.second) {
4429     const std::string pchSource = this->GetPchSource(config, language, arch);
4430     if (pchSource.empty()) {
4431       return std::string();
4432     }
4433     std::string& filename = inserted.first->second;
4434
4435     auto* pchSf = this->Makefile->GetOrCreateSource(
4436       pchSource, false, cmSourceFileLocationKind::Known);
4437
4438     filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
4439     if (this->GetGlobalGenerator()->IsMultiConfig()) {
4440       cmSystemTools::ReplaceString(
4441         filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
4442     }
4443   }
4444   return inserted.first->second;
4445 }
4446
4447 std::string cmGeneratorTarget::GetPchFile(const std::string& config,
4448                                           const std::string& language,
4449                                           const std::string& arch)
4450 {
4451   const auto inserted =
4452     this->PchFiles.insert(std::make_pair(language + config + arch, ""));
4453   if (inserted.second) {
4454     std::string& pchFile = inserted.first->second;
4455
4456     const std::string pchExtension =
4457       this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
4458
4459     if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
4460       auto replaceExtension = [](const std::string& str,
4461                                  const std::string& ext) -> std::string {
4462         auto dot_pos = str.rfind('.');
4463         std::string result;
4464         if (dot_pos != std::string::npos) {
4465           result = str.substr(0, dot_pos);
4466         }
4467         result += ext;
4468         return result;
4469       };
4470
4471       cmGeneratorTarget* generatorTarget = this;
4472       cmValue pchReuseFrom =
4473         generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4474       if (pchReuseFrom) {
4475         generatorTarget =
4476           this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4477       }
4478
4479       const std::string pchFileObject =
4480         generatorTarget->GetPchFileObject(config, language, arch);
4481       if (!pchExtension.empty()) {
4482         pchFile = replaceExtension(pchFileObject, pchExtension);
4483       }
4484     } else {
4485       pchFile = this->GetPchHeader(config, language, arch);
4486       pchFile += pchExtension;
4487     }
4488   }
4489   return inserted.first->second;
4490 }
4491
4492 std::string cmGeneratorTarget::GetPchCreateCompileOptions(
4493   const std::string& config, const std::string& language,
4494   const std::string& arch)
4495 {
4496   const auto inserted = this->PchCreateCompileOptions.insert(
4497     std::make_pair(language + config + arch, ""));
4498   if (inserted.second) {
4499     std::string& createOptionList = inserted.first->second;
4500
4501     if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4502       createOptionList = this->Makefile->GetSafeDefinition(
4503         cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
4504     }
4505
4506     if (this->GetPropertyAsBool("PCH_INSTANTIATE_TEMPLATES")) {
4507       std::string varName = cmStrCat(
4508         "CMAKE_", language, "_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH");
4509       std::string instantiateOption =
4510         this->Makefile->GetSafeDefinition(varName);
4511       if (!instantiateOption.empty()) {
4512         createOptionList = cmStrCat(createOptionList, ";", instantiateOption);
4513       }
4514     }
4515
4516     const std::string createOptVar =
4517       cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
4518
4519     createOptionList = cmStrCat(
4520       createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar));
4521
4522     const std::string pchHeader = this->GetPchHeader(config, language, arch);
4523     const std::string pchFile = this->GetPchFile(config, language, arch);
4524
4525     cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader);
4526     cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile);
4527   }
4528   return inserted.first->second;
4529 }
4530
4531 std::string cmGeneratorTarget::GetPchUseCompileOptions(
4532   const std::string& config, const std::string& language,
4533   const std::string& arch)
4534 {
4535   const auto inserted = this->PchUseCompileOptions.insert(
4536     std::make_pair(language + config + arch, ""));
4537   if (inserted.second) {
4538     std::string& useOptionList = inserted.first->second;
4539
4540     if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4541       useOptionList = this->Makefile->GetSafeDefinition(
4542         cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
4543     }
4544
4545     const std::string useOptVar =
4546       cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH");
4547
4548     std::string const& useOptionListProperty =
4549       this->GetSafeProperty(useOptVar);
4550
4551     useOptionList = cmStrCat(
4552       useOptionList, ";",
4553       useOptionListProperty.empty()
4554         ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar))
4555         : useOptionListProperty);
4556
4557     const std::string pchHeader = this->GetPchHeader(config, language, arch);
4558     const std::string pchFile = this->GetPchFile(config, language, arch);
4559
4560     cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
4561     cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
4562   }
4563   return inserted.first->second;
4564 }
4565
4566 void cmGeneratorTarget::AddSourceFileToUnityBatch(
4567   const std::string& sourceFilename)
4568 {
4569   this->UnityBatchedSourceFiles.insert(sourceFilename);
4570 }
4571
4572 bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
4573   const std::string& sourceFilename) const
4574 {
4575   if (!this->GetPropertyAsBool("UNITY_BUILD")) {
4576     return false;
4577   }
4578
4579   return this->UnityBatchedSourceFiles.find(sourceFilename) !=
4580     this->UnityBatchedSourceFiles.end();
4581 }
4582
4583 void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
4584                                        const std::string& config,
4585                                        const std::string& language) const
4586 {
4587   if (this->IsDeviceLink() &&
4588       this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
4589     // link options are not propagated to the device link step
4590     return;
4591   }
4592
4593   std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
4594   result.reserve(tmp.size());
4595   for (BT<std::string>& v : tmp) {
4596     result.emplace_back(std::move(v.Value));
4597   }
4598 }
4599
4600 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
4601   std::string const& config, std::string const& language) const
4602 {
4603   std::vector<BT<std::string>> result;
4604   std::unordered_set<std::string> uniqueOptions;
4605
4606   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
4607                                              nullptr);
4608
4609   std::vector<std::string> debugProperties;
4610   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4611                                    debugProperties);
4612
4613   bool debugOptions = !this->DebugLinkOptionsDone &&
4614     cm::contains(debugProperties, "LINK_OPTIONS");
4615
4616   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4617     this->DebugLinkOptionsDone = true;
4618   }
4619
4620   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4621     this, config, language, &dagChecker, this->LinkOptionsEntries);
4622
4623   AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
4624                       &dagChecker, entries, IncludeRuntimeInterface::Yes,
4625                       this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4626                         ? LinkInterfaceFor::Link
4627                         : LinkInterfaceFor::Usage);
4628
4629   processOptions(this, entries, result, uniqueOptions, debugOptions,
4630                  "link options", OptionsParse::Shell, this->IsDeviceLink());
4631
4632   if (this->IsDeviceLink()) {
4633     // wrap host link options
4634     const std::string wrapper(this->Makefile->GetSafeDefinition(
4635       "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
4636     std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4637     const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4638       "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
4639     bool concatFlagAndArgs = true;
4640     if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4641       concatFlagAndArgs = false;
4642       wrapperFlag.pop_back();
4643     }
4644
4645     auto it = result.begin();
4646     while (it != result.end()) {
4647       if (it->Value == DL_BEGIN) {
4648         // device link options, no treatment
4649         it = result.erase(it);
4650         it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
4651           return item.Value == DL_END;
4652         });
4653         if (it != result.end()) {
4654           it = result.erase(it);
4655         }
4656       } else {
4657         // host link options must be wrapped
4658         std::vector<std::string> options;
4659         cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
4660         auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
4661                                        wrapperSep, concatFlagAndArgs);
4662         it = result.erase(it);
4663         // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
4664         // C++11 standard: 'std::vector::insert()' do not returns an iterator,
4665         // so need to recompute the iterator after insertion.
4666         if (it == result.end()) {
4667           cm::append(result, hostOptions);
4668           it = result.end();
4669         } else {
4670           auto index = it - result.begin();
4671           result.insert(it, hostOptions.begin(), hostOptions.end());
4672           it = result.begin() + index + hostOptions.size();
4673         }
4674       }
4675     }
4676   }
4677
4678   // Last step: replace "LINKER:" prefixed elements by
4679   // actual linker wrapper
4680   return this->ResolveLinkerWrapper(result, language);
4681 }
4682
4683 std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper(
4684   std::vector<BT<std::string>>& result, const std::string& language,
4685   bool joinItems) const
4686 {
4687   // replace "LINKER:" prefixed elements by actual linker wrapper
4688   const std::string wrapper(this->Makefile->GetSafeDefinition(
4689     "CMAKE_" + language +
4690     (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
4691                           : "_LINKER_WRAPPER_FLAG")));
4692   std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4693   const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4694     "CMAKE_" + language +
4695     (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
4696                           : "_LINKER_WRAPPER_FLAG_SEP")));
4697   bool concatFlagAndArgs = true;
4698   if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4699     concatFlagAndArgs = false;
4700     wrapperFlag.pop_back();
4701   }
4702
4703   const std::string LINKER{ "LINKER:" };
4704   const std::string SHELL{ "SHELL:" };
4705   const std::string LINKER_SHELL = LINKER + SHELL;
4706
4707   std::vector<BT<std::string>>::iterator entry;
4708   while ((entry = std::find_if(result.begin(), result.end(),
4709                                [&LINKER](BT<std::string> const& item) -> bool {
4710                                  return item.Value.compare(0, LINKER.length(),
4711                                                            LINKER) == 0;
4712                                })) != result.end()) {
4713     std::string value = std::move(entry->Value);
4714     cmListFileBacktrace bt = std::move(entry->Backtrace);
4715     entry = result.erase(entry);
4716
4717     std::vector<std::string> linkerOptions;
4718     if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
4719       cmSystemTools::ParseUnixCommandLine(
4720         value.c_str() + LINKER_SHELL.length(), linkerOptions);
4721     } else {
4722       linkerOptions = cmTokenize(value.substr(LINKER.length()), ",");
4723     }
4724
4725     if (linkerOptions.empty() ||
4726         (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
4727       continue;
4728     }
4729
4730     // for now, raise an error if prefix SHELL: is part of arguments
4731     if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
4732                      [&SHELL](const std::string& item) -> bool {
4733                        return item.find(SHELL) != std::string::npos;
4734                      }) != linkerOptions.end()) {
4735       this->LocalGenerator->GetCMakeInstance()->IssueMessage(
4736         MessageType::FATAL_ERROR,
4737         "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
4738         this->GetBacktrace());
4739       return result;
4740     }
4741
4742     std::vector<BT<std::string>> options = wrapOptions(
4743       linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
4744     if (joinItems) {
4745       result.insert(entry,
4746                     cmJoin(cmRange<decltype(options.cbegin())>(
4747                              options.cbegin(), options.cend()),
4748                            " "_s));
4749     } else {
4750       result.insert(entry, options.begin(), options.end());
4751     }
4752   }
4753   return result;
4754 }
4755
4756 void cmGeneratorTarget::GetStaticLibraryLinkOptions(
4757   std::vector<std::string>& result, const std::string& config,
4758   const std::string& language) const
4759 {
4760   std::vector<BT<std::string>> tmp =
4761     this->GetStaticLibraryLinkOptions(config, language);
4762   result.reserve(tmp.size());
4763   for (BT<std::string>& v : tmp) {
4764     result.emplace_back(std::move(v.Value));
4765   }
4766 }
4767
4768 std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
4769   std::string const& config, std::string const& language) const
4770 {
4771   std::vector<BT<std::string>> result;
4772   std::unordered_set<std::string> uniqueOptions;
4773
4774   cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
4775                                              nullptr, nullptr);
4776
4777   EvaluatedTargetPropertyEntries entries;
4778   if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
4779     std::vector<std::string> options = cmExpandedList(*linkOptions);
4780     for (const auto& option : options) {
4781       std::unique_ptr<TargetPropertyEntry> entry =
4782         CreateTargetPropertyEntry(option);
4783       entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4784         this, config, language, &dagChecker, *entry));
4785     }
4786   }
4787   processOptions(this, entries, result, uniqueOptions, false,
4788                  "static library link options", OptionsParse::Shell);
4789
4790   return result;
4791 }
4792
4793 namespace {
4794 void processLinkDirectories(cmGeneratorTarget const* tgt,
4795                             EvaluatedTargetPropertyEntries& entries,
4796                             std::vector<BT<std::string>>& directories,
4797                             std::unordered_set<std::string>& uniqueDirectories,
4798                             bool debugDirectories)
4799 {
4800   for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
4801     cmLinkImplItem const& item = entry.LinkImplItem;
4802     std::string const& targetName = item.AsStr();
4803
4804     std::string usedDirectories;
4805     for (std::string& entryDirectory : entry.Values) {
4806       if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
4807         std::ostringstream e;
4808         bool noMessage = false;
4809         MessageType messageType = MessageType::FATAL_ERROR;
4810         if (!targetName.empty()) {
4811           /* clang-format off */
4812           e << "Target \"" << targetName << "\" contains relative "
4813             "path in its INTERFACE_LINK_DIRECTORIES:\n"
4814             "  \"" << entryDirectory << "\"";
4815           /* clang-format on */
4816         } else {
4817           switch (tgt->GetPolicyStatusCMP0081()) {
4818             case cmPolicies::WARN: {
4819               e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
4820               messageType = MessageType::AUTHOR_WARNING;
4821             } break;
4822             case cmPolicies::OLD:
4823               noMessage = true;
4824               break;
4825             case cmPolicies::REQUIRED_IF_USED:
4826             case cmPolicies::REQUIRED_ALWAYS:
4827             case cmPolicies::NEW:
4828               // Issue the fatal message.
4829               break;
4830           }
4831           e << "Found relative path while evaluating link directories of "
4832                "\""
4833             << tgt->GetName() << "\":\n  \"" << entryDirectory << "\"\n";
4834         }
4835         if (!noMessage) {
4836           tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
4837           if (messageType == MessageType::FATAL_ERROR) {
4838             return;
4839           }
4840         }
4841       }
4842
4843       // Sanitize the path the same way the link_directories command does
4844       // in case projects set the LINK_DIRECTORIES property directly.
4845       cmSystemTools::ConvertToUnixSlashes(entryDirectory);
4846       if (uniqueDirectories.insert(entryDirectory).second) {
4847         directories.emplace_back(entryDirectory, entry.Backtrace);
4848         if (debugDirectories) {
4849           usedDirectories += " * " + entryDirectory + "\n";
4850         }
4851       }
4852     }
4853     if (!usedDirectories.empty()) {
4854       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
4855         MessageType::LOG,
4856         std::string("Used link directories for target ") + tgt->GetName() +
4857           ":\n" + usedDirectories,
4858         entry.Backtrace);
4859     }
4860   }
4861 }
4862 }
4863
4864 void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
4865                                            const std::string& config,
4866                                            const std::string& language) const
4867 {
4868   std::vector<BT<std::string>> tmp =
4869     this->GetLinkDirectories(config, language);
4870   result.reserve(tmp.size());
4871   for (BT<std::string>& v : tmp) {
4872     result.emplace_back(std::move(v.Value));
4873   }
4874 }
4875
4876 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
4877   std::string const& config, std::string const& language) const
4878 {
4879   std::vector<BT<std::string>> result;
4880   std::unordered_set<std::string> uniqueDirectories;
4881
4882   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
4883                                              nullptr);
4884
4885   std::vector<std::string> debugProperties;
4886   this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4887                                    debugProperties);
4888
4889   bool debugDirectories = !this->DebugLinkDirectoriesDone &&
4890     cm::contains(debugProperties, "LINK_DIRECTORIES");
4891
4892   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4893     this->DebugLinkDirectoriesDone = true;
4894   }
4895
4896   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4897     this, config, language, &dagChecker, this->LinkDirectoriesEntries);
4898
4899   AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
4900                       &dagChecker, entries, IncludeRuntimeInterface::Yes,
4901                       this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4902                         ? LinkInterfaceFor::Link
4903                         : LinkInterfaceFor::Usage);
4904
4905   processLinkDirectories(this, entries, result, uniqueDirectories,
4906                          debugDirectories);
4907
4908   return result;
4909 }
4910
4911 void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
4912                                        const std::string& config,
4913                                        const std::string& language) const
4914 {
4915   std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language);
4916   result.reserve(tmp.size());
4917   for (BT<std::string>& v : tmp) {
4918     result.emplace_back(std::move(v.Value));
4919   }
4920 }
4921
4922 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
4923   std::string const& config, std::string const& language) const
4924 {
4925   std::vector<BT<std::string>> result;
4926   std::unordered_set<std::string> uniqueOptions;
4927   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
4928                                              nullptr);
4929
4930   EvaluatedTargetPropertyEntries entries;
4931   if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
4932     std::vector<std::string> depends = cmExpandedList(*linkDepends);
4933     for (const auto& depend : depends) {
4934       std::unique_ptr<TargetPropertyEntry> entry =
4935         CreateTargetPropertyEntry(depend);
4936       entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4937         this, config, language, &dagChecker, *entry));
4938     }
4939   }
4940   AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
4941                       &dagChecker, entries, IncludeRuntimeInterface::Yes,
4942                       this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4943                         ? LinkInterfaceFor::Link
4944                         : LinkInterfaceFor::Usage);
4945
4946   processOptions(this, entries, result, uniqueOptions, false, "link depends",
4947                  OptionsParse::None);
4948
4949   return result;
4950 }
4951
4952 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
4953 {
4954   if (this->IsImported()) {
4955     return;
4956   }
4957   cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
4958
4959   // Get the names.
4960   cmGeneratorTarget::Names targetNames;
4961   if (this->GetType() == cmStateEnums::EXECUTABLE) {
4962     targetNames = this->GetExecutableNames(config);
4963   } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
4964              this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4965              this->GetType() == cmStateEnums::MODULE_LIBRARY) {
4966     targetNames = this->GetLibraryNames(config);
4967   } else {
4968     return;
4969   }
4970
4971   // Get the directory.
4972   std::string dir =
4973     this->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
4974
4975   // Add each name.
4976   std::string f;
4977   if (!targetNames.Output.empty()) {
4978     f = cmStrCat(dir, '/', targetNames.Output);
4979     gg->AddToManifest(f);
4980   }
4981   if (!targetNames.SharedObject.empty()) {
4982     f = cmStrCat(dir, '/', targetNames.SharedObject);
4983     gg->AddToManifest(f);
4984   }
4985   if (!targetNames.Real.empty()) {
4986     f = cmStrCat(dir, '/', targetNames.Real);
4987     gg->AddToManifest(f);
4988   }
4989   if (!targetNames.PDB.empty()) {
4990     f = cmStrCat(dir, '/', targetNames.PDB);
4991     gg->AddToManifest(f);
4992   }
4993   if (!targetNames.ImportLibrary.empty()) {
4994     f =
4995       cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact),
4996                '/', targetNames.ImportLibrary);
4997     gg->AddToManifest(f);
4998   }
4999 }
5000
5001 bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
5002 {
5003   // Compute the language standard based on the compile features.
5004   cmStandardLevelResolver standardResolver(this->Makefile);
5005   std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
5006   for (BT<std::string> const& f : features) {
5007     std::string lang;
5008     if (!standardResolver.CompileFeatureKnown(this->Target->GetName(), f.Value,
5009                                               lang, nullptr)) {
5010       return false;
5011     }
5012
5013     std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
5014     cmValue currentLanguageStandard = this->GetLanguageStandard(lang, config);
5015
5016     std::string newRequiredStandard;
5017     if (!standardResolver.GetNewRequiredStandard(
5018           this->Target->GetName(), f.Value, currentLanguageStandard,
5019           newRequiredStandard)) {
5020       return false;
5021     }
5022
5023     if (!newRequiredStandard.empty()) {
5024       BTs<std::string>& languageStandardProperty =
5025         this->LanguageStandardMap[key];
5026       if (languageStandardProperty.Value != newRequiredStandard) {
5027         languageStandardProperty.Value = newRequiredStandard;
5028         languageStandardProperty.Backtraces.clear();
5029       }
5030       languageStandardProperty.Backtraces.emplace_back(f.Backtrace);
5031     }
5032   }
5033
5034   return true;
5035 }
5036
5037 bool cmGeneratorTarget::ComputeCompileFeatures(
5038   std::string const& config, std::set<LanguagePair> const& languagePairs) const
5039 {
5040   for (const auto& language : languagePairs) {
5041     BTs<std::string> const* generatorTargetLanguageStandard =
5042       this->GetLanguageStandardProperty(language.first, config);
5043     if (!generatorTargetLanguageStandard) {
5044       // If the standard isn't explicitly set we copy it over from the
5045       // specified paired language.
5046       std::string key =
5047         cmStrCat(cmSystemTools::UpperCase(config), '-', language.first);
5048       BTs<std::string> const* standardToCopy =
5049         this->GetLanguageStandardProperty(language.second, config);
5050       if (standardToCopy) {
5051         this->LanguageStandardMap[key] = *standardToCopy;
5052         generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
5053       } else {
5054         cmValue defaultStandard = this->Makefile->GetDefinition(
5055           cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
5056         if (defaultStandard) {
5057           this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
5058           generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
5059         }
5060       }
5061
5062       // Custom updates for the CUDA standard.
5063       if (generatorTargetLanguageStandard != nullptr &&
5064           (language.first == "CUDA")) {
5065         if (generatorTargetLanguageStandard->Value == "98") {
5066           this->LanguageStandardMap[key].Value = "03";
5067         }
5068       }
5069     }
5070   }
5071
5072   return true;
5073 }
5074
5075 std::string cmGeneratorTarget::GetImportedLibName(
5076   std::string const& config) const
5077 {
5078   if (cmGeneratorTarget::ImportInfo const* info =
5079         this->GetImportInfo(config)) {
5080     return info->LibName;
5081   }
5082   return std::string();
5083 }
5084
5085 std::string cmGeneratorTarget::GetFullPath(const std::string& config,
5086                                            cmStateEnums::ArtifactType artifact,
5087                                            bool realname) const
5088 {
5089   if (this->IsImported()) {
5090     return this->Target->ImportedGetFullPath(config, artifact);
5091   }
5092   return this->NormalGetFullPath(config, artifact, realname);
5093 }
5094
5095 std::string cmGeneratorTarget::NormalGetFullPath(
5096   const std::string& config, cmStateEnums::ArtifactType artifact,
5097   bool realname) const
5098 {
5099   std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
5100   if (this->IsAppBundleOnApple()) {
5101     fpath =
5102       cmStrCat(this->BuildBundleDirectory(fpath, config, FullLevel), '/');
5103   }
5104
5105   // Add the full name of the target.
5106   switch (artifact) {
5107     case cmStateEnums::RuntimeBinaryArtifact:
5108       if (realname) {
5109         fpath += this->NormalGetRealName(config);
5110       } else {
5111         fpath +=
5112           this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact);
5113       }
5114       break;
5115     case cmStateEnums::ImportLibraryArtifact:
5116       fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
5117       break;
5118   }
5119   return fpath;
5120 }
5121
5122 std::string cmGeneratorTarget::NormalGetRealName(
5123   const std::string& config) const
5124 {
5125   // This should not be called for imported targets.
5126   // TODO: Split cmTarget into a class hierarchy to get compile-time
5127   // enforcement of the limited imported target API.
5128   if (this->IsImported()) {
5129     std::string msg = cmStrCat("NormalGetRealName called on imported target: ",
5130                                this->GetName());
5131     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5132   }
5133
5134   if (this->GetType() == cmStateEnums::EXECUTABLE) {
5135     // Compute the real name that will be built.
5136     return this->GetExecutableNames(config).Real;
5137   }
5138   // Compute the real name that will be built.
5139   return this->GetLibraryNames(config).Real;
5140 }
5141
5142 cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
5143   const std::string& config) const
5144 {
5145   cmGeneratorTarget::Names targetNames;
5146
5147   // This should not be called for imported targets.
5148   // TODO: Split cmTarget into a class hierarchy to get compile-time
5149   // enforcement of the limited imported target API.
5150   if (this->IsImported()) {
5151     std::string msg =
5152       cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
5153     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5154   }
5155
5156   // Check for library version properties.
5157   cmValue version = this->GetProperty("VERSION");
5158   cmValue soversion = this->GetProperty("SOVERSION");
5159   if (!this->HasSOName(config) ||
5160       this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
5161       this->IsFrameworkOnApple()) {
5162     // Versioning is supported only for shared libraries and modules,
5163     // and then only when the platform supports an soname flag.
5164     version = nullptr;
5165     soversion = nullptr;
5166   }
5167   if (version && !soversion) {
5168     // The soversion must be set if the library version is set.  Use
5169     // the library version as the soversion.
5170     soversion = version;
5171   }
5172   if (!version && soversion) {
5173     // Use the soversion as the library version.
5174     version = soversion;
5175   }
5176
5177   // Get the components of the library name.
5178   std::string prefix;
5179   std::string suffix;
5180   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5181                             prefix, targetNames.Base, suffix);
5182
5183   // The library name.
5184   targetNames.Output = prefix + targetNames.Base + suffix;
5185
5186   if (this->IsFrameworkOnApple()) {
5187     targetNames.Real = prefix;
5188     if (!this->Makefile->PlatformIsAppleEmbedded()) {
5189       targetNames.Real += "Versions/";
5190       targetNames.Real += this->GetFrameworkVersion();
5191       targetNames.Real += "/";
5192     }
5193     targetNames.Real += targetNames.Base + suffix;
5194     targetNames.SharedObject = targetNames.Real + suffix;
5195   } else {
5196     // The library's soname.
5197     this->ComputeVersionedName(targetNames.SharedObject, prefix,
5198                                targetNames.Base, suffix, targetNames.Output,
5199                                soversion);
5200
5201     // The library's real name on disk.
5202     this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
5203                                suffix, targetNames.Output, version);
5204   }
5205
5206   // The import library name.
5207   if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5208       this->GetType() == cmStateEnums::MODULE_LIBRARY) {
5209     targetNames.ImportLibrary =
5210       this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
5211   }
5212
5213   // The program database file name.
5214   targetNames.PDB = this->GetPDBName(config);
5215
5216   return targetNames;
5217 }
5218
5219 cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
5220   const std::string& config) const
5221 {
5222   cmGeneratorTarget::Names targetNames;
5223
5224   // This should not be called for imported targets.
5225   // TODO: Split cmTarget into a class hierarchy to get compile-time
5226   // enforcement of the limited imported target API.
5227   if (this->IsImported()) {
5228     std::string msg = cmStrCat(
5229       "GetExecutableNames called on imported target: ", this->GetName());
5230     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5231   }
5232
5233 // This versioning is supported only for executables and then only
5234 // when the platform supports symbolic links.
5235 #if defined(_WIN32) && !defined(__CYGWIN__)
5236   cmValue version;
5237 #else
5238   // Check for executable version properties.
5239   cmValue version = this->GetProperty("VERSION");
5240   if (this->GetType() != cmStateEnums::EXECUTABLE ||
5241       this->Makefile->IsOn("XCODE")) {
5242     version = nullptr;
5243   }
5244 #endif
5245
5246   // Get the components of the executable name.
5247   std::string prefix;
5248   std::string suffix;
5249   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5250                             prefix, targetNames.Base, suffix);
5251
5252   // The executable name.
5253   targetNames.Output = prefix + targetNames.Base + suffix;
5254
5255 // The executable's real name on disk.
5256 #if defined(__CYGWIN__)
5257   targetNames.Real = prefix + targetNames.Base;
5258 #else
5259   targetNames.Real = targetNames.Output;
5260 #endif
5261   if (version) {
5262     targetNames.Real += "-";
5263     targetNames.Real += *version;
5264   }
5265 #if defined(__CYGWIN__)
5266   targetNames.Real += suffix;
5267 #endif
5268
5269   // The import library name.
5270   targetNames.ImportLibrary =
5271     this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
5272
5273   // The program database file name.
5274   targetNames.PDB = this->GetPDBName(config);
5275
5276   return targetNames;
5277 }
5278
5279 std::string cmGeneratorTarget::GetFullNameInternal(
5280   const std::string& config, cmStateEnums::ArtifactType artifact) const
5281 {
5282   std::string prefix;
5283   std::string base;
5284   std::string suffix;
5285   this->GetFullNameInternal(config, artifact, prefix, base, suffix);
5286   return prefix + base + suffix;
5287 }
5288
5289 std::string cmGeneratorTarget::ImportedGetLocation(
5290   const std::string& config) const
5291 {
5292   assert(this->IsImported());
5293   return this->Target->ImportedGetFullPath(
5294     config, cmStateEnums::RuntimeBinaryArtifact);
5295 }
5296
5297 std::string cmGeneratorTarget::GetFullNameImported(
5298   const std::string& config, cmStateEnums::ArtifactType artifact) const
5299 {
5300   return cmSystemTools::GetFilenameName(
5301     this->Target->ImportedGetFullPath(config, artifact));
5302 }
5303
5304 void cmGeneratorTarget::GetFullNameInternal(
5305   const std::string& config, cmStateEnums::ArtifactType artifact,
5306   std::string& outPrefix, std::string& outBase, std::string& outSuffix) const
5307 {
5308   // Use just the target name for non-main target types.
5309   if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
5310       this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5311       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
5312       this->GetType() != cmStateEnums::EXECUTABLE) {
5313     outPrefix.clear();
5314     outBase = this->GetName();
5315     outSuffix.clear();
5316     return;
5317   }
5318
5319   const bool isImportedLibraryArtifact =
5320     (artifact == cmStateEnums::ImportLibraryArtifact);
5321
5322   // Return an empty name for the import library if this platform
5323   // does not support import libraries.
5324   if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
5325     outPrefix.clear();
5326     outBase.clear();
5327     outSuffix.clear();
5328     return;
5329   }
5330
5331   // retrieve prefix and suffix
5332   std::string ll = this->GetLinkerLanguage(config);
5333   cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
5334   cmValue targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
5335
5336   // The implib option is only allowed for shared libraries, module
5337   // libraries, and executables.
5338   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5339       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
5340       this->GetType() != cmStateEnums::EXECUTABLE) {
5341     artifact = cmStateEnums::RuntimeBinaryArtifact;
5342   }
5343
5344   // Compute the full name for main target types.
5345   const std::string configPostfix = this->GetFilePostfix(config);
5346
5347   // frameworks have directory prefix but no suffix
5348   std::string fw_prefix;
5349   if (this->IsFrameworkOnApple()) {
5350     fw_prefix =
5351       cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
5352     targetPrefix = cmValue(fw_prefix);
5353     targetSuffix = nullptr;
5354   }
5355
5356   if (this->IsCFBundleOnApple()) {
5357     fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
5358     targetPrefix = cmValue(fw_prefix);
5359     targetSuffix = nullptr;
5360   }
5361
5362   // Begin the final name with the prefix.
5363   outPrefix = targetPrefix ? *targetPrefix : "";
5364
5365   // Append the target name or property-specified name.
5366   outBase += this->GetOutputName(config, artifact);
5367
5368   // Append the per-configuration postfix.
5369   // When using Xcode, the postfix should be part of the suffix rather than
5370   // the base, because the suffix ends up being used in Xcode's
5371   // EXECUTABLE_SUFFIX attribute.
5372   if (this->IsFrameworkOnApple() &&
5373       this->GetGlobalGenerator()->GetName() == "Xcode") {
5374     targetSuffix = cmValue(configPostfix);
5375   } else {
5376     outBase += configPostfix;
5377   }
5378
5379   // Name shared libraries with their version number on some platforms.
5380   if (cmValue soversion = this->GetProperty("SOVERSION")) {
5381     if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
5382         !isImportedLibraryArtifact &&
5383         this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
5384       outBase += "-";
5385       outBase += *soversion;
5386     }
5387   }
5388
5389   // Append the suffix.
5390   outSuffix = targetSuffix ? *targetSuffix : "";
5391 }
5392
5393 std::string cmGeneratorTarget::GetLinkerLanguage(
5394   const std::string& config) const
5395 {
5396   return this->GetLinkClosure(config)->LinkerLanguage;
5397 }
5398
5399 std::string cmGeneratorTarget::GetPDBOutputName(
5400   const std::string& config) const
5401 {
5402   std::string base =
5403     this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
5404
5405   std::vector<std::string> props;
5406   std::string configUpper = cmSystemTools::UpperCase(config);
5407   if (!configUpper.empty()) {
5408     // PDB_NAME_<CONFIG>
5409     props.push_back("PDB_NAME_" + configUpper);
5410   }
5411
5412   // PDB_NAME
5413   props.emplace_back("PDB_NAME");
5414
5415   for (std::string const& p : props) {
5416     if (cmValue outName = this->GetProperty(p)) {
5417       base = *outName;
5418       break;
5419     }
5420   }
5421   return base;
5422 }
5423
5424 std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
5425 {
5426   std::string prefix;
5427   std::string base;
5428   std::string suffix;
5429   this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5430                             prefix, base, suffix);
5431
5432   std::vector<std::string> props;
5433   std::string configUpper = cmSystemTools::UpperCase(config);
5434   if (!configUpper.empty()) {
5435     // PDB_NAME_<CONFIG>
5436     props.push_back("PDB_NAME_" + configUpper);
5437   }
5438
5439   // PDB_NAME
5440   props.emplace_back("PDB_NAME");
5441
5442   for (std::string const& p : props) {
5443     if (cmValue outName = this->GetProperty(p)) {
5444       base = *outName;
5445       break;
5446     }
5447   }
5448   return prefix + base + ".pdb";
5449 }
5450
5451 std::string cmGeneratorTarget::GetObjectDirectory(
5452   std::string const& config) const
5453 {
5454   std::string obj_dir =
5455     this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
5456 #if defined(__APPLE__)
5457   // Replace Xcode's placeholder for the object file directory since
5458   // installation and export scripts need to know the real directory.
5459   // Xcode has build-time settings (e.g. for sanitizers) that affect this,
5460   // but we use the default here.  Users that want to enable sanitizers
5461   // will do so at the cost of object library installation and export.
5462   cmSystemTools::ReplaceString(obj_dir, "$(OBJECT_FILE_DIR_normal:base)",
5463                                "Objects-normal");
5464 #endif
5465   return obj_dir;
5466 }
5467
5468 void cmGeneratorTarget::GetTargetObjectNames(
5469   std::string const& config, std::vector<std::string>& objects) const
5470 {
5471   std::vector<cmSourceFile const*> objectSources;
5472   this->GetObjectSources(objectSources, config);
5473   std::map<cmSourceFile const*, std::string> mapping;
5474
5475   for (cmSourceFile const* sf : objectSources) {
5476     mapping[sf];
5477   }
5478
5479   this->LocalGenerator->ComputeObjectFilenames(mapping, this);
5480
5481   for (cmSourceFile const* src : objectSources) {
5482     // Find the object file name corresponding to this source file.
5483     auto map_it = mapping.find(src);
5484     // It must exist because we populated the mapping just above.
5485     assert(!map_it->second.empty());
5486     objects.push_back(map_it->second);
5487   }
5488
5489   // We need to compute the relative path from the root of
5490   // of the object directory to handle subdirectory paths
5491   std::string rootObjectDir = this->GetObjectDirectory(config);
5492   rootObjectDir = cmSystemTools::CollapseFullPath(rootObjectDir);
5493   auto ispcObjects = this->GetGeneratedISPCObjects(config);
5494   for (std::string const& output : ispcObjects) {
5495     auto relativePathFromObjectDir = output.substr(rootObjectDir.size());
5496     objects.push_back(relativePathFromObjectDir);
5497   }
5498 }
5499
5500 bool cmGeneratorTarget::StrictTargetComparison::operator()(
5501   cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
5502 {
5503   int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
5504   if (nameResult == 0) {
5505     return strcmp(
5506              t1->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
5507              t2->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
5508   }
5509   return nameResult < 0;
5510 }
5511
5512 struct cmGeneratorTarget::SourceFileFlags
5513 cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
5514 {
5515   struct SourceFileFlags flags;
5516   this->ConstructSourceFileFlags();
5517   auto si = this->SourceFlagsMap.find(sf);
5518   if (si != this->SourceFlagsMap.end()) {
5519     flags = si->second;
5520   } else {
5521     // Handle the MACOSX_PACKAGE_LOCATION property on source files that
5522     // were not listed in one of the other lists.
5523     if (cmValue location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
5524       flags.MacFolder = location->c_str();
5525       const bool stripResources =
5526         this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
5527       if (*location == "Resources") {
5528         flags.Type = cmGeneratorTarget::SourceFileTypeResource;
5529         if (stripResources) {
5530           flags.MacFolder = "";
5531         }
5532       } else if (cmHasLiteralPrefix(*location, "Resources/")) {
5533         flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
5534         if (stripResources) {
5535           flags.MacFolder += strlen("Resources/");
5536         }
5537       } else {
5538         flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
5539       }
5540     }
5541   }
5542   return flags;
5543 }
5544
5545 void cmGeneratorTarget::ConstructSourceFileFlags() const
5546 {
5547   if (this->SourceFileFlagsConstructed) {
5548     return;
5549   }
5550   this->SourceFileFlagsConstructed = true;
5551
5552   // Process public headers to mark the source files.
5553   if (cmValue files = this->GetProperty("PUBLIC_HEADER")) {
5554     std::vector<std::string> relFiles = cmExpandedList(*files);
5555     for (std::string const& relFile : relFiles) {
5556       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5557         SourceFileFlags& flags = this->SourceFlagsMap[sf];
5558         flags.MacFolder = "Headers";
5559         flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
5560       }
5561     }
5562   }
5563
5564   // Process private headers after public headers so that they take
5565   // precedence if a file is listed in both.
5566   if (cmValue files = this->GetProperty("PRIVATE_HEADER")) {
5567     std::vector<std::string> relFiles = cmExpandedList(*files);
5568     for (std::string const& relFile : relFiles) {
5569       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5570         SourceFileFlags& flags = this->SourceFlagsMap[sf];
5571         flags.MacFolder = "PrivateHeaders";
5572         flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
5573       }
5574     }
5575   }
5576
5577   // Mark sources listed as resources.
5578   if (cmValue files = this->GetProperty("RESOURCE")) {
5579     std::vector<std::string> relFiles = cmExpandedList(*files);
5580     for (std::string const& relFile : relFiles) {
5581       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5582         SourceFileFlags& flags = this->SourceFlagsMap[sf];
5583         flags.MacFolder = "";
5584         if (!this->GlobalGenerator->ShouldStripResourcePath(this->Makefile)) {
5585           flags.MacFolder = "Resources";
5586         }
5587         flags.Type = cmGeneratorTarget::SourceFileTypeResource;
5588       }
5589     }
5590   }
5591 }
5592
5593 const cmGeneratorTarget::CompatibleInterfacesBase&
5594 cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
5595 {
5596   cmGeneratorTarget::CompatibleInterfaces& compat =
5597     this->CompatibleInterfacesMap[config];
5598   if (!compat.Done) {
5599     compat.Done = true;
5600     compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
5601     compat.PropsString.insert("AUTOUIC_OPTIONS");
5602     std::vector<cmGeneratorTarget const*> const& deps =
5603       this->GetLinkImplementationClosure(config);
5604     for (cmGeneratorTarget const* li : deps) {
5605 #define CM_READ_COMPATIBLE_INTERFACE(X, x)                                    \
5606   if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) {           \
5607     std::vector<std::string> props;                                           \
5608     cmExpandList(*prop, props);                                               \
5609     compat.Props##x.insert(props.begin(), props.end());                       \
5610   }
5611       CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
5612       CM_READ_COMPATIBLE_INTERFACE(STRING, String)
5613       CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
5614       CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
5615 #undef CM_READ_COMPATIBLE_INTERFACE
5616     }
5617   }
5618   return compat;
5619 }
5620
5621 bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
5622   const std::string& p, const std::string& config) const
5623 {
5624   if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5625       this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5626     return false;
5627   }
5628   return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
5629 }
5630
5631 bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
5632   const std::string& p, const std::string& config) const
5633 {
5634   if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5635       this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5636     return false;
5637   }
5638   return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
5639 }
5640
5641 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
5642   const std::string& p, const std::string& config) const
5643 {
5644   if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5645       this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5646     return false;
5647   }
5648   return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
5649 }
5650
5651 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
5652   const std::string& p, const std::string& config) const
5653 {
5654   if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5655       this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5656     return false;
5657   }
5658   return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
5659 }
5660
5661 enum CompatibleType
5662 {
5663   BoolType,
5664   StringType,
5665   NumberMinType,
5666   NumberMaxType
5667 };
5668
5669 template <typename PropertyType>
5670 PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5671                                                const std::string& prop,
5672                                                const std::string& config,
5673                                                CompatibleType, PropertyType*);
5674
5675 template <>
5676 bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5677                                        const std::string& prop,
5678                                        const std::string& config,
5679                                        CompatibleType /*unused*/,
5680                                        bool* /*unused*/)
5681 {
5682   return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
5683 }
5684
5685 template <>
5686 const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5687                                               const std::string& prop,
5688                                               const std::string& config,
5689                                               CompatibleType t,
5690                                               const char** /*unused*/)
5691 {
5692   switch (t) {
5693     case BoolType:
5694       assert(false &&
5695              "String compatibility check function called for boolean");
5696       return nullptr;
5697     case StringType:
5698       return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
5699     case NumberMinType:
5700       return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
5701     case NumberMaxType:
5702       return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
5703   }
5704   assert(false && "Unreachable!");
5705   return nullptr;
5706 }
5707
5708 template <typename PropertyType>
5709 void checkPropertyConsistency(cmGeneratorTarget const* depender,
5710                               cmGeneratorTarget const* dependee,
5711                               const std::string& propName,
5712                               std::set<std::string>& emitted,
5713                               const std::string& config, CompatibleType t,
5714                               PropertyType* /*unused*/)
5715 {
5716   cmValue prop = dependee->GetProperty(propName);
5717   if (!prop) {
5718     return;
5719   }
5720
5721   std::vector<std::string> props = cmExpandedList(*prop);
5722   std::string pdir =
5723     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
5724
5725   for (std::string const& p : props) {
5726     std::string pname = cmSystemTools::HelpFileName(p);
5727     std::string pfile = pdir + pname + ".rst";
5728     if (cmSystemTools::FileExists(pfile, true)) {
5729       std::ostringstream e;
5730       e << "Target \"" << dependee->GetName() << "\" has property \"" << p
5731         << "\" listed in its " << propName
5732         << " property.  "
5733            "This is not allowed.  Only user-defined properties may appear "
5734            "listed in the "
5735         << propName << " property.";
5736       depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
5737                                                   e.str());
5738       return;
5739     }
5740     if (emitted.insert(p).second) {
5741       getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
5742                                                       nullptr);
5743       if (cmSystemTools::GetErrorOccurredFlag()) {
5744         return;
5745       }
5746     }
5747   }
5748 }
5749
5750 namespace {
5751 std::string intersect(const std::set<std::string>& s1,
5752                       const std::set<std::string>& s2)
5753 {
5754   std::set<std::string> intersect;
5755   std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
5756                         std::inserter(intersect, intersect.begin()));
5757   if (!intersect.empty()) {
5758     return *intersect.begin();
5759   }
5760   return "";
5761 }
5762
5763 std::string intersect(const std::set<std::string>& s1,
5764                       const std::set<std::string>& s2,
5765                       const std::set<std::string>& s3)
5766 {
5767   std::string result;
5768   result = intersect(s1, s2);
5769   if (!result.empty()) {
5770     return result;
5771   }
5772   result = intersect(s1, s3);
5773   if (!result.empty()) {
5774     return result;
5775   }
5776   return intersect(s2, s3);
5777 }
5778
5779 std::string intersect(const std::set<std::string>& s1,
5780                       const std::set<std::string>& s2,
5781                       const std::set<std::string>& s3,
5782                       const std::set<std::string>& s4)
5783 {
5784   std::string result;
5785   result = intersect(s1, s2);
5786   if (!result.empty()) {
5787     return result;
5788   }
5789   result = intersect(s1, s3);
5790   if (!result.empty()) {
5791     return result;
5792   }
5793   result = intersect(s1, s4);
5794   if (!result.empty()) {
5795     return result;
5796   }
5797   return intersect(s2, s3, s4);
5798 }
5799 }
5800
5801 void cmGeneratorTarget::CheckPropertyCompatibility(
5802   cmComputeLinkInformation& info, const std::string& config) const
5803 {
5804   const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
5805
5806   std::set<std::string> emittedBools;
5807   static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
5808   std::set<std::string> emittedStrings;
5809   static const std::string strString = "COMPATIBLE_INTERFACE_STRING";
5810   std::set<std::string> emittedMinNumbers;
5811   static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
5812   std::set<std::string> emittedMaxNumbers;
5813   static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
5814
5815   for (auto const& dep : deps) {
5816     if (!dep.Target) {
5817       continue;
5818     }
5819
5820     checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
5821                                    config, BoolType, nullptr);
5822     if (cmSystemTools::GetErrorOccurredFlag()) {
5823       return;
5824     }
5825     checkPropertyConsistency<const char*>(this, dep.Target, strString,
5826                                           emittedStrings, config, StringType,
5827                                           nullptr);
5828     if (cmSystemTools::GetErrorOccurredFlag()) {
5829       return;
5830     }
5831     checkPropertyConsistency<const char*>(this, dep.Target, strNumMin,
5832                                           emittedMinNumbers, config,
5833                                           NumberMinType, nullptr);
5834     if (cmSystemTools::GetErrorOccurredFlag()) {
5835       return;
5836     }
5837     checkPropertyConsistency<const char*>(this, dep.Target, strNumMax,
5838                                           emittedMaxNumbers, config,
5839                                           NumberMaxType, nullptr);
5840     if (cmSystemTools::GetErrorOccurredFlag()) {
5841       return;
5842     }
5843   }
5844
5845   std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
5846                                emittedMaxNumbers);
5847
5848   if (!prop.empty()) {
5849     // Use a sorted std::vector to keep the error message sorted.
5850     std::vector<std::string> props;
5851     auto i = emittedBools.find(prop);
5852     if (i != emittedBools.end()) {
5853       props.push_back(strBool);
5854     }
5855     i = emittedStrings.find(prop);
5856     if (i != emittedStrings.end()) {
5857       props.push_back(strString);
5858     }
5859     i = emittedMinNumbers.find(prop);
5860     if (i != emittedMinNumbers.end()) {
5861       props.push_back(strNumMin);
5862     }
5863     i = emittedMaxNumbers.find(prop);
5864     if (i != emittedMaxNumbers.end()) {
5865       props.push_back(strNumMax);
5866     }
5867     std::sort(props.begin(), props.end());
5868
5869     std::string propsString = cmStrCat(
5870       cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
5871
5872     std::ostringstream e;
5873     e << "Property \"" << prop << "\" appears in both the " << propsString
5874       << " property in the dependencies of target \"" << this->GetName()
5875       << "\".  This is not allowed. A property may only require "
5876          "compatibility "
5877          "in a boolean interpretation, a numeric minimum, a numeric maximum "
5878          "or a "
5879          "string interpretation, but not a mixture.";
5880     this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
5881   }
5882 }
5883
5884 template <typename PropertyType>
5885 std::string valueAsString(PropertyType);
5886 template <>
5887 std::string valueAsString<bool>(bool value)
5888 {
5889   return value ? "TRUE" : "FALSE";
5890 }
5891 template <>
5892 std::string valueAsString<const char*>(const char* value)
5893 {
5894   return value ? value : "(unset)";
5895 }
5896 template <>
5897 std::string valueAsString<std::string>(std::string value)
5898 {
5899   return value;
5900 }
5901 template <>
5902 std::string valueAsString<cmValue>(cmValue value)
5903 {
5904   return value ? value : std::string("(unset)");
5905 }
5906 template <>
5907 std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
5908 {
5909   return "(unset)";
5910 }
5911
5912 static std::string compatibilityType(CompatibleType t)
5913 {
5914   switch (t) {
5915     case BoolType:
5916       return "Boolean compatibility";
5917     case StringType:
5918       return "String compatibility";
5919     case NumberMaxType:
5920       return "Numeric maximum compatibility";
5921     case NumberMinType:
5922       return "Numeric minimum compatibility";
5923   }
5924   assert(false && "Unreachable!");
5925   return "";
5926 }
5927
5928 static std::string compatibilityAgree(CompatibleType t, bool dominant)
5929 {
5930   switch (t) {
5931     case BoolType:
5932     case StringType:
5933       return dominant ? "(Disagree)\n" : "(Agree)\n";
5934     case NumberMaxType:
5935     case NumberMinType:
5936       return dominant ? "(Dominant)\n" : "(Ignored)\n";
5937   }
5938   assert(false && "Unreachable!");
5939   return "";
5940 }
5941
5942 template <typename PropertyType>
5943 PropertyType getTypedProperty(
5944   cmGeneratorTarget const* tgt, const std::string& prop,
5945   cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
5946
5947 template <>
5948 bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
5949                             const std::string& prop,
5950                             cmGeneratorExpressionInterpreter* genexInterpreter)
5951 {
5952   if (genexInterpreter == nullptr) {
5953     return tgt->GetPropertyAsBool(prop);
5954   }
5955
5956   cmValue value = tgt->GetProperty(prop);
5957   return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
5958 }
5959
5960 template <>
5961 const char* getTypedProperty<const char*>(
5962   cmGeneratorTarget const* tgt, const std::string& prop,
5963   cmGeneratorExpressionInterpreter* genexInterpreter)
5964 {
5965   cmValue value = tgt->GetProperty(prop);
5966
5967   if (genexInterpreter == nullptr) {
5968     return value.GetCStr();
5969   }
5970
5971   return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
5972 }
5973
5974 template <>
5975 std::string getTypedProperty<std::string>(
5976   cmGeneratorTarget const* tgt, const std::string& prop,
5977   cmGeneratorExpressionInterpreter* genexInterpreter)
5978 {
5979   cmValue value = tgt->GetProperty(prop);
5980
5981   if (genexInterpreter == nullptr) {
5982     return valueAsString(value);
5983   }
5984
5985   return genexInterpreter->Evaluate(value ? *value : "", prop);
5986 }
5987
5988 template <typename PropertyType>
5989 PropertyType impliedValue(PropertyType);
5990 template <>
5991 bool impliedValue<bool>(bool /*unused*/)
5992 {
5993   return false;
5994 }
5995 template <>
5996 const char* impliedValue<const char*>(const char* /*unused*/)
5997 {
5998   return "";
5999 }
6000 template <>
6001 std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
6002 {
6003   return std::string();
6004 }
6005
6006 template <typename PropertyType>
6007 std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
6008                                                  PropertyType rhs,
6009                                                  CompatibleType t);
6010
6011 template <>
6012 std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
6013                                          CompatibleType /*unused*/)
6014 {
6015   return { lhs == rhs, lhs };
6016 }
6017
6018 static std::pair<bool, const char*> consistentStringProperty(const char* lhs,
6019                                                              const char* rhs)
6020 {
6021   const bool b = strcmp(lhs, rhs) == 0;
6022   return { b, b ? lhs : nullptr };
6023 }
6024
6025 static std::pair<bool, std::string> consistentStringProperty(
6026   const std::string& lhs, const std::string& rhs)
6027 {
6028   const bool b = lhs == rhs;
6029   return { b, b ? lhs : valueAsString(nullptr) };
6030 }
6031
6032 static std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
6033                                                              const char* rhs,
6034                                                              CompatibleType t)
6035 {
6036   char* pEnd;
6037
6038   long lnum = strtol(lhs, &pEnd, 0);
6039   if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
6040     return { false, nullptr };
6041   }
6042
6043   long rnum = strtol(rhs, &pEnd, 0);
6044   if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
6045     return { false, nullptr };
6046   }
6047
6048   if (t == NumberMaxType) {
6049     return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
6050   }
6051
6052   return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
6053 }
6054
6055 template <>
6056 std::pair<bool, const char*> consistentProperty(const char* lhs,
6057                                                 const char* rhs,
6058                                                 CompatibleType t)
6059 {
6060   if (!lhs && !rhs) {
6061     return { true, lhs };
6062   }
6063   if (!lhs) {
6064     return { true, rhs };
6065   }
6066   if (!rhs) {
6067     return { true, lhs };
6068   }
6069
6070   switch (t) {
6071     case BoolType: {
6072       bool same = cmIsOn(lhs) == cmIsOn(rhs);
6073       return { same, same ? lhs : nullptr };
6074     }
6075     case StringType:
6076       return consistentStringProperty(lhs, rhs);
6077     case NumberMinType:
6078     case NumberMaxType:
6079       return consistentNumberProperty(lhs, rhs, t);
6080   }
6081   assert(false && "Unreachable!");
6082   return { false, nullptr };
6083 }
6084
6085 static std::pair<bool, std::string> consistentProperty(const std::string& lhs,
6086                                                        const std::string& rhs,
6087                                                        CompatibleType t)
6088 {
6089   const std::string null_ptr = valueAsString(nullptr);
6090
6091   if (lhs == null_ptr && rhs == null_ptr) {
6092     return { true, lhs };
6093   }
6094   if (lhs == null_ptr) {
6095     return { true, rhs };
6096   }
6097   if (rhs == null_ptr) {
6098     return { true, lhs };
6099   }
6100
6101   switch (t) {
6102     case BoolType: {
6103       bool same = cmIsOn(lhs) == cmIsOn(rhs);
6104       return { same, same ? lhs : null_ptr };
6105     }
6106     case StringType:
6107       return consistentStringProperty(lhs, rhs);
6108     case NumberMinType:
6109     case NumberMaxType: {
6110       auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
6111       return { value.first,
6112                value.first ? std::string(value.second) : null_ptr };
6113     }
6114   }
6115   assert(false && "Unreachable!");
6116   return { false, null_ptr };
6117 }
6118
6119 template <typename PropertyType>
6120 PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
6121                                                  const std::string& p,
6122                                                  const std::string& config,
6123                                                  const char* defaultValue,
6124                                                  CompatibleType t,
6125                                                  PropertyType* /*unused*/)
6126 {
6127   PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
6128
6129   std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
6130   const bool explicitlySet = cm::contains(headPropKeys, p);
6131
6132   const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
6133   assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
6134
6135   std::vector<cmGeneratorTarget const*> const& deps =
6136     tgt->GetLinkImplementationClosure(config);
6137
6138   if (deps.empty()) {
6139     return propContent;
6140   }
6141   bool propInitialized = explicitlySet;
6142
6143   std::string report = cmStrCat(" * Target \"", tgt->GetName());
6144   if (explicitlySet) {
6145     report += "\" has property content \"";
6146     report += valueAsString<PropertyType>(propContent);
6147     report += "\"\n";
6148   } else if (impliedByUse) {
6149     report += "\" property is implied by use.\n";
6150   } else {
6151     report += "\" property not set.\n";
6152   }
6153
6154   std::string interfaceProperty = "INTERFACE_" + p;
6155   std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
6156   if (p == "POSITION_INDEPENDENT_CODE") {
6157     genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
6158       tgt->GetLocalGenerator(), config, tgt);
6159   }
6160
6161   for (cmGeneratorTarget const* theTarget : deps) {
6162     // An error should be reported if one dependency
6163     // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
6164     // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
6165     // target itself has a POSITION_INDEPENDENT_CODE which disagrees
6166     // with a dependency.
6167
6168     std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
6169
6170     const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty);
6171     PropertyType ifacePropContent = getTypedProperty<PropertyType>(
6172       theTarget, interfaceProperty, genexInterpreter.get());
6173
6174     std::string reportEntry;
6175     if (ifaceIsSet) {
6176       reportEntry += " * Target \"";
6177       reportEntry += theTarget->GetName();
6178       reportEntry += "\" property value \"";
6179       reportEntry += valueAsString<PropertyType>(ifacePropContent);
6180       reportEntry += "\" ";
6181     }
6182
6183     if (explicitlySet) {
6184       if (ifaceIsSet) {
6185         std::pair<bool, PropertyType> consistent =
6186           consistentProperty(propContent, ifacePropContent, t);
6187         report += reportEntry;
6188         report += compatibilityAgree(t, propContent != consistent.second);
6189         if (!consistent.first) {
6190           std::ostringstream e;
6191           e << "Property " << p << " on target \"" << tgt->GetName()
6192             << "\" does\nnot match the "
6193                "INTERFACE_"
6194             << p
6195             << " property requirement\nof "
6196                "dependency \""
6197             << theTarget->GetName() << "\".\n";
6198           cmSystemTools::Error(e.str());
6199           break;
6200         }
6201         propContent = consistent.second;
6202         continue;
6203       }
6204       // Explicitly set on target and not set in iface. Can't disagree.
6205       continue;
6206     }
6207     if (impliedByUse) {
6208       propContent = impliedValue<PropertyType>(propContent);
6209
6210       if (ifaceIsSet) {
6211         std::pair<bool, PropertyType> consistent =
6212           consistentProperty(propContent, ifacePropContent, t);
6213         report += reportEntry;
6214         report += compatibilityAgree(t, propContent != consistent.second);
6215         if (!consistent.first) {
6216           std::ostringstream e;
6217           e << "Property " << p << " on target \"" << tgt->GetName()
6218             << "\" is\nimplied to be " << defaultValue
6219             << " because it was used to determine the link libraries\n"
6220                "already. The INTERFACE_"
6221             << p << " property on\ndependency \"" << theTarget->GetName()
6222             << "\" is in conflict.\n";
6223           cmSystemTools::Error(e.str());
6224           break;
6225         }
6226         propContent = consistent.second;
6227         continue;
6228       }
6229       // Implicitly set on target and not set in iface. Can't disagree.
6230       continue;
6231     }
6232     if (ifaceIsSet) {
6233       if (propInitialized) {
6234         std::pair<bool, PropertyType> consistent =
6235           consistentProperty(propContent, ifacePropContent, t);
6236         report += reportEntry;
6237         report += compatibilityAgree(t, propContent != consistent.second);
6238         if (!consistent.first) {
6239           std::ostringstream e;
6240           e << "The INTERFACE_" << p << " property of \""
6241             << theTarget->GetName() << "\" does\nnot agree with the value of "
6242             << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
6243           cmSystemTools::Error(e.str());
6244           break;
6245         }
6246         propContent = consistent.second;
6247         continue;
6248       }
6249       report += reportEntry + "(Interface set)\n";
6250       propContent = ifacePropContent;
6251       propInitialized = true;
6252     } else {
6253       // Not set. Nothing to agree on.
6254       continue;
6255     }
6256   }
6257
6258   tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
6259                             report, compatibilityType(t));
6260   return propContent;
6261 }
6262
6263 bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
6264 {
6265   bool previous = this->DeviceLink;
6266   this->DeviceLink = deviceLink;
6267   return previous;
6268 }
6269
6270 bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
6271   const std::string& p, const std::string& config) const
6272 {
6273   return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
6274                                                    BoolType, nullptr);
6275 }
6276
6277 std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
6278   const std::string& p, const std::string& config) const
6279 {
6280   return checkInterfacePropertyCompatibility<std::string>(
6281     this, p, config, "FALSE", BoolType, nullptr);
6282 }
6283
6284 const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
6285   const std::string& p, const std::string& config) const
6286 {
6287   return checkInterfacePropertyCompatibility<const char*>(
6288     this, p, config, "empty", StringType, nullptr);
6289 }
6290
6291 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
6292   const std::string& p, const std::string& config) const
6293 {
6294   return checkInterfacePropertyCompatibility<const char*>(
6295     this, p, config, "empty", NumberMinType, nullptr);
6296 }
6297
6298 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
6299   const std::string& p, const std::string& config) const
6300 {
6301   return checkInterfacePropertyCompatibility<const char*>(
6302     this, p, config, "empty", NumberMaxType, nullptr);
6303 }
6304
6305 cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
6306   const std::string& config) const
6307 {
6308   // Lookup any existing information for this configuration.
6309   std::string key(cmSystemTools::UpperCase(config));
6310   auto i = this->LinkInformation.find(key);
6311   if (i == this->LinkInformation.end()) {
6312     // Compute information for this configuration.
6313     auto info = cm::make_unique<cmComputeLinkInformation>(this, config);
6314     if (info && !info->Compute()) {
6315       info.reset();
6316     }
6317
6318     // Store the information for this configuration.
6319     i = this->LinkInformation.emplace(key, std::move(info)).first;
6320
6321     if (i->second) {
6322       this->CheckPropertyCompatibility(*i->second, config);
6323     }
6324   }
6325   return i->second.get();
6326 }
6327
6328 void cmGeneratorTarget::CheckLinkLibraries() const
6329 {
6330   bool linkLibrariesOnlyTargets =
6331     this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS");
6332
6333   // Evaluate the link interface of this target if needed for extra checks.
6334   if (linkLibrariesOnlyTargets) {
6335     std::vector<std::string> const& configs =
6336       this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
6337     for (std::string const& config : configs) {
6338       this->GetLinkInterfaceLibraries(config, this, LinkInterfaceFor::Link);
6339     }
6340   }
6341
6342   // Check link the implementation for each generated configuration.
6343   for (auto const& hmp : this->LinkImplMap) {
6344     HeadToLinkImplementationMap const& hm = hmp.second;
6345     // There could be several entries used when computing the pre-CMP0022
6346     // default link interface.  Check only the entry for our own link impl.
6347     auto const hmi = hm.find(this);
6348     if (hmi == hm.end() || !hmi->second.LibrariesDone) {
6349       continue;
6350     }
6351     for (cmLinkImplItem const& item : hmi->second.Libraries) {
6352       if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) {
6353         return;
6354       }
6355       if (linkLibrariesOnlyTargets &&
6356           !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) {
6357         return;
6358       }
6359     }
6360   }
6361
6362   // Check link the interface for each generated combination of
6363   // configuration and consuming head target.  We should not need to
6364   // consider LinkInterfaceUsageRequirementsOnlyMap because its entries
6365   // should be a subset of LinkInterfaceMap (with LINK_ONLY left out).
6366   for (auto const& hmp : this->LinkInterfaceMap) {
6367     for (auto const& hmi : hmp.second) {
6368       if (!hmi.second.LibrariesDone) {
6369         continue;
6370       }
6371       for (cmLinkItem const& item : hmi.second.Libraries) {
6372         if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) {
6373           return;
6374         }
6375         if (linkLibrariesOnlyTargets &&
6376             !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) {
6377           return;
6378         }
6379       }
6380     }
6381   }
6382 }
6383
6384 namespace {
6385 cm::string_view missingTargetPossibleReasons =
6386   "Possible reasons include:\n"
6387   "  * There is a typo in the target name.\n"
6388   "  * A find_package call is missing for an IMPORTED target.\n"
6389   "  * An ALIAS target is missing.\n"_s;
6390 }
6391
6392 bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role,
6393                                              cmLinkItem const& item) const
6394 {
6395   if (item.Target || cmHasPrefix(item.AsStr(), "<LINK_GROUP:"_s) ||
6396       item.AsStr().find("::") == std::string::npos) {
6397     return true;
6398   }
6399   MessageType messageType = MessageType::FATAL_ERROR;
6400   std::string e;
6401   switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028)) {
6402     case cmPolicies::WARN: {
6403       e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028), "\n");
6404       messageType = MessageType::AUTHOR_WARNING;
6405     } break;
6406     case cmPolicies::OLD:
6407       return true;
6408     case cmPolicies::REQUIRED_IF_USED:
6409     case cmPolicies::REQUIRED_ALWAYS:
6410     case cmPolicies::NEW:
6411       // Issue the fatal message.
6412       break;
6413   }
6414
6415   if (role == LinkItemRole::Implementation) {
6416     e = cmStrCat(e, "Target \"", this->GetName(), "\" links to");
6417   } else {
6418     e = cmStrCat(e, "The link interface of target \"", this->GetName(),
6419                  "\" contains");
6420   }
6421   e =
6422     cmStrCat(e, ":\n  ", item.AsStr(), "\n", "but the target was not found.  ",
6423              missingTargetPossibleReasons);
6424   cmListFileBacktrace backtrace = item.Backtrace;
6425   if (backtrace.Empty()) {
6426     backtrace = this->GetBacktrace();
6427   }
6428   this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType, e,
6429                                                               backtrace);
6430   return false;
6431 }
6432
6433 bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role,
6434                                                cmLinkItem const& item) const
6435 {
6436   if (item.Target) {
6437     return true;
6438   }
6439   std::string const& str = item.AsStr();
6440   if (!str.empty() &&
6441       (str[0] == '-' || str[0] == '$' || str[0] == '`' ||
6442        str.find_first_of("/\\") != std::string::npos ||
6443        cmHasPrefix(str, "<LINK_LIBRARY:"_s) ||
6444        cmHasPrefix(str, "<LINK_GROUP:"_s))) {
6445     return true;
6446   }
6447
6448   std::string e = cmStrCat("Target \"", this->GetName(),
6449                            "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ",
6450                            role == LinkItemRole::Implementation
6451                              ? "it links to"
6452                              : "its link interface contains",
6453                            ":\n  ", item.AsStr(), "\nwhich is not a target.  ",
6454                            missingTargetPossibleReasons);
6455   cmListFileBacktrace backtrace = item.Backtrace;
6456   if (backtrace.Empty()) {
6457     backtrace = this->GetBacktrace();
6458   }
6459   this->LocalGenerator->GetCMakeInstance()->IssueMessage(
6460     MessageType::FATAL_ERROR, e, backtrace);
6461   return false;
6462 }
6463
6464 void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
6465 {
6466   int patch;
6467   this->GetTargetVersion("VERSION", major, minor, patch);
6468 }
6469
6470 void cmGeneratorTarget::GetTargetVersionFallback(
6471   const std::string& property, const std::string& fallback_property,
6472   int& major, int& minor, int& patch) const
6473 {
6474   if (this->GetProperty(property)) {
6475     this->GetTargetVersion(property, major, minor, patch);
6476   } else {
6477     this->GetTargetVersion(fallback_property, major, minor, patch);
6478   }
6479 }
6480
6481 void cmGeneratorTarget::GetTargetVersion(const std::string& property,
6482                                          int& major, int& minor,
6483                                          int& patch) const
6484 {
6485   // Set the default values.
6486   major = 0;
6487   minor = 0;
6488   patch = 0;
6489
6490   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
6491
6492   if (cmValue version = this->GetProperty(property)) {
6493     // Try to parse the version number and store the results that were
6494     // successfully parsed.
6495     int parsed_major;
6496     int parsed_minor;
6497     int parsed_patch;
6498     switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor,
6499                    &parsed_patch)) {
6500       case 3:
6501         patch = parsed_patch;
6502         CM_FALLTHROUGH;
6503       case 2:
6504         minor = parsed_minor;
6505         CM_FALLTHROUGH;
6506       case 1:
6507         major = parsed_major;
6508         CM_FALLTHROUGH;
6509       default:
6510         break;
6511     }
6512   }
6513 }
6514
6515 std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
6516   std::string const& lang, std::string const& config) const
6517 {
6518   // This is activated by the presence of a default selection whether or
6519   // not it is overridden by a property.
6520   cmValue runtimeLibraryDefault = this->Makefile->GetDefinition(
6521     cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
6522   if (!cmNonempty(runtimeLibraryDefault)) {
6523     return std::string();
6524   }
6525   cmValue runtimeLibraryValue =
6526     this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
6527   if (!runtimeLibraryValue) {
6528     runtimeLibraryValue = runtimeLibraryDefault;
6529   }
6530   return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
6531     *runtimeLibraryValue, this->LocalGenerator, config, this));
6532 }
6533
6534 std::string cmGeneratorTarget::GetFortranModuleDirectory(
6535   std::string const& working_dir) const
6536 {
6537   if (!this->FortranModuleDirectoryCreated) {
6538     this->FortranModuleDirectory =
6539       this->CreateFortranModuleDirectory(working_dir);
6540     this->FortranModuleDirectoryCreated = true;
6541   }
6542
6543   return this->FortranModuleDirectory;
6544 }
6545
6546 bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const
6547 {
6548   if (cmValue prop =
6549         this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) {
6550     return cmIsOn(*prop);
6551   }
6552   return false;
6553 }
6554
6555 std::string cmGeneratorTarget::CreateFortranModuleDirectory(
6556   std::string const& working_dir) const
6557 {
6558   std::string mod_dir;
6559   std::string target_mod_dir;
6560   if (cmValue prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
6561     target_mod_dir = *prop;
6562   } else {
6563     std::string const& default_mod_dir =
6564       this->LocalGenerator->GetCurrentBinaryDirectory();
6565     if (default_mod_dir != working_dir) {
6566       target_mod_dir = default_mod_dir;
6567     }
6568   }
6569   cmValue moddir_flag =
6570     this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
6571   if (!target_mod_dir.empty() && moddir_flag) {
6572     // Compute the full path to the module directory.
6573     if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
6574       // Already a full path.
6575       mod_dir = target_mod_dir;
6576     } else {
6577       // Interpret relative to the current output directory.
6578       mod_dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
6579                          '/', target_mod_dir);
6580     }
6581
6582     // Make sure the module output directory exists.
6583     cmSystemTools::MakeDirectory(mod_dir);
6584   }
6585   return mod_dir;
6586 }
6587
6588 void cmGeneratorTarget::AddISPCGeneratedHeader(std::string const& header,
6589                                                std::string const& config)
6590 {
6591   std::string config_upper;
6592   if (!config.empty()) {
6593     config_upper = cmSystemTools::UpperCase(config);
6594   }
6595   auto iter = this->ISPCGeneratedHeaders.find(config_upper);
6596   if (iter == this->ISPCGeneratedHeaders.end()) {
6597     std::vector<std::string> headers;
6598     headers.emplace_back(header);
6599     this->ISPCGeneratedHeaders.insert({ config_upper, headers });
6600   } else {
6601     iter->second.emplace_back(header);
6602   }
6603 }
6604
6605 std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
6606   std::string const& config) const
6607 {
6608   std::string config_upper;
6609   if (!config.empty()) {
6610     config_upper = cmSystemTools::UpperCase(config);
6611   }
6612   auto iter = this->ISPCGeneratedHeaders.find(config_upper);
6613   if (iter == this->ISPCGeneratedHeaders.end()) {
6614     return std::vector<std::string>{};
6615   }
6616   return iter->second;
6617 }
6618
6619 void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
6620                                                std::string const& config)
6621 {
6622   std::string config_upper;
6623   if (!config.empty()) {
6624     config_upper = cmSystemTools::UpperCase(config);
6625   }
6626   auto iter = this->ISPCGeneratedObjects.find(config_upper);
6627   if (iter == this->ISPCGeneratedObjects.end()) {
6628     this->ISPCGeneratedObjects.insert({ config_upper, objs });
6629   } else {
6630     iter->second.insert(iter->second.end(), objs.begin(), objs.end());
6631   }
6632 }
6633
6634 std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
6635   std::string const& config) const
6636 {
6637   std::string config_upper;
6638   if (!config.empty()) {
6639     config_upper = cmSystemTools::UpperCase(config);
6640   }
6641   auto iter = this->ISPCGeneratedObjects.find(config_upper);
6642   if (iter == this->ISPCGeneratedObjects.end()) {
6643     return std::vector<std::string>{};
6644   }
6645   return iter->second;
6646 }
6647
6648 std::string cmGeneratorTarget::GetFrameworkVersion() const
6649 {
6650   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
6651
6652   if (cmValue fversion = this->GetProperty("FRAMEWORK_VERSION")) {
6653     return *fversion;
6654   }
6655   if (cmValue tversion = this->GetProperty("VERSION")) {
6656     return *tversion;
6657   }
6658   return "A";
6659 }
6660
6661 void cmGeneratorTarget::ComputeVersionedName(
6662   std::string& vName, std::string const& prefix, std::string const& base,
6663   std::string const& suffix, std::string const& name, cmValue version) const
6664 {
6665   vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
6666   if (version) {
6667     vName += ".";
6668     vName += *version;
6669   }
6670   vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
6671 }
6672
6673 std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
6674 {
6675   return this->Target->GetProperties().GetKeys();
6676 }
6677
6678 void cmGeneratorTarget::ReportPropertyOrigin(
6679   const std::string& p, const std::string& result, const std::string& report,
6680   const std::string& compatibilityType) const
6681 {
6682   std::vector<std::string> debugProperties;
6683   this->Target->GetMakefile()->GetDefExpandList(
6684     "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties);
6685
6686   bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
6687     cm::contains(debugProperties, p);
6688
6689   if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
6690     this->DebugCompatiblePropertiesDone[p] = true;
6691   }
6692   if (!debugOrigin) {
6693     return;
6694   }
6695
6696   std::string areport =
6697     cmStrCat(compatibilityType, " of property \"", p, "\" for target \"",
6698              this->GetName(), "\" (result: \"", result, "\"):\n", report);
6699
6700   this->LocalGenerator->GetCMakeInstance()->IssueMessage(MessageType::LOG,
6701                                                          areport);
6702 }
6703
6704 bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
6705                                           cmLocalGenerator const*& lg) const
6706 {
6707   if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
6708     cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
6709     if (dirId.String.empty()) {
6710       lg = this->LocalGenerator;
6711       return true;
6712     }
6713     if (cmLocalGenerator const* otherLG =
6714           this->GlobalGenerator->FindLocalGenerator(dirId)) {
6715       lg = otherLG;
6716       return true;
6717     }
6718   }
6719   return false;
6720 }
6721
6722 cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
6723   std::string const& n, cmListFileBacktrace const& bt,
6724   LookupLinkItemScope* scope, LookupSelf lookupSelf) const
6725 {
6726   cm::optional<cmLinkItem> maybeItem;
6727   if (this->IsLinkLookupScope(n, scope->LG)) {
6728     return maybeItem;
6729   }
6730
6731   std::string name = this->CheckCMP0004(n);
6732   if (name.empty() ||
6733       (lookupSelf == LookupSelf::No && name == this->GetName())) {
6734     return maybeItem;
6735   }
6736   maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG);
6737   return maybeItem;
6738 }
6739
6740 void cmGeneratorTarget::ExpandLinkItems(
6741   std::string const& prop, cmBTStringRange entries, std::string const& config,
6742   cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor,
6743   LinkInterfaceField field, cmLinkInterface& iface) const
6744 {
6745   if (entries.empty()) {
6746     return;
6747   }
6748   // Keep this logic in sync with ComputeLinkImplementationLibraries.
6749   cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
6750   // The $<LINK_ONLY> expression may be in a link interface to specify
6751   // private link dependencies that are otherwise excluded from usage
6752   // requirements.
6753   if (interfaceFor == LinkInterfaceFor::Usage) {
6754     dagChecker.SetTransitivePropertiesOnly();
6755   }
6756   cmMakefile const* mf = this->LocalGenerator->GetMakefile();
6757   LookupLinkItemScope scope{ this->LocalGenerator };
6758   for (BT<std::string> const& entry : entries) {
6759     cmGeneratorExpression ge(entry.Backtrace);
6760     std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value);
6761     cge->SetEvaluateForBuildsystem(true);
6762     std::vector<std::string> libs = cmExpandedList(
6763       cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker,
6764                     this, headTarget->LinkerLanguage));
6765     for (std::string const& lib : libs) {
6766       if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
6767             lib, cge->GetBacktrace(), &scope,
6768             field == LinkInterfaceField::Libraries ? LookupSelf::No
6769                                                    : LookupSelf::Yes)) {
6770         cmLinkItem item = std::move(*maybeItem);
6771
6772         if (field == LinkInterfaceField::HeadInclude) {
6773           iface.HeadInclude.emplace_back(std::move(item));
6774           continue;
6775         }
6776         if (field == LinkInterfaceField::HeadExclude) {
6777           iface.HeadExclude.emplace_back(std::move(item));
6778           continue;
6779         }
6780         if (!item.Target) {
6781           // Report explicitly linked object files separately.
6782           std::string const& maybeObj = item.AsStr();
6783           if (cmSystemTools::FileIsFullPath(maybeObj)) {
6784             cmSourceFile const* sf =
6785               mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
6786             if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
6787               iface.Objects.emplace_back(std::move(item));
6788               continue;
6789             }
6790           }
6791         }
6792
6793         iface.Libraries.emplace_back(std::move(item));
6794       }
6795     }
6796     if (cge->GetHadHeadSensitiveCondition()) {
6797       iface.HadHeadSensitiveCondition = true;
6798     }
6799     if (cge->GetHadContextSensitiveCondition()) {
6800       iface.HadContextSensitiveCondition = true;
6801     }
6802     if (cge->GetHadLinkLanguageSensitiveCondition()) {
6803       iface.HadLinkLanguageSensitiveCondition = true;
6804     }
6805   }
6806 }
6807
6808 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
6809   const std::string& config, cmGeneratorTarget const* head) const
6810 {
6811   return this->GetLinkInterface(config, head, false);
6812 }
6813
6814 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
6815   const std::string& config, cmGeneratorTarget const* head,
6816   bool secondPass) const
6817 {
6818   // Imported targets have their own link interface.
6819   if (this->IsImported()) {
6820     return this->GetImportLinkInterface(config, head, LinkInterfaceFor::Link,
6821                                         secondPass);
6822   }
6823
6824   // Link interfaces are not supported for executables that do not
6825   // export symbols.
6826   if (this->GetType() == cmStateEnums::EXECUTABLE &&
6827       !this->IsExecutableWithExports()) {
6828     return nullptr;
6829   }
6830
6831   // Lookup any existing link interface for this configuration.
6832   cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
6833
6834   // If the link interface does not depend on the head target
6835   // then re-use the one from the head we computed first.
6836   if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6837     head = hm.begin()->first;
6838   }
6839
6840   cmOptionalLinkInterface& iface = hm[head];
6841   if (secondPass) {
6842     iface = cmOptionalLinkInterface();
6843   }
6844   if (!iface.LibrariesDone) {
6845     iface.LibrariesDone = true;
6846     this->ComputeLinkInterfaceLibraries(config, iface, head,
6847                                         LinkInterfaceFor::Link);
6848   }
6849   if (!iface.AllDone) {
6850     iface.AllDone = true;
6851     if (iface.Exists) {
6852       this->ComputeLinkInterface(config, iface, head, secondPass);
6853       this->ComputeLinkInterfaceRuntimeLibraries(config, iface);
6854     }
6855   }
6856
6857   return iface.Exists ? &iface : nullptr;
6858 }
6859
6860 void cmGeneratorTarget::ComputeLinkInterface(
6861   const std::string& config, cmOptionalLinkInterface& iface,
6862   cmGeneratorTarget const* headTarget) const
6863 {
6864   this->ComputeLinkInterface(config, iface, headTarget, false);
6865 }
6866
6867 void cmGeneratorTarget::ComputeLinkInterface(
6868   const std::string& config, cmOptionalLinkInterface& iface,
6869   cmGeneratorTarget const* headTarget, bool secondPass) const
6870 {
6871   if (iface.Explicit) {
6872     if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6873         this->GetType() == cmStateEnums::STATIC_LIBRARY ||
6874         this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
6875       // Shared libraries may have runtime implementation dependencies
6876       // on other shared libraries that are not in the interface.
6877       std::set<cmLinkItem> emitted;
6878       for (cmLinkItem const& lib : iface.Libraries) {
6879         emitted.insert(lib);
6880       }
6881       if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
6882         cmLinkImplementation const* impl = this->GetLinkImplementation(
6883           config, LinkInterfaceFor::Link, secondPass);
6884         for (cmLinkImplItem const& lib : impl->Libraries) {
6885           if (emitted.insert(lib).second) {
6886             if (lib.Target) {
6887               // This is a runtime dependency on another shared library.
6888               if (lib.Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
6889                 iface.SharedDeps.push_back(lib);
6890               }
6891             } else {
6892               // TODO: Recognize shared library file names.  Perhaps this
6893               // should be moved to cmComputeLinkInformation, but that
6894               // creates a chicken-and-egg problem since this list is needed
6895               // for its construction.
6896             }
6897           }
6898         }
6899       }
6900     }
6901   } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
6902              this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
6903     // The link implementation is the default link interface.
6904     cmLinkImplementationLibraries const* impl =
6905       this->GetLinkImplementationLibrariesInternal(config, headTarget,
6906                                                    LinkInterfaceFor::Link);
6907     iface.ImplementationIsInterface = true;
6908     iface.WrongConfigLibraries = impl->WrongConfigLibraries;
6909   }
6910
6911   if (this->LinkLanguagePropagatesToDependents()) {
6912     // Targets using this archive need its language runtime libraries.
6913     if (cmLinkImplementation const* impl = this->GetLinkImplementation(
6914           config, LinkInterfaceFor::Link, secondPass)) {
6915       iface.Languages = impl->Languages;
6916     }
6917   }
6918
6919   if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
6920     // Construct the property name suffix for this configuration.
6921     std::string suffix = "_";
6922     if (!config.empty()) {
6923       suffix += cmSystemTools::UpperCase(config);
6924     } else {
6925       suffix += "NOCONFIG";
6926     }
6927
6928     // How many repetitions are needed if this library has cyclic
6929     // dependencies?
6930     std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix);
6931     if (cmValue config_reps = this->GetProperty(propName)) {
6932       sscanf(config_reps->c_str(), "%u", &iface.Multiplicity);
6933     } else if (cmValue reps =
6934                  this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
6935       sscanf(reps->c_str(), "%u", &iface.Multiplicity);
6936     }
6937   }
6938 }
6939
6940 const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
6941   const std::string& config, cmGeneratorTarget const* head,
6942   LinkInterfaceFor interfaceFor) const
6943 {
6944   // Imported targets have their own link interface.
6945   if (this->IsImported()) {
6946     return this->GetImportLinkInterface(config, head, interfaceFor);
6947   }
6948
6949   // Link interfaces are not supported for executables that do not
6950   // export symbols.
6951   if (this->GetType() == cmStateEnums::EXECUTABLE &&
6952       !this->IsExecutableWithExports()) {
6953     return nullptr;
6954   }
6955
6956   // Lookup any existing link interface for this configuration.
6957   cmHeadToLinkInterfaceMap& hm =
6958     (interfaceFor == LinkInterfaceFor::Usage
6959        ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
6960        : this->GetHeadToLinkInterfaceMap(config));
6961
6962   // If the link interface does not depend on the head target
6963   // then re-use the one from the head we computed first.
6964   if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6965     head = hm.begin()->first;
6966   }
6967
6968   cmOptionalLinkInterface& iface = hm[head];
6969   if (!iface.LibrariesDone) {
6970     iface.LibrariesDone = true;
6971     this->ComputeLinkInterfaceLibraries(config, iface, head, interfaceFor);
6972   }
6973
6974   return iface.Exists ? &iface : nullptr;
6975 }
6976
6977 std::string cmGeneratorTarget::GetDirectory(
6978   const std::string& config, cmStateEnums::ArtifactType artifact) const
6979 {
6980   if (this->IsImported()) {
6981     auto fullPath = this->Target->ImportedGetFullPath(config, artifact);
6982     if (this->IsFrameworkOnApple()) {
6983       cmsys::RegularExpressionMatch match;
6984       if (FrameworkRegularExpression.find(fullPath.c_str(), match)) {
6985         auto path = match.match(1);
6986         if (!path.empty()) {
6987           path.erase(path.length() - 1);
6988         }
6989         return path;
6990       }
6991     }
6992     // Return the directory from which the target is imported.
6993     return cmSystemTools::GetFilenamePath(fullPath);
6994   }
6995   if (OutputInfo const* info = this->GetOutputInfo(config)) {
6996     // Return the directory in which the target will be built.
6997     switch (artifact) {
6998       case cmStateEnums::RuntimeBinaryArtifact:
6999         return info->OutDir;
7000       case cmStateEnums::ImportLibraryArtifact:
7001         return info->ImpDir;
7002     }
7003   }
7004   return "";
7005 }
7006
7007 bool cmGeneratorTarget::UsesDefaultOutputDir(
7008   const std::string& config, cmStateEnums::ArtifactType artifact) const
7009 {
7010   std::string dir;
7011   return this->ComputeOutputDir(config, artifact, dir);
7012 }
7013
7014 cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
7015   const std::string& config) const
7016 {
7017   // There is no output information for imported targets.
7018   if (this->IsImported()) {
7019     return nullptr;
7020   }
7021
7022   // Only libraries and executables have well-defined output files.
7023   if (!this->HaveWellDefinedOutputFiles()) {
7024     std::string msg = cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
7025                                this->GetName(), " which has type ",
7026                                cmState::GetTargetTypeName(this->GetType()));
7027     this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
7028     return nullptr;
7029   }
7030
7031   // Lookup/compute/cache the output information for this configuration.
7032   std::string config_upper;
7033   if (!config.empty()) {
7034     config_upper = cmSystemTools::UpperCase(config);
7035   }
7036   auto i = this->OutputInfoMap.find(config_upper);
7037   if (i == this->OutputInfoMap.end()) {
7038     // Add empty info in map to detect potential recursion.
7039     OutputInfo info;
7040     OutputInfoMapType::value_type entry(config_upper, info);
7041     i = this->OutputInfoMap.insert(entry).first;
7042
7043     // Compute output directories.
7044     this->ComputeOutputDir(config, cmStateEnums::RuntimeBinaryArtifact,
7045                            info.OutDir);
7046     this->ComputeOutputDir(config, cmStateEnums::ImportLibraryArtifact,
7047                            info.ImpDir);
7048     if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
7049       info.PdbDir = info.OutDir;
7050     }
7051
7052     // Now update the previously-prepared map entry.
7053     i->second = info;
7054   } else if (i->second.empty()) {
7055     // An empty map entry indicates we have been called recursively
7056     // from the above block.
7057     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
7058       MessageType::FATAL_ERROR,
7059       "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
7060       this->GetBacktrace());
7061     return nullptr;
7062   }
7063   return &i->second;
7064 }
7065
7066 bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
7067                                          cmStateEnums::ArtifactType artifact,
7068                                          std::string& out) const
7069 {
7070   bool usesDefaultOutputDir = false;
7071   std::string conf = config;
7072
7073   // Look for a target property defining the target output directory
7074   // based on the target type.
7075   std::string targetTypeName = this->GetOutputTargetType(artifact);
7076   std::string propertyName;
7077   if (!targetTypeName.empty()) {
7078     propertyName = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY");
7079   }
7080
7081   // Check for a per-configuration output directory target property.
7082   std::string configUpper = cmSystemTools::UpperCase(conf);
7083   std::string configProp;
7084   if (!targetTypeName.empty()) {
7085     configProp = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY_", configUpper);
7086   }
7087
7088   // Select an output directory.
7089   if (cmValue config_outdir = this->GetProperty(configProp)) {
7090     // Use the user-specified per-configuration output directory.
7091     out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
7092                                           config, this);
7093
7094     // Skip per-configuration subdirectory.
7095     conf.clear();
7096   } else if (cmValue outdir = this->GetProperty(propertyName)) {
7097     // Use the user-specified output directory.
7098     out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
7099                                           config, this);
7100     // Skip per-configuration subdirectory if the value contained a
7101     // generator expression.
7102     if (out != *outdir) {
7103       conf.clear();
7104     }
7105   } else if (this->GetType() == cmStateEnums::EXECUTABLE) {
7106     // Lookup the output path for executables.
7107     out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
7108   } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
7109              this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7110              this->GetType() == cmStateEnums::MODULE_LIBRARY) {
7111     // Lookup the output path for libraries.
7112     out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
7113   }
7114   if (out.empty()) {
7115     // Default to the current output directory.
7116     usesDefaultOutputDir = true;
7117     out = ".";
7118   }
7119
7120   // Convert the output path to a full path in case it is
7121   // specified as a relative path.  Treat a relative path as
7122   // relative to the current output directory for this makefile.
7123   out = (cmSystemTools::CollapseFullPath(
7124     out, this->LocalGenerator->GetCurrentBinaryDirectory()));
7125
7126   // The generator may add the configuration's subdirectory.
7127   if (!conf.empty()) {
7128     bool useEPN =
7129       this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
7130     std::string suffix =
7131       usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
7132     this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
7133       "/", conf, suffix, out);
7134   }
7135
7136   return usesDefaultOutputDir;
7137 }
7138
7139 bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
7140                                             const std::string& config,
7141                                             std::string& out) const
7142 {
7143   // Look for a target property defining the target output directory
7144   // based on the target type.
7145   std::string propertyName;
7146   if (!kind.empty()) {
7147     propertyName = cmStrCat(kind, "_OUTPUT_DIRECTORY");
7148   }
7149   std::string conf = config;
7150
7151   // Check for a per-configuration output directory target property.
7152   std::string configUpper = cmSystemTools::UpperCase(conf);
7153   std::string configProp;
7154   if (!kind.empty()) {
7155     configProp = cmStrCat(kind, "_OUTPUT_DIRECTORY_", configUpper);
7156   }
7157
7158   // Select an output directory.
7159   if (cmValue config_outdir = this->GetProperty(configProp)) {
7160     // Use the user-specified per-configuration output directory.
7161     out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
7162                                           config);
7163
7164     // Skip per-configuration subdirectory.
7165     conf.clear();
7166   } else if (cmValue outdir = this->GetProperty(propertyName)) {
7167     // Use the user-specified output directory.
7168     out =
7169       cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
7170
7171     // Skip per-configuration subdirectory if the value contained a
7172     // generator expression.
7173     if (out != *outdir) {
7174       conf.clear();
7175     }
7176   }
7177   if (out.empty()) {
7178     return false;
7179   }
7180
7181   // Convert the output path to a full path in case it is
7182   // specified as a relative path.  Treat a relative path as
7183   // relative to the current output directory for this makefile.
7184   out = (cmSystemTools::CollapseFullPath(
7185     out, this->LocalGenerator->GetCurrentBinaryDirectory()));
7186
7187   // The generator may add the configuration's subdirectory.
7188   if (!conf.empty()) {
7189     this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
7190       "/", conf, "", out);
7191   }
7192   return true;
7193 }
7194
7195 bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string& config) const
7196 {
7197   std::string install_rpath;
7198   this->GetInstallRPATH(config, install_rpath);
7199   return !install_rpath.empty() &&
7200     !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
7201 }
7202
7203 bool cmGeneratorTarget::GetBuildRPATH(const std::string& config,
7204                                       std::string& rpath) const
7205 {
7206   return this->GetRPATH(config, "BUILD_RPATH", rpath);
7207 }
7208
7209 bool cmGeneratorTarget::GetInstallRPATH(const std::string& config,
7210                                         std::string& rpath) const
7211 {
7212   return this->GetRPATH(config, "INSTALL_RPATH", rpath);
7213 }
7214
7215 bool cmGeneratorTarget::GetRPATH(const std::string& config,
7216                                  const std::string& prop,
7217                                  std::string& rpath) const
7218 {
7219   cmValue value = this->GetProperty(prop);
7220   if (!value) {
7221     return false;
7222   }
7223
7224   rpath =
7225     cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config);
7226
7227   return true;
7228 }
7229
7230 void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
7231   const std::string& config, cmOptionalLinkInterface& iface,
7232   cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor) const
7233 {
7234   // Construct the property name suffix for this configuration.
7235   std::string suffix = "_";
7236   if (!config.empty()) {
7237     suffix += cmSystemTools::UpperCase(config);
7238   } else {
7239     suffix += "NOCONFIG";
7240   }
7241
7242   // An explicit list of interface libraries may be set for shared
7243   // libraries and executables that export symbols.
7244   bool haveExplicitLibraries = false;
7245   cmValue explicitLibrariesCMP0022OLD;
7246   std::string linkIfacePropCMP0022OLD;
7247   bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
7248                            this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
7249   if (cmp0022NEW) {
7250     // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
7251     haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty() ||
7252       !this->Target->GetLinkInterfaceDirectEntries().empty() ||
7253       !this->Target->GetLinkInterfaceDirectExcludeEntries().empty();
7254   } else {
7255     // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
7256     // shared lib or executable.
7257     if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7258         this->IsExecutableWithExports()) {
7259       // Lookup the per-configuration property.
7260       linkIfacePropCMP0022OLD = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
7261       explicitLibrariesCMP0022OLD = this->GetProperty(linkIfacePropCMP0022OLD);
7262
7263       // If not set, try the generic property.
7264       if (!explicitLibrariesCMP0022OLD) {
7265         linkIfacePropCMP0022OLD = "LINK_INTERFACE_LIBRARIES";
7266         explicitLibrariesCMP0022OLD =
7267           this->GetProperty(linkIfacePropCMP0022OLD);
7268       }
7269     }
7270
7271     if (explicitLibrariesCMP0022OLD &&
7272         this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
7273         !this->PolicyWarnedCMP0022) {
7274       // Compare the explicitly set old link interface properties to the
7275       // preferred new link interface property one and warn if different.
7276       cmValue newExplicitLibraries =
7277         this->GetProperty("INTERFACE_LINK_LIBRARIES");
7278       if (newExplicitLibraries &&
7279           (*newExplicitLibraries != *explicitLibrariesCMP0022OLD)) {
7280         std::ostringstream w;
7281         /* clang-format off */
7282         w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
7283           "Target \"" << this->GetName() << "\" has an "
7284           "INTERFACE_LINK_LIBRARIES property which differs from its " <<
7285           linkIfacePropCMP0022OLD << " properties."
7286           "\n"
7287           "INTERFACE_LINK_LIBRARIES:\n"
7288           "  " << *newExplicitLibraries << "\n" <<
7289           linkIfacePropCMP0022OLD << ":\n"
7290           "  " << *explicitLibrariesCMP0022OLD << "\n";
7291         /* clang-format on */
7292         this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
7293                                            w.str());
7294         this->PolicyWarnedCMP0022 = true;
7295       }
7296     }
7297
7298     haveExplicitLibraries = static_cast<bool>(explicitLibrariesCMP0022OLD);
7299   }
7300
7301   // There is no implicit link interface for executables or modules
7302   // so if none was explicitly set then there is no link interface.
7303   if (!haveExplicitLibraries &&
7304       (this->GetType() == cmStateEnums::EXECUTABLE ||
7305        (this->GetType() == cmStateEnums::MODULE_LIBRARY))) {
7306     return;
7307   }
7308   iface.Exists = true;
7309
7310   // If CMP0022 is NEW then the plain tll signature sets the
7311   // INTERFACE_LINK_LIBRARIES property.  Even if the project
7312   // clears it, the link interface is still explicit.
7313   iface.Explicit = cmp0022NEW || explicitLibrariesCMP0022OLD;
7314
7315   if (cmp0022NEW) {
7316     // The interface libraries are specified by INTERFACE_LINK_LIBRARIES.
7317     // Use its special representation directly to get backtraces.
7318     this->ExpandLinkItems(
7319       kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(),
7320       config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface);
7321     this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
7322                           this->Target->GetLinkInterfaceDirectEntries(),
7323                           config, headTarget, interfaceFor,
7324                           LinkInterfaceField::HeadInclude, iface);
7325     this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
7326                           this->Target->GetLinkInterfaceDirectExcludeEntries(),
7327                           config, headTarget, interfaceFor,
7328                           LinkInterfaceField::HeadExclude, iface);
7329   } else if (explicitLibrariesCMP0022OLD) {
7330     // The interface libraries have been explicitly set in pre-CMP0022 style.
7331     std::vector<BT<std::string>> entries;
7332     entries.emplace_back(*explicitLibrariesCMP0022OLD);
7333     this->ExpandLinkItems(linkIfacePropCMP0022OLD, cmMakeRange(entries),
7334                           config, headTarget, interfaceFor,
7335                           LinkInterfaceField::Libraries, iface);
7336   }
7337
7338   // If the link interface is explicit, do not fall back to the link impl.
7339   if (iface.Explicit) {
7340     return;
7341   }
7342
7343   // The link implementation is the default link interface.
7344   if (cmLinkImplementationLibraries const* impl =
7345         this->GetLinkImplementationLibrariesInternal(config, headTarget,
7346                                                      interfaceFor)) {
7347     iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
7348                            impl->Libraries.end());
7349     if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
7350         !this->PolicyWarnedCMP0022 && interfaceFor == LinkInterfaceFor::Link) {
7351       // Compare the link implementation fallback link interface to the
7352       // preferred new link interface property and warn if different.
7353       cmLinkInterface ifaceNew;
7354       this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES,
7355                             this->Target->GetLinkInterfaceEntries(), config,
7356                             headTarget, interfaceFor,
7357                             LinkInterfaceField::Libraries, ifaceNew);
7358       if (ifaceNew.Libraries != iface.Libraries) {
7359         std::string oldLibraries = cmJoin(impl->Libraries, ";");
7360         std::string newLibraries = cmJoin(ifaceNew.Libraries, ";");
7361         if (oldLibraries.empty()) {
7362           oldLibraries = "(empty)";
7363         }
7364         if (newLibraries.empty()) {
7365           newLibraries = "(empty)";
7366         }
7367
7368         std::ostringstream w;
7369         /* clang-format off */
7370         w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
7371           "Target \"" << this->GetName() << "\" has an "
7372           "INTERFACE_LINK_LIBRARIES property.  "
7373           "This should be preferred as the source of the link interface "
7374           "for this library but because CMP0022 is not set CMake is "
7375           "ignoring the property and using the link implementation "
7376           "as the link interface instead."
7377           "\n"
7378           "INTERFACE_LINK_LIBRARIES:\n"
7379           "  " << newLibraries << "\n"
7380           "Link implementation:\n"
7381           "  " << oldLibraries << "\n";
7382         /* clang-format on */
7383         this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
7384                                            w.str());
7385         this->PolicyWarnedCMP0022 = true;
7386       }
7387     }
7388   }
7389 }
7390
7391 namespace {
7392
7393 template <typename ReturnType>
7394 ReturnType constructItem(cmGeneratorTarget* target,
7395                          cmListFileBacktrace const& bt);
7396
7397 template <>
7398 inline cmLinkImplItem constructItem(cmGeneratorTarget* target,
7399                                     cmListFileBacktrace const& bt)
7400 {
7401   return cmLinkImplItem(cmLinkItem(target, false, bt), false);
7402 }
7403
7404 template <>
7405 inline cmLinkItem constructItem(cmGeneratorTarget* target,
7406                                 cmListFileBacktrace const& bt)
7407 {
7408   return cmLinkItem(target, false, bt);
7409 }
7410
7411 template <typename ValueType>
7412 std::vector<ValueType> computeImplicitLanguageTargets(
7413   std::string const& lang, std::string const& config,
7414   cmGeneratorTarget const* currentTarget)
7415 {
7416   cmListFileBacktrace bt;
7417   std::vector<ValueType> result;
7418   cmLocalGenerator* lg = currentTarget->GetLocalGenerator();
7419
7420   std::string const& runtimeLibrary =
7421     currentTarget->GetRuntimeLinkLibrary(lang, config);
7422   if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition(
7423         "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) {
7424     std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
7425     result.reserve(libsVec.size());
7426
7427     for (std::string const& i : libsVec) {
7428       cmGeneratorTarget::TargetOrString resolved =
7429         currentTarget->ResolveTargetReference(i, lg);
7430       if (resolved.Target) {
7431         result.emplace_back(constructItem<ValueType>(resolved.Target, bt));
7432       }
7433     }
7434   }
7435
7436   return result;
7437 }
7438 }
7439
7440 void cmGeneratorTarget::ComputeLinkInterfaceRuntimeLibraries(
7441   const std::string& config, cmOptionalLinkInterface& iface) const
7442 {
7443   for (std::string const& lang : iface.Languages) {
7444     if ((lang == "CUDA" || lang == "HIP") &&
7445         iface.LanguageRuntimeLibraries.find(lang) ==
7446           iface.LanguageRuntimeLibraries.end()) {
7447       auto implicitTargets =
7448         computeImplicitLanguageTargets<cmLinkItem>(lang, config, this);
7449       iface.LanguageRuntimeLibraries[lang] = std::move(implicitTargets);
7450     }
7451   }
7452 }
7453
7454 void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries(
7455   const std::string& config, cmOptionalLinkImplementation& impl) const
7456 {
7457   for (std::string const& lang : impl.Languages) {
7458     if ((lang == "CUDA" || lang == "HIP") &&
7459         impl.LanguageRuntimeLibraries.find(lang) ==
7460           impl.LanguageRuntimeLibraries.end()) {
7461       auto implicitTargets =
7462         computeImplicitLanguageTargets<cmLinkImplItem>(lang, config, this);
7463       impl.LanguageRuntimeLibraries[lang] = std::move(implicitTargets);
7464     }
7465   }
7466 }
7467
7468 const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
7469   const std::string& config, cmGeneratorTarget const* headTarget,
7470   LinkInterfaceFor interfaceFor, bool secondPass) const
7471 {
7472   cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config);
7473   if (!info) {
7474     return nullptr;
7475   }
7476
7477   cmHeadToLinkInterfaceMap& hm =
7478     (interfaceFor == LinkInterfaceFor::Usage
7479        ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
7480        : this->GetHeadToLinkInterfaceMap(config));
7481
7482   // If the link interface does not depend on the head target
7483   // then re-use the one from the head we computed first.
7484   if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
7485     headTarget = hm.begin()->first;
7486   }
7487
7488   cmOptionalLinkInterface& iface = hm[headTarget];
7489   if (secondPass) {
7490     iface = cmOptionalLinkInterface();
7491   }
7492   if (!iface.AllDone) {
7493     iface.AllDone = true;
7494     iface.LibrariesDone = true;
7495     iface.Multiplicity = info->Multiplicity;
7496     cmExpandList(info->Languages, iface.Languages);
7497     this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
7498                           cmMakeRange(info->LibrariesHeadInclude), config,
7499                           headTarget, interfaceFor,
7500                           LinkInterfaceField::HeadInclude, iface);
7501     this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
7502                           cmMakeRange(info->LibrariesHeadExclude), config,
7503                           headTarget, interfaceFor,
7504                           LinkInterfaceField::HeadExclude, iface);
7505     this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries),
7506                           config, headTarget, interfaceFor,
7507                           LinkInterfaceField::Libraries, iface);
7508     std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
7509     LookupLinkItemScope scope{ this->LocalGenerator };
7510     for (std::string const& dep : deps) {
7511       if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
7512             dep, cmListFileBacktrace(), &scope, LookupSelf::No)) {
7513         iface.SharedDeps.emplace_back(std::move(*maybeItem));
7514       }
7515     }
7516   }
7517
7518   return &iface;
7519 }
7520
7521 cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
7522   const std::string& config) const
7523 {
7524   // There is no imported information for non-imported targets.
7525   if (!this->IsImported()) {
7526     return nullptr;
7527   }
7528
7529   // Lookup/compute/cache the import information for this
7530   // configuration.
7531   std::string config_upper;
7532   if (!config.empty()) {
7533     config_upper = cmSystemTools::UpperCase(config);
7534   } else {
7535     config_upper = "NOCONFIG";
7536   }
7537
7538   auto i = this->ImportInfoMap.find(config_upper);
7539   if (i == this->ImportInfoMap.end()) {
7540     ImportInfo info;
7541     this->ComputeImportInfo(config_upper, info);
7542     ImportInfoMapType::value_type entry(config_upper, info);
7543     i = this->ImportInfoMap.insert(entry).first;
7544   }
7545
7546   if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
7547     return &i->second;
7548   }
7549   // If the location is empty then the target is not available for
7550   // this configuration.
7551   if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
7552     return nullptr;
7553   }
7554
7555   // Return the import information.
7556   return &i->second;
7557 }
7558
7559 void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
7560                                           ImportInfo& info) const
7561 {
7562   // This method finds information about an imported target from its
7563   // properties.  The "IMPORTED_" namespace is reserved for properties
7564   // defined by the project exporting the target.
7565
7566   // Initialize members.
7567   info.NoSOName = false;
7568
7569   cmValue loc = nullptr;
7570   cmValue imp = nullptr;
7571   std::string suffix;
7572   if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
7573     return;
7574   }
7575
7576   // Get the link interface.
7577   {
7578     // Use the INTERFACE_LINK_LIBRARIES special representation directly
7579     // to get backtraces.
7580     cmBTStringRange entries = this->Target->GetLinkInterfaceEntries();
7581     if (!entries.empty()) {
7582       info.LibrariesProp = "INTERFACE_LINK_LIBRARIES";
7583       for (BT<std::string> const& entry : entries) {
7584         info.Libraries.emplace_back(entry);
7585       }
7586     } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
7587       std::string linkProp =
7588         cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix);
7589       cmValue propertyLibs = this->GetProperty(linkProp);
7590       if (!propertyLibs) {
7591         linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
7592         propertyLibs = this->GetProperty(linkProp);
7593       }
7594       if (propertyLibs) {
7595         info.LibrariesProp = linkProp;
7596         info.Libraries.emplace_back(*propertyLibs);
7597       }
7598     }
7599   }
7600   for (BT<std::string> const& entry :
7601        this->Target->GetLinkInterfaceDirectEntries()) {
7602     info.LibrariesHeadInclude.emplace_back(entry);
7603   }
7604   for (BT<std::string> const& entry :
7605        this->Target->GetLinkInterfaceDirectExcludeEntries()) {
7606     info.LibrariesHeadExclude.emplace_back(entry);
7607   }
7608   if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
7609     if (loc) {
7610       info.LibName = *loc;
7611     }
7612     return;
7613   }
7614
7615   // A provided configuration has been chosen.  Load the
7616   // configuration's properties.
7617
7618   // Get the location.
7619   if (loc) {
7620     info.Location = *loc;
7621   } else {
7622     std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
7623     if (cmValue config_location = this->GetProperty(impProp)) {
7624       info.Location = *config_location;
7625     } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
7626       info.Location = *location;
7627     }
7628   }
7629
7630   // Get the soname.
7631   if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
7632     std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
7633     if (cmValue config_soname = this->GetProperty(soProp)) {
7634       info.SOName = *config_soname;
7635     } else if (cmValue soname = this->GetProperty("IMPORTED_SONAME")) {
7636       info.SOName = *soname;
7637     }
7638   }
7639
7640   // Get the "no-soname" mark.
7641   if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
7642     std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
7643     if (cmValue config_no_soname = this->GetProperty(soProp)) {
7644       info.NoSOName = cmIsOn(*config_no_soname);
7645     } else if (cmValue no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
7646       info.NoSOName = cmIsOn(*no_soname);
7647     }
7648   }
7649
7650   // Get the import library.
7651   if (imp) {
7652     info.ImportLibrary = *imp;
7653   } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7654              this->IsExecutableWithExports()) {
7655     std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
7656     if (cmValue config_implib = this->GetProperty(impProp)) {
7657       info.ImportLibrary = *config_implib;
7658     } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
7659       info.ImportLibrary = *implib;
7660     }
7661   }
7662
7663   // Get the link dependencies.
7664   {
7665     std::string linkProp =
7666       cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
7667     if (cmValue config_libs = this->GetProperty(linkProp)) {
7668       info.SharedDeps = *config_libs;
7669     } else if (cmValue libs =
7670                  this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
7671       info.SharedDeps = *libs;
7672     }
7673   }
7674
7675   // Get the link languages.
7676   if (this->LinkLanguagePropagatesToDependents()) {
7677     std::string linkProp =
7678       cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
7679     if (cmValue config_libs = this->GetProperty(linkProp)) {
7680       info.Languages = *config_libs;
7681     } else if (cmValue libs =
7682                  this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
7683       info.Languages = *libs;
7684     }
7685   }
7686
7687   // Get information if target is managed assembly.
7688   {
7689     std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
7690     if (cmValue pc = this->GetProperty(linkProp + suffix)) {
7691       info.Managed = this->CheckManagedType(*pc);
7692     } else if (cmValue p = this->GetProperty(linkProp)) {
7693       info.Managed = this->CheckManagedType(*p);
7694     }
7695   }
7696
7697   // Get the cyclic repetition count.
7698   if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
7699     std::string linkProp =
7700       cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
7701     if (cmValue config_reps = this->GetProperty(linkProp)) {
7702       sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
7703     } else if (cmValue reps =
7704                  this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
7705       sscanf(reps->c_str(), "%u", &info.Multiplicity);
7706     }
7707   }
7708 }
7709
7710 cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
7711   const std::string& config) const
7712 {
7713   return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)];
7714 }
7715
7716 cmHeadToLinkInterfaceMap&
7717 cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
7718   const std::string& config) const
7719 {
7720   return this
7721     ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
7722 }
7723
7724 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
7725   const std::string& config, LinkInterfaceFor implFor) const
7726 {
7727   return this->GetLinkImplementation(config, implFor, false);
7728 }
7729
7730 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
7731   const std::string& config, LinkInterfaceFor implFor, bool secondPass) const
7732 {
7733   // There is no link implementation for targets that cannot compile sources.
7734   if (!this->CanCompileSources()) {
7735     return nullptr;
7736   }
7737
7738   HeadToLinkImplementationMap& hm =
7739     (implFor == LinkInterfaceFor::Usage
7740        ? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
7741        : this->GetHeadToLinkImplementationMap(config));
7742   cmOptionalLinkImplementation& impl = hm[this];
7743   if (secondPass) {
7744     impl = cmOptionalLinkImplementation();
7745   }
7746   if (!impl.LibrariesDone) {
7747     impl.LibrariesDone = true;
7748     this->ComputeLinkImplementationLibraries(config, impl, this, implFor);
7749   }
7750   if (!impl.LanguagesDone) {
7751     impl.LanguagesDone = true;
7752     this->ComputeLinkImplementationLanguages(config, impl);
7753     this->ComputeLinkImplementationRuntimeLibraries(config, impl);
7754   }
7755   return &impl;
7756 }
7757
7758 cmGeneratorTarget::HeadToLinkImplementationMap&
7759 cmGeneratorTarget::GetHeadToLinkImplementationMap(
7760   std::string const& config) const
7761 {
7762   return this->LinkImplMap[cmSystemTools::UpperCase(config)];
7763 }
7764
7765 cmGeneratorTarget::HeadToLinkImplementationMap&
7766 cmGeneratorTarget::GetHeadToLinkImplementationUsageRequirementsMap(
7767   std::string const& config) const
7768 {
7769   return this
7770     ->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
7771 }
7772
7773 bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
7774   std::vector<cmSourceFile*>& files) const
7775 {
7776   std::vector<std::string> const& configs =
7777     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
7778
7779   auto it = configs.begin();
7780   const std::string& firstConfig = *it;
7781   this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
7782
7783   for (; it != configs.end(); ++it) {
7784     std::vector<cmSourceFile*> configFiles;
7785     this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
7786     if (configFiles != files) {
7787       std::string firstConfigFiles;
7788       const char* sep = "";
7789       for (cmSourceFile* f : files) {
7790         firstConfigFiles += sep;
7791         firstConfigFiles += f->ResolveFullPath();
7792         sep = "\n  ";
7793       }
7794
7795       std::string thisConfigFiles;
7796       sep = "";
7797       for (cmSourceFile* f : configFiles) {
7798         thisConfigFiles += sep;
7799         thisConfigFiles += f->ResolveFullPath();
7800         sep = "\n  ";
7801       }
7802       std::ostringstream e;
7803       /* clang-format off */
7804       e << "Target \"" << this->GetName()
7805         << "\" has source files which vary by "
7806         "configuration. This is not supported by the \""
7807         << this->GlobalGenerator->GetName()
7808         << "\" generator.\n"
7809           "Config \"" << firstConfig << "\":\n"
7810           "  " << firstConfigFiles << "\n"
7811           "Config \"" << *it << "\":\n"
7812           "  " << thisConfigFiles << "\n";
7813       /* clang-format on */
7814       this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
7815       return false;
7816     }
7817   }
7818   return true;
7819 }
7820
7821 void cmGeneratorTarget::GetObjectLibrariesCMP0026(
7822   std::vector<cmGeneratorTarget*>& objlibs) const
7823 {
7824   // At configure-time, this method can be called as part of getting the
7825   // LOCATION property or to export() a file to be include()d.  However
7826   // there is no cmGeneratorTarget at configure-time, so search the SOURCES
7827   // for TARGET_OBJECTS instead for backwards compatibility with OLD
7828   // behavior of CMP0024 and CMP0026 only.
7829   cmBTStringRange rng = this->Target->GetSourceEntries();
7830   for (auto const& entry : rng) {
7831     std::vector<std::string> files = cmExpandedList(entry.Value);
7832     for (std::string const& li : files) {
7833       if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
7834         std::string objLibName = li.substr(17, li.size() - 18);
7835
7836         if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
7837           continue;
7838         }
7839         cmGeneratorTarget* objLib =
7840           this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
7841         if (objLib) {
7842           objlibs.push_back(objLib);
7843         }
7844       }
7845     }
7846   }
7847 }
7848
7849 std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
7850 {
7851   // Strip whitespace off the library names because we used to do this
7852   // in case variables were expanded at generate time.  We no longer
7853   // do the expansion but users link to libraries like " ${VAR} ".
7854   std::string lib = item;
7855   std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
7856   if (pos != std::string::npos) {
7857     lib = lib.substr(pos);
7858   }
7859   pos = lib.find_last_not_of(" \t\r\n");
7860   if (pos != std::string::npos) {
7861     lib = lib.substr(0, pos + 1);
7862   }
7863   if (lib != item) {
7864     cmake* cm = this->LocalGenerator->GetCMakeInstance();
7865     switch (this->GetPolicyStatusCMP0004()) {
7866       case cmPolicies::WARN: {
7867         std::ostringstream w;
7868         w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
7869           << "Target \"" << this->GetName() << "\" links to item \"" << item
7870           << "\" which has leading or trailing whitespace.";
7871         cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
7872                          this->GetBacktrace());
7873       }
7874         CM_FALLTHROUGH;
7875       case cmPolicies::OLD:
7876         break;
7877       case cmPolicies::NEW: {
7878         std::ostringstream e;
7879         e << "Target \"" << this->GetName() << "\" links to item \"" << item
7880           << "\" which has leading or trailing whitespace.  "
7881           << "This is now an error according to policy CMP0004.";
7882         cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
7883                          this->GetBacktrace());
7884       } break;
7885       case cmPolicies::REQUIRED_IF_USED:
7886       case cmPolicies::REQUIRED_ALWAYS: {
7887         std::ostringstream e;
7888         e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
7889           << "Target \"" << this->GetName() << "\" links to item \"" << item
7890           << "\" which has leading or trailing whitespace.";
7891         cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
7892                          this->GetBacktrace());
7893       } break;
7894     }
7895   }
7896   return lib;
7897 }
7898
7899 bool cmGeneratorTarget::IsDeprecated() const
7900 {
7901   cmValue deprecation = this->GetProperty("DEPRECATION");
7902   return cmNonempty(deprecation);
7903 }
7904
7905 std::string cmGeneratorTarget::GetDeprecation() const
7906 {
7907   // find DEPRECATION property
7908   if (cmValue deprecation = this->GetProperty("DEPRECATION")) {
7909     return *deprecation;
7910   }
7911   return std::string();
7912 }
7913
7914 void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
7915                                      const std::string& config) const
7916 {
7917   // Targets that do not compile anything have no languages.
7918   if (!this->CanCompileSources()) {
7919     return;
7920   }
7921
7922   std::vector<cmSourceFile*> sourceFiles;
7923   this->GetSourceFiles(sourceFiles, config);
7924   for (cmSourceFile* src : sourceFiles) {
7925     const std::string& lang = src->GetOrDetermineLanguage();
7926     if (!lang.empty()) {
7927       languages.insert(lang);
7928     }
7929   }
7930
7931   std::vector<cmGeneratorTarget*> objectLibraries;
7932   std::vector<cmSourceFile const*> externalObjects;
7933   if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
7934     std::vector<cmGeneratorTarget*> objectTargets;
7935     this->GetObjectLibrariesCMP0026(objectTargets);
7936     objectLibraries.reserve(objectTargets.size());
7937     for (cmGeneratorTarget* gt : objectTargets) {
7938       objectLibraries.push_back(gt);
7939     }
7940   } else {
7941     this->GetExternalObjects(externalObjects, config);
7942     for (cmSourceFile const* extObj : externalObjects) {
7943       std::string objLib = extObj->GetObjectLibrary();
7944       if (cmGeneratorTarget* tgt =
7945             this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
7946         auto const objLibIt =
7947           std::find_if(objectLibraries.cbegin(), objectLibraries.cend(),
7948                        [tgt](cmGeneratorTarget* t) { return t == tgt; });
7949         if (objectLibraries.cend() == objLibIt) {
7950           objectLibraries.push_back(tgt);
7951         }
7952       }
7953     }
7954   }
7955   for (cmGeneratorTarget* objLib : objectLibraries) {
7956     objLib->GetLanguages(languages, config);
7957   }
7958 }
7959
7960 bool cmGeneratorTarget::IsLanguageUsed(std::string const& language,
7961                                        std::string const& config) const
7962 {
7963   std::set<std::string> languages;
7964   this->GetLanguages(languages, config);
7965   return languages.count(language);
7966 }
7967
7968 bool cmGeneratorTarget::IsCSharpOnly() const
7969 {
7970   // Only certain target types may compile CSharp.
7971   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
7972       this->GetType() != cmStateEnums::STATIC_LIBRARY &&
7973       this->GetType() != cmStateEnums::EXECUTABLE) {
7974     return false;
7975   }
7976   std::set<std::string> languages = this->GetAllConfigCompileLanguages();
7977   // Consider an explicit linker language property, but *not* the
7978   // computed linker language that may depend on linked targets.
7979   cmValue linkLang = this->GetProperty("LINKER_LANGUAGE");
7980   if (cmNonempty(linkLang)) {
7981     languages.insert(*linkLang);
7982   }
7983   return languages.size() == 1 && languages.count("CSharp") > 0;
7984 }
7985
7986 bool cmGeneratorTarget::IsDotNetSdkTarget() const
7987 {
7988   return !this->GetProperty("DOTNET_SDK").IsEmpty();
7989 }
7990
7991 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
7992   const std::string& config, cmOptionalLinkImplementation& impl) const
7993 {
7994   // This target needs runtime libraries for its source languages.
7995   std::set<std::string> languages;
7996   // Get languages used in our source files.
7997   this->GetLanguages(languages, config);
7998   // Copy the set of languages to the link implementation.
7999   impl.Languages.insert(impl.Languages.begin(), languages.begin(),
8000                         languages.end());
8001 }
8002
8003 bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
8004 {
8005   if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
8006     return false;
8007   }
8008   std::string build_rpath;
8009   if (this->GetBuildRPATH(config, build_rpath)) {
8010     return true;
8011   }
8012   if (cmLinkImplementationLibraries const* impl =
8013         this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Link)) {
8014     return !impl->Libraries.empty();
8015   }
8016   return false;
8017 }
8018
8019 cmLinkImplementationLibraries const*
8020 cmGeneratorTarget::GetLinkImplementationLibraries(
8021   const std::string& config, LinkInterfaceFor implFor) const
8022 {
8023   return this->GetLinkImplementationLibrariesInternal(config, this, implFor);
8024 }
8025
8026 cmLinkImplementationLibraries const*
8027 cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
8028   const std::string& config, cmGeneratorTarget const* head,
8029   LinkInterfaceFor implFor) const
8030 {
8031   // There is no link implementation for targets that cannot compile sources.
8032   if (!this->CanCompileSources()) {
8033     return nullptr;
8034   }
8035
8036   // Populate the link implementation libraries for this configuration.
8037   HeadToLinkImplementationMap& hm =
8038     (implFor == LinkInterfaceFor::Usage
8039        ? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
8040        : this->GetHeadToLinkImplementationMap(config));
8041
8042   // If the link implementation does not depend on the head target
8043   // then re-use the one from the head we computed first.
8044   if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
8045     head = hm.begin()->first;
8046   }
8047
8048   cmOptionalLinkImplementation& impl = hm[head];
8049   if (!impl.LibrariesDone) {
8050     impl.LibrariesDone = true;
8051     this->ComputeLinkImplementationLibraries(config, impl, head, implFor);
8052   }
8053   return &impl;
8054 }
8055
8056 bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
8057   const std::string& p) const
8058 {
8059   return cm::contains(this->LinkImplicitNullProperties, p);
8060 }
8061
8062 namespace {
8063 class TransitiveLinkImpl
8064 {
8065   cmGeneratorTarget const* Self;
8066   std::string const& Config;
8067   LinkInterfaceFor ImplFor;
8068   cmLinkImplementation& Impl;
8069
8070   std::set<cmLinkItem> Emitted;
8071   std::set<cmLinkItem> Excluded;
8072   std::unordered_set<cmGeneratorTarget const*> Followed;
8073
8074   void Follow(cmGeneratorTarget const* target);
8075
8076 public:
8077   TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config,
8078                      LinkInterfaceFor implFor, cmLinkImplementation& impl)
8079     : Self(self)
8080     , Config(config)
8081     , ImplFor(implFor)
8082     , Impl(impl)
8083   {
8084   }
8085
8086   void Compute();
8087 };
8088
8089 void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target)
8090 {
8091   if (!target || !this->Followed.insert(target).second ||
8092       target->GetPolicyStatusCMP0022() == cmPolicies::OLD ||
8093       target->GetPolicyStatusCMP0022() == cmPolicies::WARN) {
8094     return;
8095   }
8096
8097   // Get this target's usage requirements.
8098   cmLinkInterfaceLibraries const* iface =
8099     target->GetLinkInterfaceLibraries(this->Config, this->Self, this->ImplFor);
8100   if (!iface) {
8101     return;
8102   }
8103   if (iface->HadContextSensitiveCondition) {
8104     this->Impl.HadContextSensitiveCondition = true;
8105   }
8106
8107   // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements.
8108   for (cmLinkItem const& item : iface->HeadInclude) {
8109     // Inject direct dependencies from the item's usage requirements
8110     // before the item itself.
8111     this->Follow(item.Target);
8112
8113     // Add the item itself, but at most once.
8114     if (this->Emitted.insert(item).second) {
8115       this->Impl.Libraries.emplace_back(item, /* checkCMP0027= */ false);
8116     }
8117   }
8118
8119   // Follow transitive dependencies.
8120   for (cmLinkItem const& item : iface->Libraries) {
8121     this->Follow(item.Target);
8122   }
8123
8124   // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8125   // usage requirements.
8126   for (cmLinkItem const& item : iface->HeadExclude) {
8127     this->Excluded.insert(item);
8128   }
8129 }
8130
8131 void TransitiveLinkImpl::Compute()
8132 {
8133   // Save the original items and start with an empty list.
8134   std::vector<cmLinkImplItem> original = std::move(this->Impl.Libraries);
8135
8136   // Avoid injecting any original items as usage requirements.
8137   // This gives LINK_LIBRARIES final control over the order
8138   // if it explicitly lists everything.
8139   this->Emitted.insert(original.cbegin(), original.cend());
8140
8141   // Process each original item.
8142   for (cmLinkImplItem& item : original) {
8143     // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT'
8144     // usage requirements before the item itself.
8145     this->Follow(item.Target);
8146
8147     // Add the item itself.
8148     this->Impl.Libraries.emplace_back(std::move(item));
8149   }
8150
8151   // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8152   // usage requirements found through any dependency above.
8153   this->Impl.Libraries.erase(
8154     std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(),
8155                    [this](cmLinkImplItem const& item) {
8156                      return this->Excluded.find(item) != this->Excluded.end();
8157                    }),
8158     this->Impl.Libraries.end());
8159 }
8160
8161 void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
8162                                std::string const& config,
8163                                LinkInterfaceFor implFor,
8164                                cmLinkImplementation& impl)
8165 {
8166   TransitiveLinkImpl transitiveLinkImpl(self, config, implFor, impl);
8167   transitiveLinkImpl.Compute();
8168 }
8169 }
8170
8171 void cmGeneratorTarget::ComputeLinkImplementationLibraries(
8172   const std::string& config, cmOptionalLinkImplementation& impl,
8173   cmGeneratorTarget const* head, LinkInterfaceFor implFor) const
8174 {
8175   cmLocalGenerator const* lg = this->LocalGenerator;
8176   cmMakefile const* mf = lg->GetMakefile();
8177   cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
8178   // Collect libraries directly linked in this configuration.
8179   for (auto const& entry : entryRange) {
8180     std::vector<std::string> llibs;
8181     // Keep this logic in sync with ExpandLinkItems.
8182     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
8183                                                nullptr);
8184     // The $<LINK_ONLY> expression may be used to specify link dependencies
8185     // that are otherwise excluded from usage requirements.
8186     if (implFor == LinkInterfaceFor::Usage) {
8187       switch (this->GetPolicyStatusCMP0131()) {
8188         case cmPolicies::WARN:
8189         case cmPolicies::OLD:
8190           break;
8191         case cmPolicies::REQUIRED_IF_USED:
8192         case cmPolicies::REQUIRED_ALWAYS:
8193         case cmPolicies::NEW:
8194           dagChecker.SetTransitivePropertiesOnly();
8195           break;
8196       }
8197     }
8198     cmGeneratorExpression ge(entry.Backtrace);
8199     std::unique_ptr<cmCompiledGeneratorExpression> const cge =
8200       ge.Parse(entry.Value);
8201     cge->SetEvaluateForBuildsystem(true);
8202     std::string const& evaluated =
8203       cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
8204                     this->LinkerLanguage);
8205     bool const checkCMP0027 = evaluated != entry.Value;
8206     cmExpandList(evaluated, llibs);
8207     if (cge->GetHadHeadSensitiveCondition()) {
8208       impl.HadHeadSensitiveCondition = true;
8209     }
8210     if (cge->GetHadContextSensitiveCondition()) {
8211       impl.HadContextSensitiveCondition = true;
8212     }
8213     if (cge->GetHadLinkLanguageSensitiveCondition()) {
8214       impl.HadLinkLanguageSensitiveCondition = true;
8215     }
8216
8217     for (std::string const& lib : llibs) {
8218       if (this->IsLinkLookupScope(lib, lg)) {
8219         continue;
8220       }
8221
8222       // Skip entries that resolve to the target itself or are empty.
8223       std::string name = this->CheckCMP0004(lib);
8224       if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) {
8225         // resolve alias name
8226         auto* target = this->Makefile->FindTargetToUse(name);
8227         if (target) {
8228           name = target->GetName();
8229         }
8230       }
8231       if (name == this->GetName() || name.empty()) {
8232         if (name == this->GetName()) {
8233           bool noMessage = false;
8234           MessageType messageType = MessageType::FATAL_ERROR;
8235           std::ostringstream e;
8236           switch (this->GetPolicyStatusCMP0038()) {
8237             case cmPolicies::WARN: {
8238               e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
8239               messageType = MessageType::AUTHOR_WARNING;
8240             } break;
8241             case cmPolicies::OLD:
8242               noMessage = true;
8243               break;
8244             case cmPolicies::REQUIRED_IF_USED:
8245             case cmPolicies::REQUIRED_ALWAYS:
8246             case cmPolicies::NEW:
8247               // Issue the fatal message.
8248               break;
8249           }
8250
8251           if (!noMessage) {
8252             e << "Target \"" << this->GetName() << "\" links to itself.";
8253             this->LocalGenerator->GetCMakeInstance()->IssueMessage(
8254               messageType, e.str(), this->GetBacktrace());
8255             if (messageType == MessageType::FATAL_ERROR) {
8256               return;
8257             }
8258           }
8259         }
8260         continue;
8261       }
8262
8263       // The entry is meant for this configuration.
8264       cmLinkItem item =
8265         this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg);
8266       if (!item.Target) {
8267         // Report explicitly linked object files separately.
8268         std::string const& maybeObj = item.AsStr();
8269         if (cmSystemTools::FileIsFullPath(maybeObj)) {
8270           cmSourceFile const* sf =
8271             mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
8272           if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
8273             impl.Objects.emplace_back(std::move(item));
8274             continue;
8275           }
8276         }
8277       }
8278
8279       impl.Libraries.emplace_back(std::move(item), checkCMP0027);
8280     }
8281
8282     std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
8283     for (std::string const& sp : seenProps) {
8284       if (!this->GetProperty(sp)) {
8285         this->LinkImplicitNullProperties.insert(sp);
8286       }
8287     }
8288     cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
8289   }
8290
8291   // Update the list of direct link dependencies from usage requirements.
8292   if (head == this) {
8293     ComputeLinkImplTransitive(this, config, implFor, impl);
8294   }
8295
8296   // Get the list of configurations considered to be DEBUG.
8297   std::vector<std::string> debugConfigs =
8298     this->Makefile->GetCMakeInstance()->GetDebugConfigs();
8299
8300   cmTargetLinkLibraryType linkType =
8301     CMP0003_ComputeLinkType(config, debugConfigs);
8302   cmTarget::LinkLibraryVectorType const& oldllibs =
8303     this->Target->GetOriginalLinkLibraries();
8304   for (cmTarget::LibraryID const& oldllib : oldllibs) {
8305     if (oldllib.second != GENERAL_LibraryType && oldllib.second != linkType) {
8306       std::string name = this->CheckCMP0004(oldllib.first);
8307       if (name == this->GetName() || name.empty()) {
8308         continue;
8309       }
8310       // Support OLD behavior for CMP0003.
8311       impl.WrongConfigLibraries.push_back(
8312         this->ResolveLinkItem(BT<std::string>(name)));
8313     }
8314   }
8315 }
8316
8317 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
8318   std::string const& name) const
8319 {
8320   return this->ResolveTargetReference(name, this->LocalGenerator);
8321 }
8322
8323 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
8324   std::string const& name, cmLocalGenerator const* lg) const
8325 {
8326   TargetOrString resolved;
8327
8328   if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
8329     resolved.Target = tgt;
8330   } else {
8331     resolved.String = name;
8332   }
8333
8334   return resolved;
8335 }
8336
8337 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
8338   BT<std::string> const& name) const
8339 {
8340   return this->ResolveLinkItem(name, this->LocalGenerator);
8341 }
8342
8343 cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name,
8344                                               cmLocalGenerator const* lg) const
8345 {
8346   auto bt = name.Backtrace;
8347   TargetOrString resolved = this->ResolveTargetReference(name.Value, lg);
8348
8349   if (!resolved.Target) {
8350     return cmLinkItem(resolved.String, false, bt);
8351   }
8352
8353   // Check deprecation, issue message with `bt` backtrace.
8354   if (resolved.Target->IsDeprecated()) {
8355     std::ostringstream w;
8356     /* clang-format off */
8357     w <<
8358       "The library that is being linked to, "  << resolved.Target->GetName() <<
8359       ", is marked as being deprecated by the owner.  The message provided by "
8360       "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
8361     /* clang-format on */
8362     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
8363       MessageType::AUTHOR_WARNING, w.str(), bt);
8364   }
8365
8366   // Skip targets that will not really be linked.  This is probably a
8367   // name conflict between an external library and an executable
8368   // within the project.
8369   if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
8370       !resolved.Target->IsExecutableWithExports()) {
8371     return cmLinkItem(resolved.Target->GetName(), false, bt);
8372   }
8373
8374   return cmLinkItem(resolved.Target, false, bt);
8375 }
8376
8377 bool cmGeneratorTarget::HasPackageReferences() const
8378 {
8379   return this->IsInBuildSystem() &&
8380     !this->GetProperty("VS_PACKAGE_REFERENCES")->empty();
8381 }
8382
8383 std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const
8384 {
8385   std::vector<std::string> packageReferences;
8386
8387   if (this->IsInBuildSystem()) {
8388     if (cmValue vsPackageReferences =
8389           this->GetProperty("VS_PACKAGE_REFERENCES")) {
8390       cmExpandList(*vsPackageReferences, packageReferences);
8391     }
8392   }
8393
8394   return packageReferences;
8395 }
8396
8397 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
8398 {
8399   if (OutputInfo const* info = this->GetOutputInfo(config)) {
8400     // Return the directory in which the target will be built.
8401     return info->PdbDir;
8402   }
8403   return "";
8404 }
8405
8406 bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
8407 {
8408   return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
8409 }
8410
8411 bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
8412                                          std::string const& gnuName,
8413                                          std::string& out,
8414                                          const char* newExt) const
8415 {
8416   if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
8417       gnuName.substr(gnuName.size() - 6) == ".dll.a") {
8418     out = cmStrCat(cm::string_view(gnuName).substr(0, gnuName.size() - 6),
8419                    newExt ? newExt : ".lib");
8420     return true;
8421   }
8422   return false;
8423 }
8424
8425 bool cmGeneratorTarget::HasContextDependentSources() const
8426 {
8427   return this->SourcesAreContextDependent == Tribool::True;
8428 }
8429
8430 bool cmGeneratorTarget::IsExecutableWithExports() const
8431 {
8432   return (this->GetType() == cmStateEnums::EXECUTABLE &&
8433           this->GetPropertyAsBool("ENABLE_EXPORTS"));
8434 }
8435
8436 bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
8437 {
8438   return (this->IsDLLPlatform() &&
8439           (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8440            this->IsExecutableWithExports()) &&
8441           // Assemblies which have only managed code do not have
8442           // import libraries.
8443           this->GetManagedType(config) != ManagedType::Managed) ||
8444     (this->Target->IsAIX() && this->IsExecutableWithExports());
8445 }
8446
8447 bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
8448 {
8449   return this->HasImportLibrary(config) ||
8450     // On DLL platforms we always generate the import library name
8451     // just in case the sources have export markup.
8452     (this->IsDLLPlatform() &&
8453      (this->GetType() == cmStateEnums::EXECUTABLE ||
8454       this->GetType() == cmStateEnums::MODULE_LIBRARY));
8455 }
8456
8457 std::string cmGeneratorTarget::GetSupportDirectory() const
8458 {
8459   std::string dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
8460                              "/CMakeFiles/", this->GetName());
8461 #if defined(__VMS)
8462   dir += "_dir";
8463 #else
8464   dir += ".dir";
8465 #endif
8466   return dir;
8467 }
8468
8469 bool cmGeneratorTarget::IsLinkable() const
8470 {
8471   return (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
8472           this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8473           this->GetType() == cmStateEnums::MODULE_LIBRARY ||
8474           this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
8475           this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
8476           this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
8477           this->IsExecutableWithExports());
8478 }
8479
8480 bool cmGeneratorTarget::IsFrameworkOnApple() const
8481 {
8482   return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8483            this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
8484           this->Makefile->IsOn("APPLE") &&
8485           this->GetPropertyAsBool("FRAMEWORK"));
8486 }
8487
8488 bool cmGeneratorTarget::IsAppBundleOnApple() const
8489 {
8490   return (this->GetType() == cmStateEnums::EXECUTABLE &&
8491           this->Makefile->IsOn("APPLE") &&
8492           this->GetPropertyAsBool("MACOSX_BUNDLE"));
8493 }
8494
8495 bool cmGeneratorTarget::IsXCTestOnApple() const
8496 {
8497   return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
8498 }
8499
8500 bool cmGeneratorTarget::IsCFBundleOnApple() const
8501 {
8502   return (this->GetType() == cmStateEnums::MODULE_LIBRARY &&
8503           this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
8504 }
8505
8506 cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
8507   std::string const& propval) const
8508 {
8509   // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
8510   // or only C++/CLI) does only depend on whether the property is an empty
8511   // string or contains any value at all. In Visual Studio generators
8512   // this propval is prepended with /clr[:] which results in:
8513   //
8514   // 1. propval does not exist: no /clr flag, unmanaged target, has import
8515   //                            lib
8516   // 2. empty propval:          add /clr as flag, mixed unmanaged/managed
8517   //                            target, has import lib
8518   // 3. any value (safe,pure):  add /clr:[propval] as flag, target with
8519   //                            managed code only, no import lib
8520   return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
8521 }
8522
8523 cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
8524   const std::string& config) const
8525 {
8526   // Only libraries and executables can be managed targets.
8527   if (this->GetType() > cmStateEnums::SHARED_LIBRARY) {
8528     return ManagedType::Undefined;
8529   }
8530
8531   if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
8532     return ManagedType::Native;
8533   }
8534
8535   // Check imported target.
8536   if (this->IsImported()) {
8537     if (cmGeneratorTarget::ImportInfo const* info =
8538           this->GetImportInfo(config)) {
8539       return info->Managed;
8540     }
8541     return ManagedType::Undefined;
8542   }
8543
8544   // Check for explicitly set clr target property.
8545   if (cmValue clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
8546     return this->CheckManagedType(*clr);
8547   }
8548
8549   // C# targets are always managed. This language specific check
8550   // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
8551   // has to be set manually for C# targets.
8552   return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;
8553 }
8554
8555 bool cmGeneratorTarget::AddHeaderSetVerification()
8556 {
8557   if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) {
8558     return true;
8559   }
8560
8561   if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
8562       this->GetType() != cmStateEnums::SHARED_LIBRARY &&
8563       this->GetType() != cmStateEnums::UNKNOWN_LIBRARY &&
8564       this->GetType() != cmStateEnums::OBJECT_LIBRARY &&
8565       this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
8566       !this->IsExecutableWithExports()) {
8567     return true;
8568   }
8569
8570   auto verifyValue = this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY");
8571   const bool all = verifyValue.IsEmpty();
8572   std::set<std::string> verifySet;
8573   if (!all) {
8574     auto verifyList = cmExpandedList(verifyValue);
8575     verifySet.insert(verifyList.begin(), verifyList.end());
8576   }
8577
8578   cmTarget* verifyTarget = nullptr;
8579   cmTarget* allVerifyTarget =
8580     this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
8581       "all_verify_interface_header_sets", true);
8582
8583   auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries();
8584
8585   std::set<cmFileSet*> fileSets;
8586   for (auto const& entry : interfaceFileSetEntries) {
8587     for (auto const& name : cmExpandedList(entry.Value)) {
8588       if (all || verifySet.count(name)) {
8589         fileSets.insert(this->Target->GetFileSet(name));
8590         verifySet.erase(name);
8591       }
8592     }
8593   }
8594   if (!verifySet.empty()) {
8595     this->Makefile->IssueMessage(
8596       MessageType::FATAL_ERROR,
8597       cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"",
8598                this->GetName(),
8599                "\" contained the following header sets that are nonexistent "
8600                "or not INTERFACE:\n  ",
8601                cmJoin(verifySet, "\n  ")));
8602     return false;
8603   }
8604
8605   cm::optional<std::set<std::string>> languages;
8606   for (auto* fileSet : fileSets) {
8607     auto dirCges = fileSet->CompileDirectoryEntries();
8608     auto fileCges = fileSet->CompileFileEntries();
8609
8610     static auto const contextSensitive =
8611       [](const std::unique_ptr<cmCompiledGeneratorExpression>& cge) {
8612         return cge->GetHadContextSensitiveCondition();
8613       };
8614     bool dirCgesContextSensitive = false;
8615     bool fileCgesContextSensitive = false;
8616
8617     std::vector<std::string> dirs;
8618     std::map<std::string, std::vector<std::string>> filesPerDir;
8619     bool first = true;
8620     for (auto const& config : this->Makefile->GetGeneratorConfigs(
8621            cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
8622       if (first || dirCgesContextSensitive) {
8623         dirs = fileSet->EvaluateDirectoryEntries(dirCges, this->LocalGenerator,
8624                                                  config, this);
8625         dirCgesContextSensitive =
8626           std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
8627       }
8628       if (first || fileCgesContextSensitive) {
8629         filesPerDir.clear();
8630         for (auto const& fileCge : fileCges) {
8631           fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge,
8632                                      this->LocalGenerator, config, this);
8633           if (fileCge->GetHadContextSensitiveCondition()) {
8634             fileCgesContextSensitive = true;
8635           }
8636         }
8637       }
8638
8639       for (auto const& files : filesPerDir) {
8640         for (auto const& file : files.second) {
8641           std::string filename = this->GenerateHeaderSetVerificationFile(
8642             *this->Makefile->GetOrCreateSource(file), files.first, languages);
8643           if (filename.empty()) {
8644             continue;
8645           }
8646
8647           if (!verifyTarget) {
8648             {
8649               cmMakefile::PolicyPushPop polScope(this->Makefile);
8650               this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW);
8651               verifyTarget = this->Makefile->AddLibrary(
8652                 cmStrCat(this->GetName(), "_verify_interface_header_sets"),
8653                 cmStateEnums::OBJECT_LIBRARY, {}, true);
8654             }
8655
8656             verifyTarget->AddLinkLibrary(
8657               *this->Makefile, this->GetName(),
8658               cmTargetLinkLibraryType::GENERAL_LibraryType);
8659             verifyTarget->SetProperty("AUTOMOC", "OFF");
8660             verifyTarget->SetProperty("AUTORCC", "OFF");
8661             verifyTarget->SetProperty("AUTOUIC", "OFF");
8662             verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
8663             verifyTarget->SetProperty("UNITY_BUILD", "OFF");
8664             cm::optional<std::map<std::string, cmValue>>
8665               perConfigCompileDefinitions;
8666             verifyTarget->FinalizeTargetConfiguration(
8667               this->Makefile->GetCompileDefinitionsEntries(),
8668               perConfigCompileDefinitions);
8669
8670             if (!allVerifyTarget) {
8671               allVerifyTarget = this->GlobalGenerator->GetMakefiles()
8672                                   .front()
8673                                   ->AddNewUtilityTarget(
8674                                     "all_verify_interface_header_sets", true);
8675             }
8676
8677             allVerifyTarget->AddUtility(verifyTarget->GetName(), false);
8678           }
8679
8680           if (fileCgesContextSensitive) {
8681             filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, ">");
8682           }
8683           verifyTarget->AddSource(filename);
8684         }
8685       }
8686
8687       if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
8688         break;
8689       }
8690       first = false;
8691     }
8692   }
8693
8694   if (verifyTarget) {
8695     this->LocalGenerator->AddGeneratorTarget(
8696       cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator));
8697   }
8698
8699   return true;
8700 }
8701
8702 std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
8703   cmSourceFile& source, const std::string& dir,
8704   cm::optional<std::set<std::string>>& languages) const
8705 {
8706   std::string extension;
8707   std::string language = source.GetOrDetermineLanguage();
8708
8709   if (language.empty()) {
8710     if (!languages) {
8711       languages.emplace();
8712       for (auto const& tgtSource : this->GetAllConfigSources()) {
8713         auto const& tgtSourceLanguage =
8714           tgtSource.Source->GetOrDetermineLanguage();
8715         if (tgtSourceLanguage == "CXX") {
8716           languages->insert("CXX");
8717           break; // C++ overrides everything else, so we don't need to keep
8718                  // checking.
8719         }
8720         if (tgtSourceLanguage == "C") {
8721           languages->insert("C");
8722         }
8723       }
8724
8725       if (languages->empty()) {
8726         std::vector<std::string> languagesVector;
8727         this->GlobalGenerator->GetEnabledLanguages(languagesVector);
8728         languages->insert(languagesVector.begin(), languagesVector.end());
8729       }
8730     }
8731
8732     if (languages->count("CXX")) {
8733       language = "CXX";
8734     } else if (languages->count("C")) {
8735       language = "C";
8736     }
8737   }
8738
8739   if (language == "C") {
8740     extension = ".c";
8741   } else if (language == "CXX") {
8742     extension = ".cxx";
8743   } else {
8744     return "";
8745   }
8746
8747   std::string headerFilename = dir;
8748   if (!headerFilename.empty()) {
8749     headerFilename += '/';
8750   }
8751   headerFilename += source.GetLocation().GetName();
8752
8753   auto filename = cmStrCat(
8754     this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->GetName(),
8755     "_verify_interface_header_sets/", headerFilename, extension);
8756   auto* verificationSource = this->Makefile->GetOrCreateSource(filename);
8757   verificationSource->SetProperty("LANGUAGE", language);
8758
8759   cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename));
8760
8761   cmGeneratedFileStream fout(filename);
8762   fout.SetCopyIfDifferent(true);
8763   // IWYU pragma: associated allows include what you use to
8764   // consider the headerFile as part of the entire language
8765   // unit within include-what-you-use and as a result allows
8766   // one to get IWYU advice for headers :)
8767   fout << "#include <" << headerFilename << "> // IWYU pragma: associated\n";
8768   fout.close();
8769
8770   return filename;
8771 }
8772
8773 bool cmGeneratorTarget::HaveCxx20ModuleSources() const
8774 {
8775   auto const& fs_names = this->Target->GetAllFileSetNames();
8776   return std::any_of(fs_names.begin(), fs_names.end(),
8777                      [this](std::string const& name) -> bool {
8778                        auto const* file_set = this->Target->GetFileSet(name);
8779                        if (!file_set) {
8780                          this->Makefile->IssueMessage(
8781                            MessageType::INTERNAL_ERROR,
8782                            cmStrCat("Target \"", this->Target->GetName(),
8783                                     "\" is tracked to have file set \"", name,
8784                                     "\", but it was not found."));
8785                          return false;
8786                        }
8787
8788                        auto const& fs_type = file_set->GetType();
8789                        return fs_type == "CXX_MODULES"_s ||
8790                          fs_type == "CXX_MODULE_HEADER_UNITS"_s;
8791                      });
8792 }
8793
8794 cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
8795   std::string const& config) const
8796 {
8797   auto const* state = this->Makefile->GetState();
8798   if (!state->GetLanguageEnabled("CXX")) {
8799     return Cxx20SupportLevel::MissingCxx;
8800   }
8801   cmValue standardDefault =
8802     this->Target->GetMakefile()->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
8803   if (standardDefault && !standardDefault->empty()) {
8804     cmStandardLevelResolver standardResolver(this->Makefile);
8805     if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
8806                                                 "cxx_std_20")) {
8807       return Cxx20SupportLevel::NoCxx20;
8808     }
8809   }
8810   // Else, an empty CMAKE_CXX_STANDARD_DEFAULT means CMake does not detect and
8811   // set a default standard level for this compiler, so assume all standards
8812   // are available.
8813   if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
8814     return Cxx20SupportLevel::MissingExperimentalFlag;
8815   }
8816   return Cxx20SupportLevel::Supported;
8817 }
8818
8819 void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
8820 {
8821   // Check for `CXX_MODULE*` file sets and a lack of support.
8822   if (this->HaveCxx20ModuleSources()) {
8823     switch (this->HaveCxxModuleSupport(config)) {
8824       case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
8825         this->Makefile->IssueMessage(
8826           MessageType::FATAL_ERROR,
8827           cmStrCat("The \"", this->GetName(),
8828                    "\" target has C++ module sources but the \"CXX\" language "
8829                    "has not been enabled"));
8830         break;
8831       case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag:
8832         this->Makefile->IssueMessage(
8833           MessageType::FATAL_ERROR,
8834           cmStrCat("The \"", this->GetName(),
8835                    "\" target has C++ module sources but its experimental "
8836                    "support has not been requested"));
8837         break;
8838       case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20:
8839         this->Makefile->IssueMessage(
8840           MessageType::FATAL_ERROR,
8841           cmStrCat(
8842             "The \"", this->GetName(),
8843             "\" target has C++ module sources but is not using at least "
8844             "\"cxx_std_20\""));
8845         break;
8846       case cmGeneratorTarget::Cxx20SupportLevel::Supported:
8847         // All is well.
8848         break;
8849     }
8850   }
8851 }