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