1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmGeneratorTarget.h"
15 #include <unordered_set>
19 #include <cm/optional>
20 #include <cm/string_view>
21 #include <cmext/algorithm>
22 #include <cmext/string_view>
24 #include "cmsys/RegularExpression.hxx"
26 #include "cmAlgorithms.h"
27 #include "cmComputeLinkInformation.h"
28 #include "cmCustomCommandGenerator.h"
29 #include "cmFileSet.h"
30 #include "cmFileTimes.h"
31 #include "cmGeneratedFileStream.h"
32 #include "cmGeneratorExpression.h"
33 #include "cmGeneratorExpressionContext.h"
34 #include "cmGeneratorExpressionDAGChecker.h"
35 #include "cmGeneratorExpressionNode.h"
36 #include "cmGlobalGenerator.h"
37 #include "cmLocalGenerator.h"
38 #include "cmMakefile.h"
39 #include "cmMessageType.h"
40 #include "cmOutputConverter.h"
41 #include "cmPropertyMap.h"
43 #include "cmSourceFile.h"
44 #include "cmSourceFileLocation.h"
45 #include "cmSourceFileLocationKind.h"
46 #include "cmSourceGroup.h"
47 #include "cmStandardLevelResolver.h"
49 #include "cmStringAlgorithms.h"
50 #include "cmSystemTools.h"
52 #include "cmTargetLinkLibraryType.h"
53 #include "cmTargetPropertyComputer.h"
57 using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor;
59 const cmsys::RegularExpression FrameworkRegularExpression(
60 "^(.*/)?([^/]*)\\.framework/(.*)$");
61 const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES";
62 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT =
63 "INTERFACE_LINK_LIBRARIES_DIRECT";
64 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
65 "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
69 cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
70 cmGeneratorTarget const* tgt, cmMakefile const& /* mf */)
72 return tgt->GetSourcesProperty();
77 cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
78 cmGeneratorTarget const* tgt)
80 return tgt->GetLocation("");
85 cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
86 cmGeneratorTarget const* tgt, const std::string& config)
88 return tgt->GetLocation(config);
91 class cmGeneratorTarget::TargetPropertyEntry
94 static cmLinkImplItem NoLinkImplItem;
97 TargetPropertyEntry(cmLinkImplItem const& item)
101 virtual ~TargetPropertyEntry() = default;
103 virtual const std::string& Evaluate(
104 cmLocalGenerator* lg, const std::string& config,
105 cmGeneratorTarget const* headTarget,
106 cmGeneratorExpressionDAGChecker* dagChecker,
107 std::string const& language) const = 0;
109 virtual cmListFileBacktrace GetBacktrace() const = 0;
110 virtual std::string const& GetInput() const = 0;
111 virtual bool GetHadContextSensitiveCondition() const { return false; }
113 cmLinkImplItem const& LinkImplItem;
115 cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
117 class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
120 TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
121 cmLinkImplItem const& item = NoLinkImplItem)
122 : cmGeneratorTarget::TargetPropertyEntry(item)
127 const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
128 cmGeneratorTarget const* headTarget,
129 cmGeneratorExpressionDAGChecker* dagChecker,
130 std::string const& language) const override
132 return this->ge->Evaluate(lg, config, headTarget, dagChecker, nullptr,
136 cmListFileBacktrace GetBacktrace() const override
138 return this->ge->GetBacktrace();
141 std::string const& GetInput() const override { return this->ge->GetInput(); }
143 bool GetHadContextSensitiveCondition() const override
145 return this->ge->GetHadContextSensitiveCondition();
149 const std::unique_ptr<cmCompiledGeneratorExpression> ge;
152 class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
155 TargetPropertyEntryString(BT<std::string> propertyValue,
156 cmLinkImplItem const& item = NoLinkImplItem)
157 : cmGeneratorTarget::TargetPropertyEntry(item)
158 , PropertyValue(std::move(propertyValue))
162 const std::string& Evaluate(cmLocalGenerator*, const std::string&,
163 cmGeneratorTarget const*,
164 cmGeneratorExpressionDAGChecker*,
165 std::string const&) const override
167 return this->PropertyValue.Value;
170 cmListFileBacktrace GetBacktrace() const override
172 return this->PropertyValue.Backtrace;
174 std::string const& GetInput() const override
176 return this->PropertyValue.Value;
180 BT<std::string> PropertyValue;
183 class TargetPropertyEntryFileSet
184 : public cmGeneratorTarget::TargetPropertyEntry
187 TargetPropertyEntryFileSet(
188 std::vector<std::string> dirs, bool contextSensitiveDirs,
189 std::unique_ptr<cmCompiledGeneratorExpression> entryCge,
190 const cmFileSet* fileSet, cmLinkImplItem const& item = NoLinkImplItem)
191 : cmGeneratorTarget::TargetPropertyEntry(item)
192 , BaseDirs(std::move(dirs))
193 , ContextSensitiveDirs(contextSensitiveDirs)
194 , EntryCge(std::move(entryCge))
199 const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
200 cmGeneratorTarget const* headTarget,
201 cmGeneratorExpressionDAGChecker* dagChecker,
202 std::string const& /*lang*/) const override
204 std::map<std::string, std::vector<std::string>> filesPerDir;
205 this->FileSet->EvaluateFileEntry(this->BaseDirs, filesPerDir,
206 this->EntryCge, lg, config, headTarget,
209 std::vector<std::string> files;
210 for (auto const& it : filesPerDir) {
211 files.insert(files.end(), it.second.begin(), it.second.end());
214 static std::string filesStr;
215 filesStr = cmJoin(files, ";");
219 cmListFileBacktrace GetBacktrace() const override
221 return this->EntryCge->GetBacktrace();
224 std::string const& GetInput() const override
226 return this->EntryCge->GetInput();
229 bool GetHadContextSensitiveCondition() const override
231 return this->ContextSensitiveDirs ||
232 this->EntryCge->GetHadContextSensitiveCondition();
236 const std::vector<std::string> BaseDirs;
237 const bool ContextSensitiveDirs;
238 const std::unique_ptr<cmCompiledGeneratorExpression> EntryCge;
239 const cmFileSet* FileSet;
244 TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std::
248 evaluateForBuildsystem =
251 if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) {
252 cmGeneratorExpression ge(propertyValue.Backtrace);
253 std::unique_ptr<cmCompiledGeneratorExpression> cge =
254 ge.Parse(propertyValue.Value);
255 cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
256 return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
257 cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
260 return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
261 cm::make_unique<TargetPropertyEntryString>(propertyValue));
264 static void CreatePropertyGeneratorExpressions(
265 cmBTStringRange entries,
266 std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
267 bool evaluateForBuildsystem = false)
269 for (auto const& entry : entries) {
270 items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem));
275 // Represent a target property entry after evaluating generator expressions
276 // and splitting up lists.
277 struct EvaluatedTargetPropertyEntry
279 EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
280 cmListFileBacktrace bt)
282 , Backtrace(std::move(bt))
287 EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
288 EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
289 EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
291 EvaluatedTargetPropertyEntry& operator=(
292 EvaluatedTargetPropertyEntry const&) = delete;
294 cmLinkImplItem const& LinkImplItem;
295 cmListFileBacktrace Backtrace;
296 std::vector<std::string> Values;
297 bool ContextDependent = false;
300 EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
301 cmGeneratorTarget const* thisTarget, std::string const& config,
302 std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
303 cmGeneratorTarget::TargetPropertyEntry& entry)
305 EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
306 cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
307 thisTarget, dagChecker, lang),
309 if (entry.GetHadContextSensitiveCondition()) {
310 ee.ContextDependent = true;
315 struct EvaluatedTargetPropertyEntries
317 std::vector<EvaluatedTargetPropertyEntry> Entries;
318 bool HadContextSensitiveCondition = false;
321 EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
322 cmGeneratorTarget const* thisTarget, std::string const& config,
323 std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
324 std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
327 EvaluatedTargetPropertyEntries out;
328 out.Entries.reserve(in.size());
329 for (auto const& entry : in) {
330 out.Entries.emplace_back(EvaluateTargetPropertyEntry(
331 thisTarget, config, lang, dagChecker, *entry));
337 cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
340 this->Makefile = this->Target->GetMakefile();
341 this->LocalGenerator = lg;
342 this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
344 this->GlobalGenerator->ComputeTargetObjectDirectory(this);
346 CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
347 this->IncludeDirectoriesEntries);
349 CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
350 this->CompileOptionsEntries);
352 CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
353 this->CompileFeaturesEntries);
355 CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
356 this->CompileDefinitionsEntries);
358 CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
359 this->LinkOptionsEntries);
361 CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
362 this->LinkDirectoriesEntries);
364 CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
365 this->PrecompileHeadersEntries);
367 CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
368 this->SourceEntries, true);
370 this->PolicyMap = t->GetPolicyMap();
372 // Get hard-coded linker language
373 if (this->Target->GetProperty("HAS_CXX")) {
374 this->LinkerLanguage = "CXX";
376 this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
380 cmGeneratorTarget::~cmGeneratorTarget() = default;
382 cmValue cmGeneratorTarget::GetSourcesProperty() const
384 std::vector<std::string> values;
385 for (auto const& se : this->SourceEntries) {
386 values.push_back(se->GetInput());
388 static std::string value;
390 value = cmJoin(values, ";");
391 return cmValue(value);
394 cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
396 return this->GetLocalGenerator()->GetGlobalGenerator();
399 cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
401 return this->LocalGenerator;
404 cmStateEnums::TargetType cmGeneratorTarget::GetType() const
406 return this->Target->GetType();
409 const std::string& cmGeneratorTarget::GetName() const
411 return this->Target->GetName();
414 std::string cmGeneratorTarget::GetExportName() const
416 cmValue exportName = this->GetProperty("EXPORT_NAME");
418 if (cmNonempty(exportName)) {
419 if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
420 std::ostringstream e;
421 e << "EXPORT_NAME property \"" << *exportName << "\" for \""
422 << this->GetName() << "\": is not valid.";
423 cmSystemTools::Error(e.str());
428 return this->GetName();
431 cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const
434 cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) {
437 if (cmSystemTools::GetFatalErrorOccurred()) {
440 return this->Target->GetProperty(prop);
443 std::string const& cmGeneratorTarget::GetSafeProperty(
444 std::string const& prop) const
446 return this->GetProperty(prop);
449 const char* cmGeneratorTarget::GetOutputTargetType(
450 cmStateEnums::ArtifactType artifact) const
452 switch (this->GetType()) {
453 case cmStateEnums::SHARED_LIBRARY:
454 if (this->IsDLLPlatform()) {
456 case cmStateEnums::RuntimeBinaryArtifact:
457 // A DLL shared library is treated as a runtime target.
459 case cmStateEnums::ImportLibraryArtifact:
460 // A DLL import library is treated as an archive target.
464 // For non-DLL platforms shared libraries are treated as
469 case cmStateEnums::STATIC_LIBRARY:
470 // Static libraries are always treated as archive targets.
472 case cmStateEnums::MODULE_LIBRARY:
474 case cmStateEnums::RuntimeBinaryArtifact:
475 // Module libraries are always treated as library targets.
477 case cmStateEnums::ImportLibraryArtifact:
478 // Module import libraries are treated as archive targets.
482 case cmStateEnums::OBJECT_LIBRARY:
483 // Object libraries are always treated as object targets.
485 case cmStateEnums::EXECUTABLE:
487 case cmStateEnums::RuntimeBinaryArtifact:
488 // Executables are always treated as runtime targets.
490 case cmStateEnums::ImportLibraryArtifact:
491 // Executable import libraries are treated as archive targets.
501 std::string cmGeneratorTarget::GetOutputName(
502 const std::string& config, cmStateEnums::ArtifactType artifact) const
504 // Lookup/compute/cache the output name for this configuration.
505 OutputNameKey key(config, artifact);
506 auto i = this->OutputNameMap.find(key);
507 if (i == this->OutputNameMap.end()) {
508 // Add empty name in map to detect potential recursion.
509 OutputNameMapType::value_type entry(key, "");
510 i = this->OutputNameMap.insert(entry).first;
512 // Compute output name.
513 std::vector<std::string> props;
514 std::string type = this->GetOutputTargetType(artifact);
515 std::string configUpper = cmSystemTools::UpperCase(config);
516 if (!type.empty() && !configUpper.empty()) {
517 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
518 props.push_back(type + "_OUTPUT_NAME_" + configUpper);
521 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
522 props.push_back(type + "_OUTPUT_NAME");
524 if (!configUpper.empty()) {
525 // OUTPUT_NAME_<CONFIG>
526 props.push_back("OUTPUT_NAME_" + configUpper);
527 // <CONFIG>_OUTPUT_NAME
528 props.push_back(configUpper + "_OUTPUT_NAME");
531 props.emplace_back("OUTPUT_NAME");
534 for (std::string const& p : props) {
535 if (cmValue outNameProp = this->GetProperty(p)) {
536 outName = *outNameProp;
541 if (outName.empty()) {
542 outName = this->GetName();
545 // Now evaluate genex and update the previously-prepared map entry.
547 cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
548 } else if (i->second.empty()) {
549 // An empty map entry indicates we have been called recursively
550 // from the above block.
551 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
552 MessageType::FATAL_ERROR,
553 "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
554 this->GetBacktrace());
559 std::string cmGeneratorTarget::GetFilePrefix(
560 const std::string& config, cmStateEnums::ArtifactType artifact) const
562 if (this->IsImported()) {
563 cmValue prefix = this->GetFilePrefixInternal(config, artifact);
564 return prefix ? *prefix : std::string();
570 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
573 std::string cmGeneratorTarget::GetFileSuffix(
574 const std::string& config, cmStateEnums::ArtifactType artifact) const
576 if (this->IsImported()) {
577 cmValue suffix = this->GetFileSuffixInternal(config, artifact);
578 return suffix ? *suffix : std::string();
584 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
588 std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
590 cmValue postfix = nullptr;
591 std::string frameworkPostfix;
592 if (!config.empty()) {
593 std::string configProp =
594 cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
595 postfix = this->GetProperty(configProp);
597 // Mac application bundles and frameworks have no regular postfix like
599 if (!this->IsImported() && postfix &&
600 (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
604 // Frameworks created by multi config generators can have a special
605 // framework postfix.
606 frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
607 if (!frameworkPostfix.empty()) {
608 postfix = cmValue(frameworkPostfix);
611 return postfix ? *postfix : std::string();
614 std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
615 const std::string& config) const
617 cmValue postfix = nullptr;
618 if (!config.empty()) {
619 std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
620 cmSystemTools::UpperCase(config));
621 postfix = this->GetProperty(configProp);
623 if (!this->IsImported() && postfix &&
624 (this->IsFrameworkOnApple() &&
625 !this->GetGlobalGenerator()->IsMultiConfig())) {
629 return postfix ? *postfix : std::string();
632 cmValue cmGeneratorTarget::GetFilePrefixInternal(
633 std::string const& config, cmStateEnums::ArtifactType artifact,
634 const std::string& language) const
636 // no prefix for non-main target types.
637 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
638 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
639 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
640 this->GetType() != cmStateEnums::EXECUTABLE) {
644 const bool isImportedLibraryArtifact =
645 (artifact == cmStateEnums::ImportLibraryArtifact);
647 // Return an empty prefix for the import library if this platform
648 // does not support import libraries.
649 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
653 // The implib option is only allowed for shared libraries, module
654 // libraries, and executables.
655 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
656 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
657 this->GetType() != cmStateEnums::EXECUTABLE) {
658 artifact = cmStateEnums::RuntimeBinaryArtifact;
661 // Compute prefix value.
662 cmValue targetPrefix =
663 (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
664 : this->GetProperty("PREFIX"));
667 const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
668 if (!language.empty() && cmNonempty(prefixVar)) {
669 std::string langPrefix = cmStrCat(prefixVar, "_", language);
670 targetPrefix = this->Makefile->GetDefinition(langPrefix);
673 // if there is no prefix on the target nor specific language
674 // use the cmake definition.
675 if (!targetPrefix && prefixVar) {
676 targetPrefix = this->Makefile->GetDefinition(prefixVar);
683 cmValue cmGeneratorTarget::GetFileSuffixInternal(
684 std::string const& config, cmStateEnums::ArtifactType artifact,
685 const std::string& language) const
687 // no suffix for non-main target types.
688 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
689 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
690 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
691 this->GetType() != cmStateEnums::EXECUTABLE) {
695 const bool isImportedLibraryArtifact =
696 (artifact == cmStateEnums::ImportLibraryArtifact);
698 // Return an empty suffix for the import library if this platform
699 // does not support import libraries.
700 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
704 // The implib option is only allowed for shared libraries, module
705 // libraries, and executables.
706 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
707 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
708 this->GetType() != cmStateEnums::EXECUTABLE) {
709 artifact = cmStateEnums::RuntimeBinaryArtifact;
712 // Compute suffix value.
713 cmValue targetSuffix =
714 (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
715 : this->GetProperty("SUFFIX"));
718 const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
719 if (!language.empty() && cmNonempty(suffixVar)) {
720 std::string langSuffix = cmStrCat(suffixVar, "_", language);
721 targetSuffix = this->Makefile->GetDefinition(langSuffix);
724 // if there is no suffix on the target nor specific language
725 // use the cmake definition.
726 if (!targetSuffix && suffixVar) {
727 targetSuffix = this->Makefile->GetDefinition(suffixVar);
734 void cmGeneratorTarget::ClearSourcesCache()
736 this->AllConfigSources.clear();
737 this->KindedSourcesMap.clear();
738 this->SourcesAreContextDependent = Tribool::Indeterminate;
739 this->Objects.clear();
740 this->VisitedConfigsForObjects.clear();
741 this->LinkImplMap.clear();
742 this->LinkImplUsageRequirementsOnlyMap.clear();
745 void cmGeneratorTarget::ClearLinkInterfaceCache()
747 this->LinkInterfaceMap.clear();
748 this->LinkInterfaceUsageRequirementsOnlyMap.clear();
751 void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
753 this->SourceEntries.insert(
754 before ? this->SourceEntries.begin() : this->SourceEntries.end(),
755 CreateTargetPropertyEntry(
756 BT<std::string>(src, this->Makefile->GetBacktrace()), true));
757 this->ClearSourcesCache();
760 void cmGeneratorTarget::AddSource(const std::string& src, bool before)
762 this->Target->AddSource(src, before);
763 this->AddSourceCommon(src, before);
766 void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
768 this->Target->AddTracedSources(srcs);
770 this->AddSourceCommon(cmJoin(srcs, ";"));
774 void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
777 this->Target->InsertInclude(
778 BT<std::string>(src, this->Makefile->GetBacktrace()), before);
779 this->IncludeDirectoriesEntries.insert(
780 before ? this->IncludeDirectoriesEntries.begin()
781 : this->IncludeDirectoriesEntries.end(),
782 CreateTargetPropertyEntry(
783 BT<std::string>(src, this->Makefile->GetBacktrace()), true));
786 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
787 cmSourceFile const* sf) const
789 auto i = this->SourceDepends.find(sf);
790 if (i != this->SourceDepends.end()) {
791 return &i->second.Depends;
797 void handleSystemIncludesDep(cmLocalGenerator* lg,
798 cmGeneratorTarget const* depTgt,
799 const std::string& config,
800 cmGeneratorTarget const* headTarget,
801 cmGeneratorExpressionDAGChecker* dagChecker,
802 std::vector<std::string>& result,
803 bool excludeImported, std::string const& language)
806 depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
807 cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
808 dagChecker, depTgt, language),
811 if (!depTgt->IsImported() || excludeImported) {
814 if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
818 if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
819 cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
820 dagChecker, depTgt, language),
826 /* clang-format off */
827 #define IMPLEMENT_VISIT(KIND) \
829 KindedSources const& kinded = this->GetKindedSources(config); \
830 for (SourceAndKind const& s : kinded.Sources) { \
831 if (s.Kind == KIND) { \
832 data.push_back(s.Source.Value); \
836 /* clang-format on */
838 void cmGeneratorTarget::GetObjectSources(
839 std::vector<cmSourceFile const*>& data, const std::string& config) const
841 IMPLEMENT_VISIT(SourceKindObjectSource);
843 if (this->VisitedConfigsForObjects.count(config)) {
847 for (cmSourceFile const* it : data) {
851 this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
852 this->VisitedConfigsForObjects.insert(config);
855 void cmGeneratorTarget::ComputeObjectMapping()
857 auto const& configs =
858 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
859 std::set<std::string> configSet(configs.begin(), configs.end());
860 if (configSet == this->VisitedConfigsForObjects) {
864 for (std::string const& c : configs) {
865 std::vector<cmSourceFile const*> sourceFiles;
866 this->GetObjectSources(sourceFiles, c);
870 cmValue cmGeneratorTarget::GetFeature(const std::string& feature,
871 const std::string& config) const
873 if (!config.empty()) {
874 std::string featureConfig =
875 cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
876 if (cmValue value = this->GetProperty(featureConfig)) {
880 if (cmValue value = this->GetProperty(feature)) {
883 return this->LocalGenerator->GetFeature(feature, config);
886 const char* cmGeneratorTarget::GetLinkPIEProperty(
887 const std::string& config) const
889 static std::string PICValue;
891 PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
892 "POSITION_INDEPENDENT_CODE", config);
894 if (PICValue == "(unset)") {
895 // POSITION_INDEPENDENT_CODE is not set
899 auto status = this->GetPolicyStatusCMP0083();
900 return (status != cmPolicies::WARN && status != cmPolicies::OLD)
905 bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
906 std::string const& config) const
908 cmValue feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
910 if (!cmIsOn(feature)) {
911 // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
915 if (lang != "C" && lang != "CXX" && lang != "Fortran") {
916 // We do not define IPO behavior for other languages.
920 cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
922 if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
923 if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
926 if (this->PolicyReportedCMP0069) {
927 // problem is already reported, no need to issue a message
930 const bool in_try_compile =
931 this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
932 if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
933 std::ostringstream w;
934 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
935 w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
936 << "'" << this->GetName() << "'.";
937 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
938 MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
940 this->PolicyReportedCMP0069 = true;
945 // Note: check consistency with messages from CheckIPOSupported
946 const char* message = nullptr;
947 if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
948 message = "CMake doesn't support IPO for current compiler";
949 } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
950 "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
951 message = "Compiler doesn't support IPO";
952 } else if (!this->GlobalGenerator->IsIPOSupported()) {
953 message = "CMake doesn't support IPO for current generator";
957 // No error/warning messages
961 if (this->PolicyReportedCMP0069) {
962 // problem is already reported, no need to issue a message
966 this->PolicyReportedCMP0069 = true;
968 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
969 MessageType::FATAL_ERROR, message, this->GetBacktrace());
973 const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
975 this->ComputeObjectMapping();
976 return this->Objects[file];
979 const char* cmGeneratorTarget::GetCustomObjectExtension() const
981 static std::string extension;
982 const bool has_ptx_extension =
983 this->GetPropertyAsBool("CUDA_PTX_COMPILATION");
984 if (has_ptx_extension) {
986 return extension.c_str();
991 void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
993 this->ExplicitObjectName.insert(sf);
996 bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
998 const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
999 auto it = this->ExplicitObjectName.find(file);
1000 return it != this->ExplicitObjectName.end();
1003 BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
1004 std::string const& lang, std::string const& config) const
1006 std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
1007 auto langStandardIter = this->LanguageStandardMap.find(key);
1008 if (langStandardIter != this->LanguageStandardMap.end()) {
1009 return &langStandardIter->second;
1012 return this->Target->GetLanguageStandardProperty(
1013 cmStrCat(lang, "_STANDARD"));
1016 cmValue cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
1017 std::string const& config) const
1019 BTs<std::string> const* languageStandard =
1020 this->GetLanguageStandardProperty(lang, config);
1022 if (languageStandard) {
1023 return cmValue(languageStandard->Value);
1029 cmValue cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
1030 std::string const& lang, const char* suffix) const
1032 cmValue propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
1033 if (!propertyValue) {
1034 // Check if we should use the value set by another language.
1035 if (lang == "OBJC") {
1036 propertyValue = this->GetPropertyWithPairedLanguageSupport("C", suffix);
1037 } else if (lang == "OBJCXX" || lang == "CUDA" || lang == "HIP") {
1039 this->GetPropertyWithPairedLanguageSupport("CXX", suffix);
1042 return propertyValue;
1045 cmValue cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
1047 return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS");
1050 bool cmGeneratorTarget::GetLanguageStandardRequired(
1051 std::string const& lang) const
1054 this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"));
1057 void cmGeneratorTarget::GetModuleDefinitionSources(
1058 std::vector<cmSourceFile const*>& data, const std::string& config) const
1060 IMPLEMENT_VISIT(SourceKindModuleDefinition);
1063 void cmGeneratorTarget::GetHeaderSources(
1064 std::vector<cmSourceFile const*>& data, const std::string& config) const
1066 IMPLEMENT_VISIT(SourceKindHeader);
1069 void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
1070 const std::string& config) const
1072 IMPLEMENT_VISIT(SourceKindExtra);
1075 void cmGeneratorTarget::GetCustomCommands(
1076 std::vector<cmSourceFile const*>& data, const std::string& config) const
1078 IMPLEMENT_VISIT(SourceKindCustomCommand);
1081 void cmGeneratorTarget::GetExternalObjects(
1082 std::vector<cmSourceFile const*>& data, const std::string& config) const
1084 IMPLEMENT_VISIT(SourceKindExternalObject);
1087 void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
1088 const std::string& config) const
1090 IMPLEMENT_VISIT(SourceKindManifest);
1093 std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
1095 if (!this->UtilityItemsDone) {
1096 this->UtilityItemsDone = true;
1097 std::set<BT<std::pair<std::string, bool>>> const& utilities =
1098 this->GetUtilities();
1099 for (BT<std::pair<std::string, bool>> const& i : utilities) {
1100 if (cmGeneratorTarget* gt =
1101 this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
1102 this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
1104 this->UtilityItems.insert(
1105 cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
1109 return this->UtilityItems;
1112 const std::string& cmGeneratorTarget::GetLocation(
1113 const std::string& config) const
1115 static std::string location;
1116 if (this->IsImported()) {
1117 location = this->Target->ImportedGetFullPath(
1118 config, cmStateEnums::RuntimeBinaryArtifact);
1120 location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1125 cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
1126 std::string const& config) const
1128 cm::optional<std::string> location;
1129 if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
1130 if (!imp->Location.empty()) {
1131 location = imp->Location;
1134 location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1139 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
1142 return this->Target->GetPreBuildCommands();
1145 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
1148 return this->Target->GetPreLinkCommands();
1151 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
1154 return this->Target->GetPostBuildCommands();
1157 void cmGeneratorTarget::AppendCustomCommandSideEffects(
1158 std::set<cmGeneratorTarget const*>& sideEffects) const
1160 if (!this->GetPreBuildCommands().empty() ||
1161 !this->GetPreLinkCommands().empty() ||
1162 !this->GetPostBuildCommands().empty()) {
1163 sideEffects.insert(this);
1165 for (auto const& source : this->GetAllConfigSources()) {
1166 if (source.Source->GetCustomCommand() != nullptr) {
1167 sideEffects.insert(this);
1174 void cmGeneratorTarget::AppendLanguageSideEffects(
1175 std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const
1177 static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = {
1178 "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, "HIP"_s
1181 for (auto const& lang : this->GetAllConfigCompileLanguages()) {
1182 if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) {
1183 sideEffects[lang].insert(this);
1188 bool cmGeneratorTarget::IsInBuildSystem() const
1190 if (this->IsImported()) {
1193 switch (this->Target->GetType()) {
1194 case cmStateEnums::EXECUTABLE:
1195 case cmStateEnums::STATIC_LIBRARY:
1196 case cmStateEnums::SHARED_LIBRARY:
1197 case cmStateEnums::MODULE_LIBRARY:
1198 case cmStateEnums::OBJECT_LIBRARY:
1199 case cmStateEnums::UTILITY:
1200 case cmStateEnums::GLOBAL_TARGET:
1202 case cmStateEnums::INTERFACE_LIBRARY:
1203 // An INTERFACE library is in the build system if it has SOURCES or
1205 if (!this->SourceEntries.empty() ||
1206 !this->Target->GetHeaderSetsEntries().empty()) {
1210 case cmStateEnums::UNKNOWN_LIBRARY:
1216 bool cmGeneratorTarget::IsImported() const
1218 return this->Target->IsImported();
1221 bool cmGeneratorTarget::IsImportedGloballyVisible() const
1223 return this->Target->IsImportedGloballyVisible();
1226 bool cmGeneratorTarget::CanCompileSources() const
1228 return this->Target->CanCompileSources();
1231 const std::string& cmGeneratorTarget::GetLocationForBuild() const
1233 static std::string location;
1234 if (this->IsImported()) {
1235 location = this->Target->ImportedGetFullPath(
1236 "", cmStateEnums::RuntimeBinaryArtifact);
1240 // Now handle the deprecated build-time configuration location.
1241 std::string const noConfig;
1242 location = this->GetDirectory(noConfig);
1243 cmValue cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
1244 if (cfgid && (*cfgid != ".")) {
1249 if (this->IsAppBundleOnApple()) {
1250 std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
1251 if (!macdir.empty()) {
1257 location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
1261 bool cmGeneratorTarget::IsSystemIncludeDirectory(
1262 const std::string& dir, const std::string& config,
1263 const std::string& language) const
1265 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
1266 std::string config_upper;
1267 if (!config.empty()) {
1268 config_upper = cmSystemTools::UpperCase(config);
1271 std::string key = cmStrCat(config_upper, "/", language);
1272 auto iter = this->SystemIncludesCache.find(key);
1274 if (iter == this->SystemIncludesCache.end()) {
1275 cmGeneratorExpressionDAGChecker dagChecker(
1276 this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
1278 bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
1280 std::vector<std::string> result;
1281 for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
1282 cmExpandList(cmGeneratorExpression::Evaluate(it, this->LocalGenerator,
1283 config, this, &dagChecker,
1288 std::vector<cmGeneratorTarget const*> const& deps =
1289 this->GetLinkImplementationClosure(config);
1290 for (cmGeneratorTarget const* dep : deps) {
1291 handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
1292 &dagChecker, result, excludeImported, language);
1295 cmLinkImplementation const* impl =
1296 this->GetLinkImplementation(config, LinkInterfaceFor::Usage);
1297 if (impl != nullptr) {
1298 auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language);
1299 if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) {
1300 for (auto const& lib : runtimeEntries->second) {
1302 handleSystemIncludesDep(this->LocalGenerator, lib.Target, config,
1303 this, &dagChecker, result, excludeImported,
1310 std::for_each(result.begin(), result.end(),
1311 cmSystemTools::ConvertToUnixSlashes);
1312 std::sort(result.begin(), result.end());
1313 result.erase(std::unique(result.begin(), result.end()), result.end());
1315 iter = this->SystemIncludesCache.emplace(key, result).first;
1318 return std::binary_search(iter->second.begin(), iter->second.end(), dir);
1321 bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
1323 return this->Target->GetPropertyAsBool(prop);
1326 bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
1327 std::string const& prop, cmGeneratorExpressionContext* context,
1328 LinkInterfaceFor interfaceFor) const
1330 std::string const key = prop + '@' + context->Config;
1331 auto i = this->MaybeInterfacePropertyExists.find(key);
1332 if (i == this->MaybeInterfacePropertyExists.end()) {
1333 // Insert an entry now in case there is a cycle.
1334 i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
1335 bool& maybeInterfaceProp = i->second;
1337 // If this target itself has a non-empty property value, we are done.
1338 maybeInterfaceProp = cmNonempty(this->GetProperty(prop));
1340 // Otherwise, recurse to interface dependencies.
1341 if (!maybeInterfaceProp) {
1342 cmGeneratorTarget const* headTarget =
1343 context->HeadTarget ? context->HeadTarget : this;
1344 if (cmLinkInterfaceLibraries const* iface =
1345 this->GetLinkInterfaceLibraries(context->Config, headTarget,
1347 if (iface->HadHeadSensitiveCondition) {
1348 // With a different head target we may get to a library with
1349 // this interface property.
1350 maybeInterfaceProp = true;
1352 // The transitive interface libraries do not depend on the
1353 // head target, so we can follow them.
1354 for (cmLinkItem const& lib : iface->Libraries) {
1356 lib.Target->MaybeHaveInterfaceProperty(prop, context,
1358 maybeInterfaceProp = true;
1369 std::string cmGeneratorTarget::EvaluateInterfaceProperty(
1370 std::string const& prop, cmGeneratorExpressionContext* context,
1371 cmGeneratorExpressionDAGChecker* dagCheckerParent,
1372 LinkInterfaceFor interfaceFor) const
1376 // If the property does not appear transitively at all, we are done.
1377 if (!this->MaybeHaveInterfaceProperty(prop, context, interfaceFor)) {
1381 // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is
1382 // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
1383 // but sufficient for transitive interface properties.
1384 cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
1385 nullptr, dagCheckerParent);
1386 switch (dagChecker.Check()) {
1387 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1388 dagChecker.ReportError(
1389 context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
1391 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1392 // No error. We just skip cyclic references.
1393 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1394 // No error. We have already seen this transitive property.
1396 case cmGeneratorExpressionDAGChecker::DAG:
1400 cmGeneratorTarget const* headTarget =
1401 context->HeadTarget ? context->HeadTarget : this;
1403 if (cmValue p = this->GetProperty(prop)) {
1404 result = cmGeneratorExpressionNode::EvaluateDependentExpression(
1405 *p, context->LG, context, headTarget, &dagChecker, this);
1408 if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
1409 context->Config, headTarget, interfaceFor)) {
1410 context->HadContextSensitiveCondition =
1411 context->HadContextSensitiveCondition ||
1412 iface->HadContextSensitiveCondition;
1413 for (cmLinkItem const& lib : iface->Libraries) {
1414 // Broken code can have a target in its own link interface.
1415 // Don't follow such link interface entries so as not to create a
1416 // self-referencing loop.
1417 if (lib.Target && lib.Target != this) {
1418 // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
1419 // above property and hand-evaluate it as if it were compiled.
1420 // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1421 cmGeneratorExpressionContext libContext(
1422 context->LG, context->Config, context->Quiet, headTarget, this,
1423 context->EvaluateForBuildsystem, context->Backtrace,
1425 std::string libResult = cmGeneratorExpression::StripEmptyListElements(
1426 lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker,
1428 if (!libResult.empty()) {
1429 if (result.empty()) {
1430 result = std::move(libResult);
1432 result.reserve(result.size() + 1 + libResult.size());
1434 result += libResult;
1437 context->HadContextSensitiveCondition =
1438 context->HadContextSensitiveCondition ||
1439 libContext.HadContextSensitiveCondition;
1440 context->HadHeadSensitiveCondition =
1441 context->HadHeadSensitiveCondition ||
1442 libContext.HadHeadSensitiveCondition;
1452 enum class IncludeDirectoryFallBack
1458 std::string AddLangSpecificInterfaceIncludeDirectories(
1459 const cmGeneratorTarget* root, const cmGeneratorTarget* target,
1460 const std::string& lang, const std::string& config,
1461 const std::string& propertyName, IncludeDirectoryFallBack mode,
1462 cmGeneratorExpressionDAGChecker* context)
1464 cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1465 propertyName, nullptr, context };
1466 switch (dag.Check()) {
1467 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1469 nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
1471 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1472 // No error. We just skip cyclic references.
1473 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1474 // No error. We have already seen this transitive property.
1476 case cmGeneratorExpressionDAGChecker::DAG:
1480 std::string directories;
1481 if (const auto* interface = target->GetLinkInterfaceLibraries(
1482 config, root, LinkInterfaceFor::Usage)) {
1483 for (const cmLinkItem& library : interface->Libraries) {
1484 if (const cmGeneratorTarget* dependency = library.Target) {
1485 if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
1486 auto* lg = dependency->GetLocalGenerator();
1487 std::string value = dependency->GetSafeProperty(propertyName);
1488 if (value.empty()) {
1489 if (mode == IncludeDirectoryFallBack::BINARY) {
1490 value = lg->GetCurrentBinaryDirectory();
1491 } else if (mode == IncludeDirectoryFallBack::OBJECT) {
1492 value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
1493 lg->GetTargetDirectory(dependency));
1497 if (!directories.empty()) {
1500 directories += value;
1508 void AddLangSpecificImplicitIncludeDirectories(
1509 const cmGeneratorTarget* target, const std::string& lang,
1510 const std::string& config, const std::string& propertyName,
1511 IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
1513 if (const auto* libraries = target->GetLinkImplementationLibraries(
1514 config, LinkInterfaceFor::Usage)) {
1515 cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1516 propertyName, nullptr, nullptr };
1518 for (const cmLinkImplItem& library : libraries->Libraries) {
1519 if (const cmGeneratorTarget* dependency = library.Target) {
1520 if (!dependency->IsInBuildSystem()) {
1523 if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
1524 auto* lg = dependency->GetLocalGenerator();
1525 EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
1527 if (cmValue val = dependency->GetProperty(propertyName)) {
1528 entry.Values.emplace_back(*val);
1530 if (mode == IncludeDirectoryFallBack::BINARY) {
1531 entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
1532 } else if (mode == IncludeDirectoryFallBack::OBJECT) {
1533 entry.Values.emplace_back(
1534 dependency->GetObjectDirectory(config));
1539 AddLangSpecificInterfaceIncludeDirectories(
1540 target, dependency, lang, config, propertyName, mode, &dag),
1542 entries.Entries.emplace_back(std::move(entry));
1549 void addInterfaceEntry(cmGeneratorTarget const* headTarget,
1550 std::string const& config, std::string const& prop,
1551 std::string const& lang,
1552 cmGeneratorExpressionDAGChecker* dagChecker,
1553 EvaluatedTargetPropertyEntries& entries,
1554 LinkInterfaceFor interfaceFor,
1555 std::vector<cmLinkImplItem> const& libraries)
1557 for (cmLinkImplItem const& lib : libraries) {
1559 EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1560 // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
1561 // caller's property and hand-evaluate it as if it were compiled.
1562 // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1563 cmGeneratorExpressionContext context(
1564 headTarget->GetLocalGenerator(), config, false, headTarget, headTarget,
1565 true, lib.Backtrace, lang);
1566 cmExpandList(lib.Target->EvaluateInterfaceProperty(
1567 prop, &context, dagChecker, interfaceFor),
1569 ee.ContextDependent = context.HadContextSensitiveCondition;
1570 entries.Entries.emplace_back(std::move(ee));
1575 // IncludeRuntimeInterface is used to break the cycle in computing
1576 // the necessary transitive dependencies of targets that can occur
1577 // now that we have implicit language runtime targets.
1579 // To determine the set of languages that a target has we need to iterate
1580 // all the sources which includes transitive INTERFACE sources.
1581 // Therefore we can't determine what language runtimes are needed
1582 // for a target until after all sources are computed.
1584 // Therefore while computing the applicable INTERFACE_SOURCES we
1585 // must ignore anything in LanguageRuntimeLibraries or we would
1586 // create a cycle ( INTERFACE_SOURCES requires LanguageRuntimeLibraries,
1587 // LanguageRuntimeLibraries requires INTERFACE_SOURCES).
1589 enum class IncludeRuntimeInterface
1594 void AddInterfaceEntries(
1595 cmGeneratorTarget const* headTarget, std::string const& config,
1596 std::string const& prop, std::string const& lang,
1597 cmGeneratorExpressionDAGChecker* dagChecker,
1598 EvaluatedTargetPropertyEntries& entries,
1599 IncludeRuntimeInterface searchRuntime,
1600 LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage)
1602 if (searchRuntime == IncludeRuntimeInterface::Yes) {
1603 if (cmLinkImplementation const* impl =
1604 headTarget->GetLinkImplementation(config, interfaceFor)) {
1605 entries.HadContextSensitiveCondition =
1606 impl->HadContextSensitiveCondition;
1608 auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang);
1609 if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) {
1610 addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1611 interfaceFor, runtimeLibIt->second);
1613 addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1614 interfaceFor, impl->Libraries);
1617 if (cmLinkImplementationLibraries const* impl =
1618 headTarget->GetLinkImplementationLibraries(config, interfaceFor)) {
1619 entries.HadContextSensitiveCondition =
1620 impl->HadContextSensitiveCondition;
1621 addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
1622 interfaceFor, impl->Libraries);
1627 void AddObjectEntries(cmGeneratorTarget const* headTarget,
1628 std::string const& config,
1629 cmGeneratorExpressionDAGChecker* dagChecker,
1630 EvaluatedTargetPropertyEntries& entries)
1632 if (cmLinkImplementationLibraries const* impl =
1633 headTarget->GetLinkImplementationLibraries(config,
1634 LinkInterfaceFor::Usage)) {
1635 entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
1636 for (cmLinkImplItem const& lib : impl->Libraries) {
1638 lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1639 std::string uniqueName =
1640 headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
1642 std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
1643 cmGeneratorExpression ge(lib.Backtrace);
1644 std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
1645 cge->SetEvaluateForBuildsystem(true);
1647 EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1648 cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config,
1649 headTarget, dagChecker),
1651 if (cge->GetHadContextSensitiveCondition()) {
1652 ee.ContextDependent = true;
1654 entries.Entries.emplace_back(std::move(ee));
1660 void addFileSetEntry(cmGeneratorTarget const* headTarget,
1661 std::string const& config,
1662 cmGeneratorExpressionDAGChecker* dagChecker,
1663 cmFileSet const* fileSet,
1664 EvaluatedTargetPropertyEntries& entries)
1666 auto dirCges = fileSet->CompileDirectoryEntries();
1667 auto dirs = fileSet->EvaluateDirectoryEntries(
1668 dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker);
1669 bool contextSensitiveDirs = false;
1670 for (auto const& dirCge : dirCges) {
1671 if (dirCge->GetHadContextSensitiveCondition()) {
1672 contextSensitiveDirs = true;
1676 cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance();
1677 for (auto& entryCge : fileSet->CompileFileEntries()) {
1678 TargetPropertyEntryFileSet tpe(dirs, contextSensitiveDirs,
1679 std::move(entryCge), fileSet);
1680 entries.Entries.emplace_back(
1681 EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, tpe));
1682 for (auto const& file : entries.Entries.back().Values) {
1683 auto* sf = headTarget->Makefile->GetOrCreateSource(file);
1684 if (fileSet->GetType() == "HEADERS"_s) {
1685 sf->SetProperty("HEADER_FILE_ONLY", "TRUE");
1688 #ifndef CMAKE_BOOTSTRAP
1691 auto path = sf->ResolveFullPath(&e, &w);
1693 cm->IssueMessage(MessageType::AUTHOR_WARNING, w,
1694 headTarget->GetBacktrace());
1698 cm->IssueMessage(MessageType::FATAL_ERROR, e,
1699 headTarget->GetBacktrace());
1704 for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
1705 if (sg.MatchChildrenFiles(path)) {
1711 if (fileSet->GetType() == "HEADERS"_s) {
1712 headTarget->Makefile->GetOrCreateSourceGroup("Header Files")
1713 ->AddGroupFile(path);
1721 void AddFileSetEntries(cmGeneratorTarget const* headTarget,
1722 std::string const& config,
1723 cmGeneratorExpressionDAGChecker* dagChecker,
1724 EvaluatedTargetPropertyEntries& entries)
1726 for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) {
1727 for (auto const& name : cmExpandedList(entry.Value)) {
1728 auto const* headerSet = headTarget->Target->GetFileSet(name);
1729 addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
1734 bool processSources(cmGeneratorTarget const* tgt,
1735 EvaluatedTargetPropertyEntries& entries,
1736 std::vector<BT<std::string>>& srcs,
1737 std::unordered_set<std::string>& uniqueSrcs,
1740 cmMakefile* mf = tgt->Target->GetMakefile();
1742 bool contextDependent = entries.HadContextSensitiveCondition;
1744 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
1745 if (entry.ContextDependent) {
1746 contextDependent = true;
1749 cmLinkImplItem const& item = entry.LinkImplItem;
1750 std::string const& targetName = item.AsStr();
1752 for (std::string& src : entry.Values) {
1753 cmSourceFile* sf = mf->GetOrCreateSource(src);
1756 std::string fullPath = sf->ResolveFullPath(&e, &w);
1757 cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
1759 cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
1761 if (fullPath.empty()) {
1763 cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
1765 return contextDependent;
1768 if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
1769 std::ostringstream err;
1770 if (!targetName.empty()) {
1771 err << "Target \"" << targetName
1772 << "\" contains relative path in its INTERFACE_SOURCES:\n \""
1775 err << "Found relative path while evaluating sources of \""
1776 << tgt->GetName() << "\":\n \"" << src << "\"\n";
1778 tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
1780 return contextDependent;
1784 std::string usedSources;
1785 for (std::string const& src : entry.Values) {
1786 if (uniqueSrcs.insert(src).second) {
1787 srcs.emplace_back(src, entry.Backtrace);
1789 usedSources += " * " + src + "\n";
1793 if (!usedSources.empty()) {
1794 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
1796 std::string("Used sources for target ") + tgt->GetName() + ":\n" +
1801 return contextDependent;
1805 std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
1806 std::string const& config) const
1808 std::vector<BT<std::string>> files;
1810 if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1811 // At configure-time, this method can be called as part of getting the
1812 // LOCATION property or to export() a file to be include()d. However
1813 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
1814 // for TARGET_OBJECTS instead for backwards compatibility with OLD
1815 // behavior of CMP0024 and CMP0026 only.
1817 cmBTStringRange sourceEntries = this->Target->GetSourceEntries();
1818 for (auto const& entry : sourceEntries) {
1819 std::vector<std::string> items = cmExpandedList(entry.Value);
1820 for (std::string const& item : items) {
1821 if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
1822 item.back() == '>') {
1825 files.emplace_back(item);
1831 std::vector<std::string> debugProperties;
1832 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
1836 !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES");
1838 if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1839 this->DebugSourcesDone = true;
1842 cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
1845 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
1846 this, config, std::string(), &dagChecker, this->SourceEntries);
1848 std::unordered_set<std::string> uniqueSrcs;
1849 bool contextDependentDirectSources =
1850 processSources(this, entries, files, uniqueSrcs, debugSources);
1852 // Collect INTERFACE_SOURCES of all direct link-dependencies.
1853 EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries;
1854 AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(),
1855 &dagChecker, linkInterfaceSourcesEntries,
1856 IncludeRuntimeInterface::No, LinkInterfaceFor::Usage);
1857 std::vector<std::string>::size_type numFilesBefore = files.size();
1858 bool contextDependentInterfaceSources = processSources(
1859 this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources);
1861 // Collect TARGET_OBJECTS of direct object link-dependencies.
1862 bool contextDependentObjects = false;
1863 std::vector<std::string>::size_type numFilesBefore2 = files.size();
1864 if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
1865 EvaluatedTargetPropertyEntries linkObjectsEntries;
1866 AddObjectEntries(this, config, &dagChecker, linkObjectsEntries);
1867 contextDependentObjects = processSources(this, linkObjectsEntries, files,
1868 uniqueSrcs, debugSources);
1871 // Collect this target's file sets.
1872 std::vector<std::string>::size_type numFilesBefore3 = files.size();
1873 EvaluatedTargetPropertyEntries fileSetEntries;
1874 AddFileSetEntries(this, config, &dagChecker, fileSetEntries);
1875 bool contextDependentFileSets =
1876 processSources(this, fileSetEntries, files, uniqueSrcs, debugSources);
1878 // Determine if sources are context-dependent or not.
1879 if (!contextDependentDirectSources &&
1880 !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
1881 !(contextDependentObjects && numFilesBefore2 < files.size()) &&
1882 !(contextDependentFileSets && numFilesBefore3 < files.size())) {
1883 this->SourcesAreContextDependent = Tribool::False;
1885 this->SourcesAreContextDependent = Tribool::True;
1891 void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
1892 const std::string& config) const
1894 std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config);
1895 files.reserve(tmp.size());
1896 for (BT<cmSourceFile*>& v : tmp) {
1897 files.push_back(v.Value);
1901 std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles(
1902 std::string const& config) const
1904 std::vector<BT<cmSourceFile*>> files;
1905 if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
1906 // Since we are still configuring not all sources may exist yet,
1907 // so we need to avoid full source classification because that
1908 // requires the absolute paths to all sources to be determined.
1909 // Since this is only for compatibility with old policies that
1910 // projects should not depend on anymore, just compute the files
1911 // without memoizing them.
1912 std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
1913 std::set<cmSourceFile*> emitted;
1914 for (BT<std::string> const& s : srcs) {
1915 cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
1916 if (emitted.insert(sf).second) {
1917 files.emplace_back(sf, s.Backtrace);
1923 KindedSources const& kinded = this->GetKindedSources(config);
1924 files.reserve(kinded.Sources.size());
1925 for (SourceAndKind const& si : kinded.Sources) {
1926 files.push_back(si.Source);
1931 void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1932 std::vector<cmSourceFile*>& files, const std::string& config) const
1934 std::vector<BT<cmSourceFile*>> tmp =
1935 this->GetSourceFilesWithoutObjectLibraries(config);
1936 files.reserve(tmp.size());
1937 for (BT<cmSourceFile*>& v : tmp) {
1938 files.push_back(v.Value);
1942 std::vector<BT<cmSourceFile*>>
1943 cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1944 std::string const& config) const
1946 std::vector<BT<cmSourceFile*>> files;
1947 KindedSources const& kinded = this->GetKindedSources(config);
1948 files.reserve(kinded.Sources.size());
1949 for (SourceAndKind const& si : kinded.Sources) {
1950 if (si.Source.Value->GetObjectLibrary().empty()) {
1951 files.push_back(si.Source);
1957 cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
1958 std::string const& config) const
1960 // If we already processed one configuration and found no dependency
1961 // on configuration then always use the one result.
1962 if (this->SourcesAreContextDependent == Tribool::False) {
1963 return this->KindedSourcesMap.begin()->second;
1966 // Lookup any existing link implementation for this configuration.
1967 std::string const key = cmSystemTools::UpperCase(config);
1968 auto it = this->KindedSourcesMap.find(key);
1969 if (it != this->KindedSourcesMap.end()) {
1970 if (!it->second.Initialized) {
1971 std::ostringstream e;
1972 e << "The SOURCES of \"" << this->GetName()
1973 << "\" use a generator expression that depends on the "
1974 "SOURCES themselves.";
1975 this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
1976 MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
1977 static KindedSources empty;
1983 // Add an entry to the map for this configuration.
1984 KindedSources& files = this->KindedSourcesMap[key];
1985 this->ComputeKindedSources(files, config);
1986 files.Initialized = true;
1990 void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
1991 std::string const& config) const
1993 // Get the source file paths by string.
1994 std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
1996 cmsys::RegularExpression header_regex(CM_HEADER_REGEX);
1997 std::vector<cmSourceFile*> badObjLib;
1999 std::set<cmSourceFile*> emitted;
2000 for (BT<std::string> const& s : srcs) {
2001 // Create each source at most once.
2002 cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
2003 if (!emitted.insert(sf).second) {
2007 // Compute the kind (classification) of this source file.
2009 std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
2010 if (sf->GetCustomCommand()) {
2011 kind = SourceKindCustomCommand;
2012 } else if (this->Target->GetType() == cmStateEnums::UTILITY ||
2013 this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY
2014 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2015 // NOLINTNEXTLINE(bugprone-branch-clone)
2017 kind = SourceKindExtra;
2018 } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) {
2019 kind = SourceKindUnityBatched;
2020 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2021 // NOLINTNEXTLINE(bugprone-branch-clone)
2022 } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) {
2023 kind = SourceKindHeader;
2024 } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
2025 kind = SourceKindExternalObject;
2026 } else if (!sf->GetOrDetermineLanguage().empty()) {
2027 kind = SourceKindObjectSource;
2028 } else if (ext == "def") {
2029 kind = SourceKindModuleDefinition;
2030 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2031 badObjLib.push_back(sf);
2033 } else if (ext == "idl") {
2034 kind = SourceKindIDL;
2035 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2036 badObjLib.push_back(sf);
2038 } else if (ext == "resx") {
2039 kind = SourceKindResx;
2040 } else if (ext == "appxmanifest") {
2041 kind = SourceKindAppManifest;
2042 } else if (ext == "manifest") {
2043 if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) {
2044 kind = SourceKindExtra;
2046 kind = SourceKindManifest;
2048 } else if (ext == "pfx") {
2049 kind = SourceKindCertificate;
2050 } else if (ext == "xaml") {
2051 kind = SourceKindXaml;
2052 } else if (header_regex.find(sf->ResolveFullPath())) {
2053 kind = SourceKindHeader;
2055 kind = SourceKindExtra;
2058 // Save this classified source file in the result vector.
2059 files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind });
2062 if (!badObjLib.empty()) {
2063 std::ostringstream e;
2064 e << "OBJECT library \"" << this->GetName() << "\" contains:\n";
2065 for (cmSourceFile* i : badObjLib) {
2066 e << " " << i->GetLocation().GetName() << "\n";
2068 e << "but may contain only sources that compile, header files, and "
2069 "other files that would not affect linking of a normal library.";
2070 this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
2071 MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
2075 std::vector<cmGeneratorTarget::AllConfigSource> const&
2076 cmGeneratorTarget::GetAllConfigSources() const
2078 if (this->AllConfigSources.empty()) {
2079 this->ComputeAllConfigSources();
2081 return this->AllConfigSources;
2084 void cmGeneratorTarget::ComputeAllConfigSources() const
2086 std::vector<std::string> configs =
2087 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2089 std::map<cmSourceFile const*, size_t> index;
2091 for (size_t ci = 0; ci < configs.size(); ++ci) {
2092 KindedSources const& sources = this->GetKindedSources(configs[ci]);
2093 for (SourceAndKind const& src : sources.Sources) {
2094 auto mi = index.find(src.Source.Value);
2095 if (mi == index.end()) {
2096 AllConfigSource acs;
2097 acs.Source = src.Source.Value;
2098 acs.Kind = src.Kind;
2099 this->AllConfigSources.push_back(std::move(acs));
2100 std::map<cmSourceFile const*, size_t>::value_type entry(
2101 src.Source.Value, this->AllConfigSources.size() - 1);
2102 mi = index.insert(entry).first;
2104 this->AllConfigSources[mi->second].Configs.push_back(ci);
2109 std::vector<cmGeneratorTarget::AllConfigSource>
2110 cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
2112 std::vector<AllConfigSource> result;
2113 for (AllConfigSource const& source : this->GetAllConfigSources()) {
2114 if (source.Kind == kind) {
2115 result.push_back(source);
2121 std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
2123 std::set<std::string> languages;
2124 std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
2125 for (AllConfigSource const& si : sources) {
2126 std::string const& lang = si.Source->GetOrDetermineLanguage();
2127 if (!lang.empty()) {
2128 languages.emplace(lang);
2134 std::string cmGeneratorTarget::GetCompilePDBName(
2135 const std::string& config) const
2140 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
2141 prefix, base, suffix);
2143 // Check for a per-configuration output directory target property.
2144 std::string configUpper = cmSystemTools::UpperCase(config);
2145 std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
2146 cmValue config_name = this->GetProperty(configProp);
2147 if (cmNonempty(config_name)) {
2148 return prefix + *config_name + ".pdb";
2151 cmValue name = this->GetProperty("COMPILE_PDB_NAME");
2152 if (cmNonempty(name)) {
2153 return prefix + *name + ".pdb";
2159 std::string cmGeneratorTarget::GetCompilePDBPath(
2160 const std::string& config) const
2162 std::string dir = this->GetCompilePDBDirectory(config);
2163 std::string name = this->GetCompilePDBName(config);
2164 if (dir.empty() && !name.empty() && this->HaveWellDefinedOutputFiles()) {
2165 dir = this->GetPDBDirectory(config);
2173 bool cmGeneratorTarget::HasSOName(const std::string& config) const
2175 // soname is supported only for shared libraries and modules,
2176 // and then only when the platform supports an soname flag.
2177 return ((this->GetType() == cmStateEnums::SHARED_LIBRARY) &&
2178 !this->GetPropertyAsBool("NO_SONAME") &&
2179 this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
2182 bool cmGeneratorTarget::NeedRelinkBeforeInstall(
2183 const std::string& config) const
2185 // Only executables and shared libraries can have an rpath and may
2187 if (this->GetType() != cmStateEnums::EXECUTABLE &&
2188 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
2189 this->GetType() != cmStateEnums::MODULE_LIBRARY) {
2193 // If there is no install location this target will not be installed
2194 // and therefore does not need relinking.
2195 if (!this->Target->GetHaveInstallRule()) {
2199 // If skipping all rpaths completely then no relinking is needed.
2200 if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
2204 // If building with the install-tree rpath no relinking is needed.
2205 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2209 // If chrpath is going to be used no relinking is needed.
2210 if (this->IsChrpathUsed(config)) {
2214 // Check for rpath support on this platform.
2215 std::string ll = this->GetLinkerLanguage(config);
2217 std::string flagVar =
2218 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG");
2219 if (!this->Makefile->IsSet(flagVar)) {
2220 // There is no rpath support on this platform so nothing needs
2225 // No linker language is known. This error will be reported by
2230 // If either a build or install tree rpath is set then the rpath
2231 // will likely change between the build tree and install tree and
2232 // this target must be relinked.
2234 this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
2235 bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja();
2237 if (have_rpath && is_ninja) {
2238 std::ostringstream w;
2239 /* clang-format off */
2241 "The install of the " << this->GetName() << " target requires changing "
2242 "an RPATH from the build tree, but this is not supported with the Ninja "
2243 "generator unless on an ELF-based or XCOFF-based platform. "
2244 "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
2247 /* clang-format on */
2249 cmake* cm = this->LocalGenerator->GetCMakeInstance();
2250 cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
2256 bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
2258 // Only certain target types have an rpath.
2259 if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2260 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2261 this->GetType() == cmStateEnums::EXECUTABLE)) {
2265 // If the target will not be installed we do not need to change its
2267 if (!this->Target->GetHaveInstallRule()) {
2271 // Skip chrpath if skipping rpath altogether.
2272 if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
2276 // Skip chrpath if it does not need to be changed at install time.
2277 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2281 // Allow the user to disable builtin chrpath explicitly.
2282 if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
2286 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2290 // Enable if the rpath flag uses a separator and the target uses
2291 // binaries we know how to edit.
2292 std::string ll = this->GetLinkerLanguage(config);
2294 std::string sepVar =
2295 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
2296 cmValue sep = this->Makefile->GetDefinition(sepVar);
2297 if (cmNonempty(sep)) {
2298 // TODO: Add binary format check to ABI detection and get rid of
2299 // CMAKE_EXECUTABLE_FORMAT.
2301 this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
2302 if (*fmt == "ELF") {
2305 #if defined(CMake_USE_XCOFF_PARSER)
2306 if (*fmt == "XCOFF") {
2316 bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
2317 const std::string& config) const
2319 if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY) {
2320 if (cmGeneratorTarget::ImportInfo const* info =
2321 this->GetImportInfo(config)) {
2322 return info->NoSOName;
2328 bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
2329 const std::string& config) const
2331 TargetPtrToBoolMap& cache = this->MacOSXRpathInstallNameDirCache[config];
2332 const auto lookup = cache.find(this->Target);
2334 if (lookup != cache.cend()) {
2335 return lookup->second;
2338 const bool result = this->DetermineHasMacOSXRpathInstallNameDir(config);
2339 cache[this->Target] = result;
2343 bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir(
2344 const std::string& config) const
2346 bool install_name_is_rpath = false;
2347 bool macosx_rpath = false;
2349 if (!this->IsImported()) {
2350 if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
2353 cmValue install_name = this->GetProperty("INSTALL_NAME_DIR");
2354 bool use_install_name = this->MacOSXUseInstallNameDir();
2355 if (install_name && use_install_name && *install_name == "@rpath") {
2356 install_name_is_rpath = true;
2357 } else if (install_name && use_install_name) {
2360 if (!install_name_is_rpath) {
2361 macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
2364 // Lookup the imported soname.
2365 if (cmGeneratorTarget::ImportInfo const* info =
2366 this->GetImportInfo(config)) {
2367 if (!info->NoSOName && !info->SOName.empty()) {
2368 if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
2369 install_name_is_rpath = true;
2372 std::string install_name;
2373 cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
2374 if (install_name.find("@rpath") != std::string::npos) {
2375 install_name_is_rpath = true;
2381 if (!install_name_is_rpath && !macosx_rpath) {
2385 if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2386 std::ostringstream w;
2387 w << "Attempting to use ";
2389 w << "MACOSX_RPATH";
2393 w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
2394 w << " This could be because you are using a Mac OS X version";
2395 w << " less than 10.5 or because CMake's platform configuration is";
2397 cmake* cm = this->LocalGenerator->GetCMakeInstance();
2398 cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
2404 bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
2406 // we can't do rpaths when unsupported
2407 if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2411 cmValue macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
2412 if (macosx_rpath_str) {
2413 return this->GetPropertyAsBool("MACOSX_RPATH");
2416 cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
2418 if (cmp0042 == cmPolicies::WARN) {
2419 this->LocalGenerator->GetGlobalGenerator()->AddCMP0042WarnTarget(
2423 return cmp0042 == cmPolicies::NEW;
2426 bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
2428 cmValue build_with_install_name =
2429 this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
2430 if (build_with_install_name) {
2431 return cmIsOn(*build_with_install_name);
2434 cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2435 if (cmp0068 == cmPolicies::NEW) {
2439 bool use_install_name = this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
2441 if (use_install_name && cmp0068 == cmPolicies::WARN) {
2442 this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2446 return use_install_name;
2449 bool cmGeneratorTarget::CanGenerateInstallNameDir(
2450 InstallNameType name_type) const
2452 cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2454 if (cmp0068 == cmPolicies::NEW) {
2458 bool skip = this->Makefile->IsOn("CMAKE_SKIP_RPATH");
2459 if (name_type == INSTALL_NAME_FOR_INSTALL) {
2460 skip |= this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
2462 skip |= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
2465 if (skip && cmp0068 == cmPolicies::WARN) {
2466 this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2473 std::string cmGeneratorTarget::GetSOName(const std::string& config) const
2475 if (this->IsImported()) {
2476 // Lookup the imported soname.
2477 if (cmGeneratorTarget::ImportInfo const* info =
2478 this->GetImportInfo(config)) {
2479 if (info->NoSOName) {
2480 // The imported library has no builtin soname so the name
2481 // searched at runtime will be just the filename.
2482 return cmSystemTools::GetFilenameName(info->Location);
2484 // Use the soname given if any.
2485 if (this->IsFrameworkOnApple()) {
2486 cmsys::RegularExpressionMatch match;
2487 if (FrameworkRegularExpression.find(info->SOName.c_str(), match)) {
2488 auto frameworkName = match.match(2);
2489 auto fileName = match.match(3);
2490 return cmStrCat(frameworkName, ".framework/", fileName);
2493 if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
2494 return info->SOName.substr(cmStrLen("@rpath/"));
2496 return info->SOName;
2500 // Compute the soname that will be built.
2501 return this->GetLibraryNames(config).SharedObject;
2505 bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2507 return level == cmGeneratorTarget::FullLevel;
2510 bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2512 return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
2516 std::string cmGeneratorTarget::GetAppBundleDirectory(
2517 const std::string& config, BundleDirectoryLevel level) const
2519 std::string fpath = cmStrCat(
2520 this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2521 cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
2522 fpath += (ext ? *ext : "app");
2523 if (shouldAddContentLevel(level) &&
2524 !this->Makefile->PlatformIsAppleEmbedded()) {
2525 fpath += "/Contents";
2526 if (shouldAddFullLevel(level)) {
2533 bool cmGeneratorTarget::IsBundleOnApple() const
2535 return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
2536 this->IsCFBundleOnApple();
2539 bool cmGeneratorTarget::IsWin32Executable(const std::string& config) const
2541 return cmIsOn(cmGeneratorExpression::Evaluate(
2542 this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator, config));
2545 std::string cmGeneratorTarget::GetCFBundleDirectory(
2546 const std::string& config, BundleDirectoryLevel level) const
2548 std::string fpath = cmStrCat(
2549 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2551 if (cmValue p = this->GetProperty("BUNDLE_EXTENSION")) {
2554 if (this->IsXCTestOnApple()) {
2561 if (shouldAddContentLevel(level) &&
2562 !this->Makefile->PlatformIsAppleEmbedded()) {
2563 fpath += "/Contents";
2564 if (shouldAddFullLevel(level)) {
2571 std::string cmGeneratorTarget::GetFrameworkDirectory(
2572 const std::string& config, BundleDirectoryLevel level) const
2574 std::string fpath = cmStrCat(
2575 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2576 cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
2577 fpath += (ext ? *ext : "framework");
2578 if (shouldAddFullLevel(level) &&
2579 !this->Makefile->PlatformIsAppleEmbedded()) {
2580 fpath += "/Versions/";
2581 fpath += this->GetFrameworkVersion();
2586 std::string cmGeneratorTarget::GetFullName(
2587 const std::string& config, cmStateEnums::ArtifactType artifact) const
2589 if (this->IsImported()) {
2590 return this->GetFullNameImported(config, artifact);
2592 return this->GetFullNameInternal(config, artifact);
2595 std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
2596 const std::string& config) const
2598 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2600 // If building directly for installation then the build tree install_name
2601 // is the same as the install tree.
2602 if (this->MacOSXUseInstallNameDir()) {
2603 std::string installPrefix =
2604 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2605 return this->GetInstallNameDirForInstallTree(config, installPrefix);
2608 // Use the build tree directory for the target.
2609 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD)) {
2611 if (this->MacOSXRpathInstallNameDirDefault()) {
2614 dir = this->GetDirectory(config);
2623 std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
2624 const std::string& config, const std::string& installPrefix) const
2626 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2628 cmValue install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
2630 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
2631 if (cmNonempty(install_name_dir)) {
2632 dir = *install_name_dir;
2633 cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
2635 cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
2637 dir = cmStrCat(dir, '/');
2641 if (!install_name_dir) {
2642 if (this->MacOSXRpathInstallNameDirDefault()) {
2651 cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
2653 return this->Target->GetBacktrace();
2656 const std::set<BT<std::pair<std::string, bool>>>&
2657 cmGeneratorTarget::GetUtilities() const
2659 return this->Target->GetUtilities();
2662 bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
2664 return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
2665 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2666 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2667 this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
2668 this->GetType() == cmStateEnums::EXECUTABLE;
2671 const std::string* cmGeneratorTarget::GetExportMacro() const
2673 // Define the symbol for targets that export symbols.
2674 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2675 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2676 this->IsExecutableWithExports()) {
2677 if (cmValue custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
2678 this->ExportMacro = *custom_export_name;
2680 std::string in = cmStrCat(this->GetName(), "_EXPORTS");
2681 this->ExportMacro = cmSystemTools::MakeCidentifier(in);
2683 return &this->ExportMacro;
2688 class cmTargetCollectLinkLanguages
2691 cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
2693 std::unordered_set<std::string>& languages,
2694 cmGeneratorTarget const* head, bool secondPass)
2695 : Config(std::move(config))
2696 , Languages(languages)
2698 , SecondPass(secondPass)
2700 this->Visited.insert(target);
2703 void Visit(cmLinkItem const& item)
2708 if (!this->Visited.insert(item.Target).second) {
2711 cmLinkInterface const* iface = item.Target->GetLinkInterface(
2712 this->Config, this->HeadTarget, this->SecondPass);
2716 if (iface->HadLinkLanguageSensitiveCondition) {
2717 this->HadLinkLanguageSensitiveCondition = true;
2720 for (std::string const& language : iface->Languages) {
2721 this->Languages.insert(language);
2724 for (cmLinkItem const& lib : iface->Libraries) {
2729 bool GetHadLinkLanguageSensitiveCondition() const
2731 return this->HadLinkLanguageSensitiveCondition;
2736 std::unordered_set<std::string>& Languages;
2737 cmGeneratorTarget const* HeadTarget;
2738 std::set<cmGeneratorTarget const*> Visited;
2740 bool HadLinkLanguageSensitiveCondition = false;
2743 cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure(
2744 const std::string& config) const
2746 // There is no link implementation for targets that cannot compile sources.
2747 if (!this->CanCompileSources()) {
2748 static LinkClosure const empty = { {}, {} };
2752 std::string key(cmSystemTools::UpperCase(config));
2753 auto i = this->LinkClosureMap.find(key);
2754 if (i == this->LinkClosureMap.end()) {
2756 this->ComputeLinkClosure(config, lc);
2757 LinkClosureMapType::value_type entry(key, lc);
2758 i = this->LinkClosureMap.insert(entry).first;
2763 class cmTargetSelectLinker
2766 cmGeneratorTarget const* Target;
2767 cmGlobalGenerator* GG;
2768 std::set<std::string> Preferred;
2771 cmTargetSelectLinker(cmGeneratorTarget const* target)
2774 this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator();
2776 void Consider(const std::string& lang)
2778 int preference = this->GG->GetLinkerPreference(lang);
2779 if (preference > this->Preference) {
2780 this->Preference = preference;
2781 this->Preferred.clear();
2783 if (preference == this->Preference) {
2784 this->Preferred.insert(lang);
2787 std::string Choose()
2789 if (this->Preferred.empty()) {
2792 if (this->Preferred.size() > 1) {
2793 std::ostringstream e;
2794 e << "Target " << this->Target->GetName()
2795 << " contains multiple languages with the highest linker preference"
2796 << " (" << this->Preference << "):\n";
2797 for (std::string const& li : this->Preferred) {
2798 e << " " << li << "\n";
2800 e << "Set the LINKER_LANGUAGE property for this target.";
2801 cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance();
2802 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2803 this->Target->GetBacktrace());
2805 return *this->Preferred.begin();
2809 bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2811 bool secondPass) const
2813 // Get languages built in this target.
2814 std::unordered_set<std::string> languages;
2815 cmLinkImplementation const* impl =
2816 this->GetLinkImplementation(config, LinkInterfaceFor::Link, secondPass);
2818 languages.insert(impl->Languages.cbegin(), impl->Languages.cend());
2820 // Add interface languages from linked targets.
2821 // cmTargetCollectLinkLanguages cll(this, config, languages, this,
2823 cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass);
2824 for (cmLinkImplItem const& lib : impl->Libraries) {
2828 // Store the transitive closure of languages.
2829 cm::append(lc.Languages, languages);
2831 // Choose the language whose linker should be used.
2832 if (secondPass || lc.LinkerLanguage.empty()) {
2833 // Find the language with the highest preference value.
2834 cmTargetSelectLinker tsl(this);
2836 // First select from the languages compiled directly in this target.
2837 for (std::string const& l : impl->Languages) {
2841 // Now consider languages that propagate from linked targets.
2842 for (std::string const& lang : languages) {
2843 std::string propagates =
2844 "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES";
2845 if (this->Makefile->IsOn(propagates)) {
2850 lc.LinkerLanguage = tsl.Choose();
2853 return impl->HadLinkLanguageSensitiveCondition ||
2854 cll.GetHadLinkLanguageSensitiveCondition();
2857 void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2858 LinkClosure& lc) const
2860 bool secondPass = false;
2863 LinkClosure linkClosure;
2864 linkClosure.LinkerLanguage = this->LinkerLanguage;
2866 bool hasHardCodedLinkerLanguage = this->Target->GetProperty("HAS_CXX") ||
2867 !this->Target->GetSafeProperty("LINKER_LANGUAGE").empty();
2869 // Get languages built in this target.
2870 secondPass = this->ComputeLinkClosure(config, linkClosure, false) &&
2871 !hasHardCodedLinkerLanguage;
2872 this->LinkerLanguage = linkClosure.LinkerLanguage;
2874 lc = std::move(linkClosure);
2879 LinkClosure linkClosure;
2881 this->ComputeLinkClosure(config, linkClosure, secondPass);
2882 lc = std::move(linkClosure);
2884 // linker language must not be changed between the two passes
2885 if (this->LinkerLanguage != lc.LinkerLanguage) {
2886 std::ostringstream e;
2887 e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> "
2888 "changes\nthe linker language for target \""
2889 << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '"
2890 << lc.LinkerLanguage << "') which is invalid.";
2891 cmSystemTools::Error(e.str());
2896 void cmGeneratorTarget::GetFullNameComponents(
2897 std::string& prefix, std::string& base, std::string& suffix,
2898 const std::string& config, cmStateEnums::ArtifactType artifact) const
2900 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
2903 std::string cmGeneratorTarget::BuildBundleDirectory(
2904 const std::string& base, const std::string& config,
2905 BundleDirectoryLevel level) const
2907 std::string fpath = base;
2908 if (this->IsAppBundleOnApple()) {
2909 fpath += this->GetAppBundleDirectory(config, level);
2911 if (this->IsFrameworkOnApple()) {
2912 fpath += this->GetFrameworkDirectory(config, level);
2914 if (this->IsCFBundleOnApple()) {
2915 fpath += this->GetCFBundleDirectory(config, level);
2920 std::string cmGeneratorTarget::GetMacContentDirectory(
2921 const std::string& config, cmStateEnums::ArtifactType artifact) const
2923 // Start with the output directory for the target.
2924 std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
2925 BundleDirectoryLevel level = ContentLevel;
2926 if (this->IsFrameworkOnApple()) {
2927 // additional files with a framework go into the version specific
2931 fpath = this->BuildBundleDirectory(fpath, config, level);
2935 std::string cmGeneratorTarget::GetEffectiveFolderName() const
2937 std::string effectiveFolder;
2939 if (!this->GlobalGenerator->UseFolderProperty()) {
2940 return effectiveFolder;
2943 cmValue targetFolder = this->GetProperty("FOLDER");
2945 effectiveFolder += *targetFolder;
2948 return effectiveFolder;
2951 cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
2952 const std::string& config) const
2954 // There is no compile information for imported targets.
2955 if (this->IsImported()) {
2959 if (this->GetType() > cmStateEnums::OBJECT_LIBRARY) {
2960 std::string msg = cmStrCat("cmTarget::GetCompileInfo called for ",
2961 this->GetName(), " which has type ",
2962 cmState::GetTargetTypeName(this->GetType()));
2963 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
2967 // Lookup/compute/cache the compile information for this configuration.
2968 std::string config_upper;
2969 if (!config.empty()) {
2970 config_upper = cmSystemTools::UpperCase(config);
2972 auto i = this->CompileInfoMap.find(config_upper);
2973 if (i == this->CompileInfoMap.end()) {
2975 this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
2976 CompileInfoMapType::value_type entry(config_upper, info);
2977 i = this->CompileInfoMap.insert(entry).first;
2982 cmGeneratorTarget::ModuleDefinitionInfo const*
2983 cmGeneratorTarget::GetModuleDefinitionInfo(std::string const& config) const
2985 // A module definition file only makes sense on certain target types.
2986 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
2987 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
2988 !this->IsExecutableWithExports()) {
2992 // Lookup/compute/cache the compile information for this configuration.
2993 std::string config_upper;
2994 if (!config.empty()) {
2995 config_upper = cmSystemTools::UpperCase(config);
2997 auto i = this->ModuleDefinitionInfoMap.find(config_upper);
2998 if (i == this->ModuleDefinitionInfoMap.end()) {
2999 ModuleDefinitionInfo info;
3000 this->ComputeModuleDefinitionInfo(config, info);
3001 ModuleDefinitionInfoMapType::value_type entry(config_upper, info);
3002 i = this->ModuleDefinitionInfoMap.insert(entry).first;
3007 void cmGeneratorTarget::ComputeModuleDefinitionInfo(
3008 std::string const& config, ModuleDefinitionInfo& info) const
3010 this->GetModuleDefinitionSources(info.Sources, config);
3011 info.WindowsExportAllSymbols =
3012 this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
3013 this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
3014 #if !defined(CMAKE_BOOTSTRAP)
3015 info.DefFileGenerated =
3016 info.WindowsExportAllSymbols || info.Sources.size() > 1;
3018 // Our __create_def helper is not available during CMake bootstrap.
3019 info.DefFileGenerated = false;
3021 if (info.DefFileGenerated) {
3023 this->GetObjectDirectory(config) /* has slash */ + "exports.def";
3024 } else if (!info.Sources.empty()) {
3025 info.DefFile = info.Sources.front()->GetFullPath();
3029 bool cmGeneratorTarget::IsDLLPlatform() const
3031 return this->Target->IsDLLPlatform();
3034 void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
3035 const std::string& config) const
3038 this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
3043 cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
3045 cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
3046 config, this, &dagChecker),
3050 static void processILibs(const std::string& config,
3051 cmGeneratorTarget const* headTarget,
3052 cmLinkItem const& item, cmGlobalGenerator* gg,
3053 std::vector<cmGeneratorTarget const*>& tgts,
3054 std::set<cmGeneratorTarget const*>& emitted)
3056 if (item.Target && emitted.insert(item.Target).second) {
3057 tgts.push_back(item.Target);
3058 if (cmLinkInterfaceLibraries const* iface =
3059 item.Target->GetLinkInterfaceLibraries(config, headTarget,
3060 LinkInterfaceFor::Usage)) {
3061 for (cmLinkItem const& lib : iface->Libraries) {
3062 processILibs(config, headTarget, lib, gg, tgts, emitted);
3068 const std::vector<const cmGeneratorTarget*>&
3069 cmGeneratorTarget::GetLinkImplementationClosure(
3070 const std::string& config) const
3072 // There is no link implementation for targets that cannot compile sources.
3073 if (!this->CanCompileSources()) {
3074 static std::vector<const cmGeneratorTarget*> const empty;
3078 LinkImplClosure& tgts = this->LinkImplClosureMap[config];
3081 std::set<cmGeneratorTarget const*> emitted;
3083 cmLinkImplementationLibraries const* impl =
3084 this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Usage);
3087 for (cmLinkImplItem const& lib : impl->Libraries) {
3088 processILibs(config, this, lib,
3089 this->LocalGenerator->GetGlobalGenerator(), tgts, emitted);
3095 class cmTargetTraceDependencies
3098 cmTargetTraceDependencies(cmGeneratorTarget* target);
3102 cmGeneratorTarget* GeneratorTarget;
3103 cmMakefile* Makefile;
3104 cmLocalGenerator* LocalGenerator;
3105 cmGlobalGenerator const* GlobalGenerator;
3106 using SourceEntry = cmGeneratorTarget::SourceEntry;
3107 SourceEntry* CurrentEntry;
3108 std::queue<cmSourceFile*> SourceQueue;
3109 std::set<cmSourceFile*> SourcesQueued;
3110 using NameMapType = std::map<std::string, cmSourcesWithOutput>;
3111 NameMapType NameMap;
3112 std::vector<std::string> NewSources;
3114 void QueueSource(cmSourceFile* sf);
3115 void FollowName(std::string const& name);
3116 void FollowNames(std::vector<std::string> const& names);
3117 bool IsUtility(std::string const& dep);
3118 void CheckCustomCommand(cmCustomCommand const& cc);
3119 void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
3122 cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
3123 : GeneratorTarget(target)
3126 this->Makefile = target->Target->GetMakefile();
3127 this->LocalGenerator = target->GetLocalGenerator();
3128 this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
3129 this->CurrentEntry = nullptr;
3131 // Queue all the source files already specified for the target.
3132 std::set<cmSourceFile*> emitted;
3133 std::vector<std::string> const& configs =
3134 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
3135 for (std::string const& c : configs) {
3136 std::vector<cmSourceFile*> sources;
3137 this->GeneratorTarget->GetSourceFiles(sources, c);
3138 for (cmSourceFile* sf : sources) {
3139 const std::set<cmGeneratorTarget const*> tgts =
3140 this->GlobalGenerator->GetFilenameTargetDepends(sf);
3141 if (cm::contains(tgts, this->GeneratorTarget)) {
3142 std::ostringstream e;
3143 e << "Evaluation output file\n \"" << sf->ResolveFullPath()
3144 << "\"\ndepends on the sources of a target it is used in. This "
3145 "is a dependency loop and is not allowed.";
3146 this->GeneratorTarget->LocalGenerator->IssueMessage(
3147 MessageType::FATAL_ERROR, e.str());
3150 if (emitted.insert(sf).second && this->SourcesQueued.insert(sf).second) {
3151 this->SourceQueue.push(sf);
3156 // Queue pre-build, pre-link, and post-build rule dependencies.
3157 this->CheckCustomCommands(this->GeneratorTarget->GetPreBuildCommands());
3158 this->CheckCustomCommands(this->GeneratorTarget->GetPreLinkCommands());
3159 this->CheckCustomCommands(this->GeneratorTarget->GetPostBuildCommands());
3162 void cmTargetTraceDependencies::Trace()
3164 // Process one dependency at a time until the queue is empty.
3165 while (!this->SourceQueue.empty()) {
3166 // Get the next source from the queue.
3167 cmSourceFile* sf = this->SourceQueue.front();
3168 this->SourceQueue.pop();
3169 this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
3171 // Queue dependencies added explicitly by the user.
3172 if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
3173 std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
3174 for (std::string& objDep : objDeps) {
3175 if (cmSystemTools::FileIsFullPath(objDep)) {
3176 objDep = cmSystemTools::CollapseFullPath(objDep);
3179 this->FollowNames(objDeps);
3182 // Queue the source needed to generate this file, if any.
3183 this->FollowName(sf->ResolveFullPath());
3185 // Queue dependencies added programmatically by commands.
3186 this->FollowNames(sf->GetDepends());
3188 // Queue custom command dependencies.
3189 if (cmCustomCommand const* cc = sf->GetCustomCommand()) {
3190 this->CheckCustomCommand(*cc);
3193 this->CurrentEntry = nullptr;
3195 this->GeneratorTarget->AddTracedSources(this->NewSources);
3198 void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
3200 if (this->SourcesQueued.insert(sf).second) {
3201 this->SourceQueue.push(sf);
3203 // Make sure this file is in the target at the end.
3204 this->NewSources.push_back(sf->ResolveFullPath());
3208 void cmTargetTraceDependencies::FollowName(std::string const& name)
3210 // Use lower bound with key comparison to not repeat the search for the
3211 // insert position if the name could not be found (which is the common case).
3212 auto i = this->NameMap.lower_bound(name);
3213 if (i == this->NameMap.end() || i->first != name) {
3214 // Check if we know how to generate this file.
3215 cmSourcesWithOutput sources =
3216 this->LocalGenerator->GetSourcesWithOutput(name);
3217 // If we failed to find a target or source and we have a relative path, it
3218 // might be a valid source if made relative to the current binary
3220 if (!sources.Target && !sources.Source &&
3221 !cmSystemTools::FileIsFullPath(name)) {
3223 cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
3224 fullname = cmSystemTools::CollapseFullPath(
3225 fullname, this->Makefile->GetHomeOutputDirectory());
3226 sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
3228 i = this->NameMap.emplace_hint(i, name, sources);
3230 if (cmTarget* t = i->second.Target) {
3231 // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
3232 // POST_BUILD command.
3233 this->GeneratorTarget->Target->AddUtility(t->GetName(), false);
3235 if (cmSourceFile* sf = i->second.Source) {
3236 // For now only follow the dependency if the source file is not a
3237 // byproduct. Semantics of byproducts in a non-Ninja context will have to
3238 // be defined first.
3239 if (!i->second.SourceIsByproduct) {
3240 // Record the dependency we just followed.
3241 if (this->CurrentEntry) {
3242 this->CurrentEntry->Depends.push_back(sf);
3244 this->QueueSource(sf);
3249 void cmTargetTraceDependencies::FollowNames(
3250 std::vector<std::string> const& names)
3252 for (std::string const& name : names) {
3253 this->FollowName(name);
3257 bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
3259 // Dependencies on targets (utilities) are supposed to be named by
3260 // just the target name. However for compatibility we support
3261 // naming the output file generated by the target (assuming there is
3262 // no output-name property which old code would not have set). In
3263 // that case the target name will be the file basename of the
3265 std::string util = cmSystemTools::GetFilenameName(dep);
3266 if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
3267 util = cmSystemTools::GetFilenameWithoutLastExtension(util);
3270 // Check for a target with this name.
3271 if (cmGeneratorTarget* t =
3272 this->GeneratorTarget->GetLocalGenerator()->FindGeneratorTargetToUse(
3274 // If we find the target and the dep was given as a full path,
3275 // then make sure it was not a full path to something else, and
3276 // the fact that the name matched a target was just a coincidence.
3277 if (cmSystemTools::FileIsFullPath(dep)) {
3278 if (t->GetType() >= cmStateEnums::EXECUTABLE &&
3279 t->GetType() <= cmStateEnums::MODULE_LIBRARY) {
3280 // This is really only for compatibility so we do not need to
3281 // worry about configuration names and output names.
3282 std::string tLocation = t->GetLocationForBuild();
3283 tLocation = cmSystemTools::GetFilenamePath(tLocation);
3284 std::string depLocation = cmSystemTools::GetFilenamePath(dep);
3285 depLocation = cmSystemTools::CollapseFullPath(depLocation);
3286 tLocation = cmSystemTools::CollapseFullPath(tLocation);
3287 if (depLocation == tLocation) {
3288 this->GeneratorTarget->Target->AddUtility(util, false);
3293 // The original name of the dependency was not a full path. It
3294 // must name a target, so add the target-level dependency.
3295 this->GeneratorTarget->Target->AddUtility(util, true);
3300 // The dependency does not name a target built in this project.
3304 void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
3306 // Collect dependencies referenced by all configurations.
3307 std::set<std::string> depends;
3308 for (std::string const& config :
3309 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
3310 for (cmCustomCommandGenerator const& ccg :
3311 this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) {
3312 // Collect target-level dependencies referenced in command lines.
3313 for (auto const& util : ccg.GetUtilities()) {
3314 this->GeneratorTarget->Target->AddUtility(util);
3317 // Collect file-level dependencies referenced in DEPENDS.
3318 depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
3322 // Queue file-level dependencies.
3323 for (std::string const& dep : depends) {
3324 if (!this->IsUtility(dep)) {
3325 // The dependency does not name a target and may be a file we
3326 // know how to generate. Queue it.
3327 this->FollowName(dep);
3332 void cmTargetTraceDependencies::CheckCustomCommands(
3333 const std::vector<cmCustomCommand>& commands)
3335 for (cmCustomCommand const& command : commands) {
3336 this->CheckCustomCommand(command);
3340 void cmGeneratorTarget::TraceDependencies()
3342 // CMake-generated targets have no dependencies to trace. Normally tracing
3343 // would find nothing anyway, but when building CMake itself the "install"
3344 // target command ends up referencing the "cmake" target but we do not
3345 // really want the dependency because "install" depend on "all" anyway.
3346 if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
3350 // Use a helper object to trace the dependencies.
3351 cmTargetTraceDependencies tracer(this);
3355 std::string cmGeneratorTarget::GetCompilePDBDirectory(
3356 const std::string& config) const
3358 if (CompileInfo const* info = this->GetCompileInfo(config)) {
3359 return info->CompilePdbDir;
3364 void cmGeneratorTarget::GetAppleArchs(const std::string& config,
3365 std::vector<std::string>& archVec) const
3367 if (!this->Makefile->IsOn("APPLE")) {
3370 cmValue archs = nullptr;
3371 if (!config.empty()) {
3372 std::string defVarName =
3373 cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
3374 archs = this->GetProperty(defVarName);
3377 archs = this->GetProperty("OSX_ARCHITECTURES");
3380 cmExpandList(*archs, archVec);
3382 if (archVec.empty()) {
3383 this->Makefile->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", archVec);
3387 void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
3388 cmSourceFile const& sf) const
3390 cmValue lang = sf.GetProperty("LANGUAGE");
3395 switch (this->GetPolicyStatusCMP0119()) {
3396 case cmPolicies::WARN:
3398 case cmPolicies::OLD:
3399 // The OLD behavior is to not add explicit language flags.
3401 case cmPolicies::REQUIRED_ALWAYS:
3402 case cmPolicies::REQUIRED_IF_USED:
3403 case cmPolicies::NEW:
3404 // The NEW behavior is to add explicit language flags.
3408 this->LocalGenerator->AppendFeatureOptions(flags, *lang,
3409 "EXPLICIT_LANGUAGE");
3412 void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
3414 std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES");
3416 if (property.empty()) {
3417 switch (this->GetPolicyStatusCMP0104()) {
3418 case cmPolicies::WARN:
3419 if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
3420 this->Makefile->IssueMessage(
3421 MessageType::AUTHOR_WARNING,
3422 cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
3423 "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3427 case cmPolicies::OLD:
3430 this->Makefile->IssueMessage(
3431 MessageType::FATAL_ERROR,
3432 "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3437 // If CUDA_ARCHITECTURES is false we don't add any architectures.
3438 if (cmIsOff(property)) {
3442 std::string const& compiler =
3443 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3445 // Check for special modes: `all`, `all-major`.
3446 if (property == "all" || property == "all-major") {
3447 if (compiler == "NVIDIA" &&
3448 cmSystemTools::VersionCompare(
3449 cmSystemTools::OP_GREATER_EQUAL,
3450 this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"),
3452 flags = cmStrCat(flags, " -arch=", property);
3455 if (property == "all") {
3457 *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL");
3458 } else if (property == "all-major") {
3460 *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR");
3462 } else if (property == "native") {
3464 this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_NATIVE");
3465 if (native.IsEmpty()) {
3466 this->Makefile->IssueMessage(
3467 MessageType::FATAL_ERROR,
3468 "CUDA_ARCHITECTURES is set to \"native\", but no GPU was detected.");
3470 if (compiler == "NVIDIA" &&
3471 cmSystemTools::VersionCompare(
3472 cmSystemTools::OP_GREATER_EQUAL,
3473 this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"),
3475 flags = cmStrCat(flags, " -arch=", property);
3481 struct CudaArchitecture
3485 bool virtual_{ true };
3487 std::vector<CudaArchitecture> architectures;
3490 std::vector<std::string> options;
3491 cmExpandList(property, options);
3493 for (std::string& option : options) {
3494 CudaArchitecture architecture;
3496 // Architecture name is up to the first specifier.
3497 std::size_t pos = option.find_first_of('-');
3498 architecture.name = option.substr(0, pos);
3500 if (pos != std::string::npos) {
3501 cm::string_view specifier{ option.c_str() + pos + 1,
3502 option.length() - pos - 1 };
3504 if (specifier == "real") {
3505 architecture.real = true;
3506 architecture.virtual_ = false;
3507 } else if (specifier == "virtual") {
3508 architecture.real = false;
3509 architecture.virtual_ = true;
3511 this->Makefile->IssueMessage(
3512 MessageType::FATAL_ERROR,
3513 "Unknown CUDA architecture specifier \"" + std::string(specifier) +
3518 architectures.emplace_back(architecture);
3522 if (compiler == "NVIDIA") {
3523 for (CudaArchitecture& architecture : architectures) {
3525 " --generate-code=arch=compute_" + architecture.name + ",code=[";
3527 if (architecture.virtual_) {
3528 flags += "compute_" + architecture.name;
3530 if (architecture.real) {
3535 if (architecture.real) {
3536 flags += "sm_" + architecture.name;
3541 } else if (compiler == "Clang") {
3542 for (CudaArchitecture& architecture : architectures) {
3543 flags += " --cuda-gpu-arch=sm_" + architecture.name;
3545 if (!architecture.real) {
3546 this->Makefile->IssueMessage(
3547 MessageType::WARNING,
3548 "Clang doesn't support disabling CUDA real code generation.");
3551 if (!architecture.virtual_) {
3552 flags += " --no-cuda-include-ptx=sm_" + architecture.name;
3558 void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const
3560 const std::string& property = this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
3562 // If ISPC_TARGET is false we don't add any architectures.
3563 if (cmIsOff(property)) {
3567 std::string const& compiler =
3568 this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
3570 if (compiler == "Intel") {
3571 std::vector<std::string> targets;
3572 cmExpandList(property, targets);
3573 if (!targets.empty()) {
3574 flags += cmStrCat(" --target=", cmWrap("", targets, "", ","));
3579 void cmGeneratorTarget::AddHIPArchitectureFlags(std::string& flags) const
3581 const std::string& property = this->GetSafeProperty("HIP_ARCHITECTURES");
3583 if (property.empty()) {
3584 this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
3585 "HIP_ARCHITECTURES is empty for target \"" +
3586 this->GetName() + "\".");
3589 // If HIP_ARCHITECTURES is false we don't add any architectures.
3590 if (cmIsOff(property)) {
3594 std::vector<std::string> options;
3595 cmExpandList(property, options);
3597 for (std::string& option : options) {
3598 flags += " --offload-arch=" + option;
3602 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
3604 std::string const& compiler =
3605 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3607 if (compiler == "Clang") {
3608 // Pass CUDA toolkit explicitly to Clang.
3609 // Clang's searching for the system CUDA toolkit isn't very good and it's
3610 // expected the user will explicitly pass the toolkit path.
3611 // This also avoids Clang having to search for the toolkit on every
3613 std::string toolkitRoot =
3614 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
3616 if (!toolkitRoot.empty()) {
3617 flags += " --cuda-path=" +
3618 this->LocalGenerator->ConvertToOutputFormat(toolkitRoot,
3619 cmOutputConverter::SHELL);
3624 //----------------------------------------------------------------------------
3625 std::string cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
3626 std::string const& var, std::string const& lang,
3627 std::string const& config) const
3629 if (this->IsIPOEnabled(lang, config)) {
3630 std::string varIPO = var + "_IPO";
3631 if (this->Makefile->IsDefinitionSet(varIPO)) {
3639 //----------------------------------------------------------------------------
3640 std::string cmGeneratorTarget::GetCreateRuleVariable(
3641 std::string const& lang, std::string const& config) const
3643 switch (this->GetType()) {
3644 case cmStateEnums::STATIC_LIBRARY: {
3645 std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
3646 return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
3648 case cmStateEnums::SHARED_LIBRARY:
3649 return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
3650 case cmStateEnums::MODULE_LIBRARY:
3651 return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
3652 case cmStateEnums::EXECUTABLE:
3653 if (this->IsExecutableWithExports()) {
3654 std::string linkExeWithExports =
3655 "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
3656 if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
3657 return linkExeWithExports;
3660 return "CMAKE_" + lang + "_LINK_EXECUTABLE";
3668 void processIncludeDirectories(cmGeneratorTarget const* tgt,
3669 EvaluatedTargetPropertyEntries& entries,
3670 std::vector<BT<std::string>>& includes,
3671 std::unordered_set<std::string>& uniqueIncludes,
3674 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
3675 cmLinkImplItem const& item = entry.LinkImplItem;
3676 std::string const& targetName = item.AsStr();
3677 bool const fromImported = item.Target && item.Target->IsImported();
3678 bool const checkCMP0027 = item.CheckCMP0027;
3680 std::string usedIncludes;
3681 for (std::string& entryInclude : entry.Values) {
3682 if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
3683 std::ostringstream e;
3684 MessageType messageType = MessageType::FATAL_ERROR;
3686 switch (tgt->GetPolicyStatusCMP0027()) {
3687 case cmPolicies::WARN:
3688 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
3690 case cmPolicies::OLD:
3691 messageType = MessageType::AUTHOR_WARNING;
3693 case cmPolicies::REQUIRED_ALWAYS:
3694 case cmPolicies::REQUIRED_IF_USED:
3695 case cmPolicies::NEW:
3699 /* clang-format off */
3700 e << "Imported target \"" << targetName << "\" includes "
3701 "non-existent path\n \"" << entryInclude << "\"\nin its "
3702 "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
3703 "* The path was deleted, renamed, or moved to another "
3705 "* An install or uninstall procedure did not complete "
3707 "* The installation package was faulty and references files it "
3708 "does not provide.\n";
3709 /* clang-format on */
3710 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3714 if (!cmSystemTools::FileIsFullPath(entryInclude)) {
3715 std::ostringstream e;
3716 bool noMessage = false;
3717 MessageType messageType = MessageType::FATAL_ERROR;
3718 if (!targetName.empty()) {
3719 /* clang-format off */
3720 e << "Target \"" << targetName << "\" contains relative "
3721 "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
3722 " \"" << entryInclude << "\"";
3723 /* clang-format on */
3725 switch (tgt->GetPolicyStatusCMP0021()) {
3726 case cmPolicies::WARN: {
3727 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
3728 messageType = MessageType::AUTHOR_WARNING;
3730 case cmPolicies::OLD:
3733 case cmPolicies::REQUIRED_IF_USED:
3734 case cmPolicies::REQUIRED_ALWAYS:
3735 case cmPolicies::NEW:
3736 // Issue the fatal message.
3739 e << "Found relative path while evaluating include directories of "
3741 << tgt->GetName() << "\":\n \"" << entryInclude << "\"\n";
3744 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3745 if (messageType == MessageType::FATAL_ERROR) {
3751 if (!cmIsOff(entryInclude)) {
3752 cmSystemTools::ConvertToUnixSlashes(entryInclude);
3755 if (uniqueIncludes.insert(entryInclude).second) {
3756 includes.emplace_back(entryInclude, entry.Backtrace);
3757 if (debugIncludes) {
3758 usedIncludes += " * " + entryInclude + "\n";
3762 if (!usedIncludes.empty()) {
3763 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3765 std::string("Used includes for target ") + tgt->GetName() + ":\n" +
3773 std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
3774 const std::string& config, const std::string& lang) const
3776 std::vector<BT<std::string>> includes;
3777 std::unordered_set<std::string> uniqueIncludes;
3779 cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
3782 std::vector<std::string> debugProperties;
3783 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3786 bool debugIncludes = !this->DebugIncludesDone &&
3787 cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
3789 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3790 this->DebugIncludesDone = true;
3793 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3794 this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
3796 if (lang == "Swift") {
3797 AddLangSpecificImplicitIncludeDirectories(
3798 this, lang, config, "Swift_MODULE_DIRECTORY",
3799 IncludeDirectoryFallBack::BINARY, entries);
3802 if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
3804 const std::string propertyName = "ISPC_HEADER_DIRECTORY";
3806 // If this target has ISPC sources make sure to add the header
3807 // directory to other compilation units
3808 if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
3809 if (cmValue val = this->GetProperty(propertyName)) {
3810 includes.emplace_back(*val);
3812 includes.emplace_back(this->GetObjectDirectory(config));
3816 AddLangSpecificImplicitIncludeDirectories(
3817 this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
3821 AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
3822 &dagChecker, entries, IncludeRuntimeInterface::Yes);
3824 if (this->Makefile->IsOn("APPLE")) {
3825 if (cmLinkImplementationLibraries const* impl =
3826 this->GetLinkImplementationLibraries(config,
3827 LinkInterfaceFor::Usage)) {
3828 for (cmLinkImplItem const& lib : impl->Libraries) {
3829 std::string libDir = cmSystemTools::CollapseFullPath(
3830 lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
3832 static cmsys::RegularExpression frameworkCheck(
3833 "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
3834 if (!frameworkCheck.find(libDir)) {
3838 libDir = frameworkCheck.match(1);
3840 EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace());
3841 ee.Values.emplace_back(std::move(libDir));
3842 entries.Entries.emplace_back(std::move(ee));
3847 processIncludeDirectories(this, entries, includes, uniqueIncludes,
3853 enum class OptionsParse
3860 const auto DL_BEGIN = "<DEVICE_LINK>"_s;
3861 const auto DL_END = "</DEVICE_LINK>"_s;
3863 void processOptions(cmGeneratorTarget const* tgt,
3864 EvaluatedTargetPropertyEntries const& entries,
3865 std::vector<BT<std::string>>& options,
3866 std::unordered_set<std::string>& uniqueOptions,
3867 bool debugOptions, const char* logName, OptionsParse parse,
3868 bool processDeviceOptions = false)
3870 bool splitOption = !processDeviceOptions;
3871 for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
3872 std::string usedOptions;
3873 for (std::string const& opt : entry.Values) {
3874 if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
3875 options.emplace_back(opt, entry.Backtrace);
3876 splitOption = opt == DL_BEGIN;
3880 if (uniqueOptions.insert(opt).second) {
3881 if (parse == OptionsParse::Shell &&
3882 cmHasLiteralPrefix(opt, "SHELL:")) {
3884 std::vector<std::string> tmp;
3885 cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
3886 for (std::string& o : tmp) {
3887 options.emplace_back(std::move(o), entry.Backtrace);
3890 options.emplace_back(std::string(opt.c_str() + 6),
3894 options.emplace_back(opt, entry.Backtrace);
3897 usedOptions += " * " + opt + "\n";
3901 if (!usedOptions.empty()) {
3902 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3904 std::string("Used ") + logName + std::string(" for target ") +
3905 tgt->GetName() + ":\n" + usedOptions,
3911 std::vector<BT<std::string>> wrapOptions(
3912 std::vector<std::string>& options, const cmListFileBacktrace& bt,
3913 const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
3914 bool concatFlagAndArgs)
3916 std::vector<BT<std::string>> result;
3918 if (options.empty()) {
3922 if (wrapperFlag.empty()) {
3923 // nothing specified, insert elements as is
3924 result.reserve(options.size());
3925 for (std::string& o : options) {
3926 result.emplace_back(std::move(o), bt);
3931 for (std::vector<std::string>::size_type index = 0; index < options.size();
3933 if (cmHasLiteralPrefix(options[index], "LINKER:")) {
3934 // LINKER wrapper specified, insert elements as is
3935 result.emplace_back(std::move(options[index]), bt);
3938 if (cmHasLiteralPrefix(options[index], "-Wl,")) {
3939 // replace option by LINKER wrapper
3940 result.emplace_back(options[index].replace(0, 4, "LINKER:"), bt);
3943 if (cmHasLiteralPrefix(options[index], "-Xlinker=")) {
3944 // replace option by LINKER wrapper
3945 result.emplace_back(options[index].replace(0, 9, "LINKER:"), bt);
3948 if (options[index] == "-Xlinker") {
3949 // replace option by LINKER wrapper
3950 if (index + 1 < options.size()) {
3951 result.emplace_back("LINKER:" + options[++index], bt);
3953 result.emplace_back(std::move(options[index]), bt);
3958 // collect all options which must be transformed
3959 std::vector<std::string> opts;
3960 while (index < options.size()) {
3961 if (!cmHasLiteralPrefix(options[index], "LINKER:") &&
3962 !cmHasLiteralPrefix(options[index], "-Wl,") &&
3963 !cmHasLiteralPrefix(options[index], "-Xlinker")) {
3964 opts.emplace_back(std::move(options[index++]));
3974 if (!wrapperSep.empty()) {
3975 if (concatFlagAndArgs) {
3976 // insert flag elements except last one
3977 for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
3978 result.emplace_back(*i, bt);
3980 // concatenate last flag element and all list values
3982 result.emplace_back(wrapperFlag.back() + cmJoin(opts, wrapperSep), bt);
3984 for (std::string const& i : wrapperFlag) {
3985 result.emplace_back(i, bt);
3987 // concatenate all list values in one option
3988 result.emplace_back(cmJoin(opts, wrapperSep), bt);
3991 // prefix each element of list with wrapper
3992 if (concatFlagAndArgs) {
3993 std::transform(opts.begin(), opts.end(), opts.begin(),
3994 [&wrapperFlag](std::string const& o) -> std::string {
3995 return wrapperFlag.back() + o;
3998 for (std::string& o : opts) {
3999 for (auto i = wrapperFlag.begin(),
4000 e = concatFlagAndArgs ? wrapperFlag.end() - 1
4001 : wrapperFlag.end();
4003 result.emplace_back(*i, bt);
4005 result.emplace_back(std::move(o), bt);
4013 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
4014 const std::string& config,
4015 const std::string& language) const
4017 std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language);
4018 result.reserve(tmp.size());
4019 for (BT<std::string>& v : tmp) {
4020 result.emplace_back(std::move(v.Value));
4024 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
4025 std::string const& config, std::string const& language) const
4027 std::vector<BT<std::string>> result;
4028 std::unordered_set<std::string> uniqueOptions;
4030 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
4033 std::vector<std::string> debugProperties;
4034 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4037 bool debugOptions = !this->DebugCompileOptionsDone &&
4038 cm::contains(debugProperties, "COMPILE_OPTIONS");
4040 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4041 this->DebugCompileOptionsDone = true;
4044 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4045 this, config, language, &dagChecker, this->CompileOptionsEntries);
4047 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language,
4048 &dagChecker, entries, IncludeRuntimeInterface::Yes);
4050 processOptions(this, entries, result, uniqueOptions, debugOptions,
4051 "compile options", OptionsParse::Shell);
4056 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
4057 const std::string& config) const
4059 std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config);
4060 result.reserve(tmp.size());
4061 for (BT<std::string>& v : tmp) {
4062 result.emplace_back(std::move(v.Value));
4066 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
4067 std::string const& config) const
4069 std::vector<BT<std::string>> result;
4070 std::unordered_set<std::string> uniqueFeatures;
4072 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
4075 std::vector<std::string> debugProperties;
4076 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4079 bool debugFeatures = !this->DebugCompileFeaturesDone &&
4080 cm::contains(debugProperties, "COMPILE_FEATURES");
4082 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4083 this->DebugCompileFeaturesDone = true;
4086 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4087 this, config, std::string(), &dagChecker, this->CompileFeaturesEntries);
4089 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES",
4090 std::string(), &dagChecker, entries,
4091 IncludeRuntimeInterface::Yes);
4093 processOptions(this, entries, result, uniqueFeatures, debugFeatures,
4094 "compile features", OptionsParse::None);
4099 void cmGeneratorTarget::GetCompileDefinitions(
4100 std::vector<std::string>& result, const std::string& config,
4101 const std::string& language) const
4103 std::vector<BT<std::string>> tmp =
4104 this->GetCompileDefinitions(config, language);
4105 result.reserve(tmp.size());
4106 for (BT<std::string>& v : tmp) {
4107 result.emplace_back(std::move(v.Value));
4111 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
4112 std::string const& config, std::string const& language) const
4114 std::vector<BT<std::string>> list;
4115 std::unordered_set<std::string> uniqueOptions;
4117 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
4120 std::vector<std::string> debugProperties;
4121 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4124 bool debugDefines = !this->DebugCompileDefinitionsDone &&
4125 cm::contains(debugProperties, "COMPILE_DEFINITIONS");
4127 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4128 this->DebugCompileDefinitionsDone = true;
4131 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4132 this, config, language, &dagChecker, this->CompileDefinitionsEntries);
4134 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language,
4135 &dagChecker, entries, IncludeRuntimeInterface::Yes);
4137 if (!config.empty()) {
4138 std::string configPropName =
4139 "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
4140 cmValue configProp = this->GetProperty(configPropName);
4142 switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
4143 case cmPolicies::WARN: {
4144 this->LocalGenerator->IssueMessage(
4145 MessageType::AUTHOR_WARNING,
4146 cmPolicies::GetPolicyWarning(cmPolicies::CMP0043));
4149 case cmPolicies::OLD: {
4150 std::unique_ptr<TargetPropertyEntry> entry =
4151 CreateTargetPropertyEntry(*configProp);
4152 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4153 this, config, language, &dagChecker, *entry));
4155 case cmPolicies::NEW:
4156 case cmPolicies::REQUIRED_ALWAYS:
4157 case cmPolicies::REQUIRED_IF_USED:
4163 processOptions(this, entries, list, uniqueOptions, debugDefines,
4164 "compile definitions", OptionsParse::None);
4169 std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
4170 const std::string& config, const std::string& language) const
4172 std::unordered_set<std::string> uniqueOptions;
4174 cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
4177 std::vector<std::string> debugProperties;
4178 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4181 bool debugDefines = !this->DebugPrecompileHeadersDone &&
4182 std::find(debugProperties.begin(), debugProperties.end(),
4183 "PRECOMPILE_HEADERS") != debugProperties.end();
4185 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4186 this->DebugPrecompileHeadersDone = true;
4189 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4190 this, config, language, &dagChecker, this->PrecompileHeadersEntries);
4192 AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language,
4193 &dagChecker, entries, IncludeRuntimeInterface::Yes);
4195 std::vector<BT<std::string>> list;
4196 processOptions(this, entries, list, uniqueOptions, debugDefines,
4197 "precompile headers", OptionsParse::None);
4202 std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
4203 const std::string& language,
4204 const std::string& arch) const
4206 if (language != "C" && language != "CXX" && language != "OBJC" &&
4207 language != "OBJCXX") {
4208 return std::string();
4211 if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
4212 return std::string();
4214 const cmGeneratorTarget* generatorTarget = this;
4215 cmValue pchReuseFrom =
4216 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4218 const auto inserted =
4219 this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
4220 if (inserted.second) {
4221 const std::vector<BT<std::string>> headers =
4222 this->GetPrecompileHeaders(config, language);
4223 if (headers.empty() && !pchReuseFrom) {
4224 return std::string();
4226 std::string& filename = inserted.first->second;
4230 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4233 filename = cmStrCat(
4234 generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
4236 const std::map<std::string, std::string> languageToExtension = {
4239 { "OBJC", ".objc.h" },
4240 { "OBJCXX", ".objcxx.hxx" }
4244 cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
4246 if (this->GetGlobalGenerator()->IsMultiConfig()) {
4247 filename = cmStrCat(filename, "/", config);
4251 cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch),
4252 languageToExtension.at(language));
4254 const std::string filename_tmp = cmStrCat(filename, ".tmp");
4255 if (!pchReuseFrom) {
4256 cmValue pchPrologue =
4257 this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
4258 cmValue pchEpilogue =
4259 this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
4261 std::string firstHeaderOnDisk;
4263 cmGeneratedFileStream file(
4264 filename_tmp, false,
4265 this->GetGlobalGenerator()->GetMakefileEncoding());
4266 file << "/* generated by CMake */\n\n";
4268 file << *pchPrologue << "\n";
4270 if (this->GetGlobalGenerator()->IsXcode()) {
4271 file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4273 if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4274 file << "#ifdef __cplusplus\n";
4276 for (auto const& header_bt : headers) {
4277 if (header_bt.Value.empty()) {
4280 if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
4281 file << "#include " << header_bt.Value << "\n";
4283 file << "#include \"" << header_bt.Value << "\"\n";
4286 if (cmSystemTools::FileExists(header_bt.Value) &&
4287 firstHeaderOnDisk.empty()) {
4288 firstHeaderOnDisk = header_bt.Value;
4291 if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4292 file << "#endif // __cplusplus\n";
4294 if (this->GetGlobalGenerator()->IsXcode()) {
4295 file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4298 file << *pchEpilogue << "\n";
4302 if (!firstHeaderOnDisk.empty()) {
4303 cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
4306 cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
4309 return inserted.first->second;
4312 std::string cmGeneratorTarget::GetPchSource(const std::string& config,
4313 const std::string& language,
4314 const std::string& arch) const
4316 if (language != "C" && language != "CXX" && language != "OBJC" &&
4317 language != "OBJCXX") {
4318 return std::string();
4320 const auto inserted =
4321 this->PchSources.insert(std::make_pair(language + config + arch, ""));
4322 if (inserted.second) {
4323 const std::string pchHeader = this->GetPchHeader(config, language, arch);
4324 if (pchHeader.empty()) {
4325 return std::string();
4327 std::string& filename = inserted.first->second;
4329 const cmGeneratorTarget* generatorTarget = this;
4330 cmValue pchReuseFrom =
4331 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4334 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4338 cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(),
4339 "/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch");
4341 // For GCC the source extension will be transformed into .h[xx].gch
4342 if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
4343 const std::map<std::string, std::string> languageToExtension = {
4345 { "CXX", ".hxx.cxx" },
4346 { "OBJC", ".objc.h.m" },
4347 { "OBJCXX", ".objcxx.hxx.mm" }
4350 filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
4351 languageToExtension.at(language));
4353 const std::map<std::string, std::string> languageToExtension = {
4354 { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
4357 filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
4358 languageToExtension.at(language));
4361 const std::string filename_tmp = cmStrCat(filename, ".tmp");
4362 if (!pchReuseFrom) {
4364 cmGeneratedFileStream file(filename_tmp);
4365 file << "/* generated by CMake */\n";
4367 cmFileTimes::Copy(pchHeader, filename_tmp);
4368 cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
4371 return inserted.first->second;
4374 std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
4375 const std::string& language,
4376 const std::string& arch)
4378 if (language != "C" && language != "CXX" && language != "OBJC" &&
4379 language != "OBJCXX") {
4380 return std::string();
4382 const auto inserted =
4383 this->PchObjectFiles.insert(std::make_pair(language + config + arch, ""));
4384 if (inserted.second) {
4385 const std::string pchSource = this->GetPchSource(config, language, arch);
4386 if (pchSource.empty()) {
4387 return std::string();
4389 std::string& filename = inserted.first->second;
4391 auto* pchSf = this->Makefile->GetOrCreateSource(
4392 pchSource, false, cmSourceFileLocationKind::Known);
4394 filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
4395 if (this->GetGlobalGenerator()->IsMultiConfig()) {
4396 cmSystemTools::ReplaceString(
4397 filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
4400 return inserted.first->second;
4403 std::string cmGeneratorTarget::GetPchFile(const std::string& config,
4404 const std::string& language,
4405 const std::string& arch)
4407 const auto inserted =
4408 this->PchFiles.insert(std::make_pair(language + config + arch, ""));
4409 if (inserted.second) {
4410 std::string& pchFile = inserted.first->second;
4412 const std::string pchExtension =
4413 this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
4415 if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
4416 auto replaceExtension = [](const std::string& str,
4417 const std::string& ext) -> std::string {
4418 auto dot_pos = str.rfind('.');
4420 if (dot_pos != std::string::npos) {
4421 result = str.substr(0, dot_pos);
4427 cmGeneratorTarget* generatorTarget = this;
4428 cmValue pchReuseFrom =
4429 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4432 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
4435 const std::string pchFileObject =
4436 generatorTarget->GetPchFileObject(config, language, arch);
4437 if (!pchExtension.empty()) {
4438 pchFile = replaceExtension(pchFileObject, pchExtension);
4441 pchFile = this->GetPchHeader(config, language, arch);
4442 pchFile += pchExtension;
4445 return inserted.first->second;
4448 std::string cmGeneratorTarget::GetPchCreateCompileOptions(
4449 const std::string& config, const std::string& language,
4450 const std::string& arch)
4452 const auto inserted = this->PchCreateCompileOptions.insert(
4453 std::make_pair(language + config + arch, ""));
4454 if (inserted.second) {
4455 std::string& createOptionList = inserted.first->second;
4457 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4458 createOptionList = this->Makefile->GetSafeDefinition(
4459 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
4462 if (this->GetPropertyAsBool("PCH_INSTANTIATE_TEMPLATES")) {
4463 std::string varName = cmStrCat(
4464 "CMAKE_", language, "_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH");
4465 std::string instantiateOption =
4466 this->Makefile->GetSafeDefinition(varName);
4467 if (!instantiateOption.empty()) {
4468 createOptionList = cmStrCat(createOptionList, ";", instantiateOption);
4472 const std::string createOptVar =
4473 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
4475 createOptionList = cmStrCat(
4476 createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar));
4478 const std::string pchHeader = this->GetPchHeader(config, language, arch);
4479 const std::string pchFile = this->GetPchFile(config, language, arch);
4481 cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader);
4482 cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile);
4484 return inserted.first->second;
4487 std::string cmGeneratorTarget::GetPchUseCompileOptions(
4488 const std::string& config, const std::string& language,
4489 const std::string& arch)
4491 const auto inserted = this->PchUseCompileOptions.insert(
4492 std::make_pair(language + config + arch, ""));
4493 if (inserted.second) {
4494 std::string& useOptionList = inserted.first->second;
4496 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4497 useOptionList = this->Makefile->GetSafeDefinition(
4498 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
4501 const std::string useOptVar =
4502 cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH");
4504 std::string const& useOptionListProperty =
4505 this->GetSafeProperty(useOptVar);
4507 useOptionList = cmStrCat(
4509 useOptionListProperty.empty()
4510 ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar))
4511 : useOptionListProperty);
4513 const std::string pchHeader = this->GetPchHeader(config, language, arch);
4514 const std::string pchFile = this->GetPchFile(config, language, arch);
4516 cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
4517 cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
4519 return inserted.first->second;
4522 void cmGeneratorTarget::AddSourceFileToUnityBatch(
4523 const std::string& sourceFilename)
4525 this->UnityBatchedSourceFiles.insert(sourceFilename);
4528 bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
4529 const std::string& sourceFilename) const
4531 if (!this->GetPropertyAsBool("UNITY_BUILD")) {
4535 return this->UnityBatchedSourceFiles.find(sourceFilename) !=
4536 this->UnityBatchedSourceFiles.end();
4539 void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
4540 const std::string& config,
4541 const std::string& language) const
4543 if (this->IsDeviceLink() &&
4544 this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
4545 // link options are not propagated to the device link step
4549 std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
4550 result.reserve(tmp.size());
4551 for (BT<std::string>& v : tmp) {
4552 result.emplace_back(std::move(v.Value));
4556 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
4557 std::string const& config, std::string const& language) const
4559 std::vector<BT<std::string>> result;
4560 std::unordered_set<std::string> uniqueOptions;
4562 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
4565 std::vector<std::string> debugProperties;
4566 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4569 bool debugOptions = !this->DebugLinkOptionsDone &&
4570 cm::contains(debugProperties, "LINK_OPTIONS");
4572 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4573 this->DebugLinkOptionsDone = true;
4576 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4577 this, config, language, &dagChecker, this->LinkOptionsEntries);
4579 AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
4580 &dagChecker, entries, IncludeRuntimeInterface::Yes,
4581 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4582 ? LinkInterfaceFor::Link
4583 : LinkInterfaceFor::Usage);
4585 processOptions(this, entries, result, uniqueOptions, debugOptions,
4586 "link options", OptionsParse::Shell, this->IsDeviceLink());
4588 if (this->IsDeviceLink()) {
4589 // wrap host link options
4590 const std::string wrapper(this->Makefile->GetSafeDefinition(
4591 "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
4592 std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4593 const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4594 "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
4595 bool concatFlagAndArgs = true;
4596 if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4597 concatFlagAndArgs = false;
4598 wrapperFlag.pop_back();
4601 auto it = result.begin();
4602 while (it != result.end()) {
4603 if (it->Value == DL_BEGIN) {
4604 // device link options, no treatment
4605 it = result.erase(it);
4606 it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
4607 return item.Value == DL_END;
4609 if (it != result.end()) {
4610 it = result.erase(it);
4613 // host link options must be wrapped
4614 std::vector<std::string> options;
4615 cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
4616 auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
4617 wrapperSep, concatFlagAndArgs);
4618 it = result.erase(it);
4619 // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
4620 // C++11 standard: 'std::vector::insert()' do not returns an iterator,
4621 // so need to recompute the iterator after insertion.
4622 if (it == result.end()) {
4623 cm::append(result, hostOptions);
4626 auto index = it - result.begin();
4627 result.insert(it, hostOptions.begin(), hostOptions.end());
4628 it = result.begin() + index + hostOptions.size();
4634 // Last step: replace "LINKER:" prefixed elements by
4635 // actual linker wrapper
4636 return this->ResolveLinkerWrapper(result, language);
4639 std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper(
4640 std::vector<BT<std::string>>& result, const std::string& language,
4641 bool joinItems) const
4643 // replace "LINKER:" prefixed elements by actual linker wrapper
4644 const std::string wrapper(this->Makefile->GetSafeDefinition(
4645 "CMAKE_" + language +
4646 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
4647 : "_LINKER_WRAPPER_FLAG")));
4648 std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4649 const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4650 "CMAKE_" + language +
4651 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
4652 : "_LINKER_WRAPPER_FLAG_SEP")));
4653 bool concatFlagAndArgs = true;
4654 if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4655 concatFlagAndArgs = false;
4656 wrapperFlag.pop_back();
4659 const std::string LINKER{ "LINKER:" };
4660 const std::string SHELL{ "SHELL:" };
4661 const std::string LINKER_SHELL = LINKER + SHELL;
4663 std::vector<BT<std::string>>::iterator entry;
4664 while ((entry = std::find_if(result.begin(), result.end(),
4665 [&LINKER](BT<std::string> const& item) -> bool {
4666 return item.Value.compare(0, LINKER.length(),
4668 })) != result.end()) {
4669 std::string value = std::move(entry->Value);
4670 cmListFileBacktrace bt = std::move(entry->Backtrace);
4671 entry = result.erase(entry);
4673 std::vector<std::string> linkerOptions;
4674 if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
4675 cmSystemTools::ParseUnixCommandLine(
4676 value.c_str() + LINKER_SHELL.length(), linkerOptions);
4678 linkerOptions = cmTokenize(value.substr(LINKER.length()), ",");
4681 if (linkerOptions.empty() ||
4682 (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
4686 // for now, raise an error if prefix SHELL: is part of arguments
4687 if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
4688 [&SHELL](const std::string& item) -> bool {
4689 return item.find(SHELL) != std::string::npos;
4690 }) != linkerOptions.end()) {
4691 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
4692 MessageType::FATAL_ERROR,
4693 "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
4694 this->GetBacktrace());
4698 std::vector<BT<std::string>> options = wrapOptions(
4699 linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
4701 result.insert(entry,
4702 cmJoin(cmRange<decltype(options.cbegin())>(
4703 options.cbegin(), options.cend()),
4706 result.insert(entry, options.begin(), options.end());
4712 void cmGeneratorTarget::GetStaticLibraryLinkOptions(
4713 std::vector<std::string>& result, const std::string& config,
4714 const std::string& language) const
4716 std::vector<BT<std::string>> tmp =
4717 this->GetStaticLibraryLinkOptions(config, language);
4718 result.reserve(tmp.size());
4719 for (BT<std::string>& v : tmp) {
4720 result.emplace_back(std::move(v.Value));
4724 std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
4725 std::string const& config, std::string const& language) const
4727 std::vector<BT<std::string>> result;
4728 std::unordered_set<std::string> uniqueOptions;
4730 cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
4733 EvaluatedTargetPropertyEntries entries;
4734 if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
4735 std::vector<std::string> options = cmExpandedList(*linkOptions);
4736 for (const auto& option : options) {
4737 std::unique_ptr<TargetPropertyEntry> entry =
4738 CreateTargetPropertyEntry(option);
4739 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4740 this, config, language, &dagChecker, *entry));
4743 processOptions(this, entries, result, uniqueOptions, false,
4744 "static library link options", OptionsParse::Shell);
4750 void processLinkDirectories(cmGeneratorTarget const* tgt,
4751 EvaluatedTargetPropertyEntries& entries,
4752 std::vector<BT<std::string>>& directories,
4753 std::unordered_set<std::string>& uniqueDirectories,
4754 bool debugDirectories)
4756 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
4757 cmLinkImplItem const& item = entry.LinkImplItem;
4758 std::string const& targetName = item.AsStr();
4760 std::string usedDirectories;
4761 for (std::string& entryDirectory : entry.Values) {
4762 if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
4763 std::ostringstream e;
4764 bool noMessage = false;
4765 MessageType messageType = MessageType::FATAL_ERROR;
4766 if (!targetName.empty()) {
4767 /* clang-format off */
4768 e << "Target \"" << targetName << "\" contains relative "
4769 "path in its INTERFACE_LINK_DIRECTORIES:\n"
4770 " \"" << entryDirectory << "\"";
4771 /* clang-format on */
4773 switch (tgt->GetPolicyStatusCMP0081()) {
4774 case cmPolicies::WARN: {
4775 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
4776 messageType = MessageType::AUTHOR_WARNING;
4778 case cmPolicies::OLD:
4781 case cmPolicies::REQUIRED_IF_USED:
4782 case cmPolicies::REQUIRED_ALWAYS:
4783 case cmPolicies::NEW:
4784 // Issue the fatal message.
4787 e << "Found relative path while evaluating link directories of "
4789 << tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
4792 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
4793 if (messageType == MessageType::FATAL_ERROR) {
4799 // Sanitize the path the same way the link_directories command does
4800 // in case projects set the LINK_DIRECTORIES property directly.
4801 cmSystemTools::ConvertToUnixSlashes(entryDirectory);
4802 if (uniqueDirectories.insert(entryDirectory).second) {
4803 directories.emplace_back(entryDirectory, entry.Backtrace);
4804 if (debugDirectories) {
4805 usedDirectories += " * " + entryDirectory + "\n";
4809 if (!usedDirectories.empty()) {
4810 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
4812 std::string("Used link directories for target ") + tgt->GetName() +
4813 ":\n" + usedDirectories,
4820 void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
4821 const std::string& config,
4822 const std::string& language) const
4824 std::vector<BT<std::string>> tmp =
4825 this->GetLinkDirectories(config, language);
4826 result.reserve(tmp.size());
4827 for (BT<std::string>& v : tmp) {
4828 result.emplace_back(std::move(v.Value));
4832 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
4833 std::string const& config, std::string const& language) const
4835 std::vector<BT<std::string>> result;
4836 std::unordered_set<std::string> uniqueDirectories;
4838 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
4841 std::vector<std::string> debugProperties;
4842 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4845 bool debugDirectories = !this->DebugLinkDirectoriesDone &&
4846 cm::contains(debugProperties, "LINK_DIRECTORIES");
4848 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4849 this->DebugLinkDirectoriesDone = true;
4852 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4853 this, config, language, &dagChecker, this->LinkDirectoriesEntries);
4855 AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
4856 &dagChecker, entries, IncludeRuntimeInterface::Yes,
4857 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4858 ? LinkInterfaceFor::Link
4859 : LinkInterfaceFor::Usage);
4861 processLinkDirectories(this, entries, result, uniqueDirectories,
4867 void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
4868 const std::string& config,
4869 const std::string& language) const
4871 std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language);
4872 result.reserve(tmp.size());
4873 for (BT<std::string>& v : tmp) {
4874 result.emplace_back(std::move(v.Value));
4878 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
4879 std::string const& config, std::string const& language) const
4881 std::vector<BT<std::string>> result;
4882 std::unordered_set<std::string> uniqueOptions;
4883 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
4886 EvaluatedTargetPropertyEntries entries;
4887 if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
4888 std::vector<std::string> depends = cmExpandedList(*linkDepends);
4889 for (const auto& depend : depends) {
4890 std::unique_ptr<TargetPropertyEntry> entry =
4891 CreateTargetPropertyEntry(depend);
4892 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4893 this, config, language, &dagChecker, *entry));
4896 AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
4897 &dagChecker, entries, IncludeRuntimeInterface::Yes,
4898 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4899 ? LinkInterfaceFor::Link
4900 : LinkInterfaceFor::Usage);
4902 processOptions(this, entries, result, uniqueOptions, false, "link depends",
4903 OptionsParse::None);
4908 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
4910 if (this->IsImported()) {
4913 cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
4916 cmGeneratorTarget::Names targetNames;
4917 if (this->GetType() == cmStateEnums::EXECUTABLE) {
4918 targetNames = this->GetExecutableNames(config);
4919 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
4920 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4921 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
4922 targetNames = this->GetLibraryNames(config);
4927 // Get the directory.
4929 this->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
4933 if (!targetNames.Output.empty()) {
4934 f = cmStrCat(dir, '/', targetNames.Output);
4935 gg->AddToManifest(f);
4937 if (!targetNames.SharedObject.empty()) {
4938 f = cmStrCat(dir, '/', targetNames.SharedObject);
4939 gg->AddToManifest(f);
4941 if (!targetNames.Real.empty()) {
4942 f = cmStrCat(dir, '/', targetNames.Real);
4943 gg->AddToManifest(f);
4945 if (!targetNames.PDB.empty()) {
4946 f = cmStrCat(dir, '/', targetNames.PDB);
4947 gg->AddToManifest(f);
4949 if (!targetNames.ImportLibrary.empty()) {
4951 cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact),
4952 '/', targetNames.ImportLibrary);
4953 gg->AddToManifest(f);
4957 bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
4959 // Compute the language standard based on the compile features.
4960 cmStandardLevelResolver standardResolver(this->Makefile);
4961 std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
4962 for (BT<std::string> const& f : features) {
4964 if (!standardResolver.CompileFeatureKnown(this->Target->GetName(), f.Value,
4969 std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
4970 cmValue currentLanguageStandard = this->GetLanguageStandard(lang, config);
4972 std::string newRequiredStandard;
4973 if (!standardResolver.GetNewRequiredStandard(
4974 this->Target->GetName(), f.Value, currentLanguageStandard,
4975 newRequiredStandard)) {
4979 if (!newRequiredStandard.empty()) {
4980 BTs<std::string>& languageStandardProperty =
4981 this->LanguageStandardMap[key];
4982 if (languageStandardProperty.Value != newRequiredStandard) {
4983 languageStandardProperty.Value = newRequiredStandard;
4984 languageStandardProperty.Backtraces.clear();
4986 languageStandardProperty.Backtraces.emplace_back(f.Backtrace);
4993 bool cmGeneratorTarget::ComputeCompileFeatures(
4994 std::string const& config, std::set<LanguagePair> const& languagePairs) const
4996 for (const auto& language : languagePairs) {
4997 BTs<std::string> const* generatorTargetLanguageStandard =
4998 this->GetLanguageStandardProperty(language.first, config);
4999 if (!generatorTargetLanguageStandard) {
5000 // If the standard isn't explicitly set we copy it over from the
5001 // specified paired language.
5003 cmStrCat(cmSystemTools::UpperCase(config), '-', language.first);
5004 BTs<std::string> const* standardToCopy =
5005 this->GetLanguageStandardProperty(language.second, config);
5006 if (standardToCopy) {
5007 this->LanguageStandardMap[key] = *standardToCopy;
5008 generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
5010 cmValue defaultStandard = this->Makefile->GetDefinition(
5011 cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
5012 if (defaultStandard) {
5013 this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
5014 generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
5018 // Custom updates for the CUDA standard.
5019 if (generatorTargetLanguageStandard != nullptr &&
5020 (language.first == "CUDA")) {
5021 if (generatorTargetLanguageStandard->Value == "98") {
5022 this->LanguageStandardMap[key].Value = "03";
5031 std::string cmGeneratorTarget::GetImportedLibName(
5032 std::string const& config) const
5034 if (cmGeneratorTarget::ImportInfo const* info =
5035 this->GetImportInfo(config)) {
5036 return info->LibName;
5038 return std::string();
5041 std::string cmGeneratorTarget::GetFullPath(const std::string& config,
5042 cmStateEnums::ArtifactType artifact,
5043 bool realname) const
5045 if (this->IsImported()) {
5046 return this->Target->ImportedGetFullPath(config, artifact);
5048 return this->NormalGetFullPath(config, artifact, realname);
5051 std::string cmGeneratorTarget::NormalGetFullPath(
5052 const std::string& config, cmStateEnums::ArtifactType artifact,
5053 bool realname) const
5055 std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
5056 if (this->IsAppBundleOnApple()) {
5058 cmStrCat(this->BuildBundleDirectory(fpath, config, FullLevel), '/');
5061 // Add the full name of the target.
5063 case cmStateEnums::RuntimeBinaryArtifact:
5065 fpath += this->NormalGetRealName(config);
5068 this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact);
5071 case cmStateEnums::ImportLibraryArtifact:
5072 fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
5078 std::string cmGeneratorTarget::NormalGetRealName(
5079 const std::string& config) const
5081 // This should not be called for imported targets.
5082 // TODO: Split cmTarget into a class hierarchy to get compile-time
5083 // enforcement of the limited imported target API.
5084 if (this->IsImported()) {
5085 std::string msg = cmStrCat("NormalGetRealName called on imported target: ",
5087 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5090 if (this->GetType() == cmStateEnums::EXECUTABLE) {
5091 // Compute the real name that will be built.
5092 return this->GetExecutableNames(config).Real;
5094 // Compute the real name that will be built.
5095 return this->GetLibraryNames(config).Real;
5098 cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
5099 const std::string& config) const
5101 cmGeneratorTarget::Names targetNames;
5103 // This should not be called for imported targets.
5104 // TODO: Split cmTarget into a class hierarchy to get compile-time
5105 // enforcement of the limited imported target API.
5106 if (this->IsImported()) {
5108 cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
5109 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5112 // Check for library version properties.
5113 cmValue version = this->GetProperty("VERSION");
5114 cmValue soversion = this->GetProperty("SOVERSION");
5115 if (!this->HasSOName(config) ||
5116 this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
5117 this->IsFrameworkOnApple()) {
5118 // Versioning is supported only for shared libraries and modules,
5119 // and then only when the platform supports an soname flag.
5121 soversion = nullptr;
5123 if (version && !soversion) {
5124 // The soversion must be set if the library version is set. Use
5125 // the library version as the soversion.
5126 soversion = version;
5128 if (!version && soversion) {
5129 // Use the soversion as the library version.
5130 version = soversion;
5133 // Get the components of the library name.
5136 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5137 prefix, targetNames.Base, suffix);
5139 // The library name.
5140 targetNames.Output = prefix + targetNames.Base + suffix;
5142 if (this->IsFrameworkOnApple()) {
5143 targetNames.Real = prefix;
5144 if (!this->Makefile->PlatformIsAppleEmbedded()) {
5145 targetNames.Real += "Versions/";
5146 targetNames.Real += this->GetFrameworkVersion();
5147 targetNames.Real += "/";
5149 targetNames.Real += targetNames.Base + suffix;
5150 targetNames.SharedObject = targetNames.Real + suffix;
5152 // The library's soname.
5153 this->ComputeVersionedName(targetNames.SharedObject, prefix,
5154 targetNames.Base, suffix, targetNames.Output,
5157 // The library's real name on disk.
5158 this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
5159 suffix, targetNames.Output, version);
5162 // The import library name.
5163 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5164 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
5165 targetNames.ImportLibrary =
5166 this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
5169 // The program database file name.
5170 targetNames.PDB = this->GetPDBName(config);
5175 cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
5176 const std::string& config) const
5178 cmGeneratorTarget::Names targetNames;
5180 // This should not be called for imported targets.
5181 // TODO: Split cmTarget into a class hierarchy to get compile-time
5182 // enforcement of the limited imported target API.
5183 if (this->IsImported()) {
5184 std::string msg = cmStrCat(
5185 "GetExecutableNames called on imported target: ", this->GetName());
5186 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
5189 // This versioning is supported only for executables and then only
5190 // when the platform supports symbolic links.
5191 #if defined(_WIN32) && !defined(__CYGWIN__)
5194 // Check for executable version properties.
5195 cmValue version = this->GetProperty("VERSION");
5196 if (this->GetType() != cmStateEnums::EXECUTABLE ||
5197 this->Makefile->IsOn("XCODE")) {
5202 // Get the components of the executable name.
5205 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5206 prefix, targetNames.Base, suffix);
5208 // The executable name.
5209 targetNames.Output = prefix + targetNames.Base + suffix;
5211 // The executable's real name on disk.
5212 #if defined(__CYGWIN__)
5213 targetNames.Real = prefix + targetNames.Base;
5215 targetNames.Real = targetNames.Output;
5218 targetNames.Real += "-";
5219 targetNames.Real += *version;
5221 #if defined(__CYGWIN__)
5222 targetNames.Real += suffix;
5225 // The import library name.
5226 targetNames.ImportLibrary =
5227 this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
5229 // The program database file name.
5230 targetNames.PDB = this->GetPDBName(config);
5235 std::string cmGeneratorTarget::GetFullNameInternal(
5236 const std::string& config, cmStateEnums::ArtifactType artifact) const
5241 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
5242 return prefix + base + suffix;
5245 std::string cmGeneratorTarget::ImportedGetLocation(
5246 const std::string& config) const
5248 assert(this->IsImported());
5249 return this->Target->ImportedGetFullPath(
5250 config, cmStateEnums::RuntimeBinaryArtifact);
5253 std::string cmGeneratorTarget::GetFullNameImported(
5254 const std::string& config, cmStateEnums::ArtifactType artifact) const
5256 return cmSystemTools::GetFilenameName(
5257 this->Target->ImportedGetFullPath(config, artifact));
5260 void cmGeneratorTarget::GetFullNameInternal(
5261 const std::string& config, cmStateEnums::ArtifactType artifact,
5262 std::string& outPrefix, std::string& outBase, std::string& outSuffix) const
5264 // Use just the target name for non-main target types.
5265 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
5266 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5267 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
5268 this->GetType() != cmStateEnums::EXECUTABLE) {
5270 outBase = this->GetName();
5275 const bool isImportedLibraryArtifact =
5276 (artifact == cmStateEnums::ImportLibraryArtifact);
5278 // Return an empty name for the import library if this platform
5279 // does not support import libraries.
5280 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
5287 // retrieve prefix and suffix
5288 std::string ll = this->GetLinkerLanguage(config);
5289 cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
5290 cmValue targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
5292 // The implib option is only allowed for shared libraries, module
5293 // libraries, and executables.
5294 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5295 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
5296 this->GetType() != cmStateEnums::EXECUTABLE) {
5297 artifact = cmStateEnums::RuntimeBinaryArtifact;
5300 // Compute the full name for main target types.
5301 const std::string configPostfix = this->GetFilePostfix(config);
5303 // frameworks have directory prefix but no suffix
5304 std::string fw_prefix;
5305 if (this->IsFrameworkOnApple()) {
5307 cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
5308 targetPrefix = cmValue(fw_prefix);
5309 targetSuffix = nullptr;
5312 if (this->IsCFBundleOnApple()) {
5313 fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
5314 targetPrefix = cmValue(fw_prefix);
5315 targetSuffix = nullptr;
5318 // Begin the final name with the prefix.
5319 outPrefix = targetPrefix ? *targetPrefix : "";
5321 // Append the target name or property-specified name.
5322 outBase += this->GetOutputName(config, artifact);
5324 // Append the per-configuration postfix.
5325 // When using Xcode, the postfix should be part of the suffix rather than
5326 // the base, because the suffix ends up being used in Xcode's
5327 // EXECUTABLE_SUFFIX attribute.
5328 if (this->IsFrameworkOnApple() &&
5329 this->GetGlobalGenerator()->GetName() == "Xcode") {
5330 targetSuffix = cmValue(configPostfix);
5332 outBase += configPostfix;
5335 // Name shared libraries with their version number on some platforms.
5336 if (cmValue soversion = this->GetProperty("SOVERSION")) {
5337 if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
5338 !isImportedLibraryArtifact &&
5339 this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
5341 outBase += *soversion;
5345 // Append the suffix.
5346 outSuffix = targetSuffix ? *targetSuffix : "";
5349 std::string cmGeneratorTarget::GetLinkerLanguage(
5350 const std::string& config) const
5352 return this->GetLinkClosure(config)->LinkerLanguage;
5355 std::string cmGeneratorTarget::GetPDBOutputName(
5356 const std::string& config) const
5359 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
5361 std::vector<std::string> props;
5362 std::string configUpper = cmSystemTools::UpperCase(config);
5363 if (!configUpper.empty()) {
5364 // PDB_NAME_<CONFIG>
5365 props.push_back("PDB_NAME_" + configUpper);
5369 props.emplace_back("PDB_NAME");
5371 for (std::string const& p : props) {
5372 if (cmValue outName = this->GetProperty(p)) {
5380 std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
5385 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
5386 prefix, base, suffix);
5388 std::vector<std::string> props;
5389 std::string configUpper = cmSystemTools::UpperCase(config);
5390 if (!configUpper.empty()) {
5391 // PDB_NAME_<CONFIG>
5392 props.push_back("PDB_NAME_" + configUpper);
5396 props.emplace_back("PDB_NAME");
5398 for (std::string const& p : props) {
5399 if (cmValue outName = this->GetProperty(p)) {
5404 return prefix + base + ".pdb";
5407 std::string cmGeneratorTarget::GetObjectDirectory(
5408 std::string const& config) const
5410 std::string obj_dir =
5411 this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
5412 #if defined(__APPLE__)
5413 // find and replace $(PROJECT_NAME) xcode placeholder
5414 const std::string projectName = this->LocalGenerator->GetProjectName();
5415 cmSystemTools::ReplaceString(obj_dir, "$(PROJECT_NAME)", projectName);
5416 // Replace Xcode's placeholder for the object file directory since
5417 // installation and export scripts need to know the real directory.
5418 // Xcode has build-time settings (e.g. for sanitizers) that affect this,
5419 // but we use the default here. Users that want to enable sanitizers
5420 // will do so at the cost of object library installation and export.
5421 cmSystemTools::ReplaceString(obj_dir, "$(OBJECT_FILE_DIR_normal:base)",
5427 void cmGeneratorTarget::GetTargetObjectNames(
5428 std::string const& config, std::vector<std::string>& objects) const
5430 std::vector<cmSourceFile const*> objectSources;
5431 this->GetObjectSources(objectSources, config);
5432 std::map<cmSourceFile const*, std::string> mapping;
5434 for (cmSourceFile const* sf : objectSources) {
5438 this->LocalGenerator->ComputeObjectFilenames(mapping, this);
5440 for (cmSourceFile const* src : objectSources) {
5441 // Find the object file name corresponding to this source file.
5442 auto map_it = mapping.find(src);
5443 // It must exist because we populated the mapping just above.
5444 assert(!map_it->second.empty());
5445 objects.push_back(map_it->second);
5448 // We need to compute the relative path from the root of
5449 // of the object directory to handle subdirectory paths
5450 std::string rootObjectDir = this->GetObjectDirectory(config);
5451 rootObjectDir = cmSystemTools::CollapseFullPath(rootObjectDir);
5452 auto ispcObjects = this->GetGeneratedISPCObjects(config);
5453 for (std::string const& output : ispcObjects) {
5454 auto relativePathFromObjectDir = output.substr(rootObjectDir.size());
5455 objects.push_back(relativePathFromObjectDir);
5459 bool cmGeneratorTarget::StrictTargetComparison::operator()(
5460 cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
5462 int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
5463 if (nameResult == 0) {
5465 t1->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
5466 t2->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
5468 return nameResult < 0;
5471 struct cmGeneratorTarget::SourceFileFlags
5472 cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
5474 struct SourceFileFlags flags;
5475 this->ConstructSourceFileFlags();
5476 auto si = this->SourceFlagsMap.find(sf);
5477 if (si != this->SourceFlagsMap.end()) {
5480 // Handle the MACOSX_PACKAGE_LOCATION property on source files that
5481 // were not listed in one of the other lists.
5482 if (cmValue location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
5483 flags.MacFolder = location->c_str();
5484 const bool stripResources =
5485 this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
5486 if (*location == "Resources") {
5487 flags.Type = cmGeneratorTarget::SourceFileTypeResource;
5488 if (stripResources) {
5489 flags.MacFolder = "";
5491 } else if (cmHasLiteralPrefix(*location, "Resources/")) {
5492 flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
5493 if (stripResources) {
5494 flags.MacFolder += strlen("Resources/");
5497 flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
5504 void cmGeneratorTarget::ConstructSourceFileFlags() const
5506 if (this->SourceFileFlagsConstructed) {
5509 this->SourceFileFlagsConstructed = true;
5511 // Process public headers to mark the source files.
5512 if (cmValue files = this->GetProperty("PUBLIC_HEADER")) {
5513 std::vector<std::string> relFiles = cmExpandedList(*files);
5514 for (std::string const& relFile : relFiles) {
5515 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5516 SourceFileFlags& flags = this->SourceFlagsMap[sf];
5517 flags.MacFolder = "Headers";
5518 flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
5523 // Process private headers after public headers so that they take
5524 // precedence if a file is listed in both.
5525 if (cmValue files = this->GetProperty("PRIVATE_HEADER")) {
5526 std::vector<std::string> relFiles = cmExpandedList(*files);
5527 for (std::string const& relFile : relFiles) {
5528 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5529 SourceFileFlags& flags = this->SourceFlagsMap[sf];
5530 flags.MacFolder = "PrivateHeaders";
5531 flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
5536 // Mark sources listed as resources.
5537 if (cmValue files = this->GetProperty("RESOURCE")) {
5538 std::vector<std::string> relFiles = cmExpandedList(*files);
5539 for (std::string const& relFile : relFiles) {
5540 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
5541 SourceFileFlags& flags = this->SourceFlagsMap[sf];
5542 flags.MacFolder = "";
5543 if (!this->GlobalGenerator->ShouldStripResourcePath(this->Makefile)) {
5544 flags.MacFolder = "Resources";
5546 flags.Type = cmGeneratorTarget::SourceFileTypeResource;
5552 const cmGeneratorTarget::CompatibleInterfacesBase&
5553 cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
5555 cmGeneratorTarget::CompatibleInterfaces& compat =
5556 this->CompatibleInterfacesMap[config];
5559 compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
5560 compat.PropsString.insert("AUTOUIC_OPTIONS");
5561 std::vector<cmGeneratorTarget const*> const& deps =
5562 this->GetLinkImplementationClosure(config);
5563 for (cmGeneratorTarget const* li : deps) {
5564 #define CM_READ_COMPATIBLE_INTERFACE(X, x) \
5565 if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
5566 std::vector<std::string> props; \
5567 cmExpandList(*prop, props); \
5568 compat.Props##x.insert(props.begin(), props.end()); \
5570 CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
5571 CM_READ_COMPATIBLE_INTERFACE(STRING, String)
5572 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
5573 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
5574 #undef CM_READ_COMPATIBLE_INTERFACE
5580 bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
5581 const std::string& p, const std::string& config) const
5583 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5584 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5587 return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
5590 bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
5591 const std::string& p, const std::string& config) const
5593 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5594 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5597 return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
5600 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
5601 const std::string& p, const std::string& config) const
5603 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5604 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5607 return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
5610 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
5611 const std::string& p, const std::string& config) const
5613 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5614 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5617 return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
5628 template <typename PropertyType>
5629 PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5630 const std::string& prop,
5631 const std::string& config,
5632 CompatibleType, PropertyType*);
5635 bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5636 const std::string& prop,
5637 const std::string& config,
5638 CompatibleType /*unused*/,
5641 return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
5645 const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5646 const std::string& prop,
5647 const std::string& config,
5649 const char** /*unused*/)
5654 "String compatibility check function called for boolean");
5657 return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
5659 return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
5661 return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
5663 assert(false && "Unreachable!");
5667 template <typename PropertyType>
5668 void checkPropertyConsistency(cmGeneratorTarget const* depender,
5669 cmGeneratorTarget const* dependee,
5670 const std::string& propName,
5671 std::set<std::string>& emitted,
5672 const std::string& config, CompatibleType t,
5673 PropertyType* /*unused*/)
5675 cmValue prop = dependee->GetProperty(propName);
5680 std::vector<std::string> props = cmExpandedList(*prop);
5682 cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
5684 for (std::string const& p : props) {
5685 std::string pname = cmSystemTools::HelpFileName(p);
5686 std::string pfile = pdir + pname + ".rst";
5687 if (cmSystemTools::FileExists(pfile, true)) {
5688 std::ostringstream e;
5689 e << "Target \"" << dependee->GetName() << "\" has property \"" << p
5690 << "\" listed in its " << propName
5692 "This is not allowed. Only user-defined properties may appear "
5694 << propName << " property.";
5695 depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
5699 if (emitted.insert(p).second) {
5700 getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
5702 if (cmSystemTools::GetErrorOccurredFlag()) {
5710 std::string intersect(const std::set<std::string>& s1,
5711 const std::set<std::string>& s2)
5713 std::set<std::string> intersect;
5714 std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
5715 std::inserter(intersect, intersect.begin()));
5716 if (!intersect.empty()) {
5717 return *intersect.begin();
5722 std::string intersect(const std::set<std::string>& s1,
5723 const std::set<std::string>& s2,
5724 const std::set<std::string>& s3)
5727 result = intersect(s1, s2);
5728 if (!result.empty()) {
5731 result = intersect(s1, s3);
5732 if (!result.empty()) {
5735 return intersect(s2, s3);
5738 std::string intersect(const std::set<std::string>& s1,
5739 const std::set<std::string>& s2,
5740 const std::set<std::string>& s3,
5741 const std::set<std::string>& s4)
5744 result = intersect(s1, s2);
5745 if (!result.empty()) {
5748 result = intersect(s1, s3);
5749 if (!result.empty()) {
5752 result = intersect(s1, s4);
5753 if (!result.empty()) {
5756 return intersect(s2, s3, s4);
5760 void cmGeneratorTarget::CheckPropertyCompatibility(
5761 cmComputeLinkInformation& info, const std::string& config) const
5763 const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
5765 std::set<std::string> emittedBools;
5766 static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
5767 std::set<std::string> emittedStrings;
5768 static const std::string strString = "COMPATIBLE_INTERFACE_STRING";
5769 std::set<std::string> emittedMinNumbers;
5770 static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
5771 std::set<std::string> emittedMaxNumbers;
5772 static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
5774 for (auto const& dep : deps) {
5779 checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
5780 config, BoolType, nullptr);
5781 if (cmSystemTools::GetErrorOccurredFlag()) {
5784 checkPropertyConsistency<const char*>(this, dep.Target, strString,
5785 emittedStrings, config, StringType,
5787 if (cmSystemTools::GetErrorOccurredFlag()) {
5790 checkPropertyConsistency<const char*>(this, dep.Target, strNumMin,
5791 emittedMinNumbers, config,
5792 NumberMinType, nullptr);
5793 if (cmSystemTools::GetErrorOccurredFlag()) {
5796 checkPropertyConsistency<const char*>(this, dep.Target, strNumMax,
5797 emittedMaxNumbers, config,
5798 NumberMaxType, nullptr);
5799 if (cmSystemTools::GetErrorOccurredFlag()) {
5804 std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
5807 if (!prop.empty()) {
5808 // Use a sorted std::vector to keep the error message sorted.
5809 std::vector<std::string> props;
5810 auto i = emittedBools.find(prop);
5811 if (i != emittedBools.end()) {
5812 props.push_back(strBool);
5814 i = emittedStrings.find(prop);
5815 if (i != emittedStrings.end()) {
5816 props.push_back(strString);
5818 i = emittedMinNumbers.find(prop);
5819 if (i != emittedMinNumbers.end()) {
5820 props.push_back(strNumMin);
5822 i = emittedMaxNumbers.find(prop);
5823 if (i != emittedMaxNumbers.end()) {
5824 props.push_back(strNumMax);
5826 std::sort(props.begin(), props.end());
5828 std::string propsString = cmStrCat(
5829 cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
5831 std::ostringstream e;
5832 e << "Property \"" << prop << "\" appears in both the " << propsString
5833 << " property in the dependencies of target \"" << this->GetName()
5834 << "\". This is not allowed. A property may only require "
5836 "in a boolean interpretation, a numeric minimum, a numeric maximum "
5838 "string interpretation, but not a mixture.";
5839 this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
5843 template <typename PropertyType>
5844 std::string valueAsString(PropertyType);
5846 std::string valueAsString<bool>(bool value)
5848 return value ? "TRUE" : "FALSE";
5851 std::string valueAsString<const char*>(const char* value)
5853 return value ? value : "(unset)";
5856 std::string valueAsString<std::string>(std::string value)
5861 std::string valueAsString<cmValue>(cmValue value)
5863 return value ? value : std::string("(unset)");
5866 std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
5871 static std::string compatibilityType(CompatibleType t)
5875 return "Boolean compatibility";
5877 return "String compatibility";
5879 return "Numeric maximum compatibility";
5881 return "Numeric minimum compatibility";
5883 assert(false && "Unreachable!");
5887 static std::string compatibilityAgree(CompatibleType t, bool dominant)
5892 return dominant ? "(Disagree)\n" : "(Agree)\n";
5895 return dominant ? "(Dominant)\n" : "(Ignored)\n";
5897 assert(false && "Unreachable!");
5901 template <typename PropertyType>
5902 PropertyType getTypedProperty(
5903 cmGeneratorTarget const* tgt, const std::string& prop,
5904 cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
5907 bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
5908 const std::string& prop,
5909 cmGeneratorExpressionInterpreter* genexInterpreter)
5911 if (genexInterpreter == nullptr) {
5912 return tgt->GetPropertyAsBool(prop);
5915 cmValue value = tgt->GetProperty(prop);
5916 return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
5920 const char* getTypedProperty<const char*>(
5921 cmGeneratorTarget const* tgt, const std::string& prop,
5922 cmGeneratorExpressionInterpreter* genexInterpreter)
5924 cmValue value = tgt->GetProperty(prop);
5926 if (genexInterpreter == nullptr) {
5927 return value.GetCStr();
5930 return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
5934 std::string getTypedProperty<std::string>(
5935 cmGeneratorTarget const* tgt, const std::string& prop,
5936 cmGeneratorExpressionInterpreter* genexInterpreter)
5938 cmValue value = tgt->GetProperty(prop);
5940 if (genexInterpreter == nullptr) {
5941 return valueAsString(value);
5944 return genexInterpreter->Evaluate(value ? *value : "", prop);
5947 template <typename PropertyType>
5948 PropertyType impliedValue(PropertyType);
5950 bool impliedValue<bool>(bool /*unused*/)
5955 const char* impliedValue<const char*>(const char* /*unused*/)
5960 std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
5962 return std::string();
5965 template <typename PropertyType>
5966 std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
5971 std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
5972 CompatibleType /*unused*/)
5974 return { lhs == rhs, lhs };
5977 static std::pair<bool, const char*> consistentStringProperty(const char* lhs,
5980 const bool b = strcmp(lhs, rhs) == 0;
5981 return { b, b ? lhs : nullptr };
5984 static std::pair<bool, std::string> consistentStringProperty(
5985 const std::string& lhs, const std::string& rhs)
5987 const bool b = lhs == rhs;
5988 return { b, b ? lhs : valueAsString(nullptr) };
5991 static std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
5997 long lnum = strtol(lhs, &pEnd, 0);
5998 if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
5999 return { false, nullptr };
6002 long rnum = strtol(rhs, &pEnd, 0);
6003 if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
6004 return { false, nullptr };
6007 if (t == NumberMaxType) {
6008 return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
6011 return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
6015 std::pair<bool, const char*> consistentProperty(const char* lhs,
6020 return { true, lhs };
6023 return { true, rhs };
6026 return { true, lhs };
6031 bool same = cmIsOn(lhs) == cmIsOn(rhs);
6032 return { same, same ? lhs : nullptr };
6035 return consistentStringProperty(lhs, rhs);
6038 return consistentNumberProperty(lhs, rhs, t);
6040 assert(false && "Unreachable!");
6041 return { false, nullptr };
6044 static std::pair<bool, std::string> consistentProperty(const std::string& lhs,
6045 const std::string& rhs,
6048 const std::string null_ptr = valueAsString(nullptr);
6050 if (lhs == null_ptr && rhs == null_ptr) {
6051 return { true, lhs };
6053 if (lhs == null_ptr) {
6054 return { true, rhs };
6056 if (rhs == null_ptr) {
6057 return { true, lhs };
6062 bool same = cmIsOn(lhs) == cmIsOn(rhs);
6063 return { same, same ? lhs : null_ptr };
6066 return consistentStringProperty(lhs, rhs);
6068 case NumberMaxType: {
6069 auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
6070 return { value.first,
6071 value.first ? std::string(value.second) : null_ptr };
6074 assert(false && "Unreachable!");
6075 return { false, null_ptr };
6078 template <typename PropertyType>
6079 PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
6080 const std::string& p,
6081 const std::string& config,
6082 const char* defaultValue,
6084 PropertyType* /*unused*/)
6086 PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
6088 std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
6089 const bool explicitlySet = cm::contains(headPropKeys, p);
6091 const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
6092 assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
6094 std::vector<cmGeneratorTarget const*> const& deps =
6095 tgt->GetLinkImplementationClosure(config);
6100 bool propInitialized = explicitlySet;
6102 std::string report = cmStrCat(" * Target \"", tgt->GetName());
6103 if (explicitlySet) {
6104 report += "\" has property content \"";
6105 report += valueAsString<PropertyType>(propContent);
6107 } else if (impliedByUse) {
6108 report += "\" property is implied by use.\n";
6110 report += "\" property not set.\n";
6113 std::string interfaceProperty = "INTERFACE_" + p;
6114 std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
6115 if (p == "POSITION_INDEPENDENT_CODE") {
6116 genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
6117 tgt->GetLocalGenerator(), config, tgt);
6120 for (cmGeneratorTarget const* theTarget : deps) {
6121 // An error should be reported if one dependency
6122 // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
6123 // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
6124 // target itself has a POSITION_INDEPENDENT_CODE which disagrees
6125 // with a dependency.
6127 std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
6129 const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty);
6130 PropertyType ifacePropContent = getTypedProperty<PropertyType>(
6131 theTarget, interfaceProperty, genexInterpreter.get());
6133 std::string reportEntry;
6135 reportEntry += " * Target \"";
6136 reportEntry += theTarget->GetName();
6137 reportEntry += "\" property value \"";
6138 reportEntry += valueAsString<PropertyType>(ifacePropContent);
6139 reportEntry += "\" ";
6142 if (explicitlySet) {
6144 std::pair<bool, PropertyType> consistent =
6145 consistentProperty(propContent, ifacePropContent, t);
6146 report += reportEntry;
6147 report += compatibilityAgree(t, propContent != consistent.second);
6148 if (!consistent.first) {
6149 std::ostringstream e;
6150 e << "Property " << p << " on target \"" << tgt->GetName()
6151 << "\" does\nnot match the "
6154 << " property requirement\nof "
6156 << theTarget->GetName() << "\".\n";
6157 cmSystemTools::Error(e.str());
6160 propContent = consistent.second;
6163 // Explicitly set on target and not set in iface. Can't disagree.
6167 propContent = impliedValue<PropertyType>(propContent);
6170 std::pair<bool, PropertyType> consistent =
6171 consistentProperty(propContent, ifacePropContent, t);
6172 report += reportEntry;
6173 report += compatibilityAgree(t, propContent != consistent.second);
6174 if (!consistent.first) {
6175 std::ostringstream e;
6176 e << "Property " << p << " on target \"" << tgt->GetName()
6177 << "\" is\nimplied to be " << defaultValue
6178 << " because it was used to determine the link libraries\n"
6179 "already. The INTERFACE_"
6180 << p << " property on\ndependency \"" << theTarget->GetName()
6181 << "\" is in conflict.\n";
6182 cmSystemTools::Error(e.str());
6185 propContent = consistent.second;
6188 // Implicitly set on target and not set in iface. Can't disagree.
6192 if (propInitialized) {
6193 std::pair<bool, PropertyType> consistent =
6194 consistentProperty(propContent, ifacePropContent, t);
6195 report += reportEntry;
6196 report += compatibilityAgree(t, propContent != consistent.second);
6197 if (!consistent.first) {
6198 std::ostringstream e;
6199 e << "The INTERFACE_" << p << " property of \""
6200 << theTarget->GetName() << "\" does\nnot agree with the value of "
6201 << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
6202 cmSystemTools::Error(e.str());
6205 propContent = consistent.second;
6208 report += reportEntry + "(Interface set)\n";
6209 propContent = ifacePropContent;
6210 propInitialized = true;
6212 // Not set. Nothing to agree on.
6217 tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
6218 report, compatibilityType(t));
6222 bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
6224 bool previous = this->DeviceLink;
6225 this->DeviceLink = deviceLink;
6229 bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
6230 const std::string& p, const std::string& config) const
6232 return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
6236 std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
6237 const std::string& p, const std::string& config) const
6239 return checkInterfacePropertyCompatibility<std::string>(
6240 this, p, config, "FALSE", BoolType, nullptr);
6243 const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
6244 const std::string& p, const std::string& config) const
6246 return checkInterfacePropertyCompatibility<const char*>(
6247 this, p, config, "empty", StringType, nullptr);
6250 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
6251 const std::string& p, const std::string& config) const
6253 return checkInterfacePropertyCompatibility<const char*>(
6254 this, p, config, "empty", NumberMinType, nullptr);
6257 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
6258 const std::string& p, const std::string& config) const
6260 return checkInterfacePropertyCompatibility<const char*>(
6261 this, p, config, "empty", NumberMaxType, nullptr);
6264 cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
6265 const std::string& config) const
6267 // Lookup any existing information for this configuration.
6268 std::string key(cmSystemTools::UpperCase(config));
6269 auto i = this->LinkInformation.find(key);
6270 if (i == this->LinkInformation.end()) {
6271 // Compute information for this configuration.
6272 auto info = cm::make_unique<cmComputeLinkInformation>(this, config);
6273 if (info && !info->Compute()) {
6277 // Store the information for this configuration.
6278 i = this->LinkInformation.emplace(key, std::move(info)).first;
6281 this->CheckPropertyCompatibility(*i->second, config);
6284 return i->second.get();
6287 void cmGeneratorTarget::CheckLinkLibraries() const
6289 bool linkLibrariesOnlyTargets =
6290 this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS");
6292 // Evaluate the link interface of this target if needed for extra checks.
6293 if (linkLibrariesOnlyTargets) {
6294 std::vector<std::string> const& configs =
6295 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
6296 for (std::string const& config : configs) {
6297 this->GetLinkInterfaceLibraries(config, this, LinkInterfaceFor::Link);
6301 // Check link the implementation for each generated configuration.
6302 for (auto const& hmp : this->LinkImplMap) {
6303 HeadToLinkImplementationMap const& hm = hmp.second;
6304 // There could be several entries used when computing the pre-CMP0022
6305 // default link interface. Check only the entry for our own link impl.
6306 auto const hmi = hm.find(this);
6307 if (hmi == hm.end() || !hmi->second.LibrariesDone) {
6310 for (cmLinkImplItem const& item : hmi->second.Libraries) {
6311 if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) {
6314 if (linkLibrariesOnlyTargets &&
6315 !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) {
6321 // Check link the interface for each generated combination of
6322 // configuration and consuming head target. We should not need to
6323 // consider LinkInterfaceUsageRequirementsOnlyMap because its entries
6324 // should be a subset of LinkInterfaceMap (with LINK_ONLY left out).
6325 for (auto const& hmp : this->LinkInterfaceMap) {
6326 for (auto const& hmi : hmp.second) {
6327 if (!hmi.second.LibrariesDone) {
6330 for (cmLinkItem const& item : hmi.second.Libraries) {
6331 if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) {
6334 if (linkLibrariesOnlyTargets &&
6335 !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) {
6344 cm::string_view missingTargetPossibleReasons =
6345 "Possible reasons include:\n"
6346 " * There is a typo in the target name.\n"
6347 " * A find_package call is missing for an IMPORTED target.\n"
6348 " * An ALIAS target is missing.\n"_s;
6351 bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role,
6352 cmLinkItem const& item) const
6354 if (item.Target || cmHasPrefix(item.AsStr(), "<LINK_GROUP:"_s) ||
6355 item.AsStr().find("::") == std::string::npos) {
6358 MessageType messageType = MessageType::FATAL_ERROR;
6360 switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028)) {
6361 case cmPolicies::WARN: {
6362 e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028), "\n");
6363 messageType = MessageType::AUTHOR_WARNING;
6365 case cmPolicies::OLD:
6367 case cmPolicies::REQUIRED_IF_USED:
6368 case cmPolicies::REQUIRED_ALWAYS:
6369 case cmPolicies::NEW:
6370 // Issue the fatal message.
6374 if (role == LinkItemRole::Implementation) {
6375 e = cmStrCat(e, "Target \"", this->GetName(), "\" links to");
6377 e = cmStrCat(e, "The link interface of target \"", this->GetName(),
6381 cmStrCat(e, ":\n ", item.AsStr(), "\n", "but the target was not found. ",
6382 missingTargetPossibleReasons);
6383 cmListFileBacktrace backtrace = item.Backtrace;
6384 if (backtrace.Empty()) {
6385 backtrace = this->GetBacktrace();
6387 this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType, e,
6392 bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role,
6393 cmLinkItem const& item) const
6398 std::string const& str = item.AsStr();
6400 (str[0] == '-' || str[0] == '$' || str[0] == '`' ||
6401 str.find_first_of("/\\") != std::string::npos ||
6402 cmHasPrefix(str, "<LINK_LIBRARY:"_s) ||
6403 cmHasPrefix(str, "<LINK_GROUP:"_s))) {
6407 std::string e = cmStrCat("Target \"", this->GetName(),
6408 "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ",
6409 role == LinkItemRole::Implementation
6411 : "its link interface contains",
6412 ":\n ", item.AsStr(), "\nwhich is not a target. ",
6413 missingTargetPossibleReasons);
6414 cmListFileBacktrace backtrace = item.Backtrace;
6415 if (backtrace.Empty()) {
6416 backtrace = this->GetBacktrace();
6418 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
6419 MessageType::FATAL_ERROR, e, backtrace);
6423 void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
6426 this->GetTargetVersion("VERSION", major, minor, patch);
6429 void cmGeneratorTarget::GetTargetVersionFallback(
6430 const std::string& property, const std::string& fallback_property,
6431 int& major, int& minor, int& patch) const
6433 if (this->GetProperty(property)) {
6434 this->GetTargetVersion(property, major, minor, patch);
6436 this->GetTargetVersion(fallback_property, major, minor, patch);
6440 void cmGeneratorTarget::GetTargetVersion(const std::string& property,
6441 int& major, int& minor,
6444 // Set the default values.
6449 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
6451 if (cmValue version = this->GetProperty(property)) {
6452 // Try to parse the version number and store the results that were
6453 // successfully parsed.
6457 switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor,
6460 patch = parsed_patch;
6463 minor = parsed_minor;
6466 major = parsed_major;
6474 std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
6475 std::string const& lang, std::string const& config) const
6477 // This is activated by the presence of a default selection whether or
6478 // not it is overridden by a property.
6479 cmValue runtimeLibraryDefault = this->Makefile->GetDefinition(
6480 cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
6481 if (!cmNonempty(runtimeLibraryDefault)) {
6482 return std::string();
6484 cmValue runtimeLibraryValue =
6485 this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
6486 if (!runtimeLibraryValue) {
6487 runtimeLibraryValue = runtimeLibraryDefault;
6489 return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
6490 *runtimeLibraryValue, this->LocalGenerator, config, this));
6493 std::string cmGeneratorTarget::GetFortranModuleDirectory(
6494 std::string const& working_dir) const
6496 if (!this->FortranModuleDirectoryCreated) {
6497 this->FortranModuleDirectory =
6498 this->CreateFortranModuleDirectory(working_dir);
6499 this->FortranModuleDirectoryCreated = true;
6502 return this->FortranModuleDirectory;
6505 bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const
6508 this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) {
6509 return cmIsOn(*prop);
6514 std::string cmGeneratorTarget::CreateFortranModuleDirectory(
6515 std::string const& working_dir) const
6517 std::string mod_dir;
6518 std::string target_mod_dir;
6519 if (cmValue prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
6520 target_mod_dir = *prop;
6522 std::string const& default_mod_dir =
6523 this->LocalGenerator->GetCurrentBinaryDirectory();
6524 if (default_mod_dir != working_dir) {
6525 target_mod_dir = default_mod_dir;
6528 cmValue moddir_flag =
6529 this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
6530 if (!target_mod_dir.empty() && moddir_flag) {
6531 // Compute the full path to the module directory.
6532 if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
6533 // Already a full path.
6534 mod_dir = target_mod_dir;
6536 // Interpret relative to the current output directory.
6537 mod_dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
6538 '/', target_mod_dir);
6541 // Make sure the module output directory exists.
6542 cmSystemTools::MakeDirectory(mod_dir);
6547 void cmGeneratorTarget::AddISPCGeneratedHeader(std::string const& header,
6548 std::string const& config)
6550 std::string config_upper;
6551 if (!config.empty()) {
6552 config_upper = cmSystemTools::UpperCase(config);
6554 auto iter = this->ISPCGeneratedHeaders.find(config_upper);
6555 if (iter == this->ISPCGeneratedHeaders.end()) {
6556 std::vector<std::string> headers;
6557 headers.emplace_back(header);
6558 this->ISPCGeneratedHeaders.insert({ config_upper, headers });
6560 iter->second.emplace_back(header);
6564 std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
6565 std::string const& config) const
6567 std::string config_upper;
6568 if (!config.empty()) {
6569 config_upper = cmSystemTools::UpperCase(config);
6571 auto iter = this->ISPCGeneratedHeaders.find(config_upper);
6572 if (iter == this->ISPCGeneratedHeaders.end()) {
6573 return std::vector<std::string>{};
6575 return iter->second;
6578 void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
6579 std::string const& config)
6581 std::string config_upper;
6582 if (!config.empty()) {
6583 config_upper = cmSystemTools::UpperCase(config);
6585 auto iter = this->ISPCGeneratedObjects.find(config_upper);
6586 if (iter == this->ISPCGeneratedObjects.end()) {
6587 this->ISPCGeneratedObjects.insert({ config_upper, objs });
6589 iter->second.insert(iter->second.end(), objs.begin(), objs.end());
6593 std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
6594 std::string const& config) const
6596 std::string config_upper;
6597 if (!config.empty()) {
6598 config_upper = cmSystemTools::UpperCase(config);
6600 auto iter = this->ISPCGeneratedObjects.find(config_upper);
6601 if (iter == this->ISPCGeneratedObjects.end()) {
6602 return std::vector<std::string>{};
6604 return iter->second;
6607 std::string cmGeneratorTarget::GetFrameworkVersion() const
6609 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
6611 if (cmValue fversion = this->GetProperty("FRAMEWORK_VERSION")) {
6614 if (cmValue tversion = this->GetProperty("VERSION")) {
6620 void cmGeneratorTarget::ComputeVersionedName(
6621 std::string& vName, std::string const& prefix, std::string const& base,
6622 std::string const& suffix, std::string const& name, cmValue version) const
6624 vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
6629 vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
6632 std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
6634 return this->Target->GetProperties().GetKeys();
6637 void cmGeneratorTarget::ReportPropertyOrigin(
6638 const std::string& p, const std::string& result, const std::string& report,
6639 const std::string& compatibilityType) const
6641 std::vector<std::string> debugProperties;
6642 this->Target->GetMakefile()->GetDefExpandList(
6643 "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties);
6645 bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
6646 cm::contains(debugProperties, p);
6648 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
6649 this->DebugCompatiblePropertiesDone[p] = true;
6655 std::string areport =
6656 cmStrCat(compatibilityType, " of property \"", p, "\" for target \"",
6657 this->GetName(), "\" (result: \"", result, "\"):\n", report);
6659 this->LocalGenerator->GetCMakeInstance()->IssueMessage(MessageType::LOG,
6663 bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
6664 cmLocalGenerator const*& lg) const
6666 if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
6667 cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
6668 if (dirId.String.empty()) {
6669 lg = this->LocalGenerator;
6672 if (cmLocalGenerator const* otherLG =
6673 this->GlobalGenerator->FindLocalGenerator(dirId)) {
6681 cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
6682 std::string const& n, cmListFileBacktrace const& bt,
6683 LookupLinkItemScope* scope, LookupSelf lookupSelf) const
6685 cm::optional<cmLinkItem> maybeItem;
6686 if (this->IsLinkLookupScope(n, scope->LG)) {
6690 std::string name = this->CheckCMP0004(n);
6692 (lookupSelf == LookupSelf::No && name == this->GetName())) {
6695 maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG);
6699 void cmGeneratorTarget::ExpandLinkItems(
6700 std::string const& prop, cmBTStringRange entries, std::string const& config,
6701 cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor,
6702 LinkInterfaceField field, cmLinkInterface& iface) const
6704 if (entries.empty()) {
6707 // Keep this logic in sync with ComputeLinkImplementationLibraries.
6708 cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
6709 // The $<LINK_ONLY> expression may be in a link interface to specify
6710 // private link dependencies that are otherwise excluded from usage
6712 if (interfaceFor == LinkInterfaceFor::Usage) {
6713 dagChecker.SetTransitivePropertiesOnly();
6715 cmMakefile const* mf = this->LocalGenerator->GetMakefile();
6716 LookupLinkItemScope scope{ this->LocalGenerator };
6717 for (BT<std::string> const& entry : entries) {
6718 cmGeneratorExpression ge(entry.Backtrace);
6719 std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value);
6720 cge->SetEvaluateForBuildsystem(true);
6721 std::vector<std::string> libs = cmExpandedList(
6722 cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker,
6723 this, headTarget->LinkerLanguage));
6724 for (std::string const& lib : libs) {
6725 if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
6726 lib, cge->GetBacktrace(), &scope,
6727 field == LinkInterfaceField::Libraries ? LookupSelf::No
6728 : LookupSelf::Yes)) {
6729 cmLinkItem item = std::move(*maybeItem);
6731 if (field == LinkInterfaceField::HeadInclude) {
6732 iface.HeadInclude.emplace_back(std::move(item));
6735 if (field == LinkInterfaceField::HeadExclude) {
6736 iface.HeadExclude.emplace_back(std::move(item));
6740 // Report explicitly linked object files separately.
6741 std::string const& maybeObj = item.AsStr();
6742 if (cmSystemTools::FileIsFullPath(maybeObj)) {
6743 cmSourceFile const* sf =
6744 mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
6745 if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
6746 iface.Objects.emplace_back(std::move(item));
6752 iface.Libraries.emplace_back(std::move(item));
6755 if (cge->GetHadHeadSensitiveCondition()) {
6756 iface.HadHeadSensitiveCondition = true;
6758 if (cge->GetHadContextSensitiveCondition()) {
6759 iface.HadContextSensitiveCondition = true;
6761 if (cge->GetHadLinkLanguageSensitiveCondition()) {
6762 iface.HadLinkLanguageSensitiveCondition = true;
6767 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
6768 const std::string& config, cmGeneratorTarget const* head) const
6770 return this->GetLinkInterface(config, head, false);
6773 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
6774 const std::string& config, cmGeneratorTarget const* head,
6775 bool secondPass) const
6777 // Imported targets have their own link interface.
6778 if (this->IsImported()) {
6779 return this->GetImportLinkInterface(config, head, LinkInterfaceFor::Link,
6783 // Link interfaces are not supported for executables that do not
6785 if (this->GetType() == cmStateEnums::EXECUTABLE &&
6786 !this->IsExecutableWithExports()) {
6790 // Lookup any existing link interface for this configuration.
6791 cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
6793 // If the link interface does not depend on the head target
6794 // then re-use the one from the head we computed first.
6795 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6796 head = hm.begin()->first;
6799 cmOptionalLinkInterface& iface = hm[head];
6801 iface = cmOptionalLinkInterface();
6803 if (!iface.LibrariesDone) {
6804 iface.LibrariesDone = true;
6805 this->ComputeLinkInterfaceLibraries(config, iface, head,
6806 LinkInterfaceFor::Link);
6808 if (!iface.AllDone) {
6809 iface.AllDone = true;
6811 this->ComputeLinkInterface(config, iface, head, secondPass);
6812 this->ComputeLinkInterfaceRuntimeLibraries(config, iface);
6816 return iface.Exists ? &iface : nullptr;
6819 void cmGeneratorTarget::ComputeLinkInterface(
6820 const std::string& config, cmOptionalLinkInterface& iface,
6821 cmGeneratorTarget const* headTarget) const
6823 this->ComputeLinkInterface(config, iface, headTarget, false);
6826 void cmGeneratorTarget::ComputeLinkInterface(
6827 const std::string& config, cmOptionalLinkInterface& iface,
6828 cmGeneratorTarget const* headTarget, bool secondPass) const
6830 if (iface.Explicit) {
6831 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6832 this->GetType() == cmStateEnums::STATIC_LIBRARY ||
6833 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
6834 // Shared libraries may have runtime implementation dependencies
6835 // on other shared libraries that are not in the interface.
6836 std::set<cmLinkItem> emitted;
6837 for (cmLinkItem const& lib : iface.Libraries) {
6838 emitted.insert(lib);
6840 if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
6841 cmLinkImplementation const* impl = this->GetLinkImplementation(
6842 config, LinkInterfaceFor::Link, secondPass);
6843 for (cmLinkImplItem const& lib : impl->Libraries) {
6844 if (emitted.insert(lib).second) {
6846 // This is a runtime dependency on another shared library.
6847 if (lib.Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
6848 iface.SharedDeps.push_back(lib);
6851 // TODO: Recognize shared library file names. Perhaps this
6852 // should be moved to cmComputeLinkInformation, but that
6853 // creates a chicken-and-egg problem since this list is needed
6854 // for its construction.
6860 } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
6861 this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
6862 // The link implementation is the default link interface.
6863 cmLinkImplementationLibraries const* impl =
6864 this->GetLinkImplementationLibrariesInternal(config, headTarget,
6865 LinkInterfaceFor::Link);
6866 iface.ImplementationIsInterface = true;
6867 iface.WrongConfigLibraries = impl->WrongConfigLibraries;
6870 if (this->LinkLanguagePropagatesToDependents()) {
6871 // Targets using this archive need its language runtime libraries.
6872 if (cmLinkImplementation const* impl = this->GetLinkImplementation(
6873 config, LinkInterfaceFor::Link, secondPass)) {
6874 iface.Languages = impl->Languages;
6878 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
6879 // Construct the property name suffix for this configuration.
6880 std::string suffix = "_";
6881 if (!config.empty()) {
6882 suffix += cmSystemTools::UpperCase(config);
6884 suffix += "NOCONFIG";
6887 // How many repetitions are needed if this library has cyclic
6889 std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix);
6890 if (cmValue config_reps = this->GetProperty(propName)) {
6891 sscanf(config_reps->c_str(), "%u", &iface.Multiplicity);
6892 } else if (cmValue reps =
6893 this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
6894 sscanf(reps->c_str(), "%u", &iface.Multiplicity);
6899 const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
6900 const std::string& config, cmGeneratorTarget const* head,
6901 LinkInterfaceFor interfaceFor) const
6903 // Imported targets have their own link interface.
6904 if (this->IsImported()) {
6905 return this->GetImportLinkInterface(config, head, interfaceFor);
6908 // Link interfaces are not supported for executables that do not
6910 if (this->GetType() == cmStateEnums::EXECUTABLE &&
6911 !this->IsExecutableWithExports()) {
6915 // Lookup any existing link interface for this configuration.
6916 cmHeadToLinkInterfaceMap& hm =
6917 (interfaceFor == LinkInterfaceFor::Usage
6918 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
6919 : this->GetHeadToLinkInterfaceMap(config));
6921 // If the link interface does not depend on the head target
6922 // then re-use the one from the head we computed first.
6923 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6924 head = hm.begin()->first;
6927 cmOptionalLinkInterface& iface = hm[head];
6928 if (!iface.LibrariesDone) {
6929 iface.LibrariesDone = true;
6930 this->ComputeLinkInterfaceLibraries(config, iface, head, interfaceFor);
6933 return iface.Exists ? &iface : nullptr;
6936 std::string cmGeneratorTarget::GetDirectory(
6937 const std::string& config, cmStateEnums::ArtifactType artifact) const
6939 if (this->IsImported()) {
6940 auto fullPath = this->Target->ImportedGetFullPath(config, artifact);
6941 if (this->IsFrameworkOnApple()) {
6942 cmsys::RegularExpressionMatch match;
6943 if (FrameworkRegularExpression.find(fullPath.c_str(), match)) {
6944 auto path = match.match(1);
6945 if (!path.empty()) {
6946 path.erase(path.length() - 1);
6951 // Return the directory from which the target is imported.
6952 return cmSystemTools::GetFilenamePath(fullPath);
6954 if (OutputInfo const* info = this->GetOutputInfo(config)) {
6955 // Return the directory in which the target will be built.
6957 case cmStateEnums::RuntimeBinaryArtifact:
6958 return info->OutDir;
6959 case cmStateEnums::ImportLibraryArtifact:
6960 return info->ImpDir;
6966 bool cmGeneratorTarget::UsesDefaultOutputDir(
6967 const std::string& config, cmStateEnums::ArtifactType artifact) const
6970 return this->ComputeOutputDir(config, artifact, dir);
6973 cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
6974 const std::string& config) const
6976 // There is no output information for imported targets.
6977 if (this->IsImported()) {
6981 // Only libraries and executables have well-defined output files.
6982 if (!this->HaveWellDefinedOutputFiles()) {
6983 std::string msg = cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
6984 this->GetName(), " which has type ",
6985 cmState::GetTargetTypeName(this->GetType()));
6986 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
6990 // Lookup/compute/cache the output information for this configuration.
6991 std::string config_upper;
6992 if (!config.empty()) {
6993 config_upper = cmSystemTools::UpperCase(config);
6995 auto i = this->OutputInfoMap.find(config_upper);
6996 if (i == this->OutputInfoMap.end()) {
6997 // Add empty info in map to detect potential recursion.
6999 OutputInfoMapType::value_type entry(config_upper, info);
7000 i = this->OutputInfoMap.insert(entry).first;
7002 // Compute output directories.
7003 this->ComputeOutputDir(config, cmStateEnums::RuntimeBinaryArtifact,
7005 this->ComputeOutputDir(config, cmStateEnums::ImportLibraryArtifact,
7007 if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
7008 info.PdbDir = info.OutDir;
7011 // Now update the previously-prepared map entry.
7013 } else if (i->second.empty()) {
7014 // An empty map entry indicates we have been called recursively
7015 // from the above block.
7016 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
7017 MessageType::FATAL_ERROR,
7018 "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
7019 this->GetBacktrace());
7025 bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
7026 cmStateEnums::ArtifactType artifact,
7027 std::string& out) const
7029 bool usesDefaultOutputDir = false;
7030 std::string conf = config;
7032 // Look for a target property defining the target output directory
7033 // based on the target type.
7034 std::string targetTypeName = this->GetOutputTargetType(artifact);
7035 std::string propertyName;
7036 if (!targetTypeName.empty()) {
7037 propertyName = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY");
7040 // Check for a per-configuration output directory target property.
7041 std::string configUpper = cmSystemTools::UpperCase(conf);
7042 std::string configProp;
7043 if (!targetTypeName.empty()) {
7044 configProp = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY_", configUpper);
7047 // Select an output directory.
7048 if (cmValue config_outdir = this->GetProperty(configProp)) {
7049 // Use the user-specified per-configuration output directory.
7050 out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
7053 // Skip per-configuration subdirectory.
7055 } else if (cmValue outdir = this->GetProperty(propertyName)) {
7056 // Use the user-specified output directory.
7057 out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
7059 // Skip per-configuration subdirectory if the value contained a
7060 // generator expression.
7061 if (out != *outdir) {
7064 } else if (this->GetType() == cmStateEnums::EXECUTABLE) {
7065 // Lookup the output path for executables.
7066 out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
7067 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
7068 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7069 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
7070 // Lookup the output path for libraries.
7071 out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
7074 // Default to the current output directory.
7075 usesDefaultOutputDir = true;
7079 // Convert the output path to a full path in case it is
7080 // specified as a relative path. Treat a relative path as
7081 // relative to the current output directory for this makefile.
7082 out = (cmSystemTools::CollapseFullPath(
7083 out, this->LocalGenerator->GetCurrentBinaryDirectory()));
7085 // The generator may add the configuration's subdirectory.
7086 if (!conf.empty()) {
7088 this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
7089 std::string suffix =
7090 usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
7091 this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
7092 "/", conf, suffix, out);
7095 return usesDefaultOutputDir;
7098 bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
7099 const std::string& config,
7100 std::string& out) const
7102 // Look for a target property defining the target output directory
7103 // based on the target type.
7104 std::string propertyName;
7105 if (!kind.empty()) {
7106 propertyName = cmStrCat(kind, "_OUTPUT_DIRECTORY");
7108 std::string conf = config;
7110 // Check for a per-configuration output directory target property.
7111 std::string configUpper = cmSystemTools::UpperCase(conf);
7112 std::string configProp;
7113 if (!kind.empty()) {
7114 configProp = cmStrCat(kind, "_OUTPUT_DIRECTORY_", configUpper);
7117 // Select an output directory.
7118 if (cmValue config_outdir = this->GetProperty(configProp)) {
7119 // Use the user-specified per-configuration output directory.
7120 out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
7123 // Skip per-configuration subdirectory.
7125 } else if (cmValue outdir = this->GetProperty(propertyName)) {
7126 // Use the user-specified output directory.
7128 cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
7130 // Skip per-configuration subdirectory if the value contained a
7131 // generator expression.
7132 if (out != *outdir) {
7140 // Convert the output path to a full path in case it is
7141 // specified as a relative path. Treat a relative path as
7142 // relative to the current output directory for this makefile.
7143 out = (cmSystemTools::CollapseFullPath(
7144 out, this->LocalGenerator->GetCurrentBinaryDirectory()));
7146 // The generator may add the configuration's subdirectory.
7147 if (!conf.empty()) {
7148 this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
7149 "/", conf, "", out);
7154 bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string& config) const
7156 std::string install_rpath;
7157 this->GetInstallRPATH(config, install_rpath);
7158 return !install_rpath.empty() &&
7159 !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
7162 bool cmGeneratorTarget::GetBuildRPATH(const std::string& config,
7163 std::string& rpath) const
7165 return this->GetRPATH(config, "BUILD_RPATH", rpath);
7168 bool cmGeneratorTarget::GetInstallRPATH(const std::string& config,
7169 std::string& rpath) const
7171 return this->GetRPATH(config, "INSTALL_RPATH", rpath);
7174 bool cmGeneratorTarget::GetRPATH(const std::string& config,
7175 const std::string& prop,
7176 std::string& rpath) const
7178 cmValue value = this->GetProperty(prop);
7184 cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config);
7189 void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
7190 const std::string& config, cmOptionalLinkInterface& iface,
7191 cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor) const
7193 // Construct the property name suffix for this configuration.
7194 std::string suffix = "_";
7195 if (!config.empty()) {
7196 suffix += cmSystemTools::UpperCase(config);
7198 suffix += "NOCONFIG";
7201 // An explicit list of interface libraries may be set for shared
7202 // libraries and executables that export symbols.
7203 bool haveExplicitLibraries = false;
7204 cmValue explicitLibrariesCMP0022OLD;
7205 std::string linkIfacePropCMP0022OLD;
7206 bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
7207 this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
7209 // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
7210 haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty() ||
7211 !this->Target->GetLinkInterfaceDirectEntries().empty() ||
7212 !this->Target->GetLinkInterfaceDirectExcludeEntries().empty();
7214 // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
7215 // shared lib or executable.
7216 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7217 this->IsExecutableWithExports()) {
7218 // Lookup the per-configuration property.
7219 linkIfacePropCMP0022OLD = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
7220 explicitLibrariesCMP0022OLD = this->GetProperty(linkIfacePropCMP0022OLD);
7222 // If not set, try the generic property.
7223 if (!explicitLibrariesCMP0022OLD) {
7224 linkIfacePropCMP0022OLD = "LINK_INTERFACE_LIBRARIES";
7225 explicitLibrariesCMP0022OLD =
7226 this->GetProperty(linkIfacePropCMP0022OLD);
7230 if (explicitLibrariesCMP0022OLD &&
7231 this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
7232 !this->PolicyWarnedCMP0022) {
7233 // Compare the explicitly set old link interface properties to the
7234 // preferred new link interface property one and warn if different.
7235 cmValue newExplicitLibraries =
7236 this->GetProperty("INTERFACE_LINK_LIBRARIES");
7237 if (newExplicitLibraries &&
7238 (*newExplicitLibraries != *explicitLibrariesCMP0022OLD)) {
7239 std::ostringstream w;
7240 /* clang-format off */
7241 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
7242 "Target \"" << this->GetName() << "\" has an "
7243 "INTERFACE_LINK_LIBRARIES property which differs from its " <<
7244 linkIfacePropCMP0022OLD << " properties."
7246 "INTERFACE_LINK_LIBRARIES:\n"
7247 " " << *newExplicitLibraries << "\n" <<
7248 linkIfacePropCMP0022OLD << ":\n"
7249 " " << *explicitLibrariesCMP0022OLD << "\n";
7250 /* clang-format on */
7251 this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
7253 this->PolicyWarnedCMP0022 = true;
7257 haveExplicitLibraries = static_cast<bool>(explicitLibrariesCMP0022OLD);
7260 // There is no implicit link interface for executables or modules
7261 // so if none was explicitly set then there is no link interface.
7262 if (!haveExplicitLibraries &&
7263 (this->GetType() == cmStateEnums::EXECUTABLE ||
7264 (this->GetType() == cmStateEnums::MODULE_LIBRARY))) {
7267 iface.Exists = true;
7269 // If CMP0022 is NEW then the plain tll signature sets the
7270 // INTERFACE_LINK_LIBRARIES property. Even if the project
7271 // clears it, the link interface is still explicit.
7272 iface.Explicit = cmp0022NEW || explicitLibrariesCMP0022OLD;
7275 // The interface libraries are specified by INTERFACE_LINK_LIBRARIES.
7276 // Use its special representation directly to get backtraces.
7277 this->ExpandLinkItems(
7278 kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(),
7279 config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface);
7280 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
7281 this->Target->GetLinkInterfaceDirectEntries(),
7282 config, headTarget, interfaceFor,
7283 LinkInterfaceField::HeadInclude, iface);
7284 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
7285 this->Target->GetLinkInterfaceDirectExcludeEntries(),
7286 config, headTarget, interfaceFor,
7287 LinkInterfaceField::HeadExclude, iface);
7288 } else if (explicitLibrariesCMP0022OLD) {
7289 // The interface libraries have been explicitly set in pre-CMP0022 style.
7290 std::vector<BT<std::string>> entries;
7291 entries.emplace_back(*explicitLibrariesCMP0022OLD);
7292 this->ExpandLinkItems(linkIfacePropCMP0022OLD, cmMakeRange(entries),
7293 config, headTarget, interfaceFor,
7294 LinkInterfaceField::Libraries, iface);
7297 // If the link interface is explicit, do not fall back to the link impl.
7298 if (iface.Explicit) {
7302 // The link implementation is the default link interface.
7303 if (cmLinkImplementationLibraries const* impl =
7304 this->GetLinkImplementationLibrariesInternal(config, headTarget,
7306 iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
7307 impl->Libraries.end());
7308 if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
7309 !this->PolicyWarnedCMP0022 && interfaceFor == LinkInterfaceFor::Link) {
7310 // Compare the link implementation fallback link interface to the
7311 // preferred new link interface property and warn if different.
7312 cmLinkInterface ifaceNew;
7313 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES,
7314 this->Target->GetLinkInterfaceEntries(), config,
7315 headTarget, interfaceFor,
7316 LinkInterfaceField::Libraries, ifaceNew);
7317 if (ifaceNew.Libraries != iface.Libraries) {
7318 std::string oldLibraries = cmJoin(impl->Libraries, ";");
7319 std::string newLibraries = cmJoin(ifaceNew.Libraries, ";");
7320 if (oldLibraries.empty()) {
7321 oldLibraries = "(empty)";
7323 if (newLibraries.empty()) {
7324 newLibraries = "(empty)";
7327 std::ostringstream w;
7328 /* clang-format off */
7329 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
7330 "Target \"" << this->GetName() << "\" has an "
7331 "INTERFACE_LINK_LIBRARIES property. "
7332 "This should be preferred as the source of the link interface "
7333 "for this library but because CMP0022 is not set CMake is "
7334 "ignoring the property and using the link implementation "
7335 "as the link interface instead."
7337 "INTERFACE_LINK_LIBRARIES:\n"
7338 " " << newLibraries << "\n"
7339 "Link implementation:\n"
7340 " " << oldLibraries << "\n";
7341 /* clang-format on */
7342 this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
7344 this->PolicyWarnedCMP0022 = true;
7352 template <typename ReturnType>
7353 ReturnType constructItem(cmGeneratorTarget* target,
7354 cmListFileBacktrace const& bt);
7357 inline cmLinkImplItem constructItem(cmGeneratorTarget* target,
7358 cmListFileBacktrace const& bt)
7360 return cmLinkImplItem(cmLinkItem(target, false, bt), false);
7364 inline cmLinkItem constructItem(cmGeneratorTarget* target,
7365 cmListFileBacktrace const& bt)
7367 return cmLinkItem(target, false, bt);
7370 template <typename ValueType>
7371 std::vector<ValueType> computeImplicitLanguageTargets(
7372 std::string const& lang, std::string const& config,
7373 cmGeneratorTarget const* currentTarget)
7375 cmListFileBacktrace bt;
7376 std::vector<ValueType> result;
7377 cmLocalGenerator* lg = currentTarget->GetLocalGenerator();
7379 std::string const& runtimeLibrary =
7380 currentTarget->GetRuntimeLinkLibrary(lang, config);
7381 if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition(
7382 "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) {
7383 std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
7384 result.reserve(libsVec.size());
7386 for (std::string const& i : libsVec) {
7387 cmGeneratorTarget::TargetOrString resolved =
7388 currentTarget->ResolveTargetReference(i, lg);
7389 if (resolved.Target) {
7390 result.emplace_back(constructItem<ValueType>(resolved.Target, bt));
7399 void cmGeneratorTarget::ComputeLinkInterfaceRuntimeLibraries(
7400 const std::string& config, cmOptionalLinkInterface& iface) const
7402 for (std::string const& lang : iface.Languages) {
7403 if ((lang == "CUDA" || lang == "HIP") &&
7404 iface.LanguageRuntimeLibraries.find(lang) ==
7405 iface.LanguageRuntimeLibraries.end()) {
7406 auto implicitTargets =
7407 computeImplicitLanguageTargets<cmLinkItem>(lang, config, this);
7408 iface.LanguageRuntimeLibraries[lang] = std::move(implicitTargets);
7413 void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries(
7414 const std::string& config, cmOptionalLinkImplementation& impl) const
7416 for (std::string const& lang : impl.Languages) {
7417 if ((lang == "CUDA" || lang == "HIP") &&
7418 impl.LanguageRuntimeLibraries.find(lang) ==
7419 impl.LanguageRuntimeLibraries.end()) {
7420 auto implicitTargets =
7421 computeImplicitLanguageTargets<cmLinkImplItem>(lang, config, this);
7422 impl.LanguageRuntimeLibraries[lang] = std::move(implicitTargets);
7427 const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
7428 const std::string& config, cmGeneratorTarget const* headTarget,
7429 LinkInterfaceFor interfaceFor, bool secondPass) const
7431 cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config);
7436 cmHeadToLinkInterfaceMap& hm =
7437 (interfaceFor == LinkInterfaceFor::Usage
7438 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
7439 : this->GetHeadToLinkInterfaceMap(config));
7441 // If the link interface does not depend on the head target
7442 // then re-use the one from the head we computed first.
7443 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
7444 headTarget = hm.begin()->first;
7447 cmOptionalLinkInterface& iface = hm[headTarget];
7449 iface = cmOptionalLinkInterface();
7451 if (!iface.AllDone) {
7452 iface.AllDone = true;
7453 iface.LibrariesDone = true;
7454 iface.Multiplicity = info->Multiplicity;
7455 cmExpandList(info->Languages, iface.Languages);
7456 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
7457 cmMakeRange(info->LibrariesHeadInclude), config,
7458 headTarget, interfaceFor,
7459 LinkInterfaceField::HeadInclude, iface);
7460 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
7461 cmMakeRange(info->LibrariesHeadExclude), config,
7462 headTarget, interfaceFor,
7463 LinkInterfaceField::HeadExclude, iface);
7464 this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries),
7465 config, headTarget, interfaceFor,
7466 LinkInterfaceField::Libraries, iface);
7467 std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
7468 LookupLinkItemScope scope{ this->LocalGenerator };
7469 for (std::string const& dep : deps) {
7470 if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
7471 dep, cmListFileBacktrace(), &scope, LookupSelf::No)) {
7472 iface.SharedDeps.emplace_back(std::move(*maybeItem));
7480 cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
7481 const std::string& config) const
7483 // There is no imported information for non-imported targets.
7484 if (!this->IsImported()) {
7488 // Lookup/compute/cache the import information for this
7490 std::string config_upper;
7491 if (!config.empty()) {
7492 config_upper = cmSystemTools::UpperCase(config);
7494 config_upper = "NOCONFIG";
7497 auto i = this->ImportInfoMap.find(config_upper);
7498 if (i == this->ImportInfoMap.end()) {
7500 this->ComputeImportInfo(config_upper, info);
7501 ImportInfoMapType::value_type entry(config_upper, info);
7502 i = this->ImportInfoMap.insert(entry).first;
7505 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
7508 // If the location is empty then the target is not available for
7509 // this configuration.
7510 if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
7514 // Return the import information.
7518 void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
7519 ImportInfo& info) const
7521 // This method finds information about an imported target from its
7522 // properties. The "IMPORTED_" namespace is reserved for properties
7523 // defined by the project exporting the target.
7525 // Initialize members.
7526 info.NoSOName = false;
7528 cmValue loc = nullptr;
7529 cmValue imp = nullptr;
7531 if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
7535 // Get the link interface.
7537 // Use the INTERFACE_LINK_LIBRARIES special representation directly
7538 // to get backtraces.
7539 cmBTStringRange entries = this->Target->GetLinkInterfaceEntries();
7540 if (!entries.empty()) {
7541 info.LibrariesProp = "INTERFACE_LINK_LIBRARIES";
7542 for (BT<std::string> const& entry : entries) {
7543 info.Libraries.emplace_back(entry);
7545 } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
7546 std::string linkProp =
7547 cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix);
7548 cmValue propertyLibs = this->GetProperty(linkProp);
7549 if (!propertyLibs) {
7550 linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
7551 propertyLibs = this->GetProperty(linkProp);
7554 info.LibrariesProp = linkProp;
7555 info.Libraries.emplace_back(*propertyLibs);
7559 for (BT<std::string> const& entry :
7560 this->Target->GetLinkInterfaceDirectEntries()) {
7561 info.LibrariesHeadInclude.emplace_back(entry);
7563 for (BT<std::string> const& entry :
7564 this->Target->GetLinkInterfaceDirectExcludeEntries()) {
7565 info.LibrariesHeadExclude.emplace_back(entry);
7567 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
7569 info.LibName = *loc;
7574 // A provided configuration has been chosen. Load the
7575 // configuration's properties.
7577 // Get the location.
7579 info.Location = *loc;
7581 std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
7582 if (cmValue config_location = this->GetProperty(impProp)) {
7583 info.Location = *config_location;
7584 } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
7585 info.Location = *location;
7590 if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
7591 std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
7592 if (cmValue config_soname = this->GetProperty(soProp)) {
7593 info.SOName = *config_soname;
7594 } else if (cmValue soname = this->GetProperty("IMPORTED_SONAME")) {
7595 info.SOName = *soname;
7599 // Get the "no-soname" mark.
7600 if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
7601 std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
7602 if (cmValue config_no_soname = this->GetProperty(soProp)) {
7603 info.NoSOName = cmIsOn(*config_no_soname);
7604 } else if (cmValue no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
7605 info.NoSOName = cmIsOn(*no_soname);
7609 // Get the import library.
7611 info.ImportLibrary = *imp;
7612 } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7613 this->IsExecutableWithExports()) {
7614 std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
7615 if (cmValue config_implib = this->GetProperty(impProp)) {
7616 info.ImportLibrary = *config_implib;
7617 } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
7618 info.ImportLibrary = *implib;
7622 // Get the link dependencies.
7624 std::string linkProp =
7625 cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
7626 if (cmValue config_libs = this->GetProperty(linkProp)) {
7627 info.SharedDeps = *config_libs;
7628 } else if (cmValue libs =
7629 this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
7630 info.SharedDeps = *libs;
7634 // Get the link languages.
7635 if (this->LinkLanguagePropagatesToDependents()) {
7636 std::string linkProp =
7637 cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
7638 if (cmValue config_libs = this->GetProperty(linkProp)) {
7639 info.Languages = *config_libs;
7640 } else if (cmValue libs =
7641 this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
7642 info.Languages = *libs;
7646 // Get information if target is managed assembly.
7648 std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
7649 if (cmValue pc = this->GetProperty(linkProp + suffix)) {
7650 info.Managed = this->CheckManagedType(*pc);
7651 } else if (cmValue p = this->GetProperty(linkProp)) {
7652 info.Managed = this->CheckManagedType(*p);
7656 // Get the cyclic repetition count.
7657 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
7658 std::string linkProp =
7659 cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
7660 if (cmValue config_reps = this->GetProperty(linkProp)) {
7661 sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
7662 } else if (cmValue reps =
7663 this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
7664 sscanf(reps->c_str(), "%u", &info.Multiplicity);
7669 cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
7670 const std::string& config) const
7672 return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)];
7675 cmHeadToLinkInterfaceMap&
7676 cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
7677 const std::string& config) const
7680 ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
7683 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
7684 const std::string& config, LinkInterfaceFor implFor) const
7686 return this->GetLinkImplementation(config, implFor, false);
7689 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
7690 const std::string& config, LinkInterfaceFor implFor, bool secondPass) const
7692 // There is no link implementation for targets that cannot compile sources.
7693 if (!this->CanCompileSources()) {
7697 HeadToLinkImplementationMap& hm =
7698 (implFor == LinkInterfaceFor::Usage
7699 ? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
7700 : this->GetHeadToLinkImplementationMap(config));
7701 cmOptionalLinkImplementation& impl = hm[this];
7703 impl = cmOptionalLinkImplementation();
7705 if (!impl.LibrariesDone) {
7706 impl.LibrariesDone = true;
7707 this->ComputeLinkImplementationLibraries(config, impl, this, implFor);
7709 if (!impl.LanguagesDone) {
7710 impl.LanguagesDone = true;
7711 this->ComputeLinkImplementationLanguages(config, impl);
7712 this->ComputeLinkImplementationRuntimeLibraries(config, impl);
7717 cmGeneratorTarget::HeadToLinkImplementationMap&
7718 cmGeneratorTarget::GetHeadToLinkImplementationMap(
7719 std::string const& config) const
7721 return this->LinkImplMap[cmSystemTools::UpperCase(config)];
7724 cmGeneratorTarget::HeadToLinkImplementationMap&
7725 cmGeneratorTarget::GetHeadToLinkImplementationUsageRequirementsMap(
7726 std::string const& config) const
7729 ->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
7732 bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
7733 std::vector<cmSourceFile*>& files) const
7735 std::vector<std::string> const& configs =
7736 this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
7738 auto it = configs.begin();
7739 const std::string& firstConfig = *it;
7740 this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
7742 for (; it != configs.end(); ++it) {
7743 std::vector<cmSourceFile*> configFiles;
7744 this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
7745 if (configFiles != files) {
7746 std::string firstConfigFiles;
7747 const char* sep = "";
7748 for (cmSourceFile* f : files) {
7749 firstConfigFiles += sep;
7750 firstConfigFiles += f->ResolveFullPath();
7754 std::string thisConfigFiles;
7756 for (cmSourceFile* f : configFiles) {
7757 thisConfigFiles += sep;
7758 thisConfigFiles += f->ResolveFullPath();
7761 std::ostringstream e;
7762 /* clang-format off */
7763 e << "Target \"" << this->GetName()
7764 << "\" has source files which vary by "
7765 "configuration. This is not supported by the \""
7766 << this->GlobalGenerator->GetName()
7767 << "\" generator.\n"
7768 "Config \"" << firstConfig << "\":\n"
7769 " " << firstConfigFiles << "\n"
7770 "Config \"" << *it << "\":\n"
7771 " " << thisConfigFiles << "\n";
7772 /* clang-format on */
7773 this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
7780 void cmGeneratorTarget::GetObjectLibrariesCMP0026(
7781 std::vector<cmGeneratorTarget*>& objlibs) const
7783 // At configure-time, this method can be called as part of getting the
7784 // LOCATION property or to export() a file to be include()d. However
7785 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
7786 // for TARGET_OBJECTS instead for backwards compatibility with OLD
7787 // behavior of CMP0024 and CMP0026 only.
7788 cmBTStringRange rng = this->Target->GetSourceEntries();
7789 for (auto const& entry : rng) {
7790 std::vector<std::string> files = cmExpandedList(entry.Value);
7791 for (std::string const& li : files) {
7792 if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
7793 std::string objLibName = li.substr(17, li.size() - 18);
7795 if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
7798 cmGeneratorTarget* objLib =
7799 this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
7801 objlibs.push_back(objLib);
7808 std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
7810 // Strip whitespace off the library names because we used to do this
7811 // in case variables were expanded at generate time. We no longer
7812 // do the expansion but users link to libraries like " ${VAR} ".
7813 std::string lib = item;
7814 std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
7815 if (pos != std::string::npos) {
7816 lib = lib.substr(pos);
7818 pos = lib.find_last_not_of(" \t\r\n");
7819 if (pos != std::string::npos) {
7820 lib = lib.substr(0, pos + 1);
7823 cmake* cm = this->LocalGenerator->GetCMakeInstance();
7824 switch (this->GetPolicyStatusCMP0004()) {
7825 case cmPolicies::WARN: {
7826 std::ostringstream w;
7827 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
7828 << "Target \"" << this->GetName() << "\" links to item \"" << item
7829 << "\" which has leading or trailing whitespace.";
7830 cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
7831 this->GetBacktrace());
7834 case cmPolicies::OLD:
7836 case cmPolicies::NEW: {
7837 std::ostringstream e;
7838 e << "Target \"" << this->GetName() << "\" links to item \"" << item
7839 << "\" which has leading or trailing whitespace. "
7840 << "This is now an error according to policy CMP0004.";
7841 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
7842 this->GetBacktrace());
7844 case cmPolicies::REQUIRED_IF_USED:
7845 case cmPolicies::REQUIRED_ALWAYS: {
7846 std::ostringstream e;
7847 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
7848 << "Target \"" << this->GetName() << "\" links to item \"" << item
7849 << "\" which has leading or trailing whitespace.";
7850 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
7851 this->GetBacktrace());
7858 bool cmGeneratorTarget::IsDeprecated() const
7860 cmValue deprecation = this->GetProperty("DEPRECATION");
7861 return cmNonempty(deprecation);
7864 std::string cmGeneratorTarget::GetDeprecation() const
7866 // find DEPRECATION property
7867 if (cmValue deprecation = this->GetProperty("DEPRECATION")) {
7868 return *deprecation;
7870 return std::string();
7873 void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
7874 const std::string& config) const
7876 // Targets that do not compile anything have no languages.
7877 if (!this->CanCompileSources()) {
7881 std::vector<cmSourceFile*> sourceFiles;
7882 this->GetSourceFiles(sourceFiles, config);
7883 for (cmSourceFile* src : sourceFiles) {
7884 const std::string& lang = src->GetOrDetermineLanguage();
7885 if (!lang.empty()) {
7886 languages.insert(lang);
7890 std::vector<cmGeneratorTarget*> objectLibraries;
7891 std::vector<cmSourceFile const*> externalObjects;
7892 if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
7893 std::vector<cmGeneratorTarget*> objectTargets;
7894 this->GetObjectLibrariesCMP0026(objectTargets);
7895 objectLibraries.reserve(objectTargets.size());
7896 for (cmGeneratorTarget* gt : objectTargets) {
7897 objectLibraries.push_back(gt);
7900 this->GetExternalObjects(externalObjects, config);
7901 for (cmSourceFile const* extObj : externalObjects) {
7902 std::string objLib = extObj->GetObjectLibrary();
7903 if (cmGeneratorTarget* tgt =
7904 this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
7905 auto const objLibIt =
7906 std::find_if(objectLibraries.cbegin(), objectLibraries.cend(),
7907 [tgt](cmGeneratorTarget* t) { return t == tgt; });
7908 if (objectLibraries.cend() == objLibIt) {
7909 objectLibraries.push_back(tgt);
7914 for (cmGeneratorTarget* objLib : objectLibraries) {
7915 objLib->GetLanguages(languages, config);
7919 bool cmGeneratorTarget::IsLanguageUsed(std::string const& language,
7920 std::string const& config) const
7922 std::set<std::string> languages;
7923 this->GetLanguages(languages, config);
7924 return languages.count(language);
7927 bool cmGeneratorTarget::IsCSharpOnly() const
7929 // Only certain target types may compile CSharp.
7930 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
7931 this->GetType() != cmStateEnums::STATIC_LIBRARY &&
7932 this->GetType() != cmStateEnums::EXECUTABLE) {
7935 std::set<std::string> languages = this->GetAllConfigCompileLanguages();
7936 // Consider an explicit linker language property, but *not* the
7937 // computed linker language that may depend on linked targets.
7938 cmValue linkLang = this->GetProperty("LINKER_LANGUAGE");
7939 if (cmNonempty(linkLang)) {
7940 languages.insert(*linkLang);
7942 return languages.size() == 1 && languages.count("CSharp") > 0;
7945 bool cmGeneratorTarget::IsDotNetSdkTarget() const
7947 return !this->GetProperty("DOTNET_SDK").IsEmpty();
7950 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
7951 const std::string& config, cmOptionalLinkImplementation& impl) const
7953 // This target needs runtime libraries for its source languages.
7954 std::set<std::string> languages;
7955 // Get languages used in our source files.
7956 this->GetLanguages(languages, config);
7957 // Copy the set of languages to the link implementation.
7958 impl.Languages.insert(impl.Languages.begin(), languages.begin(),
7962 bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
7964 if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
7967 std::string build_rpath;
7968 if (this->GetBuildRPATH(config, build_rpath)) {
7971 if (cmLinkImplementationLibraries const* impl =
7972 this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Link)) {
7973 return !impl->Libraries.empty();
7978 cmLinkImplementationLibraries const*
7979 cmGeneratorTarget::GetLinkImplementationLibraries(
7980 const std::string& config, LinkInterfaceFor implFor) const
7982 return this->GetLinkImplementationLibrariesInternal(config, this, implFor);
7985 cmLinkImplementationLibraries const*
7986 cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
7987 const std::string& config, cmGeneratorTarget const* head,
7988 LinkInterfaceFor implFor) const
7990 // There is no link implementation for targets that cannot compile sources.
7991 if (!this->CanCompileSources()) {
7995 // Populate the link implementation libraries for this configuration.
7996 HeadToLinkImplementationMap& hm =
7997 (implFor == LinkInterfaceFor::Usage
7998 ? this->GetHeadToLinkImplementationUsageRequirementsMap(config)
7999 : this->GetHeadToLinkImplementationMap(config));
8001 // If the link implementation does not depend on the head target
8002 // then re-use the one from the head we computed first.
8003 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
8004 head = hm.begin()->first;
8007 cmOptionalLinkImplementation& impl = hm[head];
8008 if (!impl.LibrariesDone) {
8009 impl.LibrariesDone = true;
8010 this->ComputeLinkImplementationLibraries(config, impl, head, implFor);
8015 bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
8016 const std::string& p) const
8018 return cm::contains(this->LinkImplicitNullProperties, p);
8022 class TransitiveLinkImpl
8024 cmGeneratorTarget const* Self;
8025 std::string const& Config;
8026 LinkInterfaceFor ImplFor;
8027 cmLinkImplementation& Impl;
8029 std::set<cmLinkItem> Emitted;
8030 std::set<cmLinkItem> Excluded;
8031 std::unordered_set<cmGeneratorTarget const*> Followed;
8033 void Follow(cmGeneratorTarget const* target);
8036 TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config,
8037 LinkInterfaceFor implFor, cmLinkImplementation& impl)
8048 void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target)
8050 if (!target || !this->Followed.insert(target).second ||
8051 target->GetPolicyStatusCMP0022() == cmPolicies::OLD ||
8052 target->GetPolicyStatusCMP0022() == cmPolicies::WARN) {
8056 // Get this target's usage requirements.
8057 cmLinkInterfaceLibraries const* iface =
8058 target->GetLinkInterfaceLibraries(this->Config, this->Self, this->ImplFor);
8062 if (iface->HadContextSensitiveCondition) {
8063 this->Impl.HadContextSensitiveCondition = true;
8066 // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements.
8067 for (cmLinkItem const& item : iface->HeadInclude) {
8068 // Inject direct dependencies from the item's usage requirements
8069 // before the item itself.
8070 this->Follow(item.Target);
8072 // Add the item itself, but at most once.
8073 if (this->Emitted.insert(item).second) {
8074 this->Impl.Libraries.emplace_back(item, /* checkCMP0027= */ false);
8078 // Follow transitive dependencies.
8079 for (cmLinkItem const& item : iface->Libraries) {
8080 this->Follow(item.Target);
8083 // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8084 // usage requirements.
8085 for (cmLinkItem const& item : iface->HeadExclude) {
8086 this->Excluded.insert(item);
8090 void TransitiveLinkImpl::Compute()
8092 // Save the original items and start with an empty list.
8093 std::vector<cmLinkImplItem> original = std::move(this->Impl.Libraries);
8095 // Avoid injecting any original items as usage requirements.
8096 // This gives LINK_LIBRARIES final control over the order
8097 // if it explicitly lists everything.
8098 this->Emitted.insert(original.cbegin(), original.cend());
8100 // Process each original item.
8101 for (cmLinkImplItem& item : original) {
8102 // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT'
8103 // usage requirements before the item itself.
8104 this->Follow(item.Target);
8106 // Add the item itself.
8107 this->Impl.Libraries.emplace_back(std::move(item));
8110 // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8111 // usage requirements found through any dependency above.
8112 this->Impl.Libraries.erase(
8113 std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(),
8114 [this](cmLinkImplItem const& item) {
8115 return this->Excluded.find(item) != this->Excluded.end();
8117 this->Impl.Libraries.end());
8120 void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
8121 std::string const& config,
8122 LinkInterfaceFor implFor,
8123 cmLinkImplementation& impl)
8125 TransitiveLinkImpl transitiveLinkImpl(self, config, implFor, impl);
8126 transitiveLinkImpl.Compute();
8130 void cmGeneratorTarget::ComputeLinkImplementationLibraries(
8131 const std::string& config, cmOptionalLinkImplementation& impl,
8132 cmGeneratorTarget const* head, LinkInterfaceFor implFor) const
8134 cmLocalGenerator const* lg = this->LocalGenerator;
8135 cmMakefile const* mf = lg->GetMakefile();
8136 cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
8137 // Collect libraries directly linked in this configuration.
8138 for (auto const& entry : entryRange) {
8139 std::vector<std::string> llibs;
8140 // Keep this logic in sync with ExpandLinkItems.
8141 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
8143 // The $<LINK_ONLY> expression may be used to specify link dependencies
8144 // that are otherwise excluded from usage requirements.
8145 if (implFor == LinkInterfaceFor::Usage) {
8146 switch (this->GetPolicyStatusCMP0131()) {
8147 case cmPolicies::WARN:
8148 case cmPolicies::OLD:
8150 case cmPolicies::REQUIRED_IF_USED:
8151 case cmPolicies::REQUIRED_ALWAYS:
8152 case cmPolicies::NEW:
8153 dagChecker.SetTransitivePropertiesOnly();
8157 cmGeneratorExpression ge(entry.Backtrace);
8158 std::unique_ptr<cmCompiledGeneratorExpression> const cge =
8159 ge.Parse(entry.Value);
8160 cge->SetEvaluateForBuildsystem(true);
8161 std::string const& evaluated =
8162 cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
8163 this->LinkerLanguage);
8164 bool const checkCMP0027 = evaluated != entry.Value;
8165 cmExpandList(evaluated, llibs);
8166 if (cge->GetHadHeadSensitiveCondition()) {
8167 impl.HadHeadSensitiveCondition = true;
8169 if (cge->GetHadContextSensitiveCondition()) {
8170 impl.HadContextSensitiveCondition = true;
8172 if (cge->GetHadLinkLanguageSensitiveCondition()) {
8173 impl.HadLinkLanguageSensitiveCondition = true;
8176 for (std::string const& lib : llibs) {
8177 if (this->IsLinkLookupScope(lib, lg)) {
8181 // Skip entries that resolve to the target itself or are empty.
8182 std::string name = this->CheckCMP0004(lib);
8183 if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) {
8184 // resolve alias name
8185 auto* target = this->Makefile->FindTargetToUse(name);
8187 name = target->GetName();
8190 if (name == this->GetName() || name.empty()) {
8191 if (name == this->GetName()) {
8192 bool noMessage = false;
8193 MessageType messageType = MessageType::FATAL_ERROR;
8194 std::ostringstream e;
8195 switch (this->GetPolicyStatusCMP0038()) {
8196 case cmPolicies::WARN: {
8197 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
8198 messageType = MessageType::AUTHOR_WARNING;
8200 case cmPolicies::OLD:
8203 case cmPolicies::REQUIRED_IF_USED:
8204 case cmPolicies::REQUIRED_ALWAYS:
8205 case cmPolicies::NEW:
8206 // Issue the fatal message.
8211 e << "Target \"" << this->GetName() << "\" links to itself.";
8212 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
8213 messageType, e.str(), this->GetBacktrace());
8214 if (messageType == MessageType::FATAL_ERROR) {
8222 // The entry is meant for this configuration.
8224 this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg);
8226 // Report explicitly linked object files separately.
8227 std::string const& maybeObj = item.AsStr();
8228 if (cmSystemTools::FileIsFullPath(maybeObj)) {
8229 cmSourceFile const* sf =
8230 mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
8231 if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
8232 impl.Objects.emplace_back(std::move(item));
8238 impl.Libraries.emplace_back(std::move(item), checkCMP0027);
8241 std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
8242 for (std::string const& sp : seenProps) {
8243 if (!this->GetProperty(sp)) {
8244 this->LinkImplicitNullProperties.insert(sp);
8247 cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
8250 // Update the list of direct link dependencies from usage requirements.
8252 ComputeLinkImplTransitive(this, config, implFor, impl);
8255 // Get the list of configurations considered to be DEBUG.
8256 std::vector<std::string> debugConfigs =
8257 this->Makefile->GetCMakeInstance()->GetDebugConfigs();
8259 cmTargetLinkLibraryType linkType =
8260 CMP0003_ComputeLinkType(config, debugConfigs);
8261 cmTarget::LinkLibraryVectorType const& oldllibs =
8262 this->Target->GetOriginalLinkLibraries();
8263 for (cmTarget::LibraryID const& oldllib : oldllibs) {
8264 if (oldllib.second != GENERAL_LibraryType && oldllib.second != linkType) {
8265 std::string name = this->CheckCMP0004(oldllib.first);
8266 if (name == this->GetName() || name.empty()) {
8269 // Support OLD behavior for CMP0003.
8270 impl.WrongConfigLibraries.push_back(
8271 this->ResolveLinkItem(BT<std::string>(name)));
8276 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
8277 std::string const& name) const
8279 return this->ResolveTargetReference(name, this->LocalGenerator);
8282 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
8283 std::string const& name, cmLocalGenerator const* lg) const
8285 TargetOrString resolved;
8287 if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
8288 resolved.Target = tgt;
8290 resolved.String = name;
8296 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
8297 BT<std::string> const& name) const
8299 return this->ResolveLinkItem(name, this->LocalGenerator);
8302 cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name,
8303 cmLocalGenerator const* lg) const
8305 auto bt = name.Backtrace;
8306 TargetOrString resolved = this->ResolveTargetReference(name.Value, lg);
8308 if (!resolved.Target) {
8309 return cmLinkItem(resolved.String, false, bt);
8312 // Check deprecation, issue message with `bt` backtrace.
8313 if (resolved.Target->IsDeprecated()) {
8314 std::ostringstream w;
8315 /* clang-format off */
8317 "The library that is being linked to, " << resolved.Target->GetName() <<
8318 ", is marked as being deprecated by the owner. The message provided by "
8319 "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
8320 /* clang-format on */
8321 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
8322 MessageType::AUTHOR_WARNING, w.str(), bt);
8325 // Skip targets that will not really be linked. This is probably a
8326 // name conflict between an external library and an executable
8327 // within the project.
8328 if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
8329 !resolved.Target->IsExecutableWithExports()) {
8330 return cmLinkItem(resolved.Target->GetName(), false, bt);
8333 return cmLinkItem(resolved.Target, false, bt);
8336 bool cmGeneratorTarget::HasPackageReferences() const
8338 return this->IsInBuildSystem() &&
8339 !this->GetProperty("VS_PACKAGE_REFERENCES")->empty();
8342 std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const
8344 std::vector<std::string> packageReferences;
8346 if (this->IsInBuildSystem()) {
8347 if (cmValue vsPackageReferences =
8348 this->GetProperty("VS_PACKAGE_REFERENCES")) {
8349 cmExpandList(*vsPackageReferences, packageReferences);
8353 return packageReferences;
8356 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
8358 if (OutputInfo const* info = this->GetOutputInfo(config)) {
8359 // Return the directory in which the target will be built.
8360 return info->PdbDir;
8365 bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
8367 return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
8370 bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
8371 std::string const& gnuName,
8373 const char* newExt) const
8375 if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
8376 gnuName.substr(gnuName.size() - 6) == ".dll.a") {
8377 out = cmStrCat(cm::string_view(gnuName).substr(0, gnuName.size() - 6),
8378 newExt ? newExt : ".lib");
8384 bool cmGeneratorTarget::HasContextDependentSources() const
8386 return this->SourcesAreContextDependent == Tribool::True;
8389 bool cmGeneratorTarget::IsExecutableWithExports() const
8391 return (this->GetType() == cmStateEnums::EXECUTABLE &&
8392 this->GetPropertyAsBool("ENABLE_EXPORTS"));
8395 bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
8397 return (this->IsDLLPlatform() &&
8398 (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8399 this->IsExecutableWithExports()) &&
8400 // Assemblies which have only managed code do not have
8401 // import libraries.
8402 this->GetManagedType(config) != ManagedType::Managed) ||
8403 (this->Target->IsAIX() && this->IsExecutableWithExports());
8406 bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
8408 return this->HasImportLibrary(config) ||
8409 // On DLL platforms we always generate the import library name
8410 // just in case the sources have export markup.
8411 (this->IsDLLPlatform() &&
8412 (this->GetType() == cmStateEnums::EXECUTABLE ||
8413 this->GetType() == cmStateEnums::MODULE_LIBRARY));
8416 std::string cmGeneratorTarget::GetSupportDirectory() const
8418 std::string dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
8419 "/CMakeFiles/", this->GetName());
8428 bool cmGeneratorTarget::IsLinkable() const
8430 return (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
8431 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8432 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
8433 this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
8434 this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
8435 this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
8436 this->IsExecutableWithExports());
8439 bool cmGeneratorTarget::IsFrameworkOnApple() const
8441 return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
8442 this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
8443 this->Makefile->IsOn("APPLE") &&
8444 this->GetPropertyAsBool("FRAMEWORK"));
8447 bool cmGeneratorTarget::IsAppBundleOnApple() const
8449 return (this->GetType() == cmStateEnums::EXECUTABLE &&
8450 this->Makefile->IsOn("APPLE") &&
8451 this->GetPropertyAsBool("MACOSX_BUNDLE"));
8454 bool cmGeneratorTarget::IsXCTestOnApple() const
8456 return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
8459 bool cmGeneratorTarget::IsCFBundleOnApple() const
8461 return (this->GetType() == cmStateEnums::MODULE_LIBRARY &&
8462 this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
8465 cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
8466 std::string const& propval) const
8468 // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
8469 // or only C++/CLI) does only depend on whether the property is an empty
8470 // string or contains any value at all. In Visual Studio generators
8471 // this propval is prepended with /clr[:] which results in:
8473 // 1. propval does not exist: no /clr flag, unmanaged target, has import
8475 // 2. empty propval: add /clr as flag, mixed unmanaged/managed
8476 // target, has import lib
8477 // 3. any value (safe,pure): add /clr:[propval] as flag, target with
8478 // managed code only, no import lib
8479 return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
8482 cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
8483 const std::string& config) const
8485 // Only libraries and executables can be managed targets.
8486 if (this->GetType() > cmStateEnums::SHARED_LIBRARY) {
8487 return ManagedType::Undefined;
8490 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
8491 return ManagedType::Native;
8494 // Check imported target.
8495 if (this->IsImported()) {
8496 if (cmGeneratorTarget::ImportInfo const* info =
8497 this->GetImportInfo(config)) {
8498 return info->Managed;
8500 return ManagedType::Undefined;
8503 // Check for explicitly set clr target property.
8504 if (cmValue clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
8505 return this->CheckManagedType(*clr);
8508 // C# targets are always managed. This language specific check
8509 // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
8510 // has to be set manually for C# targets.
8511 return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;
8514 bool cmGeneratorTarget::AddHeaderSetVerification()
8516 if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) {
8520 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
8521 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
8522 this->GetType() != cmStateEnums::UNKNOWN_LIBRARY &&
8523 this->GetType() != cmStateEnums::OBJECT_LIBRARY &&
8524 this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
8525 !this->IsExecutableWithExports()) {
8529 auto verifyValue = this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY");
8530 const bool all = verifyValue.IsEmpty();
8531 std::set<std::string> verifySet;
8533 auto verifyList = cmExpandedList(verifyValue);
8534 verifySet.insert(verifyList.begin(), verifyList.end());
8537 cmTarget* verifyTarget = nullptr;
8538 cmTarget* allVerifyTarget =
8539 this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
8540 "all_verify_interface_header_sets", true);
8542 auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries();
8544 std::set<cmFileSet*> fileSets;
8545 for (auto const& entry : interfaceFileSetEntries) {
8546 for (auto const& name : cmExpandedList(entry.Value)) {
8547 if (all || verifySet.count(name)) {
8548 fileSets.insert(this->Target->GetFileSet(name));
8549 verifySet.erase(name);
8553 if (!verifySet.empty()) {
8554 this->Makefile->IssueMessage(
8555 MessageType::FATAL_ERROR,
8556 cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"",
8558 "\" contained the following header sets that are nonexistent "
8559 "or not INTERFACE:\n ",
8560 cmJoin(verifySet, "\n ")));
8564 cm::optional<std::set<std::string>> languages;
8565 for (auto* fileSet : fileSets) {
8566 auto dirCges = fileSet->CompileDirectoryEntries();
8567 auto fileCges = fileSet->CompileFileEntries();
8569 static auto const contextSensitive =
8570 [](const std::unique_ptr<cmCompiledGeneratorExpression>& cge) {
8571 return cge->GetHadContextSensitiveCondition();
8573 bool dirCgesContextSensitive = false;
8574 bool fileCgesContextSensitive = false;
8576 std::vector<std::string> dirs;
8577 std::map<std::string, std::vector<std::string>> filesPerDir;
8579 for (auto const& config : this->Makefile->GetGeneratorConfigs(
8580 cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
8581 if (first || dirCgesContextSensitive) {
8582 dirs = fileSet->EvaluateDirectoryEntries(dirCges, this->LocalGenerator,
8584 dirCgesContextSensitive =
8585 std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
8587 if (first || fileCgesContextSensitive) {
8588 filesPerDir.clear();
8589 for (auto const& fileCge : fileCges) {
8590 fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge,
8591 this->LocalGenerator, config, this);
8592 if (fileCge->GetHadContextSensitiveCondition()) {
8593 fileCgesContextSensitive = true;
8598 for (auto const& files : filesPerDir) {
8599 for (auto const& file : files.second) {
8600 std::string filename = this->GenerateHeaderSetVerificationFile(
8601 *this->Makefile->GetOrCreateSource(file), files.first, languages);
8602 if (filename.empty()) {
8606 if (!verifyTarget) {
8608 cmMakefile::PolicyPushPop polScope(this->Makefile);
8609 this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW);
8610 verifyTarget = this->Makefile->AddLibrary(
8611 cmStrCat(this->GetName(), "_verify_interface_header_sets"),
8612 cmStateEnums::OBJECT_LIBRARY, {}, true);
8615 verifyTarget->AddLinkLibrary(
8616 *this->Makefile, this->GetName(),
8617 cmTargetLinkLibraryType::GENERAL_LibraryType);
8618 verifyTarget->SetProperty("AUTOMOC", "OFF");
8619 verifyTarget->SetProperty("AUTORCC", "OFF");
8620 verifyTarget->SetProperty("AUTOUIC", "OFF");
8621 verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
8622 verifyTarget->SetProperty("UNITY_BUILD", "OFF");
8623 cm::optional<std::map<std::string, cmValue>>
8624 perConfigCompileDefinitions;
8625 verifyTarget->FinalizeTargetConfiguration(
8626 this->Makefile->GetCompileDefinitionsEntries(),
8627 perConfigCompileDefinitions);
8629 if (!allVerifyTarget) {
8630 allVerifyTarget = this->GlobalGenerator->GetMakefiles()
8632 ->AddNewUtilityTarget(
8633 "all_verify_interface_header_sets", true);
8636 allVerifyTarget->AddUtility(verifyTarget->GetName(), false);
8639 if (fileCgesContextSensitive) {
8640 filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, ">");
8642 verifyTarget->AddSource(filename);
8646 if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
8654 this->LocalGenerator->AddGeneratorTarget(
8655 cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator));
8661 std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
8662 cmSourceFile& source, const std::string& dir,
8663 cm::optional<std::set<std::string>>& languages) const
8665 std::string extension;
8666 std::string language = source.GetOrDetermineLanguage();
8668 if (language.empty()) {
8670 languages.emplace();
8671 for (auto const& tgtSource : this->GetAllConfigSources()) {
8672 auto const& tgtSourceLanguage =
8673 tgtSource.Source->GetOrDetermineLanguage();
8674 if (tgtSourceLanguage == "CXX") {
8675 languages->insert("CXX");
8676 break; // C++ overrides everything else, so we don't need to keep
8679 if (tgtSourceLanguage == "C") {
8680 languages->insert("C");
8684 if (languages->empty()) {
8685 std::vector<std::string> languagesVector;
8686 this->GlobalGenerator->GetEnabledLanguages(languagesVector);
8687 languages->insert(languagesVector.begin(), languagesVector.end());
8691 if (languages->count("CXX")) {
8693 } else if (languages->count("C")) {
8698 if (language == "C") {
8700 } else if (language == "CXX") {
8706 std::string headerFilename = dir;
8707 if (!headerFilename.empty()) {
8708 headerFilename += '/';
8710 headerFilename += source.GetLocation().GetName();
8712 auto filename = cmStrCat(
8713 this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->GetName(),
8714 "_verify_interface_header_sets/", headerFilename, extension);
8715 auto* verificationSource = this->Makefile->GetOrCreateSource(filename);
8716 verificationSource->SetProperty("LANGUAGE", language);
8718 cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename));
8720 cmGeneratedFileStream fout(filename);
8721 fout.SetCopyIfDifferent(true);
8722 fout << "#include <" << headerFilename << ">\n";