resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmTarget.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 "cmTarget.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstring>
8 #include <initializer_list>
9 #include <iterator>
10 #include <map>
11 #include <set>
12 #include <sstream>
13 #include <unordered_set>
14
15 #include <cm/memory>
16 #include <cm/string_view>
17 #include <cmext/algorithm>
18 #include <cmext/string_view>
19
20 #include "cmsys/RegularExpression.hxx"
21
22 #include "cmAlgorithms.h"
23 #include "cmCustomCommand.h"
24 #include "cmFileSet.h"
25 #include "cmGeneratorExpression.h"
26 #include "cmGeneratorTarget.h"
27 #include "cmGlobalGenerator.h"
28 #include "cmListFileCache.h"
29 #include "cmMakefile.h"
30 #include "cmMessageType.h"
31 #include "cmProperty.h"
32 #include "cmPropertyDefinition.h"
33 #include "cmPropertyMap.h"
34 #include "cmRange.h"
35 #include "cmSourceFile.h"
36 #include "cmSourceFileLocation.h"
37 #include "cmSourceFileLocationKind.h"
38 #include "cmState.h"
39 #include "cmStateDirectory.h"
40 #include "cmStateSnapshot.h"
41 #include "cmSystemTools.h"
42 #include "cmTargetPropertyComputer.h"
43 #include "cmValue.h"
44 #include "cmake.h"
45
46 template <>
47 const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
48   cmTarget const* tgt)
49 {
50   static std::string loc;
51   if (tgt->IsImported()) {
52     loc = tgt->ImportedGetFullPath("", cmStateEnums::RuntimeBinaryArtifact);
53     return loc;
54   }
55
56   cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
57   if (!gg->GetConfigureDoneCMP0026()) {
58     gg->CreateGenerationObjects();
59   }
60   cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
61   loc = gt->GetLocationForBuild();
62   return loc;
63 }
64
65 template <>
66 const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>(
67   cmTarget const* tgt, const std::string& config)
68 {
69   static std::string loc;
70   if (tgt->IsImported()) {
71     loc =
72       tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
73     return loc;
74   }
75
76   cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
77   if (!gg->GetConfigureDoneCMP0026()) {
78     gg->CreateGenerationObjects();
79   }
80   cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
81   loc = gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
82   return loc;
83 }
84
85 template <>
86 cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt,
87                                                        cmMakefile const& mf)
88 {
89   cmBTStringRange entries = tgt->GetSourceEntries();
90   if (entries.empty()) {
91     return nullptr;
92   }
93
94   std::ostringstream ss;
95   const char* sep = "";
96   for (auto const& entry : entries) {
97     std::vector<std::string> files = cmExpandedList(entry.Value);
98     for (std::string const& file : files) {
99       if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
100           file.back() == '>') {
101         std::string objLibName = file.substr(17, file.size() - 18);
102
103         if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
104           ss << sep;
105           sep = ";";
106           ss << file;
107           continue;
108         }
109
110         bool addContent = false;
111         bool noMessage = true;
112         std::ostringstream e;
113         MessageType messageType = MessageType::AUTHOR_WARNING;
114         switch (mf.GetPolicyStatus(cmPolicies::CMP0051)) {
115           case cmPolicies::WARN:
116             e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
117             noMessage = false;
118             CM_FALLTHROUGH;
119           case cmPolicies::OLD:
120             break;
121           case cmPolicies::REQUIRED_ALWAYS:
122           case cmPolicies::REQUIRED_IF_USED:
123           case cmPolicies::NEW:
124             addContent = true;
125             break;
126         }
127         if (!noMessage) {
128           e << "Target \"" << tgt->GetName()
129             << "\" contains $<TARGET_OBJECTS> generator expression in its "
130                "sources list.  This content was not previously part of the "
131                "SOURCES property when that property was read at configure "
132                "time.  Code reading that property needs to be adapted to "
133                "ignore the generator expression using the string(GENEX_STRIP) "
134                "command.";
135           mf.IssueMessage(messageType, e.str());
136         }
137         if (addContent) {
138           ss << sep;
139           sep = ";";
140           ss << file;
141         }
142       } else if (cmGeneratorExpression::Find(file) == std::string::npos) {
143         ss << sep;
144         sep = ";";
145         ss << file;
146       } else {
147         cmSourceFile* sf = tgt->GetMakefile()->GetOrCreateSource(file);
148         // Construct what is known about this source file location.
149         cmSourceFileLocation const& location = sf->GetLocation();
150         std::string sname = location.GetDirectory();
151         if (!sname.empty()) {
152           sname += "/";
153         }
154         sname += location.GetName();
155
156         ss << sep;
157         sep = ";";
158         // Append this list entry.
159         ss << sname;
160       }
161     }
162   }
163   static std::string srcs;
164   srcs = ss.str();
165   return cmValue(srcs);
166 }
167
168 namespace {
169 struct FileSetEntries
170 {
171   FileSetEntries(cm::static_string_view propertyName)
172     : PropertyName(propertyName)
173   {
174   }
175
176   cm::static_string_view const PropertyName;
177   std::vector<BT<std::string>> Entries;
178 };
179
180 struct FileSetType
181 {
182   FileSetType(cm::static_string_view typeName,
183               cm::static_string_view defaultDirectoryProperty,
184               cm::static_string_view defaultPathProperty,
185               cm::static_string_view directoryPrefix,
186               cm::static_string_view pathPrefix,
187               cm::static_string_view typeDescription,
188               cm::static_string_view defaultDescription,
189               cm::static_string_view arbitraryDescription,
190               FileSetEntries selfEntries, FileSetEntries interfaceEntries)
191     : TypeName(typeName)
192     , DefaultDirectoryProperty(defaultDirectoryProperty)
193     , DefaultPathProperty(defaultPathProperty)
194     , DirectoryPrefix(directoryPrefix)
195     , PathPrefix(pathPrefix)
196     , TypeDescription(typeDescription)
197     , DefaultDescription(defaultDescription)
198     , ArbitraryDescription(arbitraryDescription)
199     , SelfEntries(std::move(selfEntries))
200     , InterfaceEntries(std::move(interfaceEntries))
201   {
202   }
203
204   cm::static_string_view const TypeName;
205   cm::static_string_view const DefaultDirectoryProperty;
206   cm::static_string_view const DefaultPathProperty;
207   cm::static_string_view const DirectoryPrefix;
208   cm::static_string_view const PathPrefix;
209   cm::static_string_view const TypeDescription;
210   cm::static_string_view const DefaultDescription;
211   cm::static_string_view const ArbitraryDescription;
212
213   FileSetEntries SelfEntries;
214   FileSetEntries InterfaceEntries;
215
216   template <typename ValueType>
217   bool WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
218                        const std::string& prop, ValueType value, bool clear);
219   std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt,
220                                           cmTargetInternals const* impl,
221                                           const std::string& prop) const;
222
223   void AddFileSet(const std::string& name, cmFileSetVisibility vis,
224                   cmListFileBacktrace bt);
225 };
226 }
227
228 class cmTargetInternals
229 {
230 public:
231   cmStateEnums::TargetType TargetType;
232   cmMakefile* Makefile;
233   cmPolicies::PolicyMap PolicyMap;
234   std::string Name;
235   std::string InstallPath;
236   std::string RuntimeInstallPath;
237   cmPropertyMap Properties;
238   bool IsGeneratorProvided;
239   bool HaveInstallRule;
240   bool IsDLLPlatform;
241   bool IsAIX;
242   bool IsAndroid;
243   bool IsImportedTarget;
244   bool ImportedGloballyVisible;
245   bool BuildInterfaceIncludesAppended;
246   bool PerConfig;
247   std::set<BT<std::pair<std::string, bool>>> Utilities;
248   std::vector<cmCustomCommand> PreBuildCommands;
249   std::vector<cmCustomCommand> PreLinkCommands;
250   std::vector<cmCustomCommand> PostBuildCommands;
251   std::vector<cmInstallTargetGenerator*> InstallGenerators;
252   std::set<std::string> SystemIncludeDirectories;
253   cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
254   std::map<std::string, BTs<std::string>> LanguageStandardProperties;
255   std::vector<BT<std::string>> IncludeDirectoriesEntries;
256   std::map<cmTargetExport const*, std::vector<std::string>>
257     InstallIncludeDirectoriesEntries;
258   std::vector<BT<std::string>> CompileOptionsEntries;
259   std::vector<BT<std::string>> CompileFeaturesEntries;
260   std::vector<BT<std::string>> CompileDefinitionsEntries;
261   std::vector<BT<std::string>> PrecompileHeadersEntries;
262   std::vector<BT<std::string>> SourceEntries;
263   std::vector<BT<std::string>> LinkOptionsEntries;
264   std::vector<BT<std::string>> LinkDirectoriesEntries;
265   std::vector<BT<std::string>> LinkImplementationPropertyEntries;
266   std::vector<BT<std::string>> LinkInterfacePropertyEntries;
267   std::vector<BT<std::string>> LinkInterfaceDirectPropertyEntries;
268   std::vector<BT<std::string>> LinkInterfaceDirectExcludePropertyEntries;
269   std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
270     TLLCommands;
271   std::map<std::string, cmFileSet> FileSets;
272   cmListFileBacktrace Backtrace;
273
274   FileSetType HeadersFileSets;
275   FileSetType CxxModulesFileSets;
276   FileSetType CxxModuleHeadersFileSets;
277
278   cmTargetInternals();
279
280   bool CheckImportedLibName(std::string const& prop,
281                             std::string const& value) const;
282
283   std::string ProcessSourceItemCMP0049(const std::string& s) const;
284
285   template <typename ValueType>
286   void AddDirectoryToFileSet(cmTarget* self, std::string const& fileSetName,
287                              ValueType value, cm::string_view fileSetType,
288                              cm::string_view description, bool clear);
289   template <typename ValueType>
290   void AddPathToFileSet(cmTarget* self, std::string const& fileSetName,
291                         ValueType value, cm::string_view fileSetType,
292                         cm::string_view description, bool clear);
293   cmValue GetFileSetDirectories(cmTarget const* self,
294                                 std::string const& fileSetName,
295                                 cm::string_view fileSetType) const;
296   cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName,
297                           cm::string_view fileSetType) const;
298
299   cmListFileBacktrace GetBacktrace(
300     cm::optional<cmListFileBacktrace> const& bt) const
301   {
302     return bt ? *bt : this->Makefile->GetBacktrace();
303   }
304 };
305
306 cmTargetInternals::cmTargetInternals()
307   : HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s,
308                     "HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s,
309                     "The default header set"_s, "Header set"_s,
310                     FileSetEntries("HEADER_SETS"_s),
311                     FileSetEntries("INTERFACE_HEADER_SETS"_s))
312   , CxxModulesFileSets("CXX_MODULES"_s, "CXX_MODULE_DIRS"_s,
313                        "CXX_MODULE_SET"_s, "CXX_MODULE_DIRS_"_s,
314                        "CXX_MODULE_SET_"_s, "C++ module"_s,
315                        "The default C++ module set"_s, "C++ module set"_s,
316                        FileSetEntries("CXX_MODULE_SETS"_s),
317                        FileSetEntries("INTERFACE_CXX_MODULE_SETS"_s))
318   , CxxModuleHeadersFileSets(
319       "CXX_MODULE_HEADER_UNITS"_s, "CXX_MODULE_HEADER_UNIT_DIRS"_s,
320       "CXX_MODULE_HEADER_UNIT_SET"_s, "CXX_MODULE_HEADER_UNIT_DIRS_"_s,
321       "CXX_MODULE_HEADER_UNIT_SET_"_s, "C++ module header"_s,
322       "The default C++ module header set"_s, "C++ module header set"_s,
323       FileSetEntries("CXX_MODULE_HEADER_UNIT_SETS"_s),
324       FileSetEntries("INTERFACE_CXX_MODULE_HEADER_UNIT_SETS"_s))
325 {
326 }
327
328 template <typename ValueType>
329 bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
330                                   const std::string& prop, ValueType value,
331                                   bool clear)
332 {
333   if (prop == this->DefaultDirectoryProperty) {
334     impl->AddDirectoryToFileSet(tgt, std::string(this->TypeName), value,
335                                 this->TypeName, this->DefaultDescription,
336                                 clear);
337     return true;
338   }
339   if (prop == this->DefaultPathProperty) {
340     impl->AddPathToFileSet(tgt, std::string(this->TypeName), value,
341                            this->TypeName, this->DefaultDescription, clear);
342     return true;
343   }
344   if (cmHasPrefix(prop, this->DirectoryPrefix)) {
345     auto fileSetName = prop.substr(this->DirectoryPrefix.size());
346     if (fileSetName.empty()) {
347       impl->Makefile->IssueMessage(
348         MessageType::FATAL_ERROR,
349         cmStrCat(this->ArbitraryDescription, " name cannot be empty."));
350     } else {
351       impl->AddDirectoryToFileSet(
352         tgt, fileSetName, value, this->TypeName,
353         cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear);
354     }
355     return true;
356   }
357   if (cmHasPrefix(prop, this->PathPrefix)) {
358     auto fileSetName = prop.substr(this->PathPrefix.size());
359     if (fileSetName.empty()) {
360       impl->Makefile->IssueMessage(
361         MessageType::FATAL_ERROR,
362         cmStrCat(this->ArbitraryDescription, " name cannot be empty."));
363     } else {
364       impl->AddPathToFileSet(
365         tgt, fileSetName, value, this->TypeName,
366         cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear);
367     }
368     return true;
369   }
370   if (prop == this->SelfEntries.PropertyName) {
371     impl->Makefile->IssueMessage(
372       MessageType::FATAL_ERROR,
373       cmStrCat(this->SelfEntries.PropertyName, " property is read-only\n"));
374     return true;
375   }
376   if (prop == this->InterfaceEntries.PropertyName) {
377     impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
378                                  cmStrCat(this->InterfaceEntries.PropertyName,
379                                           " property is read-only\n"));
380     return true;
381   }
382   return false;
383 }
384
385 std::pair<bool, cmValue> FileSetType::ReadProperties(
386   cmTarget const* tgt, cmTargetInternals const* impl,
387   const std::string& prop) const
388 {
389   bool did_read = false;
390   cmValue value = nullptr;
391   if (prop == this->DefaultDirectoryProperty) {
392     value = impl->GetFileSetDirectories(tgt, std::string(this->TypeName),
393                                         this->TypeName);
394     did_read = true;
395   } else if (prop == this->DefaultPathProperty) {
396     value =
397       impl->GetFileSetPaths(tgt, std::string(this->TypeName), this->TypeName);
398     did_read = true;
399   } else if (prop == this->SelfEntries.PropertyName) {
400     static std::string output;
401     output = cmJoin(this->SelfEntries.Entries, ";"_s);
402     value = cmValue(output);
403     did_read = true;
404   } else if (prop == this->InterfaceEntries.PropertyName) {
405     static std::string output;
406     output = cmJoin(this->InterfaceEntries.Entries, ";"_s);
407     value = cmValue(output);
408     did_read = true;
409   } else if (cmHasPrefix(prop, this->DirectoryPrefix)) {
410     std::string fileSetName = prop.substr(this->DirectoryPrefix.size());
411     if (!fileSetName.empty()) {
412       value = impl->GetFileSetDirectories(tgt, fileSetName, this->TypeName);
413     }
414     did_read = true;
415   } else if (cmHasPrefix(prop, this->PathPrefix)) {
416     std::string fileSetName = prop.substr(this->PathPrefix.size());
417     if (!fileSetName.empty()) {
418       value = impl->GetFileSetPaths(tgt, fileSetName, this->TypeName);
419     }
420     did_read = true;
421   }
422   return { did_read, value };
423 }
424
425 void FileSetType::AddFileSet(const std::string& name, cmFileSetVisibility vis,
426                              cmListFileBacktrace bt)
427 {
428   if (cmFileSetVisibilityIsForSelf(vis)) {
429     this->SelfEntries.Entries.emplace_back(name, bt);
430   }
431   if (cmFileSetVisibilityIsForInterface(vis)) {
432     this->InterfaceEntries.Entries.emplace_back(name, std::move(bt));
433   }
434 }
435
436 namespace {
437 #define SETUP_COMMON_LANGUAGE_PROPERTIES(lang)                                \
438   initProp(#lang "_COMPILER_LAUNCHER");                                       \
439   initProp(#lang "_STANDARD");                                                \
440   initProp(#lang "_STANDARD_REQUIRED");                                       \
441   initProp(#lang "_EXTENSIONS");                                              \
442   initProp(#lang "_VISIBILITY_PRESET")
443 }
444
445 cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
446                    Visibility vis, cmMakefile* mf, PerConfig perConfig)
447   : impl(cm::make_unique<cmTargetInternals>())
448 {
449   assert(mf);
450   this->impl->TargetType = type;
451   this->impl->Makefile = mf;
452   this->impl->Name = name;
453   this->impl->IsGeneratorProvided = false;
454   this->impl->HaveInstallRule = false;
455   this->impl->IsDLLPlatform = false;
456   this->impl->IsAIX = false;
457   this->impl->IsAndroid = false;
458   this->impl->IsImportedTarget =
459     (vis == VisibilityImported || vis == VisibilityImportedGlobally);
460   this->impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
461   this->impl->BuildInterfaceIncludesAppended = false;
462   this->impl->PerConfig = (perConfig == PerConfig::Yes);
463
464   // Check whether this is a DLL platform.
465   this->impl->IsDLLPlatform =
466     !this->impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")
467        .empty();
468
469   // Check whether we are targeting AIX.
470   {
471     std::string const& systemName =
472       this->impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
473     this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400");
474   }
475
476   // Check whether we are targeting an Android platform.
477   this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition(
478                              "CMAKE_SYSTEM_NAME") == "Android");
479
480   std::string defKey;
481   defKey.reserve(128);
482   defKey += "CMAKE_";
483   auto initProp = [this, mf, &defKey](const std::string& property) {
484     // Replace everything after "CMAKE_"
485     defKey.replace(defKey.begin() + 6, defKey.end(), property);
486     if (cmValue value = mf->GetDefinition(defKey)) {
487       this->SetProperty(property, value);
488     }
489   };
490   auto initPropValue = [this, mf, &defKey](const std::string& property,
491                                            const char* default_value) {
492     // Replace everything after "CMAKE_"
493     defKey.replace(defKey.begin() + 6, defKey.end(), property);
494     if (cmValue value = mf->GetDefinition(defKey)) {
495       this->SetProperty(property, value);
496     } else if (default_value) {
497       this->SetProperty(property, default_value);
498     }
499   };
500
501   // Setup default property values.
502   if (this->CanCompileSources()) {
503
504     SETUP_COMMON_LANGUAGE_PROPERTIES(C);
505     SETUP_COMMON_LANGUAGE_PROPERTIES(OBJC);
506     SETUP_COMMON_LANGUAGE_PROPERTIES(CXX);
507     SETUP_COMMON_LANGUAGE_PROPERTIES(OBJCXX);
508     SETUP_COMMON_LANGUAGE_PROPERTIES(CUDA);
509     SETUP_COMMON_LANGUAGE_PROPERTIES(HIP);
510
511     initProp("ANDROID_API");
512     initProp("ANDROID_API_MIN");
513     initProp("ANDROID_ARCH");
514     initProp("ANDROID_STL_TYPE");
515     initProp("ANDROID_SKIP_ANT_STEP");
516     initProp("ANDROID_PROCESS_MAX");
517     initProp("ANDROID_PROGUARD");
518     initProp("ANDROID_PROGUARD_CONFIG_PATH");
519     initProp("ANDROID_SECURE_PROPS_PATH");
520     initProp("ANDROID_NATIVE_LIB_DIRECTORIES");
521     initProp("ANDROID_NATIVE_LIB_DEPENDENCIES");
522     initProp("ANDROID_JAVA_SOURCE_DIR");
523     initProp("ANDROID_JAR_DIRECTORIES");
524     initProp("ANDROID_JAR_DEPENDENCIES");
525     initProp("ANDROID_ASSETS_DIRECTORIES");
526     initProp("ANDROID_ANT_ADDITIONAL_OPTIONS");
527     initProp("BUILD_RPATH");
528     initProp("BUILD_RPATH_USE_ORIGIN");
529     initProp("INSTALL_NAME_DIR");
530     initProp("INSTALL_REMOVE_ENVIRONMENT_RPATH");
531     initPropValue("INSTALL_RPATH", "");
532     initPropValue("INSTALL_RPATH_USE_LINK_PATH", "OFF");
533     initProp("INTERPROCEDURAL_OPTIMIZATION");
534     initPropValue("SKIP_BUILD_RPATH", "OFF");
535     initPropValue("BUILD_WITH_INSTALL_RPATH", "OFF");
536     initProp("ARCHIVE_OUTPUT_DIRECTORY");
537     initProp("LIBRARY_OUTPUT_DIRECTORY");
538     initProp("RUNTIME_OUTPUT_DIRECTORY");
539     initProp("PDB_OUTPUT_DIRECTORY");
540     initProp("COMPILE_PDB_OUTPUT_DIRECTORY");
541     initProp("FRAMEWORK");
542     initProp("FRAMEWORK_MULTI_CONFIG_POSTFIX");
543     initProp("Fortran_FORMAT");
544     initProp("Fortran_MODULE_DIRECTORY");
545     initProp("Fortran_COMPILER_LAUNCHER");
546     initProp("Fortran_PREPROCESS");
547     initProp("Fortran_VISIBILITY_PRESET");
548     initProp("GNUtoMS");
549     initProp("OSX_ARCHITECTURES");
550     initProp("IOS_INSTALL_COMBINED");
551     initProp("AUTOMOC");
552     initProp("AUTOUIC");
553     initProp("AUTORCC");
554     initProp("AUTOGEN_ORIGIN_DEPENDS");
555     initProp("AUTOGEN_PARALLEL");
556     initProp("AUTOMOC_COMPILER_PREDEFINES");
557     initProp("AUTOMOC_DEPEND_FILTERS");
558     initProp("AUTOMOC_MACRO_NAMES");
559     initProp("AUTOMOC_MOC_OPTIONS");
560     initProp("AUTOUIC_OPTIONS");
561     initProp("AUTOMOC_PATH_PREFIX");
562     initProp("AUTOUIC_SEARCH_PATHS");
563     initProp("AUTORCC_OPTIONS");
564     initProp("LINK_DEPENDS_NO_SHARED");
565     initProp("LINK_INTERFACE_LIBRARIES");
566     initProp("MSVC_DEBUG_INFORMATION_FORMAT");
567     initProp("MSVC_RUNTIME_LIBRARY");
568     initProp("WATCOM_RUNTIME_LIBRARY");
569     initProp("WIN32_EXECUTABLE");
570     initProp("MACOSX_BUNDLE");
571     initProp("MACOSX_RPATH");
572     initProp("NO_SYSTEM_FROM_IMPORTED");
573     initProp("BUILD_WITH_INSTALL_NAME_DIR");
574     initProp("C_CLANG_TIDY");
575     initProp("C_CPPLINT");
576     initProp("C_CPPCHECK");
577     initProp("C_INCLUDE_WHAT_YOU_USE");
578     initProp("C_LINKER_LAUNCHER");
579     initProp("LINK_WHAT_YOU_USE");
580     initProp("CXX_CLANG_TIDY");
581     initProp("CXX_CPPLINT");
582     initProp("CXX_CPPCHECK");
583     initProp("CXX_INCLUDE_WHAT_YOU_USE");
584     initProp("CXX_LINKER_LAUNCHER");
585     initProp("CUDA_SEPARABLE_COMPILATION");
586     initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
587     initProp("CUDA_RUNTIME_LIBRARY");
588     initProp("CUDA_ARCHITECTURES");
589     initProp("HIP_RUNTIME_LIBRARY");
590     initProp("HIP_ARCHITECTURES");
591     initProp("VISIBILITY_INLINES_HIDDEN");
592     initProp("JOB_POOL_COMPILE");
593     initProp("JOB_POOL_LINK");
594     initProp("JOB_POOL_PRECOMPILE_HEADER");
595     initProp("ISPC_COMPILER_LAUNCHER");
596     initProp("ISPC_HEADER_DIRECTORY");
597     initPropValue("ISPC_HEADER_SUFFIX", "_ispc.h");
598     initProp("ISPC_INSTRUCTION_SETS");
599     initProp("LINK_SEARCH_START_STATIC");
600     initProp("LINK_SEARCH_END_STATIC");
601     initProp("OBJC_CLANG_TIDY");
602     initProp("OBJC_LINKER_LAUNCHER");
603     initProp("OBJCXX_CLANG_TIDY");
604     initProp("OBJCXX_LINKER_LAUNCHER");
605     initProp("Swift_LANGUAGE_VERSION");
606     initProp("Swift_MODULE_DIRECTORY");
607     initProp("VS_JUST_MY_CODE_DEBUGGING");
608     initProp("VS_NO_COMPILE_BATCHING");
609     initProp("DISABLE_PRECOMPILE_HEADERS");
610     initProp("UNITY_BUILD");
611     initProp("UNITY_BUILD_UNIQUE_ID");
612     initProp("OPTIMIZE_DEPENDENCIES");
613     initProp("EXPORT_COMPILE_COMMANDS");
614     initProp("COMPILE_WARNING_AS_ERROR");
615     initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
616     initPropValue("UNITY_BUILD_MODE", "BATCH");
617     initPropValue("PCH_WARN_INVALID", "ON");
618     initPropValue("PCH_INSTANTIATE_TEMPLATES", "ON");
619
620 #ifdef __APPLE__
621     if (this->GetGlobalGenerator()->IsXcode()) {
622       initProp("XCODE_SCHEME_ADDRESS_SANITIZER");
623       initProp("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN");
624       initProp("XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING");
625       initProp("XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE");
626       initProp("XCODE_SCHEME_THREAD_SANITIZER");
627       initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP");
628       initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
629       initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
630       initProp("XCODE_SCHEME_LAUNCH_CONFIGURATION");
631       initProp("XCODE_SCHEME_ENABLE_GPU_API_VALIDATION");
632       initProp("XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION");
633       initProp("XCODE_SCHEME_WORKING_DIRECTORY");
634       initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER");
635       initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
636       initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
637       initProp("XCODE_SCHEME_MALLOC_GUARD_EDGES");
638       initProp("XCODE_SCHEME_GUARD_MALLOC");
639       initProp("XCODE_SCHEME_LAUNCH_MODE");
640       initProp("XCODE_SCHEME_ZOMBIE_OBJECTS");
641       initProp("XCODE_SCHEME_MALLOC_STACK");
642       initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
643       initProp("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
644       initProp("XCODE_SCHEME_ENVIRONMENT");
645       initPropValue("XCODE_LINK_BUILD_PHASE_MODE", "NONE");
646     }
647 #endif
648   }
649
650   initProp("FOLDER");
651   initProp("VERIFY_INTERFACE_HEADER_SETS");
652
653   if (this->GetGlobalGenerator()->IsXcode()) {
654     initProp("XCODE_GENERATE_SCHEME");
655   }
656
657   // Setup per-configuration property default values.
658   if (this->GetType() != cmStateEnums::UTILITY &&
659       this->GetType() != cmStateEnums::GLOBAL_TARGET) {
660     static const auto configProps = {
661       /* clang-format needs this comment to break after the opening brace */
662       "ARCHIVE_OUTPUT_DIRECTORY_",     "LIBRARY_OUTPUT_DIRECTORY_",
663       "RUNTIME_OUTPUT_DIRECTORY_",     "PDB_OUTPUT_DIRECTORY_",
664       "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
665       "INTERPROCEDURAL_OPTIMIZATION_"
666     };
667     // Collect the set of configuration types.
668     std::vector<std::string> configNames =
669       mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
670     for (std::string const& configName : configNames) {
671       std::string configUpper = cmSystemTools::UpperCase(configName);
672       for (auto const& prop : configProps) {
673         // Interface libraries have no output locations, so honor only
674         // the configuration map.
675         if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
676             strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
677           continue;
678         }
679         std::string property = cmStrCat(prop, configUpper);
680         initProp(property);
681       }
682
683       // Initialize per-configuration name postfix property from the
684       // variable only for non-executable targets.  This preserves
685       // compatibility with previous CMake versions in which executables
686       // did not support this variable.  Projects may still specify the
687       // property directly.
688       if (this->impl->TargetType != cmStateEnums::EXECUTABLE &&
689           this->impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
690         std::string property =
691           cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX");
692         initProp(property);
693       }
694
695       if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
696           this->impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
697         std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
698                                         cmSystemTools::UpperCase(configName));
699         initProp(property);
700       }
701     }
702     if (!this->IsImported()) {
703       initProp("LINK_LIBRARIES_ONLY_TARGETS");
704     }
705   }
706
707   // Save the backtrace of target construction.
708   this->impl->Backtrace = this->impl->Makefile->GetBacktrace();
709
710   if (!this->IsImported()) {
711     // Initialize the INCLUDE_DIRECTORIES property based on the current value
712     // of the same directory property:
713     cm::append(this->impl->IncludeDirectoriesEntries,
714                this->impl->Makefile->GetIncludeDirectoriesEntries());
715
716     {
717       auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
718       this->impl->SystemIncludeDirectories.insert(sysInc.begin(),
719                                                   sysInc.end());
720     }
721
722     cm::append(this->impl->CompileOptionsEntries,
723                this->impl->Makefile->GetCompileOptionsEntries());
724
725     cm::append(this->impl->LinkOptionsEntries,
726                this->impl->Makefile->GetLinkOptionsEntries());
727
728     cm::append(this->impl->LinkDirectoriesEntries,
729                this->impl->Makefile->GetLinkDirectoriesEntries());
730   }
731
732   if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
733     initProp("ANDROID_GUI");
734     initProp("CROSSCOMPILING_EMULATOR");
735     initProp("ENABLE_EXPORTS");
736   }
737   if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
738       this->impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
739     this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
740   } else if (this->CanCompileSources()) {
741     initProp("POSITION_INDEPENDENT_CODE");
742   }
743   if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
744       this->impl->TargetType == cmStateEnums::EXECUTABLE) {
745     initProp("AIX_EXPORT_ALL_SYMBOLS");
746     initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
747   }
748
749   // Record current policies for later use.
750   this->impl->Makefile->RecordPolicies(this->impl->PolicyMap);
751
752   if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
753     // This policy is checked in a few conditions. The properties relevant
754     // to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
755     // targets,
756     // so ensure that the conditions don't lead to nonsense.
757     this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
758   }
759
760   if (!this->IsImported()) {
761     initProp("DOTNET_SDK");
762   }
763
764   if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
765     initProp("DOTNET_TARGET_FRAMEWORK");
766     initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
767   }
768
769   // check for "CMAKE_VS_GLOBALS" variable and set up target properties
770   // if any
771   cmValue globals = mf->GetDefinition("CMAKE_VS_GLOBALS");
772   if (globals) {
773     const std::string genName = mf->GetGlobalGenerator()->GetName();
774     if (cmHasLiteralPrefix(genName, "Visual Studio")) {
775       std::vector<std::string> props = cmExpandedList(*globals);
776       const std::string vsGlobal = "VS_GLOBAL_";
777       for (const std::string& i : props) {
778         // split NAME=VALUE
779         const std::string::size_type assignment = i.find('=');
780         if (assignment != std::string::npos) {
781           const std::string propName = vsGlobal + i.substr(0, assignment);
782           const std::string propValue = i.substr(assignment + 1);
783           initPropValue(propName, propValue.c_str());
784         }
785       }
786     }
787   }
788
789   if (this->IsImported() || mf->GetPropertyAsBool("SYSTEM")) {
790     this->SetProperty("SYSTEM", "ON");
791   }
792
793   for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
794     if (prop.first.second == cmProperty::TARGET &&
795         !prop.second.GetInitializeFromVariable().empty()) {
796       if (auto value =
797             mf->GetDefinition(prop.second.GetInitializeFromVariable())) {
798         this->SetProperty(prop.first.first, value);
799       }
800     }
801   }
802 }
803
804 cmTarget::cmTarget(cmTarget&&) noexcept = default;
805 cmTarget::~cmTarget() = default;
806
807 cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
808
809 cmStateEnums::TargetType cmTarget::GetType() const
810 {
811   return this->impl->TargetType;
812 }
813
814 cmMakefile* cmTarget::GetMakefile() const
815 {
816   return this->impl->Makefile;
817 }
818
819 cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
820 {
821   return this->impl->PolicyMap;
822 }
823
824 const std::string& cmTarget::GetName() const
825 {
826   return this->impl->Name;
827 }
828
829 cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
830   cmPolicies::PolicyID policy) const
831 {
832   return this->impl->PolicyMap.Get(policy);
833 }
834
835 cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
836 {
837   return this->impl->Makefile->GetGlobalGenerator();
838 }
839
840 BTs<std::string> const* cmTarget::GetLanguageStandardProperty(
841   const std::string& propertyName) const
842 {
843   auto entry = this->impl->LanguageStandardProperties.find(propertyName);
844   if (entry != this->impl->LanguageStandardProperties.end()) {
845     return &entry->second;
846   }
847
848   return nullptr;
849 }
850
851 void cmTarget::SetLanguageStandardProperty(std::string const& lang,
852                                            std::string const& value,
853                                            const std::string& feature)
854 {
855   cmListFileBacktrace featureBacktrace;
856   for (auto const& entry : this->impl->CompileFeaturesEntries) {
857     if (entry.Value == feature) {
858       featureBacktrace = entry.Backtrace;
859       break;
860     }
861   }
862
863   BTs<std::string>& languageStandardProperty =
864     this->impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
865   if (languageStandardProperty.Value != value) {
866     languageStandardProperty.Value = value;
867     languageStandardProperty.Backtraces.clear();
868   }
869   languageStandardProperty.Backtraces.emplace_back(featureBacktrace);
870 }
871
872 void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf)
873 {
874   this->impl->Utilities.insert(BT<std::pair<std::string, bool>>(
875     { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
876 }
877
878 void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util)
879 {
880   this->impl->Utilities.emplace(std::move(util));
881 }
882
883 std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities()
884   const
885 {
886   return this->impl->Utilities;
887 }
888
889 cmListFileBacktrace const& cmTarget::GetBacktrace() const
890 {
891   return this->impl->Backtrace;
892 }
893
894 bool cmTarget::IsExecutableWithExports() const
895 {
896   return (this->GetType() == cmStateEnums::EXECUTABLE &&
897           this->GetPropertyAsBool("ENABLE_EXPORTS"));
898 }
899
900 bool cmTarget::IsFrameworkOnApple() const
901 {
902   return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
903            this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
904           this->impl->Makefile->IsOn("APPLE") &&
905           this->GetPropertyAsBool("FRAMEWORK"));
906 }
907
908 bool cmTarget::IsAppBundleOnApple() const
909 {
910   return (this->GetType() == cmStateEnums::EXECUTABLE &&
911           this->impl->Makefile->IsOn("APPLE") &&
912           this->GetPropertyAsBool("MACOSX_BUNDLE"));
913 }
914
915 bool cmTarget::IsAndroidGuiExecutable() const
916 {
917   return (this->GetType() == cmStateEnums::EXECUTABLE &&
918           this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI"));
919 }
920
921 bool cmTarget::HasKnownObjectFileLocation(std::string* reason) const
922 {
923   return this->GetGlobalGenerator()->HasKnownObjectFileLocation(*this, reason);
924 }
925
926 std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
927 {
928   return this->impl->PreBuildCommands;
929 }
930
931 void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
932 {
933   this->impl->PreBuildCommands.push_back(cmd);
934 }
935
936 void cmTarget::AddPreBuildCommand(cmCustomCommand&& cmd)
937 {
938   this->impl->PreBuildCommands.push_back(std::move(cmd));
939 }
940
941 std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
942 {
943   return this->impl->PreLinkCommands;
944 }
945
946 void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
947 {
948   this->impl->PreLinkCommands.push_back(cmd);
949 }
950
951 void cmTarget::AddPreLinkCommand(cmCustomCommand&& cmd)
952 {
953   this->impl->PreLinkCommands.push_back(std::move(cmd));
954 }
955
956 std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
957 {
958   return this->impl->PostBuildCommands;
959 }
960
961 void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
962 {
963   this->impl->PostBuildCommands.push_back(cmd);
964 }
965
966 void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd)
967 {
968   this->impl->PostBuildCommands.push_back(std::move(cmd));
969 }
970
971 void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
972 {
973   if (!srcs.empty()) {
974     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
975     this->impl->SourceEntries.emplace_back(cmJoin(srcs, ";"), lfbt);
976   }
977 }
978
979 void cmTarget::AddSources(std::vector<std::string> const& srcs)
980 {
981   std::string srcFiles;
982   const char* sep = "";
983   for (auto filename : srcs) {
984     if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
985       if (!filename.empty()) {
986         filename = this->impl->ProcessSourceItemCMP0049(filename);
987         if (filename.empty()) {
988           return;
989         }
990       }
991       this->impl->Makefile->GetOrCreateSource(filename);
992     }
993     srcFiles += sep;
994     srcFiles += filename;
995     sep = ";";
996   }
997   if (!srcFiles.empty()) {
998     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
999     this->impl->SourceEntries.emplace_back(std::move(srcFiles), lfbt);
1000   }
1001 }
1002
1003 std::string cmTargetInternals::ProcessSourceItemCMP0049(
1004   const std::string& s) const
1005 {
1006   std::string src = s;
1007
1008   // For backwards compatibility replace variables in source names.
1009   // This should eventually be removed.
1010   this->Makefile->ExpandVariablesInString(src);
1011   if (src != s) {
1012     std::ostringstream e;
1013     bool noMessage = false;
1014     MessageType messageType = MessageType::AUTHOR_WARNING;
1015     switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0049)) {
1016       case cmPolicies::WARN:
1017         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
1018         break;
1019       case cmPolicies::OLD:
1020         noMessage = true;
1021         break;
1022       case cmPolicies::REQUIRED_ALWAYS:
1023       case cmPolicies::REQUIRED_IF_USED:
1024       case cmPolicies::NEW:
1025         messageType = MessageType::FATAL_ERROR;
1026     }
1027     if (!noMessage) {
1028       e << "Legacy variable expansion in source file \"" << s
1029         << "\" expanded to \"" << src << "\" in target \"" << this->Name
1030         << "\".  This behavior will be removed in a "
1031            "future version of CMake.";
1032       this->Makefile->IssueMessage(messageType, e.str());
1033       if (messageType == MessageType::FATAL_ERROR) {
1034         return "";
1035       }
1036     }
1037   }
1038   return src;
1039 }
1040
1041 std::string cmTarget::GetSourceCMP0049(const std::string& s)
1042 {
1043   return this->impl->ProcessSourceItemCMP0049(s);
1044 }
1045
1046 struct CreateLocation
1047 {
1048   cmMakefile const* Makefile;
1049
1050   CreateLocation(cmMakefile const* mf)
1051     : Makefile(mf)
1052   {
1053   }
1054
1055   cmSourceFileLocation operator()(const std::string& filename) const
1056   {
1057     return cmSourceFileLocation(this->Makefile, filename);
1058   }
1059 };
1060
1061 struct LocationMatcher
1062 {
1063   const cmSourceFileLocation& Needle;
1064
1065   LocationMatcher(const cmSourceFileLocation& needle)
1066     : Needle(needle)
1067   {
1068   }
1069
1070   bool operator()(cmSourceFileLocation& loc)
1071   {
1072     return loc.Matches(this->Needle);
1073   }
1074 };
1075
1076 struct TargetPropertyEntryFinder
1077 {
1078 private:
1079   const cmSourceFileLocation& Needle;
1080
1081 public:
1082   TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
1083     : Needle(needle)
1084   {
1085   }
1086
1087   bool operator()(BT<std::string> const& entry)
1088   {
1089     std::vector<std::string> files = cmExpandedList(entry.Value);
1090     std::vector<cmSourceFileLocation> locations;
1091     locations.reserve(files.size());
1092     std::transform(files.begin(), files.end(), std::back_inserter(locations),
1093                    CreateLocation(this->Needle.GetMakefile()));
1094
1095     return std::find_if(locations.begin(), locations.end(),
1096                         LocationMatcher(this->Needle)) != locations.end();
1097   }
1098 };
1099
1100 cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
1101 {
1102   cmSourceFileLocation sfl(this->impl->Makefile, src,
1103                            cmSourceFileLocationKind::Known);
1104   if (std::find_if(
1105         this->impl->SourceEntries.begin(), this->impl->SourceEntries.end(),
1106         TargetPropertyEntryFinder(sfl)) == this->impl->SourceEntries.end()) {
1107     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1108     this->impl->SourceEntries.insert(before ? this->impl->SourceEntries.begin()
1109                                             : this->impl->SourceEntries.end(),
1110                                      BT<std::string>(src, lfbt));
1111   }
1112   if (cmGeneratorExpression::Find(src) != std::string::npos) {
1113     return nullptr;
1114   }
1115   return this->impl->Makefile->GetOrCreateSource(
1116     src, false, cmSourceFileLocationKind::Known);
1117 }
1118
1119 void cmTarget::ClearDependencyInformation(cmMakefile& mf) const
1120 {
1121   std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS");
1122   mf.RemoveCacheDefinition(depname);
1123 }
1124
1125 std::string cmTarget::GetDebugGeneratorExpressions(
1126   const std::string& value, cmTargetLinkLibraryType llt) const
1127 {
1128   if (llt == GENERAL_LibraryType) {
1129     return value;
1130   }
1131
1132   // Get the list of configurations considered to be DEBUG.
1133   std::vector<std::string> debugConfigs =
1134     this->impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
1135
1136   std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
1137
1138   if (debugConfigs.size() > 1) {
1139     for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
1140       configString += ",$<CONFIG:" + conf + ">";
1141     }
1142     configString = "$<OR:" + configString + ">";
1143   }
1144
1145   if (llt == OPTIMIZED_LibraryType) {
1146     configString = "$<NOT:" + configString + ">";
1147   }
1148   return "$<" + configString + ":" + value + ">";
1149 }
1150
1151 static std::string targetNameGenex(const std::string& lib)
1152 {
1153   return "$<TARGET_NAME:" + lib + ">";
1154 }
1155
1156 bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
1157                                    cmListFileContext const& lfc)
1158 {
1159   bool ret = true;
1160   if (!this->impl->TLLCommands.empty()) {
1161     if (this->impl->TLLCommands.back().first != signature) {
1162       ret = false;
1163     }
1164   }
1165   if (this->impl->TLLCommands.empty() ||
1166       this->impl->TLLCommands.back().second != lfc) {
1167     this->impl->TLLCommands.emplace_back(signature, lfc);
1168   }
1169   return ret;
1170 }
1171
1172 void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
1173 {
1174   const char* sigString =
1175     (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
1176   s << "The uses of the " << sigString << " signature are here:\n";
1177   for (auto const& cmd : this->impl->TLLCommands) {
1178     if (cmd.first == sig) {
1179       cmListFileContext lfc = cmd.second;
1180       lfc.FilePath = cmSystemTools::RelativeIfUnder(
1181         this->impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
1182       s << " * " << lfc << '\n';
1183     }
1184   }
1185 }
1186
1187 std::string const& cmTarget::GetInstallPath() const
1188 {
1189   return this->impl->InstallPath;
1190 }
1191
1192 void cmTarget::SetInstallPath(std::string const& name)
1193 {
1194   this->impl->InstallPath = name;
1195 }
1196
1197 std::string const& cmTarget::GetRuntimeInstallPath() const
1198 {
1199   return this->impl->RuntimeInstallPath;
1200 }
1201
1202 void cmTarget::SetRuntimeInstallPath(std::string const& name)
1203 {
1204   this->impl->RuntimeInstallPath = name;
1205 }
1206
1207 bool cmTarget::GetHaveInstallRule() const
1208 {
1209   return this->impl->HaveInstallRule;
1210 }
1211
1212 void cmTarget::SetHaveInstallRule(bool hir)
1213 {
1214   this->impl->HaveInstallRule = hir;
1215 }
1216
1217 void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g)
1218 {
1219   this->impl->InstallGenerators.emplace_back(g);
1220 }
1221
1222 std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators()
1223   const
1224 {
1225   return this->impl->InstallGenerators;
1226 }
1227
1228 bool cmTarget::GetIsGeneratorProvided() const
1229 {
1230   return this->impl->IsGeneratorProvided;
1231 }
1232
1233 void cmTarget::SetIsGeneratorProvided(bool igp)
1234 {
1235   this->impl->IsGeneratorProvided = igp;
1236 }
1237
1238 cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
1239   const
1240 {
1241   return this->impl->OriginalLinkLibraries;
1242 }
1243
1244 void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
1245                               cmTargetLinkLibraryType llt)
1246 {
1247   cmTarget* tgt = mf.FindTargetToUse(lib);
1248   {
1249     const bool isNonImportedTarget = tgt && !tgt->IsImported();
1250
1251     const std::string libName =
1252       (isNonImportedTarget && llt != GENERAL_LibraryType)
1253       ? targetNameGenex(lib)
1254       : lib;
1255     this->AppendProperty("LINK_LIBRARIES",
1256                          this->GetDebugGeneratorExpressions(libName, llt),
1257                          mf.GetBacktrace());
1258   }
1259
1260   if (cmGeneratorExpression::Find(lib) != std::string::npos ||
1261       (tgt &&
1262        (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
1263         tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
1264       (this->impl->Name == lib)) {
1265     return;
1266   }
1267
1268   this->impl->OriginalLinkLibraries.emplace_back(lib, llt);
1269
1270   // Add the explicit dependency information for libraries. This is
1271   // simply a set of libraries separated by ";". There should always
1272   // be a trailing ";". These library names are not canonical, in that
1273   // they may be "-framework x", "-ly", "/path/libz.a", etc.
1274   // We shouldn't remove duplicates here because external libraries
1275   // may be purposefully duplicated to handle recursive dependencies,
1276   // and we removing one instance will break the link line. Duplicates
1277   // will be appropriately eliminated at emit time.
1278   if (this->impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
1279       this->impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
1280       (this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
1281        this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
1282     std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS");
1283     std::string dependencies;
1284     cmValue old_val = mf.GetDefinition(targetEntry);
1285     if (old_val) {
1286       dependencies += *old_val;
1287     }
1288     switch (llt) {
1289       case GENERAL_LibraryType:
1290         dependencies += "general";
1291         break;
1292       case DEBUG_LibraryType:
1293         dependencies += "debug";
1294         break;
1295       case OPTIMIZED_LibraryType:
1296         dependencies += "optimized";
1297         break;
1298     }
1299     dependencies += ";";
1300     dependencies += lib;
1301     dependencies += ";";
1302     mf.AddCacheDefinition(targetEntry, dependencies,
1303                           "Dependencies for the target", cmStateEnums::STATIC);
1304   }
1305 }
1306
1307 void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
1308 {
1309   this->impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
1310 }
1311
1312 std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
1313 {
1314   return this->impl->SystemIncludeDirectories;
1315 }
1316
1317 void cmTarget::AddInstallIncludeDirectories(cmTargetExport const& te,
1318                                             cmStringRange const& incs)
1319 {
1320   std::copy(
1321     incs.begin(), incs.end(),
1322     std::back_inserter(this->impl->InstallIncludeDirectoriesEntries[&te]));
1323 }
1324
1325 cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries(
1326   cmTargetExport const& te) const
1327 {
1328   auto i = this->impl->InstallIncludeDirectoriesEntries.find(&te);
1329   if (i == this->impl->InstallIncludeDirectoriesEntries.end()) {
1330     decltype(i->second) empty;
1331     return cmMakeRange(empty);
1332   }
1333   return cmMakeRange(i->second);
1334 }
1335
1336 cmBTStringRange cmTarget::GetIncludeDirectoriesEntries() const
1337 {
1338   return cmMakeRange(this->impl->IncludeDirectoriesEntries);
1339 }
1340
1341 cmBTStringRange cmTarget::GetCompileOptionsEntries() const
1342 {
1343   return cmMakeRange(this->impl->CompileOptionsEntries);
1344 }
1345
1346 cmBTStringRange cmTarget::GetCompileFeaturesEntries() const
1347 {
1348   return cmMakeRange(this->impl->CompileFeaturesEntries);
1349 }
1350
1351 cmBTStringRange cmTarget::GetCompileDefinitionsEntries() const
1352 {
1353   return cmMakeRange(this->impl->CompileDefinitionsEntries);
1354 }
1355
1356 cmBTStringRange cmTarget::GetPrecompileHeadersEntries() const
1357 {
1358   return cmMakeRange(this->impl->PrecompileHeadersEntries);
1359 }
1360
1361 cmBTStringRange cmTarget::GetSourceEntries() const
1362 {
1363   return cmMakeRange(this->impl->SourceEntries);
1364 }
1365
1366 cmBTStringRange cmTarget::GetLinkOptionsEntries() const
1367 {
1368   return cmMakeRange(this->impl->LinkOptionsEntries);
1369 }
1370
1371 cmBTStringRange cmTarget::GetLinkDirectoriesEntries() const
1372 {
1373   return cmMakeRange(this->impl->LinkDirectoriesEntries);
1374 }
1375
1376 cmBTStringRange cmTarget::GetLinkImplementationEntries() const
1377 {
1378   return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
1379 }
1380
1381 cmBTStringRange cmTarget::GetLinkInterfaceEntries() const
1382 {
1383   return cmMakeRange(this->impl->LinkInterfacePropertyEntries);
1384 }
1385
1386 cmBTStringRange cmTarget::GetLinkInterfaceDirectEntries() const
1387 {
1388   return cmMakeRange(this->impl->LinkInterfaceDirectPropertyEntries);
1389 }
1390
1391 cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const
1392 {
1393   return cmMakeRange(this->impl->LinkInterfaceDirectExcludePropertyEntries);
1394 }
1395
1396 cmBTStringRange cmTarget::GetHeaderSetsEntries() const
1397 {
1398   return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
1399 }
1400
1401 cmBTStringRange cmTarget::GetCxxModuleSetsEntries() const
1402 {
1403   return cmMakeRange(this->impl->CxxModulesFileSets.SelfEntries.Entries);
1404 }
1405
1406 cmBTStringRange cmTarget::GetCxxModuleHeaderSetsEntries() const
1407 {
1408   return cmMakeRange(this->impl->CxxModuleHeadersFileSets.SelfEntries.Entries);
1409 }
1410
1411 cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
1412 {
1413   return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries);
1414 }
1415
1416 cmBTStringRange cmTarget::GetInterfaceCxxModuleSetsEntries() const
1417 {
1418   return cmMakeRange(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
1419 }
1420
1421 cmBTStringRange cmTarget::GetInterfaceCxxModuleHeaderSetsEntries() const
1422 {
1423   return cmMakeRange(
1424     this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
1425 }
1426
1427 namespace {
1428 #define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
1429 MAKE_PROP(C_STANDARD);
1430 MAKE_PROP(CXX_STANDARD);
1431 MAKE_PROP(CUDA_STANDARD);
1432 MAKE_PROP(HIP_STANDARD);
1433 MAKE_PROP(OBJC_STANDARD);
1434 MAKE_PROP(OBJCXX_STANDARD);
1435 MAKE_PROP(COMPILE_DEFINITIONS);
1436 MAKE_PROP(COMPILE_FEATURES);
1437 MAKE_PROP(COMPILE_OPTIONS);
1438 MAKE_PROP(PRECOMPILE_HEADERS);
1439 MAKE_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
1440 MAKE_PROP(CUDA_PTX_COMPILATION);
1441 MAKE_PROP(EXPORT_NAME);
1442 MAKE_PROP(IMPORTED);
1443 MAKE_PROP(IMPORTED_GLOBAL);
1444 MAKE_PROP(INCLUDE_DIRECTORIES);
1445 MAKE_PROP(LINK_OPTIONS);
1446 MAKE_PROP(LINK_DIRECTORIES);
1447 MAKE_PROP(LINK_LIBRARIES);
1448 MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES);
1449 MAKE_PROP(NAME);
1450 MAKE_PROP(SOURCES);
1451 MAKE_PROP(TYPE);
1452 MAKE_PROP(BINARY_DIR);
1453 MAKE_PROP(SOURCE_DIR);
1454 MAKE_PROP(FALSE);
1455 MAKE_PROP(TRUE);
1456 MAKE_PROP(INTERFACE_LINK_LIBRARIES);
1457 MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT);
1458 MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE);
1459 #undef MAKE_PROP
1460 }
1461
1462 namespace {
1463 // to workaround bug on GCC/AIX
1464 // Define a template to force conversion to std::string
1465 template <typename ValueType>
1466 std::string ConvertToString(ValueType value);
1467
1468 template <>
1469 std::string ConvertToString<const char*>(const char* value)
1470 {
1471   return std::string(value);
1472 }
1473 template <>
1474 std::string ConvertToString<cmValue>(cmValue value)
1475 {
1476   return std::string(*value);
1477 }
1478
1479 template <typename ValueType>
1480 bool StringIsEmpty(ValueType const& value);
1481
1482 template <>
1483 bool StringIsEmpty<const char*>(const char* const& value)
1484 {
1485   return cmValue::IsEmpty(value);
1486 }
1487
1488 template <>
1489 bool StringIsEmpty<cmValue>(cmValue const& value)
1490 {
1491   return value.IsEmpty();
1492 }
1493
1494 template <>
1495 bool StringIsEmpty<std::string>(std::string const& value)
1496 {
1497   return value.empty();
1498 }
1499 }
1500
1501 template <typename ValueType>
1502 void cmTarget::StoreProperty(const std::string& prop, ValueType value)
1503 {
1504   if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
1505     this->impl->Makefile->IssueMessage(
1506       MessageType::FATAL_ERROR,
1507       "MANUALLY_ADDED_DEPENDENCIES property is read-only\n");
1508     return;
1509   }
1510   if (prop == propNAME) {
1511     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1512                                        "NAME property is read-only\n");
1513     return;
1514   }
1515   if (prop == propTYPE) {
1516     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1517                                        "TYPE property is read-only\n");
1518     return;
1519   }
1520   if (prop == propEXPORT_NAME && this->IsImported()) {
1521     std::ostringstream e;
1522     e << "EXPORT_NAME property can't be set on imported targets (\""
1523       << this->impl->Name << "\")\n";
1524     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1525     return;
1526   }
1527   if (prop == propSOURCES && this->IsImported()) {
1528     std::ostringstream e;
1529     e << "SOURCES property can't be set on imported targets (\""
1530       << this->impl->Name << "\")\n";
1531     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1532     return;
1533   }
1534   if (prop == propIMPORTED_GLOBAL && !this->IsImported()) {
1535     std::ostringstream e;
1536     e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
1537       << this->impl->Name << "\")\n";
1538     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1539     return;
1540   }
1541
1542   if (prop == propINCLUDE_DIRECTORIES) {
1543     this->impl->IncludeDirectoriesEntries.clear();
1544     if (value) {
1545       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1546       this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
1547     }
1548   } else if (prop == propCOMPILE_OPTIONS) {
1549     this->impl->CompileOptionsEntries.clear();
1550     if (value) {
1551       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1552       this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
1553     }
1554   } else if (prop == propCOMPILE_FEATURES) {
1555     this->impl->CompileFeaturesEntries.clear();
1556     if (value) {
1557       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1558       this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
1559     }
1560   } else if (prop == propCOMPILE_DEFINITIONS) {
1561     this->impl->CompileDefinitionsEntries.clear();
1562     if (value) {
1563       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1564       this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
1565     }
1566   } else if (prop == propLINK_OPTIONS) {
1567     this->impl->LinkOptionsEntries.clear();
1568     if (value) {
1569       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1570       this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
1571     }
1572   } else if (prop == propLINK_DIRECTORIES) {
1573     this->impl->LinkDirectoriesEntries.clear();
1574     if (value) {
1575       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1576       this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
1577     }
1578   } else if (prop == propPRECOMPILE_HEADERS) {
1579     this->impl->PrecompileHeadersEntries.clear();
1580     if (value) {
1581       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1582       this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
1583     }
1584   } else if (prop == propLINK_LIBRARIES) {
1585     this->impl->LinkImplementationPropertyEntries.clear();
1586     if (value) {
1587       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1588       this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
1589     }
1590   } else if (prop == propINTERFACE_LINK_LIBRARIES) {
1591     this->impl->LinkInterfacePropertyEntries.clear();
1592     if (value) {
1593       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1594       this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
1595     }
1596   } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
1597     this->impl->LinkInterfaceDirectPropertyEntries.clear();
1598     if (value) {
1599       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1600       this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
1601     }
1602   } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
1603     this->impl->LinkInterfaceDirectExcludePropertyEntries.clear();
1604     if (value) {
1605       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1606       this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
1607                                                                          lfbt);
1608     }
1609   } else if (prop == propSOURCES) {
1610     this->impl->SourceEntries.clear();
1611     if (value) {
1612       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
1613       this->impl->SourceEntries.emplace_back(value, lfbt);
1614     }
1615   } else if (prop == propIMPORTED_GLOBAL) {
1616     if (!cmIsOn(value)) {
1617       std::ostringstream e;
1618       e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
1619         << this->impl->Name << "\")\n";
1620       this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1621       return;
1622     }
1623     /* no need to change anything if value does not change */
1624     if (!this->impl->ImportedGloballyVisible) {
1625       this->impl->ImportedGloballyVisible = true;
1626       this->GetGlobalGenerator()->IndexTarget(this);
1627     }
1628   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
1629              !this->impl->CheckImportedLibName(
1630                prop,
1631                value ? value
1632                      : std::string{})) { // NOLINT(bugprone-branch-clone)
1633     /* error was reported by check method */
1634   } else if (prop == propCUDA_PTX_COMPILATION &&
1635              this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
1636     std::ostringstream e;
1637     e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT "
1638          "targets (\""
1639       << this->impl->Name << "\")\n";
1640     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1641     return;
1642   } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) {
1643     if (this->GetProperty("PRECOMPILE_HEADERS")) {
1644       std::ostringstream e;
1645       e << "PRECOMPILE_HEADERS property is already set on target (\""
1646         << this->impl->Name << "\")\n";
1647       this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1648       return;
1649     }
1650     auto* reusedTarget = this->impl->Makefile->GetCMakeInstance()
1651                            ->GetGlobalGenerator()
1652                            ->FindTarget(value);
1653     if (!reusedTarget) {
1654       const std::string e(
1655         "PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
1656       this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
1657       return;
1658     }
1659
1660     std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
1661     if (reusedFrom.empty()) {
1662       reusedFrom = ConvertToString(value);
1663     }
1664
1665     this->impl->Properties.SetProperty(prop, reusedFrom);
1666
1667     reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
1668     reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
1669                               cmStrCat(reusedFrom, ".dir/"));
1670
1671     cmValue tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
1672     this->SetProperty("COMPILE_PDB_NAME", tmp);
1673     this->AddUtility(reusedFrom, false, this->impl->Makefile);
1674   } else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
1675              prop == propCUDA_STANDARD || prop == propHIP_STANDARD ||
1676              prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) {
1677     if (value) {
1678       this->impl->LanguageStandardProperties[prop] =
1679         BTs<std::string>(value, this->impl->Makefile->GetBacktrace());
1680     } else {
1681       this->impl->LanguageStandardProperties.erase(prop);
1682     }
1683   } else if (this->impl->HeadersFileSets.WriteProperties(
1684                this, this->impl.get(), prop, value, true)) {
1685     /* Handled in the `if` condition. */
1686   } else if (this->impl->CxxModulesFileSets.WriteProperties(
1687                this, this->impl.get(), prop, value, true)) {
1688     /* Handled in the `if` condition. */
1689   } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
1690                this, this->impl.get(), prop, value, true)) {
1691     /* Handled in the `if` condition. */
1692   } else {
1693     this->impl->Properties.SetProperty(prop, value);
1694   }
1695 }
1696
1697 void cmTarget::AppendProperty(const std::string& prop,
1698                               const std::string& value,
1699                               cm::optional<cmListFileBacktrace> const& bt,
1700                               bool asString)
1701 {
1702   if (prop == "NAME") {
1703     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1704                                        "NAME property is read-only\n");
1705     return;
1706   }
1707   if (prop == "EXPORT_NAME" && this->IsImported()) {
1708     std::ostringstream e;
1709     e << "EXPORT_NAME property can't be set on imported targets (\""
1710       << this->impl->Name << "\")\n";
1711     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1712     return;
1713   }
1714   if (prop == "SOURCES" && this->IsImported()) {
1715     std::ostringstream e;
1716     e << "SOURCES property can't be set on imported targets (\""
1717       << this->impl->Name << "\")\n";
1718     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1719     return;
1720   }
1721   if (prop == "IMPORTED_GLOBAL") {
1722     std::ostringstream e;
1723     e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
1724          "targets (\""
1725       << this->impl->Name << "\")\n";
1726     this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1727     return;
1728   }
1729   if (prop == "INCLUDE_DIRECTORIES") {
1730     if (!value.empty()) {
1731       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1732       this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
1733     }
1734   } else if (prop == "COMPILE_OPTIONS") {
1735     if (!value.empty()) {
1736       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1737       this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
1738     }
1739   } else if (prop == "COMPILE_FEATURES") {
1740     if (!value.empty()) {
1741       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1742       this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
1743     }
1744   } else if (prop == "COMPILE_DEFINITIONS") {
1745     if (!value.empty()) {
1746       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1747       this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
1748     }
1749   } else if (prop == "LINK_OPTIONS") {
1750     if (!value.empty()) {
1751       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1752       this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
1753     }
1754   } else if (prop == "LINK_DIRECTORIES") {
1755     if (!value.empty()) {
1756       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1757       this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
1758     }
1759   } else if (prop == "PRECOMPILE_HEADERS") {
1760     if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1761       std::ostringstream e;
1762       e << "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target "
1763            "(\""
1764         << this->impl->Name << "\")\n";
1765       this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
1766       return;
1767     }
1768     if (!value.empty()) {
1769       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1770       this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
1771     }
1772   } else if (prop == "LINK_LIBRARIES") {
1773     if (!value.empty()) {
1774       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1775       this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
1776     }
1777   } else if (prop == propINTERFACE_LINK_LIBRARIES) {
1778     if (!value.empty()) {
1779       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1780       this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
1781     }
1782   } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
1783     if (!value.empty()) {
1784       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1785       this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
1786     }
1787   } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
1788     if (!value.empty()) {
1789       cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1790       this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
1791                                                                          lfbt);
1792     }
1793   } else if (prop == "SOURCES") {
1794     cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
1795     this->impl->SourceEntries.emplace_back(value, lfbt);
1796   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
1797     this->impl->Makefile->IssueMessage(
1798       MessageType::FATAL_ERROR, prop + " property may not be APPENDed.");
1799   } else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" ||
1800              prop == "CUDA_STANDARD" || prop == "HIP_STANDARD" ||
1801              prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") {
1802     this->impl->Makefile->IssueMessage(
1803       MessageType::FATAL_ERROR, prop + " property may not be appended.");
1804   } else if (this->impl->HeadersFileSets.WriteProperties(
1805                this, this->impl.get(), prop, value,
1806                false)) { // NOLINT(bugprone-branch-clone)
1807     /* Handled in the `if` condition. */
1808   } else if (this->impl->CxxModulesFileSets.WriteProperties(
1809                this, this->impl.get(), prop, value, false)) {
1810     /* Handled in the `if` condition. */
1811   } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
1812                this, this->impl.get(), prop, value, false)) {
1813     /* Handled in the `if` condition. */
1814   } else {
1815     this->impl->Properties.AppendProperty(prop, value, asString);
1816   }
1817 }
1818
1819 void cmTarget::SetProperty(const std::string& prop, const char* value)
1820 {
1821   this->StoreProperty(prop, value);
1822 }
1823 void cmTarget::SetProperty(const std::string& prop, cmValue value)
1824 {
1825   this->StoreProperty(prop, value);
1826 }
1827
1828 template <typename ValueType>
1829 void cmTargetInternals::AddDirectoryToFileSet(
1830   cmTarget* self, std::string const& fileSetName, ValueType value,
1831   cm::string_view fileSetType, cm::string_view description, bool clear)
1832 {
1833   auto* fileSet = self->GetFileSet(fileSetName);
1834   if (!fileSet) {
1835     this->Makefile->IssueMessage(
1836       MessageType::FATAL_ERROR,
1837       cmStrCat(description, "has not yet been created."));
1838     return;
1839   }
1840   if (fileSet->GetType() != fileSetType) {
1841     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1842                                  cmStrCat("File set \"", fileSetName,
1843                                           "\" is not of type \"", fileSetType,
1844                                           "\"."));
1845     return;
1846   }
1847   if (clear) {
1848     fileSet->ClearDirectoryEntries();
1849   }
1850   if (!StringIsEmpty(value)) {
1851     fileSet->AddDirectoryEntry(
1852       BT<std::string>(value, this->Makefile->GetBacktrace()));
1853   }
1854 }
1855
1856 template <typename ValueType>
1857 void cmTargetInternals::AddPathToFileSet(
1858   cmTarget* self, std::string const& fileSetName, ValueType value,
1859   cm::string_view fileSetType, cm::string_view description, bool clear)
1860 {
1861   auto* fileSet = self->GetFileSet(fileSetName);
1862   if (!fileSet) {
1863     this->Makefile->IssueMessage(
1864       MessageType::FATAL_ERROR,
1865       cmStrCat(description, "has not yet been created."));
1866     return;
1867   }
1868   if (fileSet->GetType() != fileSetType) {
1869     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1870                                  cmStrCat("File set \"", fileSetName,
1871                                           "\" is not of type \"", fileSetType,
1872                                           "\"."));
1873     return;
1874   }
1875   if (clear) {
1876     fileSet->ClearFileEntries();
1877   }
1878   if (!StringIsEmpty(value)) {
1879     fileSet->AddFileEntry(
1880       BT<std::string>(value, this->Makefile->GetBacktrace()));
1881   }
1882 }
1883
1884 cmValue cmTargetInternals::GetFileSetDirectories(
1885   cmTarget const* self, std::string const& fileSetName,
1886   cm::string_view fileSetType) const
1887 {
1888   auto const* fileSet = self->GetFileSet(fileSetName);
1889   if (!fileSet) {
1890     return nullptr;
1891   }
1892   if (fileSet->GetType() != fileSetType) {
1893     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1894                                  cmStrCat("File set \"", fileSetName,
1895                                           "\" is not of type \"", fileSetType,
1896                                           "\"."));
1897     return nullptr;
1898   }
1899   static std::string output;
1900   output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
1901   return cmValue(output);
1902 }
1903
1904 cmValue cmTargetInternals::GetFileSetPaths(cmTarget const* self,
1905                                            std::string const& fileSetName,
1906                                            cm::string_view fileSetType) const
1907 {
1908   auto const* fileSet = self->GetFileSet(fileSetName);
1909   if (!fileSet) {
1910     return nullptr;
1911   }
1912   if (fileSet->GetType() != fileSetType) {
1913     this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
1914                                  cmStrCat("File set \"", fileSetName,
1915                                           "\" is not of type \"", fileSetType,
1916                                           "\"."));
1917     return nullptr;
1918   }
1919   static std::string output;
1920   output = cmJoin(fileSet->GetFileEntries(), ";"_s);
1921   return cmValue(output);
1922 }
1923
1924 void cmTarget::AppendBuildInterfaceIncludes()
1925 {
1926   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
1927       this->GetType() != cmStateEnums::STATIC_LIBRARY &&
1928       this->GetType() != cmStateEnums::MODULE_LIBRARY &&
1929       this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
1930       !this->IsExecutableWithExports()) {
1931     return;
1932   }
1933   if (this->impl->BuildInterfaceIncludesAppended) {
1934     return;
1935   }
1936   this->impl->BuildInterfaceIncludesAppended = true;
1937
1938   if (this->impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
1939     std::string dirs = this->impl->Makefile->GetCurrentBinaryDirectory();
1940     if (!dirs.empty()) {
1941       dirs += ';';
1942     }
1943     dirs += this->impl->Makefile->GetCurrentSourceDirectory();
1944     if (!dirs.empty()) {
1945       this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
1946                            ("$<BUILD_INTERFACE:" + dirs + ">"));
1947     }
1948   }
1949 }
1950
1951 namespace {
1952 bool CheckLinkLibraryPattern(cm::string_view property,
1953                              const std::vector<BT<std::string>>& value,
1954                              cmake* context)
1955 {
1956   // Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags
1957   static cmsys::RegularExpression linkPattern(
1958     "(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)");
1959
1960   bool isValid = true;
1961
1962   for (const auto& item : value) {
1963     if (!linkPattern.find(item.Value)) {
1964       continue;
1965     }
1966
1967     isValid = false;
1968
1969     // Report an error.
1970     context->IssueMessage(
1971       MessageType::FATAL_ERROR,
1972       cmStrCat(
1973         "Property ", property, " contains the invalid item \"",
1974         linkPattern.match(2), "\". The ", property,
1975         " property may contain the generator-expression \"$<LINK_",
1976         linkPattern.match(3),
1977         ":...>\" which may be used to specify how the libraries are linked."),
1978       item.Backtrace);
1979   }
1980
1981   return isValid;
1982 }
1983 }
1984
1985 void cmTarget::FinalizeTargetConfiguration(
1986   const cmBTStringRange& noConfigCompileDefinitions,
1987   cm::optional<std::map<std::string, cmValue>>& perConfigCompileDefinitions)
1988 {
1989   if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
1990     return;
1991   }
1992
1993   if (!CheckLinkLibraryPattern("LINK_LIBRARIES"_s,
1994                                this->impl->LinkImplementationPropertyEntries,
1995                                this->GetMakefile()->GetCMakeInstance()) ||
1996       !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES"_s,
1997                                this->impl->LinkInterfacePropertyEntries,
1998                                this->GetMakefile()->GetCMakeInstance()) ||
1999       !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES_DIRECT"_s,
2000                                this->impl->LinkInterfaceDirectPropertyEntries,
2001                                this->GetMakefile()->GetCMakeInstance())) {
2002     return;
2003   }
2004
2005   this->AppendBuildInterfaceIncludes();
2006
2007   if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2008     return;
2009   }
2010
2011   for (auto const& def : noConfigCompileDefinitions) {
2012     this->InsertCompileDefinition(def);
2013   }
2014
2015   auto* mf = this->GetMakefile();
2016   cmPolicies::PolicyStatus polSt = mf->GetPolicyStatus(cmPolicies::CMP0043);
2017   if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
2018     if (perConfigCompileDefinitions) {
2019       for (auto const& it : *perConfigCompileDefinitions) {
2020         if (cmValue val = it.second) {
2021           this->AppendProperty(it.first, *val);
2022         }
2023       }
2024     } else {
2025       perConfigCompileDefinitions.emplace();
2026       std::vector<std::string> configs =
2027         mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
2028
2029       for (std::string const& c : configs) {
2030         std::string defPropName =
2031           cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
2032         cmValue val = mf->GetProperty(defPropName);
2033         (*perConfigCompileDefinitions)[defPropName] = val;
2034         if (val) {
2035           this->AppendProperty(defPropName, *val);
2036         }
2037       }
2038     }
2039   }
2040 }
2041
2042 void cmTarget::InsertInclude(BT<std::string> const& entry, bool before)
2043 {
2044   auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
2045                          : this->impl->IncludeDirectoriesEntries.end();
2046
2047   this->impl->IncludeDirectoriesEntries.insert(position, entry);
2048 }
2049
2050 void cmTarget::InsertCompileOption(BT<std::string> const& entry, bool before)
2051 {
2052   auto position = before ? this->impl->CompileOptionsEntries.begin()
2053                          : this->impl->CompileOptionsEntries.end();
2054
2055   this->impl->CompileOptionsEntries.insert(position, entry);
2056 }
2057
2058 void cmTarget::InsertCompileDefinition(BT<std::string> const& entry)
2059 {
2060   this->impl->CompileDefinitionsEntries.push_back(entry);
2061 }
2062
2063 void cmTarget::InsertLinkOption(BT<std::string> const& entry, bool before)
2064 {
2065   auto position = before ? this->impl->LinkOptionsEntries.begin()
2066                          : this->impl->LinkOptionsEntries.end();
2067
2068   this->impl->LinkOptionsEntries.insert(position, entry);
2069 }
2070
2071 void cmTarget::InsertLinkDirectory(BT<std::string> const& entry, bool before)
2072 {
2073   auto position = before ? this->impl->LinkDirectoriesEntries.begin()
2074                          : this->impl->LinkDirectoriesEntries.end();
2075
2076   this->impl->LinkDirectoriesEntries.insert(position, entry);
2077 }
2078
2079 void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry)
2080 {
2081   this->impl->PrecompileHeadersEntries.push_back(entry);
2082 }
2083
2084 namespace {
2085 void CheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
2086                                    const std::string& value,
2087                                    cmMakefile* context, bool imported)
2088 {
2089   // Support imported and non-imported versions of the property.
2090   const char* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES"
2091                                : "LINK_INTERFACE_LIBRARIES");
2092
2093   // Look for link-type keywords in the value.
2094   static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
2095   if (keys.find(value)) {
2096     // Report an error.
2097     std::ostringstream e;
2098     e << "Property " << prop << " may not contain link-type keyword \""
2099       << keys.match(2) << "\".  "
2100       << "The " << base << " property has a per-configuration "
2101       << "version called " << base << "_<CONFIG> which may be "
2102       << "used to specify per-configuration rules.";
2103     if (!imported) {
2104       e << "  "
2105         << "Alternatively, an IMPORTED library may be created, configured "
2106         << "with a per-configuration location, and then named in the "
2107         << "property value.  "
2108         << "See the add_library command's IMPORTED mode for details."
2109         << "\n"
2110         << "If you have a list of libraries that already contains the "
2111         << "keyword, use the target_link_libraries command with its "
2112         << "LINK_INTERFACE_LIBRARIES mode to set the property.  "
2113         << "The command automatically recognizes link-type keywords and sets "
2114         << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
2115         << "properties accordingly.";
2116     }
2117     context->IssueMessage(MessageType::FATAL_ERROR, e.str());
2118   }
2119 }
2120
2121 void CheckINTERFACE_LINK_LIBRARIES(const std::string& value,
2122                                    cmMakefile* context)
2123 {
2124   // Look for link-type keywords in the value.
2125   static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
2126   if (keys.find(value)) {
2127     // Report an error.
2128     std::ostringstream e;
2129
2130     e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type "
2131          "keyword \""
2132       << keys.match(2)
2133       << "\".  The INTERFACE_LINK_LIBRARIES "
2134          "property may contain configuration-sensitive generator-expressions "
2135          "which may be used to specify per-configuration rules.";
2136
2137     context->IssueMessage(MessageType::FATAL_ERROR, e.str());
2138   }
2139 }
2140
2141 void CheckIMPORTED_GLOBAL(const cmTarget* target, cmMakefile* context)
2142 {
2143   const auto& targets = context->GetOwnedImportedTargets();
2144   auto it =
2145     std::find_if(targets.begin(), targets.end(),
2146                  [&](const std::unique_ptr<cmTarget>& importTarget) -> bool {
2147                    return target == importTarget.get();
2148                  });
2149   if (it == targets.end()) {
2150     std::ostringstream e;
2151     e << "Attempt to promote imported target \"" << target->GetName()
2152       << "\" to global scope (by setting IMPORTED_GLOBAL) "
2153          "which is not built in this directory.";
2154     context->IssueMessage(MessageType::FATAL_ERROR, e.str());
2155   }
2156 }
2157 }
2158
2159 void cmTarget::CheckProperty(const std::string& prop,
2160                              cmMakefile* context) const
2161 {
2162   // Certain properties need checking.
2163   if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) {
2164     if (cmValue value = this->GetProperty(prop)) {
2165       CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false);
2166     }
2167   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) {
2168     if (cmValue value = this->GetProperty(prop)) {
2169       CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true);
2170     }
2171   } else if (prop == "INTERFACE_LINK_LIBRARIES") {
2172     if (cmValue value = this->GetProperty(prop)) {
2173       CheckINTERFACE_LINK_LIBRARIES(*value, context);
2174     }
2175   } else if (prop == "IMPORTED_GLOBAL") {
2176     if (this->IsImported()) {
2177       CheckIMPORTED_GLOBAL(this, context);
2178     }
2179   }
2180 }
2181
2182 cmValue cmTarget::GetComputedProperty(const std::string& prop,
2183                                       cmMakefile& mf) const
2184 {
2185   return cmTargetPropertyComputer::GetProperty(this, prop, mf);
2186 }
2187
2188 cmValue cmTarget::GetProperty(const std::string& prop) const
2189 {
2190   static std::unordered_set<std::string> const specialProps{
2191     propC_STANDARD,
2192     propCXX_STANDARD,
2193     propCUDA_STANDARD,
2194     propOBJC_STANDARD,
2195     propOBJCXX_STANDARD,
2196     propLINK_LIBRARIES,
2197     propTYPE,
2198     propINCLUDE_DIRECTORIES,
2199     propCOMPILE_FEATURES,
2200     propCOMPILE_OPTIONS,
2201     propCOMPILE_DEFINITIONS,
2202     propPRECOMPILE_HEADERS,
2203     propLINK_OPTIONS,
2204     propLINK_DIRECTORIES,
2205     propIMPORTED,
2206     propIMPORTED_GLOBAL,
2207     propMANUALLY_ADDED_DEPENDENCIES,
2208     propNAME,
2209     propBINARY_DIR,
2210     propSOURCE_DIR,
2211     propSOURCES,
2212     propINTERFACE_LINK_LIBRARIES,
2213     propINTERFACE_LINK_LIBRARIES_DIRECT,
2214     propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
2215   };
2216   if (specialProps.count(prop)) {
2217     if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
2218         prop == propCUDA_STANDARD || prop == propOBJC_STANDARD ||
2219         prop == propOBJCXX_STANDARD) {
2220       auto propertyIter = this->impl->LanguageStandardProperties.find(prop);
2221       if (propertyIter == this->impl->LanguageStandardProperties.end()) {
2222         return nullptr;
2223       }
2224       return cmValue(propertyIter->second.Value);
2225     }
2226     if (prop == propLINK_LIBRARIES) {
2227       if (this->impl->LinkImplementationPropertyEntries.empty()) {
2228         return nullptr;
2229       }
2230
2231       static std::string output;
2232       output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
2233       return cmValue(output);
2234     }
2235     if (prop == propINTERFACE_LINK_LIBRARIES) {
2236       if (this->impl->LinkInterfacePropertyEntries.empty()) {
2237         return nullptr;
2238       }
2239
2240       static std::string output;
2241       output = cmJoin(this->impl->LinkInterfacePropertyEntries, ";");
2242       return cmValue(output);
2243     }
2244     if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
2245       if (this->impl->LinkInterfaceDirectPropertyEntries.empty()) {
2246         return nullptr;
2247       }
2248
2249       static std::string output;
2250       output = cmJoin(this->impl->LinkInterfaceDirectPropertyEntries, ";");
2251       return cmValue(output);
2252     }
2253     if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
2254       if (this->impl->LinkInterfaceDirectExcludePropertyEntries.empty()) {
2255         return nullptr;
2256       }
2257
2258       static std::string output;
2259       output =
2260         cmJoin(this->impl->LinkInterfaceDirectExcludePropertyEntries, ";");
2261       return cmValue(output);
2262     }
2263     // the type property returns what type the target is
2264     if (prop == propTYPE) {
2265       return cmValue(cmState::GetTargetTypeName(this->GetType()));
2266     }
2267     if (prop == propINCLUDE_DIRECTORIES) {
2268       if (this->impl->IncludeDirectoriesEntries.empty()) {
2269         return nullptr;
2270       }
2271
2272       static std::string output;
2273       output = cmJoin(this->impl->IncludeDirectoriesEntries, ";");
2274       return cmValue(output);
2275     }
2276     if (prop == propCOMPILE_FEATURES) {
2277       if (this->impl->CompileFeaturesEntries.empty()) {
2278         return nullptr;
2279       }
2280
2281       static std::string output;
2282       output = cmJoin(this->impl->CompileFeaturesEntries, ";");
2283       return cmValue(output);
2284     }
2285     if (prop == propCOMPILE_OPTIONS) {
2286       if (this->impl->CompileOptionsEntries.empty()) {
2287         return nullptr;
2288       }
2289
2290       static std::string output;
2291       output = cmJoin(this->impl->CompileOptionsEntries, ";");
2292       return cmValue(output);
2293     }
2294     if (prop == propCOMPILE_DEFINITIONS) {
2295       if (this->impl->CompileDefinitionsEntries.empty()) {
2296         return nullptr;
2297       }
2298
2299       static std::string output;
2300       output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
2301       return cmValue(output);
2302     }
2303     if (prop == propLINK_OPTIONS) {
2304       if (this->impl->LinkOptionsEntries.empty()) {
2305         return nullptr;
2306       }
2307
2308       static std::string output;
2309       output = cmJoin(this->impl->LinkOptionsEntries, ";");
2310       return cmValue(output);
2311     }
2312     if (prop == propLINK_DIRECTORIES) {
2313       if (this->impl->LinkDirectoriesEntries.empty()) {
2314         return nullptr;
2315       }
2316
2317       static std::string output;
2318       output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
2319
2320       return cmValue(output);
2321     }
2322     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
2323       if (this->impl->Utilities.empty()) {
2324         return nullptr;
2325       }
2326
2327       static std::string output;
2328       static std::vector<std::string> utilities;
2329       utilities.resize(this->impl->Utilities.size());
2330       std::transform(
2331         this->impl->Utilities.cbegin(), this->impl->Utilities.cend(),
2332         utilities.begin(),
2333         [](const BT<std::pair<std::string, bool>>& item) -> std::string {
2334           return item.Value.first;
2335         });
2336       output = cmJoin(utilities, ";");
2337       return cmValue(output);
2338     }
2339     if (prop == propPRECOMPILE_HEADERS) {
2340       if (this->impl->PrecompileHeadersEntries.empty()) {
2341         return nullptr;
2342       }
2343
2344       static std::string output;
2345       output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
2346       return cmValue(output);
2347     }
2348     if (prop == propIMPORTED) {
2349       return this->IsImported() ? cmValue(propTRUE) : cmValue(propFALSE);
2350     }
2351     if (prop == propIMPORTED_GLOBAL) {
2352       return this->IsImportedGloballyVisible() ? cmValue(propTRUE)
2353                                                : cmValue(propFALSE);
2354     }
2355     if (prop == propNAME) {
2356       return cmValue(this->GetName());
2357     }
2358     if (prop == propBINARY_DIR) {
2359       return cmValue(this->impl->Makefile->GetStateSnapshot()
2360                        .GetDirectory()
2361                        .GetCurrentBinary());
2362     }
2363     if (prop == propSOURCE_DIR) {
2364       return cmValue(this->impl->Makefile->GetStateSnapshot()
2365                        .GetDirectory()
2366                        .GetCurrentSource());
2367     }
2368   }
2369
2370   // Check fileset properties.
2371   {
2372     auto headers =
2373       this->impl->HeadersFileSets.ReadProperties(this, this->impl.get(), prop);
2374     if (headers.first) {
2375       return headers.second;
2376     }
2377     auto cxx_modules = this->impl->CxxModulesFileSets.ReadProperties(
2378       this, this->impl.get(), prop);
2379     if (cxx_modules.first) {
2380       return cxx_modules.second;
2381     }
2382     auto cxx_module_headers =
2383       this->impl->CxxModuleHeadersFileSets.ReadProperties(
2384         this, this->impl.get(), prop);
2385     if (cxx_module_headers.first) {
2386       return cxx_module_headers.second;
2387     }
2388   }
2389
2390   cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
2391   if (!retVal) {
2392     const bool chain = this->impl->Makefile->GetState()->IsPropertyChained(
2393       prop, cmProperty::TARGET);
2394     if (chain) {
2395       return this->impl->Makefile->GetStateSnapshot()
2396         .GetDirectory()
2397         .GetProperty(prop, chain);
2398     }
2399     return nullptr;
2400   }
2401   return retVal;
2402 }
2403
2404 std::string const& cmTarget::GetSafeProperty(std::string const& prop) const
2405 {
2406   cmValue ret = this->GetProperty(prop);
2407   if (ret) {
2408     return *ret;
2409   }
2410
2411   static std::string const s_empty;
2412   return s_empty;
2413 }
2414
2415 bool cmTarget::GetPropertyAsBool(const std::string& prop) const
2416 {
2417   return cmIsOn(this->GetProperty(prop));
2418 }
2419
2420 cmPropertyMap const& cmTarget::GetProperties() const
2421 {
2422   return this->impl->Properties;
2423 }
2424
2425 bool cmTarget::IsDLLPlatform() const
2426 {
2427   return this->impl->IsDLLPlatform;
2428 }
2429
2430 bool cmTarget::IsAIX() const
2431 {
2432   return this->impl->IsAIX;
2433 }
2434
2435 bool cmTarget::IsImported() const
2436 {
2437   return this->impl->IsImportedTarget;
2438 }
2439
2440 bool cmTarget::IsImportedGloballyVisible() const
2441 {
2442   return this->impl->ImportedGloballyVisible;
2443 }
2444
2445 bool cmTarget::IsPerConfig() const
2446 {
2447   return this->impl->PerConfig;
2448 }
2449
2450 bool cmTarget::CanCompileSources() const
2451 {
2452   if (this->IsImported()) {
2453     return false;
2454   }
2455   switch (this->GetType()) {
2456     case cmStateEnums::EXECUTABLE:
2457     case cmStateEnums::STATIC_LIBRARY:
2458     case cmStateEnums::SHARED_LIBRARY:
2459     case cmStateEnums::MODULE_LIBRARY:
2460     case cmStateEnums::OBJECT_LIBRARY:
2461       return true;
2462     case cmStateEnums::UTILITY:
2463     case cmStateEnums::INTERFACE_LIBRARY:
2464     case cmStateEnums::GLOBAL_TARGET:
2465     case cmStateEnums::UNKNOWN_LIBRARY:
2466       break;
2467   }
2468   return false;
2469 }
2470
2471 const char* cmTarget::GetSuffixVariableInternal(
2472   cmStateEnums::ArtifactType artifact) const
2473 {
2474   switch (this->GetType()) {
2475     case cmStateEnums::STATIC_LIBRARY:
2476       return "CMAKE_STATIC_LIBRARY_SUFFIX";
2477     case cmStateEnums::SHARED_LIBRARY:
2478       switch (artifact) {
2479         case cmStateEnums::RuntimeBinaryArtifact:
2480           return "CMAKE_SHARED_LIBRARY_SUFFIX";
2481         case cmStateEnums::ImportLibraryArtifact:
2482           return "CMAKE_IMPORT_LIBRARY_SUFFIX";
2483       }
2484       break;
2485     case cmStateEnums::MODULE_LIBRARY:
2486       switch (artifact) {
2487         case cmStateEnums::RuntimeBinaryArtifact:
2488           return "CMAKE_SHARED_MODULE_SUFFIX";
2489         case cmStateEnums::ImportLibraryArtifact:
2490           return "CMAKE_IMPORT_LIBRARY_SUFFIX";
2491       }
2492       break;
2493     case cmStateEnums::EXECUTABLE:
2494       switch (artifact) {
2495         case cmStateEnums::RuntimeBinaryArtifact:
2496           // Android GUI application packages store the native
2497           // binary as a shared library.
2498           return (this->IsAndroidGuiExecutable()
2499                     ? "CMAKE_SHARED_LIBRARY_SUFFIX"
2500                     : "CMAKE_EXECUTABLE_SUFFIX");
2501         case cmStateEnums::ImportLibraryArtifact:
2502           return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX"
2503                                     : "CMAKE_IMPORT_LIBRARY_SUFFIX");
2504       }
2505       break;
2506     default:
2507       break;
2508   }
2509   return "";
2510 }
2511
2512 const char* cmTarget::GetPrefixVariableInternal(
2513   cmStateEnums::ArtifactType artifact) const
2514 {
2515   switch (this->GetType()) {
2516     case cmStateEnums::STATIC_LIBRARY:
2517       return "CMAKE_STATIC_LIBRARY_PREFIX";
2518     case cmStateEnums::SHARED_LIBRARY:
2519       switch (artifact) {
2520         case cmStateEnums::RuntimeBinaryArtifact:
2521           return "CMAKE_SHARED_LIBRARY_PREFIX";
2522         case cmStateEnums::ImportLibraryArtifact:
2523           return "CMAKE_IMPORT_LIBRARY_PREFIX";
2524       }
2525       break;
2526     case cmStateEnums::MODULE_LIBRARY:
2527       switch (artifact) {
2528         case cmStateEnums::RuntimeBinaryArtifact:
2529           return "CMAKE_SHARED_MODULE_PREFIX";
2530         case cmStateEnums::ImportLibraryArtifact:
2531           return "CMAKE_IMPORT_LIBRARY_PREFIX";
2532       }
2533       break;
2534     case cmStateEnums::EXECUTABLE:
2535       switch (artifact) {
2536         case cmStateEnums::RuntimeBinaryArtifact:
2537           // Android GUI application packages store the native
2538           // binary as a shared library.
2539           return (this->IsAndroidGuiExecutable()
2540                     ? "CMAKE_SHARED_LIBRARY_PREFIX"
2541                     : "");
2542         case cmStateEnums::ImportLibraryArtifact:
2543           return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX"
2544                                     : "CMAKE_IMPORT_LIBRARY_PREFIX");
2545       }
2546       break;
2547     default:
2548       break;
2549   }
2550   return "";
2551 }
2552
2553 std::string cmTarget::ImportedGetFullPath(
2554   const std::string& config, cmStateEnums::ArtifactType artifact) const
2555 {
2556   assert(this->IsImported());
2557
2558   // Lookup/compute/cache the import information for this
2559   // configuration.
2560   std::string desired_config = config;
2561   if (config.empty()) {
2562     desired_config = "NOCONFIG";
2563   }
2564
2565   std::string result;
2566
2567   cmValue loc = nullptr;
2568   cmValue imp = nullptr;
2569   std::string suffix;
2570
2571   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
2572       this->GetMappedConfig(desired_config, loc, imp, suffix)) {
2573     switch (artifact) {
2574       case cmStateEnums::RuntimeBinaryArtifact:
2575         if (loc) {
2576           result = *loc;
2577         } else {
2578           std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
2579           if (cmValue config_location = this->GetProperty(impProp)) {
2580             result = *config_location;
2581           } else if (cmValue location =
2582                        this->GetProperty("IMPORTED_LOCATION")) {
2583             result = *location;
2584           }
2585         }
2586         break;
2587
2588       case cmStateEnums::ImportLibraryArtifact:
2589         if (imp) {
2590           result = *imp;
2591         } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2592                    this->IsExecutableWithExports()) {
2593           std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
2594           if (cmValue config_implib = this->GetProperty(impProp)) {
2595             result = *config_implib;
2596           } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
2597             result = *implib;
2598           }
2599         }
2600         break;
2601     }
2602   }
2603
2604   if (result.empty()) {
2605     if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
2606       auto message = [&]() -> std::string {
2607         std::string unset;
2608         std::string configuration;
2609
2610         if (artifact == cmStateEnums::RuntimeBinaryArtifact) {
2611           unset = "IMPORTED_LOCATION";
2612         } else if (artifact == cmStateEnums::ImportLibraryArtifact) {
2613           unset = "IMPORTED_IMPLIB";
2614         }
2615
2616         if (!config.empty()) {
2617           configuration = cmStrCat(" configuration \"", config, "\"");
2618         }
2619
2620         return cmStrCat(unset, " not set for imported target \"",
2621                         this->GetName(), "\"", configuration, ".");
2622       };
2623
2624       switch (this->GetPolicyStatus(cmPolicies::CMP0111)) {
2625         case cmPolicies::WARN:
2626           this->impl->Makefile->IssueMessage(
2627             MessageType::AUTHOR_WARNING,
2628             cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" +
2629               message());
2630           CM_FALLTHROUGH;
2631         case cmPolicies::OLD:
2632           break;
2633         default:
2634           this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
2635                                              message());
2636       }
2637     }
2638
2639     result = cmStrCat(this->GetName(), "-NOTFOUND");
2640   }
2641   return result;
2642 }
2643
2644 const cmFileSet* cmTarget::GetFileSet(const std::string& name) const
2645 {
2646   auto it = this->impl->FileSets.find(name);
2647   return it == this->impl->FileSets.end() ? nullptr : &it->second;
2648 }
2649
2650 cmFileSet* cmTarget::GetFileSet(const std::string& name)
2651 {
2652   auto it = this->impl->FileSets.find(name);
2653   return it == this->impl->FileSets.end() ? nullptr : &it->second;
2654 }
2655
2656 std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
2657   const std::string& name, const std::string& type, cmFileSetVisibility vis)
2658 {
2659   auto result = this->impl->FileSets.emplace(
2660     std::make_pair(name, cmFileSet(name, type, vis)));
2661   if (result.second) {
2662     auto bt = this->impl->Makefile->GetBacktrace();
2663     if (type == this->impl->HeadersFileSets.TypeName) {
2664       this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
2665     } else if (type == this->impl->CxxModulesFileSets.TypeName) {
2666       this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
2667     } else if (type == this->impl->CxxModuleHeadersFileSets.TypeName) {
2668       this->impl->CxxModuleHeadersFileSets.AddFileSet(name, vis,
2669                                                       std::move(bt));
2670     }
2671   }
2672   return std::make_pair(&result.first->second, result.second);
2673 }
2674
2675 std::string cmTarget::GetFileSetsPropertyName(const std::string& type)
2676 {
2677   if (type == "HEADERS") {
2678     return "HEADER_SETS";
2679   }
2680   if (type == "CXX_MODULES") {
2681     return "CXX_MODULE_SETS";
2682   }
2683   if (type == "CXX_MODULE_HEADER_UNITS") {
2684     return "CXX_MODULE_HEADER_UNIT_SETS";
2685   }
2686   return "";
2687 }
2688
2689 std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type)
2690 {
2691   if (type == "HEADERS") {
2692     return "INTERFACE_HEADER_SETS";
2693   }
2694   if (type == "CXX_MODULES") {
2695     return "INTERFACE_CXX_MODULE_SETS";
2696   }
2697   if (type == "CXX_MODULE_HEADER_UNITS") {
2698     return "INTERFACE_CXX_MODULE_HEADER_UNIT_SETS";
2699   }
2700   return "";
2701 }
2702
2703 std::vector<std::string> cmTarget::GetAllFileSetNames() const
2704 {
2705   std::vector<std::string> result;
2706
2707   for (auto const& it : this->impl->FileSets) {
2708     result.push_back(it.first);
2709   }
2710
2711   return result;
2712 }
2713
2714 std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
2715 {
2716   std::vector<std::string> result;
2717   auto inserter = std::back_inserter(result);
2718
2719   auto appendEntries = [=](const std::vector<BT<std::string>>& entries) {
2720     for (auto const& entry : entries) {
2721       auto expanded = cmExpandedList(entry.Value);
2722       std::copy(expanded.begin(), expanded.end(), inserter);
2723     }
2724   };
2725
2726   appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
2727   appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
2728   appendEntries(this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
2729
2730   return result;
2731 }
2732
2733 bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
2734                                              std::string const& value) const
2735 {
2736   if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
2737       !this->IsImportedTarget) {
2738     this->Makefile->IssueMessage(
2739       MessageType::FATAL_ERROR,
2740       prop +
2741         " property may be set only on imported INTERFACE library targets.");
2742     return false;
2743   }
2744   if (!value.empty()) {
2745     if (value[0] == '-') {
2746       this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
2747                                    prop + " property value\n  " + value +
2748                                      "\nmay not start with '-'.");
2749       return false;
2750     }
2751     std::string::size_type bad = value.find_first_of(":/\\;");
2752     if (bad != std::string::npos) {
2753       this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
2754                                    prop + " property value\n  " + value +
2755                                      "\nmay not contain '" +
2756                                      value.substr(bad, 1) + "'.");
2757       return false;
2758     }
2759   }
2760   return true;
2761 }
2762
2763 bool cmTarget::GetMappedConfig(std::string const& desired_config, cmValue& loc,
2764                                cmValue& imp, std::string& suffix) const
2765 {
2766   std::string config_upper;
2767   if (!desired_config.empty()) {
2768     config_upper = cmSystemTools::UpperCase(desired_config);
2769   }
2770
2771   std::string locPropBase;
2772   if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2773     locPropBase = "IMPORTED_LIBNAME";
2774   } else if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2775     locPropBase = "IMPORTED_OBJECTS";
2776   } else {
2777     locPropBase = "IMPORTED_LOCATION";
2778   }
2779
2780   // Track the configuration-specific property suffix.
2781   suffix = cmStrCat('_', config_upper);
2782
2783   std::vector<std::string> mappedConfigs;
2784   {
2785     std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper);
2786     if (cmValue mapValue = this->GetProperty(mapProp)) {
2787       cmExpandList(*mapValue, mappedConfigs, true);
2788     }
2789   }
2790
2791   // If we needed to find one of the mapped configurations but did not
2792   // On a DLL platform there may be only IMPORTED_IMPLIB for a shared
2793   // library or an executable with exports.
2794   bool allowImp = (this->IsDLLPlatform() &&
2795                    (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2796                     this->IsExecutableWithExports())) ||
2797     (this->IsAIX() && this->IsExecutableWithExports());
2798
2799   // If a mapping was found, check its configurations.
2800   for (auto mci = mappedConfigs.begin();
2801        !loc && !imp && mci != mappedConfigs.end(); ++mci) {
2802     // Look for this configuration.
2803     if (mci->empty()) {
2804       // An empty string in the mapping has a special meaning:
2805       // look up the config-less properties.
2806       loc = this->GetProperty(locPropBase);
2807       if (allowImp) {
2808         imp = this->GetProperty("IMPORTED_IMPLIB");
2809       }
2810       // If it was found, set the suffix.
2811       if (loc || imp) {
2812         suffix.clear();
2813       }
2814     } else {
2815       std::string mcUpper = cmSystemTools::UpperCase(*mci);
2816       std::string locProp = cmStrCat(locPropBase, '_', mcUpper);
2817       loc = this->GetProperty(locProp);
2818       if (allowImp) {
2819         std::string impProp = cmStrCat("IMPORTED_IMPLIB_", mcUpper);
2820         imp = this->GetProperty(impProp);
2821       }
2822
2823       // If it was found, use it for all properties below.
2824       if (loc || imp) {
2825         suffix = cmStrCat('_', mcUpper);
2826       }
2827     }
2828   }
2829
2830   // If we needed to find one of the mapped configurations but did not
2831   // then the target location is not found.  The project does not want
2832   // any other configuration.
2833   if (!mappedConfigs.empty() && !loc && !imp) {
2834     // Interface libraries are always available because their
2835     // library name is optional so it is okay to leave loc empty.
2836     return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
2837   }
2838
2839   // If we have not yet found it then there are no mapped
2840   // configurations.  Look for an exact-match.
2841   if (!loc && !imp) {
2842     std::string locProp = cmStrCat(locPropBase, suffix);
2843     loc = this->GetProperty(locProp);
2844     if (allowImp) {
2845       std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
2846       imp = this->GetProperty(impProp);
2847     }
2848   }
2849
2850   // If we have not yet found it then there are no mapped
2851   // configurations and no exact match.
2852   if (!loc && !imp) {
2853     // The suffix computed above is not useful.
2854     suffix.clear();
2855
2856     // Look for a configuration-less location.  This may be set by
2857     // manually-written code.
2858     loc = this->GetProperty(locPropBase);
2859     if (allowImp) {
2860       imp = this->GetProperty("IMPORTED_IMPLIB");
2861     }
2862   }
2863
2864   // If we have not yet found it then the project is willing to try
2865   // any available configuration.
2866   if (!loc && !imp) {
2867     std::vector<std::string> availableConfigs;
2868     if (cmValue iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
2869       cmExpandList(*iconfigs, availableConfigs);
2870     }
2871     for (auto aci = availableConfigs.begin();
2872          !loc && !imp && aci != availableConfigs.end(); ++aci) {
2873       suffix = cmStrCat('_', cmSystemTools::UpperCase(*aci));
2874       std::string locProp = cmStrCat(locPropBase, suffix);
2875       loc = this->GetProperty(locProp);
2876       if (allowImp) {
2877         std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
2878         imp = this->GetProperty(impProp);
2879       }
2880     }
2881   }
2882   // If we have not yet found it then the target location is not available.
2883   if (!loc && !imp) {
2884     // Interface libraries are always available because their
2885     // library name is optional so it is okay to leave loc empty.
2886     return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
2887   }
2888
2889   return true;
2890 }