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/string_view>
20 #include <cmext/algorithm>
21 #include <cmext/string_view>
23 #include "cmsys/RegularExpression.hxx"
25 #include "cmAlgorithms.h"
26 #include "cmComputeLinkInformation.h"
27 #include "cmCustomCommand.h"
28 #include "cmCustomCommandGenerator.h"
29 #include "cmCustomCommandLines.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"
47 #include "cmStringAlgorithms.h"
48 #include "cmSystemTools.h"
50 #include "cmTargetLinkLibraryType.h"
51 #include "cmTargetPropertyComputer.h"
57 cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
58 cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
59 cmListFileBacktrace const& /* context */)
61 return &tgt->GetSourcesProperty();
66 cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
67 cmGeneratorTarget const* tgt)
69 return tgt->GetLocation("");
74 cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
75 cmGeneratorTarget const* tgt, const std::string& config)
77 return tgt->GetLocation(config);
80 class cmGeneratorTarget::TargetPropertyEntry
83 static cmLinkImplItem NoLinkImplItem;
86 TargetPropertyEntry(cmLinkImplItem const& item)
90 virtual ~TargetPropertyEntry() = default;
92 virtual const std::string& Evaluate(
93 cmLocalGenerator* lg, const std::string& config,
94 cmGeneratorTarget const* headTarget,
95 cmGeneratorExpressionDAGChecker* dagChecker,
96 std::string const& language) const = 0;
98 virtual cmListFileBacktrace GetBacktrace() const = 0;
99 virtual std::string const& GetInput() const = 0;
100 virtual bool GetHadContextSensitiveCondition() const { return false; }
102 cmLinkImplItem const& LinkImplItem;
104 cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
106 class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
109 TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
110 cmLinkImplItem const& item = NoLinkImplItem)
111 : cmGeneratorTarget::TargetPropertyEntry(item)
116 const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
117 cmGeneratorTarget const* headTarget,
118 cmGeneratorExpressionDAGChecker* dagChecker,
119 std::string const& language) const override
121 return this->ge->Evaluate(lg, config, headTarget, dagChecker, nullptr,
125 cmListFileBacktrace GetBacktrace() const override
127 return this->ge->GetBacktrace();
130 std::string const& GetInput() const override { return this->ge->GetInput(); }
132 bool GetHadContextSensitiveCondition() const override
134 return this->ge->GetHadContextSensitiveCondition();
138 const std::unique_ptr<cmCompiledGeneratorExpression> ge;
141 class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
144 TargetPropertyEntryString(std::string propertyValue,
145 cmListFileBacktrace backtrace,
146 cmLinkImplItem const& item = NoLinkImplItem)
147 : cmGeneratorTarget::TargetPropertyEntry(item)
148 , PropertyValue(std::move(propertyValue))
149 , Backtrace(std::move(backtrace))
153 const std::string& Evaluate(cmLocalGenerator*, const std::string&,
154 cmGeneratorTarget const*,
155 cmGeneratorExpressionDAGChecker*,
156 std::string const&) const override
158 return this->PropertyValue;
161 cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
162 std::string const& GetInput() const override { return this->PropertyValue; }
165 std::string PropertyValue;
166 cmListFileBacktrace Backtrace;
169 std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>
170 CreateTargetPropertyEntry(
171 const std::string& propertyValue,
172 cmListFileBacktrace backtrace = cmListFileBacktrace(),
173 bool evaluateForBuildsystem = false)
175 if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
176 cmGeneratorExpression ge(std::move(backtrace));
177 std::unique_ptr<cmCompiledGeneratorExpression> cge =
178 ge.Parse(propertyValue);
179 cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
180 return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
181 cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
184 return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
185 cm::make_unique<TargetPropertyEntryString>(propertyValue,
186 std::move(backtrace)));
189 void CreatePropertyGeneratorExpressions(
190 cmStringRange entries, cmBacktraceRange backtraces,
191 std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
192 bool evaluateForBuildsystem = false)
194 auto btIt = backtraces.begin();
195 for (auto it = entries.begin(); it != entries.end(); ++it, ++btIt) {
197 CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
202 // Represent a target property entry after evaluating generator expressions
203 // and splitting up lists.
204 struct EvaluatedTargetPropertyEntry
206 EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
207 cmListFileBacktrace bt)
209 , Backtrace(std::move(bt))
214 EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
215 EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
216 EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
218 EvaluatedTargetPropertyEntry& operator=(
219 EvaluatedTargetPropertyEntry const&) = delete;
221 cmLinkImplItem const& LinkImplItem;
222 cmListFileBacktrace Backtrace;
223 std::vector<std::string> Values;
224 bool ContextDependent = false;
227 EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
228 cmGeneratorTarget const* thisTarget, std::string const& config,
229 std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
230 cmGeneratorTarget::TargetPropertyEntry& entry)
232 EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
233 cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
234 thisTarget, dagChecker, lang),
236 if (entry.GetHadContextSensitiveCondition()) {
237 ee.ContextDependent = true;
242 struct EvaluatedTargetPropertyEntries
244 std::vector<EvaluatedTargetPropertyEntry> Entries;
245 bool HadContextSensitiveCondition = false;
248 EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
249 cmGeneratorTarget const* thisTarget, std::string const& config,
250 std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
251 std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
254 EvaluatedTargetPropertyEntries out;
255 out.Entries.reserve(in.size());
256 for (auto& entry : in) {
257 out.Entries.emplace_back(EvaluateTargetPropertyEntry(
258 thisTarget, config, lang, dagChecker, *entry));
264 cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
266 , FortranModuleDirectoryCreated(false)
267 , SourceFileFlagsConstructed(false)
268 , PolicyWarnedCMP0022(false)
269 , PolicyReportedCMP0069(false)
270 , DebugIncludesDone(false)
271 , DebugCompileOptionsDone(false)
272 , DebugCompileFeaturesDone(false)
273 , DebugCompileDefinitionsDone(false)
274 , DebugLinkOptionsDone(false)
275 , DebugLinkDirectoriesDone(false)
276 , DebugPrecompileHeadersDone(false)
277 , DebugSourcesDone(false)
278 , LinkImplementationLanguageIsContextDependent(true)
279 , UtilityItemsDone(false)
281 this->Makefile = this->Target->GetMakefile();
282 this->LocalGenerator = lg;
283 this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
285 this->GlobalGenerator->ComputeTargetObjectDirectory(this);
287 CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
288 t->GetIncludeDirectoriesBacktraces(),
289 this->IncludeDirectoriesEntries);
291 CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
292 t->GetCompileOptionsBacktraces(),
293 this->CompileOptionsEntries);
295 CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
296 t->GetCompileFeaturesBacktraces(),
297 this->CompileFeaturesEntries);
299 CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
300 t->GetCompileDefinitionsBacktraces(),
301 this->CompileDefinitionsEntries);
303 CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
304 t->GetLinkOptionsBacktraces(),
305 this->LinkOptionsEntries);
307 CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
308 t->GetLinkDirectoriesBacktraces(),
309 this->LinkDirectoriesEntries);
311 CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
312 t->GetPrecompileHeadersBacktraces(),
313 this->PrecompileHeadersEntries);
315 CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
316 t->GetSourceBacktraces(),
317 this->SourceEntries, true);
319 this->PolicyMap = t->GetPolicyMap();
321 // Get hard-coded linker language
322 if (this->Target->GetProperty("HAS_CXX")) {
323 this->LinkerLanguage = "CXX";
325 this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
329 cmGeneratorTarget::~cmGeneratorTarget() = default;
331 const std::string& cmGeneratorTarget::GetSourcesProperty() const
333 std::vector<std::string> values;
334 for (auto& se : this->SourceEntries) {
335 values.push_back(se->GetInput());
337 static std::string value;
339 value = cmJoin(values, ";");
343 cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
345 return this->GetLocalGenerator()->GetGlobalGenerator();
348 cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
350 return this->LocalGenerator;
353 cmStateEnums::TargetType cmGeneratorTarget::GetType() const
355 return this->Target->GetType();
358 const std::string& cmGeneratorTarget::GetName() const
360 return this->Target->GetName();
363 std::string cmGeneratorTarget::GetExportName() const
365 cmProp exportName = this->GetProperty("EXPORT_NAME");
367 if (exportName && !exportName->empty()) {
368 if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
369 std::ostringstream e;
370 e << "EXPORT_NAME property \"" << *exportName << "\" for \""
371 << this->GetName() << "\": is not valid.";
372 cmSystemTools::Error(e.str());
377 return this->GetName();
380 cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const
382 if (!cmTargetPropertyComputer::PassesWhitelist(
383 this->GetType(), prop, this->Makefile->GetMessenger(),
384 this->GetBacktrace())) {
387 if (cmProp result = cmTargetPropertyComputer::GetProperty(
388 this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) {
391 if (cmSystemTools::GetFatalErrorOccured()) {
394 return this->Target->GetProperty(prop);
397 std::string const& cmGeneratorTarget::GetSafeProperty(
398 std::string const& prop) const
400 cmProp ret = this->GetProperty(prop);
405 static std::string const s_empty;
409 const char* cmGeneratorTarget::GetOutputTargetType(
410 cmStateEnums::ArtifactType artifact) const
412 switch (this->GetType()) {
413 case cmStateEnums::SHARED_LIBRARY:
414 if (this->IsDLLPlatform()) {
416 case cmStateEnums::RuntimeBinaryArtifact:
417 // A DLL shared library is treated as a runtime target.
419 case cmStateEnums::ImportLibraryArtifact:
420 // A DLL import library is treated as an archive target.
424 // For non-DLL platforms shared libraries are treated as
429 case cmStateEnums::STATIC_LIBRARY:
430 // Static libraries are always treated as archive targets.
432 case cmStateEnums::MODULE_LIBRARY:
434 case cmStateEnums::RuntimeBinaryArtifact:
435 // Module libraries are always treated as library targets.
437 case cmStateEnums::ImportLibraryArtifact:
438 // Module import libraries are treated as archive targets.
442 case cmStateEnums::OBJECT_LIBRARY:
443 // Object libraries are always treated as object targets.
445 case cmStateEnums::EXECUTABLE:
447 case cmStateEnums::RuntimeBinaryArtifact:
448 // Executables are always treated as runtime targets.
450 case cmStateEnums::ImportLibraryArtifact:
451 // Executable import libraries are treated as archive targets.
461 std::string cmGeneratorTarget::GetOutputName(
462 const std::string& config, cmStateEnums::ArtifactType artifact) const
464 // Lookup/compute/cache the output name for this configuration.
465 OutputNameKey key(config, artifact);
466 auto i = this->OutputNameMap.find(key);
467 if (i == this->OutputNameMap.end()) {
468 // Add empty name in map to detect potential recursion.
469 OutputNameMapType::value_type entry(key, "");
470 i = this->OutputNameMap.insert(entry).first;
472 // Compute output name.
473 std::vector<std::string> props;
474 std::string type = this->GetOutputTargetType(artifact);
475 std::string configUpper = cmSystemTools::UpperCase(config);
476 if (!type.empty() && !configUpper.empty()) {
477 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
478 props.push_back(type + "_OUTPUT_NAME_" + configUpper);
481 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
482 props.push_back(type + "_OUTPUT_NAME");
484 if (!configUpper.empty()) {
485 // OUTPUT_NAME_<CONFIG>
486 props.push_back("OUTPUT_NAME_" + configUpper);
487 // <CONFIG>_OUTPUT_NAME
488 props.push_back(configUpper + "_OUTPUT_NAME");
491 props.emplace_back("OUTPUT_NAME");
494 for (std::string const& p : props) {
495 if (cmProp outNameProp = this->GetProperty(p)) {
496 outName = *outNameProp;
501 if (outName.empty()) {
502 outName = this->GetName();
505 // Now evaluate genex and update the previously-prepared map entry.
507 cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
508 } else if (i->second.empty()) {
509 // An empty map entry indicates we have been called recursively
510 // from the above block.
511 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
512 MessageType::FATAL_ERROR,
513 "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
514 this->GetBacktrace());
519 std::string cmGeneratorTarget::GetFilePrefix(
520 const std::string& config, cmStateEnums::ArtifactType artifact) const
522 if (this->IsImported()) {
523 const char* prefix = this->GetFilePrefixInternal(config, artifact);
525 return prefix ? prefix : std::string();
531 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
534 std::string cmGeneratorTarget::GetFileSuffix(
535 const std::string& config, cmStateEnums::ArtifactType artifact) const
537 if (this->IsImported()) {
538 const char* suffix = this->GetFileSuffixInternal(config, artifact);
540 return suffix ? suffix : std::string();
546 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
550 std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
552 cmProp postfix = nullptr;
553 std::string frameworkPostfix;
554 if (!config.empty()) {
555 std::string configProp =
556 cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
557 postfix = this->GetProperty(configProp);
559 // Mac application bundles and frameworks have no regular postfix like
561 if (!this->IsImported() && postfix &&
562 (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
566 // Frameworks created by multi config generators can have a special
567 // framework postfix.
568 frameworkPostfix = GetFrameworkMultiConfigPostfix(config);
569 if (!frameworkPostfix.empty()) {
570 postfix = &frameworkPostfix;
573 return postfix ? *postfix : std::string();
576 std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
577 const std::string& config) const
579 cmProp postfix = nullptr;
580 if (!config.empty()) {
581 std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
582 cmSystemTools::UpperCase(config));
583 postfix = this->GetProperty(configProp);
585 if (!this->IsImported() && postfix &&
586 (this->IsFrameworkOnApple() &&
587 !GetGlobalGenerator()->IsMultiConfig())) {
591 return postfix ? *postfix : std::string();
594 const char* cmGeneratorTarget::GetFilePrefixInternal(
595 std::string const& config, cmStateEnums::ArtifactType artifact,
596 const std::string& language) const
598 // no prefix for non-main target types.
599 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
600 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
601 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
602 this->GetType() != cmStateEnums::EXECUTABLE) {
606 const bool isImportedLibraryArtifact =
607 (artifact == cmStateEnums::ImportLibraryArtifact);
609 // Return an empty prefix for the import library if this platform
610 // does not support import libraries.
611 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
615 // The implib option is only allowed for shared libraries, module
616 // libraries, and executables.
617 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
618 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
619 this->GetType() != cmStateEnums::EXECUTABLE) {
620 artifact = cmStateEnums::RuntimeBinaryArtifact;
623 // Compute prefix value.
624 cmProp targetPrefix =
625 (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
626 : this->GetProperty("PREFIX"));
629 const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
630 if (!language.empty() && prefixVar && *prefixVar) {
631 std::string langPrefix = prefixVar + std::string("_") + language;
632 targetPrefix = this->Makefile->GetDef(langPrefix);
635 // if there is no prefix on the target nor specific language
636 // use the cmake definition.
637 if (!targetPrefix && prefixVar) {
638 targetPrefix = this->Makefile->GetDef(prefixVar);
642 return targetPrefix ? targetPrefix->c_str() : nullptr;
644 const char* cmGeneratorTarget::GetFileSuffixInternal(
645 std::string const& config, cmStateEnums::ArtifactType artifact,
646 const std::string& language) const
648 // no suffix for non-main target types.
649 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
650 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
651 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
652 this->GetType() != cmStateEnums::EXECUTABLE) {
656 const bool isImportedLibraryArtifact =
657 (artifact == cmStateEnums::ImportLibraryArtifact);
659 // Return an empty suffix for the import library if this platform
660 // does not support import libraries.
661 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
665 // The implib option is only allowed for shared libraries, module
666 // libraries, and executables.
667 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
668 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
669 this->GetType() != cmStateEnums::EXECUTABLE) {
670 artifact = cmStateEnums::RuntimeBinaryArtifact;
673 // Compute suffix value.
674 cmProp targetSuffix =
675 (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
676 : this->GetProperty("SUFFIX"));
679 const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
680 if (!language.empty() && suffixVar && *suffixVar) {
681 std::string langSuffix = suffixVar + std::string("_") + language;
682 targetSuffix = this->Makefile->GetDef(langSuffix);
685 // if there is no suffix on the target nor specific language
686 // use the cmake definition.
687 if (!targetSuffix && suffixVar) {
688 targetSuffix = this->Makefile->GetDef(suffixVar);
692 return targetSuffix ? targetSuffix->c_str() : nullptr;
695 void cmGeneratorTarget::ClearSourcesCache()
697 this->AllConfigSources.clear();
698 this->KindedSourcesMap.clear();
699 this->LinkImplementationLanguageIsContextDependent = true;
700 this->Objects.clear();
701 this->VisitedConfigsForObjects.clear();
704 void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
706 this->SourceEntries.insert(
707 before ? this->SourceEntries.begin() : this->SourceEntries.end(),
708 CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
709 this->ClearSourcesCache();
712 void cmGeneratorTarget::AddSource(const std::string& src, bool before)
714 this->Target->AddSource(src, before);
715 this->AddSourceCommon(src, before);
718 void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
720 this->Target->AddTracedSources(srcs);
722 this->AddSourceCommon(cmJoin(srcs, ";"));
726 void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
729 this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
730 this->IncludeDirectoriesEntries.insert(
731 before ? this->IncludeDirectoriesEntries.begin()
732 : this->IncludeDirectoriesEntries.end(),
733 CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
736 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
737 cmSourceFile const* sf) const
739 auto i = this->SourceDepends.find(sf);
740 if (i != this->SourceDepends.end()) {
741 return &i->second.Depends;
747 void handleSystemIncludesDep(cmLocalGenerator* lg,
748 cmGeneratorTarget const* depTgt,
749 const std::string& config,
750 cmGeneratorTarget const* headTarget,
751 cmGeneratorExpressionDAGChecker* dagChecker,
752 std::vector<std::string>& result,
753 bool excludeImported, std::string const& language)
756 depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
757 cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
758 dagChecker, depTgt, language),
761 if (!depTgt->IsImported() || excludeImported) {
765 if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
766 cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
767 dagChecker, depTgt, language),
773 /* clang-format off */
774 #define IMPLEMENT_VISIT(KIND) \
776 KindedSources const& kinded = this->GetKindedSources(config); \
777 for (SourceAndKind const& s : kinded.Sources) { \
778 if (s.Kind == KIND) { \
779 data.push_back(s.Source.Value); \
783 /* clang-format on */
785 void cmGeneratorTarget::GetObjectSources(
786 std::vector<cmSourceFile const*>& data, const std::string& config) const
788 IMPLEMENT_VISIT(SourceKindObjectSource);
790 if (this->VisitedConfigsForObjects.count(config)) {
794 for (cmSourceFile const* it : data) {
798 this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
799 this->VisitedConfigsForObjects.insert(config);
802 void cmGeneratorTarget::ComputeObjectMapping()
804 auto const& configs = this->Makefile->GetGeneratorConfigs();
805 std::set<std::string> configSet(configs.begin(), configs.end());
806 if (configSet == this->VisitedConfigsForObjects) {
810 for (std::string const& c : configs) {
811 std::vector<cmSourceFile const*> sourceFiles;
812 this->GetObjectSources(sourceFiles, c);
816 const char* cmGeneratorTarget::GetFeature(const std::string& feature,
817 const std::string& config) const
819 if (!config.empty()) {
820 std::string featureConfig =
821 cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
822 if (cmProp value = this->GetProperty(featureConfig)) {
823 return value->c_str();
826 if (cmProp value = this->GetProperty(feature)) {
827 return value->c_str();
829 return this->LocalGenerator->GetFeature(feature, config);
832 const char* cmGeneratorTarget::GetLinkPIEProperty(
833 const std::string& config) const
835 static std::string PICValue;
837 PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
838 "POSITION_INDEPENDENT_CODE", config);
840 if (PICValue == "(unset)") {
841 // POSITION_INDEPENDENT_CODE is not set
845 auto status = this->GetPolicyStatusCMP0083();
846 return (status != cmPolicies::WARN && status != cmPolicies::OLD)
851 bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
852 std::string const& config) const
854 const char* feature = "INTERPROCEDURAL_OPTIMIZATION";
855 const bool result = cmIsOn(this->GetFeature(feature, config));
858 // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
862 if (lang != "C" && lang != "CXX" && lang != "Fortran") {
863 // We do not define IPO behavior for other languages.
867 cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
869 if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
870 if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
873 if (this->PolicyReportedCMP0069) {
874 // problem is already reported, no need to issue a message
877 const bool in_try_compile =
878 this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
879 if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
880 std::ostringstream w;
881 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
882 w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
883 << "'" << this->GetName() << "'.";
884 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
885 MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
887 this->PolicyReportedCMP0069 = true;
892 // Note: check consistency with messages from CheckIPOSupported
893 const char* message = nullptr;
894 if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
895 message = "CMake doesn't support IPO for current compiler";
896 } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
897 "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
898 message = "Compiler doesn't support IPO";
899 } else if (!this->GlobalGenerator->IsIPOSupported()) {
900 message = "CMake doesn't support IPO for current generator";
904 // No error/warning messages
908 if (this->PolicyReportedCMP0069) {
909 // problem is already reported, no need to issue a message
913 this->PolicyReportedCMP0069 = true;
915 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
916 MessageType::FATAL_ERROR, message, this->GetBacktrace());
920 const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
922 this->ComputeObjectMapping();
923 return this->Objects[file];
926 const char* cmGeneratorTarget::GetCustomObjectExtension() const
928 static std::string extension;
929 const bool has_ptx_extension =
930 this->GetPropertyAsBool("CUDA_PTX_COMPILATION");
931 if (has_ptx_extension) {
933 return extension.c_str();
938 void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
940 this->ExplicitObjectName.insert(sf);
943 bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
945 const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
946 auto it = this->ExplicitObjectName.find(file);
947 return it != this->ExplicitObjectName.end();
950 void cmGeneratorTarget::GetModuleDefinitionSources(
951 std::vector<cmSourceFile const*>& data, const std::string& config) const
953 IMPLEMENT_VISIT(SourceKindModuleDefinition);
956 void cmGeneratorTarget::GetHeaderSources(
957 std::vector<cmSourceFile const*>& data, const std::string& config) const
959 IMPLEMENT_VISIT(SourceKindHeader);
962 void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
963 const std::string& config) const
965 IMPLEMENT_VISIT(SourceKindExtra);
968 void cmGeneratorTarget::GetCustomCommands(
969 std::vector<cmSourceFile const*>& data, const std::string& config) const
971 IMPLEMENT_VISIT(SourceKindCustomCommand);
974 void cmGeneratorTarget::GetExternalObjects(
975 std::vector<cmSourceFile const*>& data, const std::string& config) const
977 IMPLEMENT_VISIT(SourceKindExternalObject);
980 void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
981 const std::string& config) const
983 IMPLEMENT_VISIT(SourceKindManifest);
986 std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
988 if (!this->UtilityItemsDone) {
989 this->UtilityItemsDone = true;
990 std::set<BT<std::pair<std::string, bool>>> const& utilities =
991 this->GetUtilities();
992 for (BT<std::pair<std::string, bool>> const& i : utilities) {
993 if (cmGeneratorTarget* gt =
994 this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
995 this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
997 this->UtilityItems.insert(
998 cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
1002 return this->UtilityItems;
1005 const std::string& cmGeneratorTarget::GetLocation(
1006 const std::string& config) const
1008 static std::string location;
1009 if (this->IsImported()) {
1010 location = this->Target->ImportedGetFullPath(
1011 config, cmStateEnums::RuntimeBinaryArtifact);
1013 location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1018 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
1021 return this->Target->GetPreBuildCommands();
1024 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
1027 return this->Target->GetPreLinkCommands();
1030 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
1033 return this->Target->GetPostBuildCommands();
1036 bool cmGeneratorTarget::IsImported() const
1038 return this->Target->IsImported();
1041 bool cmGeneratorTarget::IsImportedGloballyVisible() const
1043 return this->Target->IsImportedGloballyVisible();
1046 const std::string& cmGeneratorTarget::GetLocationForBuild() const
1048 static std::string location;
1049 if (this->IsImported()) {
1050 location = this->Target->ImportedGetFullPath(
1051 "", cmStateEnums::RuntimeBinaryArtifact);
1055 // Now handle the deprecated build-time configuration location.
1056 std::string const noConfig;
1057 location = this->GetDirectory(noConfig);
1058 const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
1059 if (cfgid && strcmp(cfgid, ".") != 0) {
1064 if (this->IsAppBundleOnApple()) {
1065 std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
1066 if (!macdir.empty()) {
1072 location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
1076 bool cmGeneratorTarget::IsSystemIncludeDirectory(
1077 const std::string& dir, const std::string& config,
1078 const std::string& language) const
1080 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
1081 std::string config_upper;
1082 if (!config.empty()) {
1083 config_upper = cmSystemTools::UpperCase(config);
1086 using IncludeCacheType = std::map<std::string, std::vector<std::string>>;
1087 auto iter = this->SystemIncludesCache.find(config_upper);
1089 if (iter == this->SystemIncludesCache.end()) {
1090 cmGeneratorExpressionDAGChecker dagChecker(
1091 this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
1093 bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
1095 std::vector<std::string> result;
1096 for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
1097 cmExpandList(cmGeneratorExpression::Evaluate(it, this->LocalGenerator,
1098 config, this, &dagChecker,
1103 std::vector<cmGeneratorTarget const*> const& deps =
1104 this->GetLinkImplementationClosure(config);
1105 for (cmGeneratorTarget const* dep : deps) {
1106 handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
1107 &dagChecker, result, excludeImported, language);
1110 std::for_each(result.begin(), result.end(),
1111 cmSystemTools::ConvertToUnixSlashes);
1112 std::sort(result.begin(), result.end());
1113 result.erase(std::unique(result.begin(), result.end()), result.end());
1115 IncludeCacheType::value_type entry(config_upper, result);
1116 iter = this->SystemIncludesCache.insert(entry).first;
1119 return std::binary_search(iter->second.begin(), iter->second.end(), dir);
1122 bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
1124 return this->Target->GetPropertyAsBool(prop);
1127 bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
1128 std::string const& prop, cmGeneratorExpressionContext* context,
1129 bool usage_requirements_only) const
1131 std::string const key = prop + '@' + context->Config;
1132 auto i = this->MaybeInterfacePropertyExists.find(key);
1133 if (i == this->MaybeInterfacePropertyExists.end()) {
1134 // Insert an entry now in case there is a cycle.
1135 i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
1136 bool& maybeInterfaceProp = i->second;
1138 // If this target itself has a non-empty property value, we are done.
1139 cmProp p = this->GetProperty(prop);
1140 maybeInterfaceProp = p && !p->empty();
1142 // Otherwise, recurse to interface dependencies.
1143 if (!maybeInterfaceProp) {
1144 cmGeneratorTarget const* headTarget =
1145 context->HeadTarget ? context->HeadTarget : this;
1146 if (cmLinkInterfaceLibraries const* iface =
1147 this->GetLinkInterfaceLibraries(context->Config, headTarget,
1148 usage_requirements_only)) {
1149 if (iface->HadHeadSensitiveCondition) {
1150 // With a different head target we may get to a library with
1151 // this interface property.
1152 maybeInterfaceProp = true;
1154 // The transitive interface libraries do not depend on the
1155 // head target, so we can follow them.
1156 for (cmLinkItem const& lib : iface->Libraries) {
1158 lib.Target->MaybeHaveInterfaceProperty(
1159 prop, context, usage_requirements_only)) {
1160 maybeInterfaceProp = true;
1171 std::string cmGeneratorTarget::EvaluateInterfaceProperty(
1172 std::string const& prop, cmGeneratorExpressionContext* context,
1173 cmGeneratorExpressionDAGChecker* dagCheckerParent,
1174 bool usage_requirements_only) const
1178 // If the property does not appear transitively at all, we are done.
1179 if (!this->MaybeHaveInterfaceProperty(prop, context,
1180 usage_requirements_only)) {
1184 // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is
1185 // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
1186 // but sufficient for transitive interface properties.
1187 cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
1188 nullptr, dagCheckerParent);
1189 switch (dagChecker.Check()) {
1190 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1191 dagChecker.ReportError(
1192 context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
1194 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1195 // No error. We just skip cyclic references.
1196 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1197 // No error. We have already seen this transitive property.
1199 case cmGeneratorExpressionDAGChecker::DAG:
1203 cmGeneratorTarget const* headTarget =
1204 context->HeadTarget ? context->HeadTarget : this;
1206 if (cmProp p = this->GetProperty(prop)) {
1207 result = cmGeneratorExpressionNode::EvaluateDependentExpression(
1208 *p, context->LG, context, headTarget, &dagChecker, this);
1211 if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
1212 context->Config, headTarget, usage_requirements_only)) {
1213 context->HadContextSensitiveCondition =
1214 context->HadContextSensitiveCondition ||
1215 iface->HadContextSensitiveCondition;
1216 for (cmLinkItem const& lib : iface->Libraries) {
1217 // Broken code can have a target in its own link interface.
1218 // Don't follow such link interface entries so as not to create a
1219 // self-referencing loop.
1220 if (lib.Target && lib.Target != this) {
1221 // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
1222 // above property and hand-evaluate it as if it were compiled.
1223 // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1224 cmGeneratorExpressionContext libContext(
1225 context->LG, context->Config, context->Quiet, headTarget, this,
1226 context->EvaluateForBuildsystem, context->Backtrace,
1228 std::string libResult = cmGeneratorExpression::StripEmptyListElements(
1229 lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker,
1230 usage_requirements_only));
1231 if (!libResult.empty()) {
1232 if (result.empty()) {
1233 result = std::move(libResult);
1235 result.reserve(result.size() + 1 + libResult.size());
1237 result += libResult;
1240 context->HadContextSensitiveCondition =
1241 context->HadContextSensitiveCondition ||
1242 libContext.HadContextSensitiveCondition;
1243 context->HadHeadSensitiveCondition =
1244 context->HadHeadSensitiveCondition ||
1245 libContext.HadHeadSensitiveCondition;
1254 std::string AddSwiftInterfaceIncludeDirectories(
1255 const cmGeneratorTarget* root, const cmGeneratorTarget* target,
1256 const std::string& config, cmGeneratorExpressionDAGChecker* context)
1258 cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1259 "Swift_MODULE_DIRECTORY", nullptr,
1261 switch (dag.Check()) {
1262 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
1263 dag.ReportError(nullptr,
1264 "$<TARGET_PROPERTY:" + target->GetName() +
1265 ",Swift_MODULE_DIRECTORY>");
1267 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
1268 // No error. We just skip cyclic references.
1269 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
1270 // No error. We have already seen this transitive property.
1272 case cmGeneratorExpressionDAGChecker::DAG:
1276 std::string directories;
1277 if (const auto* interface =
1278 target->GetLinkInterfaceLibraries(config, root, true)) {
1279 for (const cmLinkItem& library : interface->Libraries) {
1280 if (const cmGeneratorTarget* dependency = library.Target) {
1281 if (cm::contains(dependency->GetAllConfigCompileLanguages(),
1284 dependency->GetSafeProperty("Swift_MODULE_DIRECTORY");
1285 if (value.empty()) {
1287 dependency->GetLocalGenerator()->GetCurrentBinaryDirectory();
1290 if (!directories.empty()) {
1293 directories += value;
1301 void AddSwiftImplicitIncludeDirectories(
1302 const cmGeneratorTarget* target, const std::string& config,
1303 EvaluatedTargetPropertyEntries& entries)
1305 if (const auto* libraries = target->GetLinkImplementationLibraries(config)) {
1306 cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
1307 "Swift_MODULE_DIRECTORY", nullptr,
1310 for (const cmLinkImplItem& library : libraries->Libraries) {
1311 if (const cmGeneratorTarget* dependency = library.Target) {
1312 if (dependency->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1315 if (cm::contains(dependency->GetAllConfigCompileLanguages(),
1317 EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
1319 if (cmProp val = dependency->GetProperty("Swift_MODULE_DIRECTORY")) {
1320 entry.Values.emplace_back(*val);
1322 entry.Values.emplace_back(
1323 dependency->GetLocalGenerator()->GetCurrentBinaryDirectory());
1326 cmExpandList(AddSwiftInterfaceIncludeDirectories(target, dependency,
1330 entries.Entries.emplace_back(std::move(entry));
1337 void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
1338 std::string const& config, std::string const& prop,
1339 std::string const& lang,
1340 cmGeneratorExpressionDAGChecker* dagChecker,
1341 EvaluatedTargetPropertyEntries& entries,
1342 bool usage_requirements_only = true)
1344 if (cmLinkImplementationLibraries const* impl =
1345 headTarget->GetLinkImplementationLibraries(config)) {
1346 entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
1347 for (cmLinkImplItem const& lib : impl->Libraries) {
1349 EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1350 // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
1351 // caller's property and hand-evaluate it as if it were compiled.
1352 // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1353 cmGeneratorExpressionContext context(
1354 headTarget->GetLocalGenerator(), config, false, headTarget,
1355 headTarget, true, lib.Backtrace, lang);
1356 cmExpandList(lib.Target->EvaluateInterfaceProperty(
1357 prop, &context, dagChecker, usage_requirements_only),
1359 ee.ContextDependent = context.HadContextSensitiveCondition;
1360 entries.Entries.emplace_back(std::move(ee));
1366 void AddObjectEntries(cmGeneratorTarget const* headTarget,
1367 std::string const& config,
1368 cmGeneratorExpressionDAGChecker* dagChecker,
1369 EvaluatedTargetPropertyEntries& entries)
1371 if (cmLinkImplementationLibraries const* impl =
1372 headTarget->GetLinkImplementationLibraries(config)) {
1373 entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
1374 for (cmLinkImplItem const& lib : impl->Libraries) {
1376 lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1377 std::string uniqueName =
1378 headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
1380 std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
1381 cmGeneratorExpression ge(lib.Backtrace);
1382 std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
1383 cge->SetEvaluateForBuildsystem(true);
1385 EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
1386 cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config,
1387 headTarget, dagChecker),
1389 if (cge->GetHadContextSensitiveCondition()) {
1390 ee.ContextDependent = true;
1392 entries.Entries.emplace_back(std::move(ee));
1398 bool processSources(cmGeneratorTarget const* tgt,
1399 EvaluatedTargetPropertyEntries& entries,
1400 std::vector<BT<std::string>>& srcs,
1401 std::unordered_set<std::string>& uniqueSrcs,
1404 cmMakefile* mf = tgt->Target->GetMakefile();
1406 bool contextDependent = entries.HadContextSensitiveCondition;
1408 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
1409 if (entry.ContextDependent) {
1410 contextDependent = true;
1413 cmLinkImplItem const& item = entry.LinkImplItem;
1414 std::string const& targetName = item.AsStr();
1416 for (std::string& src : entry.Values) {
1417 cmSourceFile* sf = mf->GetOrCreateSource(src);
1419 std::string fullPath = sf->ResolveFullPath(&e);
1420 if (fullPath.empty()) {
1422 cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
1423 cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
1425 return contextDependent;
1428 if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
1429 std::ostringstream err;
1430 if (!targetName.empty()) {
1431 err << "Target \"" << targetName
1432 << "\" contains relative path in its INTERFACE_SOURCES:\n \""
1435 err << "Found relative path while evaluating sources of \""
1436 << tgt->GetName() << "\":\n \"" << src << "\"\n";
1438 tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
1440 return contextDependent;
1444 std::string usedSources;
1445 for (std::string const& src : entry.Values) {
1446 if (uniqueSrcs.insert(src).second) {
1447 srcs.emplace_back(src, entry.Backtrace);
1449 usedSources += " * " + src + "\n";
1453 if (!usedSources.empty()) {
1454 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
1456 std::string("Used sources for target ") + tgt->GetName() + ":\n" +
1461 return contextDependent;
1465 std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
1466 std::string const& config) const
1468 std::vector<BT<std::string>> files;
1469 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
1471 if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1472 // At configure-time, this method can be called as part of getting the
1473 // LOCATION property or to export() a file to be include()d. However
1474 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
1475 // for TARGET_OBJECTS instead for backwards compatibility with OLD
1476 // behavior of CMP0024 and CMP0026 only.
1478 cmStringRange sourceEntries = this->Target->GetSourceEntries();
1479 for (std::string const& entry : sourceEntries) {
1480 std::vector<std::string> items = cmExpandedList(entry);
1481 for (std::string const& item : items) {
1482 if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
1483 item.back() == '>') {
1486 files.emplace_back(item);
1492 std::vector<std::string> debugProperties;
1493 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
1497 !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES");
1499 if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1500 this->DebugSourcesDone = true;
1503 cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
1506 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
1507 this, config, std::string(), &dagChecker, this->SourceEntries);
1509 std::unordered_set<std::string> uniqueSrcs;
1510 bool contextDependentDirectSources =
1511 processSources(this, entries, files, uniqueSrcs, debugSources);
1513 // Collect INTERFACE_SOURCES of all direct link-dependencies.
1514 EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries;
1515 AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(),
1516 &dagChecker, linkInterfaceSourcesEntries);
1517 std::vector<std::string>::size_type numFilesBefore = files.size();
1518 bool contextDependentInterfaceSources = processSources(
1519 this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources);
1521 // Collect TARGET_OBJECTS of direct object link-dependencies.
1522 bool contextDependentObjects = false;
1523 std::vector<std::string>::size_type numFilesBefore2 = files.size();
1524 if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
1525 EvaluatedTargetPropertyEntries linkObjectsEntries;
1526 AddObjectEntries(this, config, &dagChecker, linkObjectsEntries);
1527 contextDependentObjects = processSources(this, linkObjectsEntries, files,
1528 uniqueSrcs, debugSources);
1531 if (!contextDependentDirectSources &&
1532 !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
1533 !(contextDependentObjects && numFilesBefore2 < files.size())) {
1534 this->LinkImplementationLanguageIsContextDependent = false;
1540 void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
1541 const std::string& config) const
1543 std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config);
1544 files.reserve(tmp.size());
1545 for (BT<cmSourceFile*>& v : tmp) {
1546 files.push_back(v.Value);
1550 std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles(
1551 std::string const& config) const
1553 std::vector<BT<cmSourceFile*>> files;
1554 if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
1555 // Since we are still configuring not all sources may exist yet,
1556 // so we need to avoid full source classification because that
1557 // requires the absolute paths to all sources to be determined.
1558 // Since this is only for compatibility with old policies that
1559 // projects should not depend on anymore, just compute the files
1560 // without memoizing them.
1561 std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
1562 std::set<cmSourceFile*> emitted;
1563 for (BT<std::string> const& s : srcs) {
1564 cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
1565 if (emitted.insert(sf).second) {
1566 files.emplace_back(sf, s.Backtrace);
1572 KindedSources const& kinded = this->GetKindedSources(config);
1573 files.reserve(kinded.Sources.size());
1574 for (SourceAndKind const& si : kinded.Sources) {
1575 files.push_back(si.Source);
1580 void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1581 std::vector<cmSourceFile*>& files, const std::string& config) const
1583 std::vector<BT<cmSourceFile*>> tmp =
1584 this->GetSourceFilesWithoutObjectLibraries(config);
1585 files.reserve(tmp.size());
1586 for (BT<cmSourceFile*>& v : tmp) {
1587 files.push_back(v.Value);
1591 std::vector<BT<cmSourceFile*>>
1592 cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1593 std::string const& config) const
1595 std::vector<BT<cmSourceFile*>> files;
1596 KindedSources const& kinded = this->GetKindedSources(config);
1597 files.reserve(kinded.Sources.size());
1598 for (SourceAndKind const& si : kinded.Sources) {
1599 if (si.Source.Value->GetObjectLibrary().empty()) {
1600 files.push_back(si.Source);
1606 cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
1607 std::string const& config) const
1609 // If we already processed one configuration and found no dependenc
1610 // on configuration then always use the one result.
1611 if (!this->LinkImplementationLanguageIsContextDependent) {
1612 return this->KindedSourcesMap.begin()->second;
1615 // Lookup any existing link implementation for this configuration.
1616 std::string const key = cmSystemTools::UpperCase(config);
1617 auto it = this->KindedSourcesMap.find(key);
1618 if (it != this->KindedSourcesMap.end()) {
1619 if (!it->second.Initialized) {
1620 std::ostringstream e;
1621 e << "The SOURCES of \"" << this->GetName()
1622 << "\" use a generator expression that depends on the "
1623 "SOURCES themselves.";
1624 this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
1625 MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
1626 static KindedSources empty;
1632 // Add an entry to the map for this configuration.
1633 KindedSources& files = this->KindedSourcesMap[key];
1634 this->ComputeKindedSources(files, config);
1635 files.Initialized = true;
1639 void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
1640 std::string const& config) const
1642 // Get the source file paths by string.
1643 std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
1645 cmsys::RegularExpression header_regex(CM_HEADER_REGEX);
1646 std::vector<cmSourceFile*> badObjLib;
1648 std::set<cmSourceFile*> emitted;
1649 for (BT<std::string> const& s : srcs) {
1650 // Create each source at most once.
1651 cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
1652 if (!emitted.insert(sf).second) {
1656 // Compute the kind (classification) of this source file.
1658 std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
1659 if (sf->GetCustomCommand()) {
1660 kind = SourceKindCustomCommand;
1661 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
1662 // NOLINTNEXTLINE(bugprone-branch-clone)
1663 } else if (this->Target->GetType() == cmStateEnums::UTILITY) {
1664 kind = SourceKindExtra;
1665 } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) {
1666 kind = SourceKindUnityBatched;
1667 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
1668 // NOLINTNEXTLINE(bugprone-branch-clone)
1669 } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) {
1670 kind = SourceKindHeader;
1671 } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
1672 kind = SourceKindExternalObject;
1673 } else if (!sf->GetOrDetermineLanguage().empty()) {
1674 kind = SourceKindObjectSource;
1675 } else if (ext == "def") {
1676 kind = SourceKindModuleDefinition;
1677 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1678 badObjLib.push_back(sf);
1680 } else if (ext == "idl") {
1681 kind = SourceKindIDL;
1682 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1683 badObjLib.push_back(sf);
1685 } else if (ext == "resx") {
1686 kind = SourceKindResx;
1687 } else if (ext == "appxmanifest") {
1688 kind = SourceKindAppManifest;
1689 } else if (ext == "manifest") {
1690 kind = SourceKindManifest;
1691 } else if (ext == "pfx") {
1692 kind = SourceKindCertificate;
1693 } else if (ext == "xaml") {
1694 kind = SourceKindXaml;
1695 } else if (header_regex.find(sf->ResolveFullPath())) {
1696 kind = SourceKindHeader;
1698 kind = SourceKindExtra;
1701 // Save this classified source file in the result vector.
1702 files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind });
1705 if (!badObjLib.empty()) {
1706 std::ostringstream e;
1707 e << "OBJECT library \"" << this->GetName() << "\" contains:\n";
1708 for (cmSourceFile* i : badObjLib) {
1709 e << " " << i->GetLocation().GetName() << "\n";
1711 e << "but may contain only sources that compile, header files, and "
1712 "other files that would not affect linking of a normal library.";
1713 this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
1714 MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
1718 std::vector<cmGeneratorTarget::AllConfigSource> const&
1719 cmGeneratorTarget::GetAllConfigSources() const
1721 if (this->AllConfigSources.empty()) {
1722 this->ComputeAllConfigSources();
1724 return this->AllConfigSources;
1727 void cmGeneratorTarget::ComputeAllConfigSources() const
1729 std::vector<std::string> configs;
1730 this->Makefile->GetConfigurations(configs);
1732 std::map<cmSourceFile const*, size_t> index;
1734 for (size_t ci = 0; ci < configs.size(); ++ci) {
1735 KindedSources const& sources = this->GetKindedSources(configs[ci]);
1736 for (SourceAndKind const& src : sources.Sources) {
1737 auto mi = index.find(src.Source.Value);
1738 if (mi == index.end()) {
1739 AllConfigSource acs;
1740 acs.Source = src.Source.Value;
1741 acs.Kind = src.Kind;
1742 this->AllConfigSources.push_back(std::move(acs));
1743 std::map<cmSourceFile const*, size_t>::value_type entry(
1744 src.Source.Value, this->AllConfigSources.size() - 1);
1745 mi = index.insert(entry).first;
1747 this->AllConfigSources[mi->second].Configs.push_back(ci);
1752 std::vector<cmGeneratorTarget::AllConfigSource>
1753 cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
1755 std::vector<AllConfigSource> result;
1756 for (AllConfigSource const& source : this->GetAllConfigSources()) {
1757 if (source.Kind == kind) {
1758 result.push_back(source);
1764 std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
1766 std::set<std::string> languages;
1767 std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
1768 for (AllConfigSource const& si : sources) {
1769 std::string const& lang = si.Source->GetOrDetermineLanguage();
1770 if (!lang.empty()) {
1771 languages.emplace(lang);
1777 std::string cmGeneratorTarget::GetCompilePDBName(
1778 const std::string& config) const
1783 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
1784 prefix, base, suffix);
1786 // Check for a per-configuration output directory target property.
1787 std::string configUpper = cmSystemTools::UpperCase(config);
1788 std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
1789 cmProp config_name = this->GetProperty(configProp);
1790 if (config_name && !config_name->empty()) {
1791 return prefix + *config_name + ".pdb";
1794 cmProp name = this->GetProperty("COMPILE_PDB_NAME");
1795 if (name && !name->empty()) {
1796 return prefix + *name + ".pdb";
1802 std::string cmGeneratorTarget::GetCompilePDBPath(
1803 const std::string& config) const
1805 std::string dir = this->GetCompilePDBDirectory(config);
1806 std::string name = this->GetCompilePDBName(config);
1807 if (dir.empty() && !name.empty() && this->HaveWellDefinedOutputFiles()) {
1808 dir = this->GetPDBDirectory(config);
1816 bool cmGeneratorTarget::HasSOName(const std::string& config) const
1818 // soname is supported only for shared libraries and modules,
1819 // and then only when the platform supports an soname flag.
1820 return ((this->GetType() == cmStateEnums::SHARED_LIBRARY) &&
1821 !this->GetPropertyAsBool("NO_SONAME") &&
1822 this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
1825 bool cmGeneratorTarget::NeedRelinkBeforeInstall(
1826 const std::string& config) const
1828 // Only executables and shared libraries can have an rpath and may
1830 if (this->GetType() != cmStateEnums::EXECUTABLE &&
1831 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
1832 this->GetType() != cmStateEnums::MODULE_LIBRARY) {
1836 // If there is no install location this target will not be installed
1837 // and therefore does not need relinking.
1838 if (!this->Target->GetHaveInstallRule()) {
1842 // If skipping all rpaths completely then no relinking is needed.
1843 if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
1847 // If building with the install-tree rpath no relinking is needed.
1848 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
1852 // If chrpath is going to be used no relinking is needed.
1853 if (this->IsChrpathUsed(config)) {
1857 // Check for rpath support on this platform.
1858 std::string ll = this->GetLinkerLanguage(config);
1860 std::string flagVar =
1861 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG");
1862 if (!this->Makefile->IsSet(flagVar)) {
1863 // There is no rpath support on this platform so nothing needs
1868 // No linker language is known. This error will be reported by
1873 // If either a build or install tree rpath is set then the rpath
1874 // will likely change between the build tree and install tree and
1875 // this target must be relinked.
1877 this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
1879 this->LocalGenerator->GetGlobalGenerator()->GetName() == "Ninja";
1881 if (have_rpath && is_ninja) {
1882 std::ostringstream w;
1883 /* clang-format off */
1885 "The install of the " << this->GetName() << " target requires "
1886 "changing an RPATH from the build tree, but this is not supported "
1887 "with the Ninja generator unless on an ELF-based platform. The "
1888 "CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
1891 /* clang-format on */
1893 cmake* cm = this->LocalGenerator->GetCMakeInstance();
1894 cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
1900 bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
1902 // Only certain target types have an rpath.
1903 if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
1904 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
1905 this->GetType() == cmStateEnums::EXECUTABLE)) {
1909 // If the target will not be installed we do not need to change its
1911 if (!this->Target->GetHaveInstallRule()) {
1915 // Skip chrpath if skipping rpath altogether.
1916 if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
1920 // Skip chrpath if it does not need to be changed at install time.
1921 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
1925 // Allow the user to disable builtin chrpath explicitly.
1926 if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
1930 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
1934 #if defined(CMAKE_USE_ELF_PARSER)
1935 // Enable if the rpath flag uses a separator and the target uses ELF
1937 std::string ll = this->GetLinkerLanguage(config);
1939 std::string sepVar =
1940 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
1941 const char* sep = this->Makefile->GetDefinition(sepVar);
1943 // TODO: Add ELF check to ABI detection and get rid of
1944 // CMAKE_EXECUTABLE_FORMAT.
1945 if (const char* fmt =
1946 this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
1947 return strcmp(fmt, "ELF") == 0;
1952 static_cast<void>(config);
1956 bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
1957 const std::string& config) const
1959 if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY) {
1960 if (cmGeneratorTarget::ImportInfo const* info =
1961 this->GetImportInfo(config)) {
1962 return info->NoSOName;
1968 bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
1969 const std::string& config) const
1971 bool install_name_is_rpath = false;
1972 bool macosx_rpath = false;
1974 if (!this->IsImported()) {
1975 if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
1978 cmProp install_name = this->GetProperty("INSTALL_NAME_DIR");
1979 bool use_install_name = this->MacOSXUseInstallNameDir();
1980 if (install_name && use_install_name && *install_name == "@rpath") {
1981 install_name_is_rpath = true;
1982 } else if (install_name && use_install_name) {
1985 if (!install_name_is_rpath) {
1986 macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
1989 // Lookup the imported soname.
1990 if (cmGeneratorTarget::ImportInfo const* info =
1991 this->GetImportInfo(config)) {
1992 if (!info->NoSOName && !info->SOName.empty()) {
1993 if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
1994 install_name_is_rpath = true;
1997 std::string install_name;
1998 cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
1999 if (install_name.find("@rpath") != std::string::npos) {
2000 install_name_is_rpath = true;
2006 if (!install_name_is_rpath && !macosx_rpath) {
2010 if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2011 std::ostringstream w;
2012 w << "Attempting to use ";
2014 w << "MACOSX_RPATH";
2018 w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
2019 w << " This could be because you are using a Mac OS X version";
2020 w << " less than 10.5 or because CMake's platform configuration is";
2022 cmake* cm = this->LocalGenerator->GetCMakeInstance();
2023 cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
2029 bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
2031 // we can't do rpaths when unsupported
2032 if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2036 cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
2037 if (macosx_rpath_str) {
2038 return this->GetPropertyAsBool("MACOSX_RPATH");
2041 cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
2043 if (cmp0042 == cmPolicies::WARN) {
2044 this->LocalGenerator->GetGlobalGenerator()->AddCMP0042WarnTarget(
2048 return cmp0042 == cmPolicies::NEW;
2051 bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
2053 cmProp build_with_install_name =
2054 this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
2055 if (build_with_install_name) {
2056 return cmIsOn(*build_with_install_name);
2059 cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2060 if (cmp0068 == cmPolicies::NEW) {
2064 bool use_install_name = this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
2066 if (use_install_name && cmp0068 == cmPolicies::WARN) {
2067 this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2071 return use_install_name;
2074 bool cmGeneratorTarget::CanGenerateInstallNameDir(
2075 InstallNameType name_type) const
2077 cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
2079 if (cmp0068 == cmPolicies::NEW) {
2083 bool skip = this->Makefile->IsOn("CMAKE_SKIP_RPATH");
2084 if (name_type == INSTALL_NAME_FOR_INSTALL) {
2085 skip |= this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
2087 skip |= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
2090 if (skip && cmp0068 == cmPolicies::WARN) {
2091 this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
2098 std::string cmGeneratorTarget::GetSOName(const std::string& config) const
2100 if (this->IsImported()) {
2101 // Lookup the imported soname.
2102 if (cmGeneratorTarget::ImportInfo const* info =
2103 this->GetImportInfo(config)) {
2104 if (info->NoSOName) {
2105 // The imported library has no builtin soname so the name
2106 // searched at runtime will be just the filename.
2107 return cmSystemTools::GetFilenameName(info->Location);
2109 // Use the soname given if any.
2110 if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
2111 return info->SOName.substr(6);
2113 return info->SOName;
2117 // Compute the soname that will be built.
2118 return this->GetLibraryNames(config).SharedObject;
2122 bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2124 return level == cmGeneratorTarget::FullLevel;
2127 bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level)
2129 return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
2133 std::string cmGeneratorTarget::GetAppBundleDirectory(
2134 const std::string& config, BundleDirectoryLevel level) const
2136 std::string fpath = cmStrCat(
2137 this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2138 cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
2139 fpath += (ext ? *ext : "app");
2140 if (shouldAddContentLevel(level) &&
2141 !this->Makefile->PlatformIsAppleEmbedded()) {
2142 fpath += "/Contents";
2143 if (shouldAddFullLevel(level)) {
2150 bool cmGeneratorTarget::IsBundleOnApple() const
2152 return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
2153 this->IsCFBundleOnApple();
2156 std::string cmGeneratorTarget::GetCFBundleDirectory(
2157 const std::string& config, BundleDirectoryLevel level) const
2159 std::string fpath = cmStrCat(
2160 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2162 if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) {
2165 if (this->IsXCTestOnApple()) {
2172 if (shouldAddContentLevel(level) &&
2173 !this->Makefile->PlatformIsAppleEmbedded()) {
2174 fpath += "/Contents";
2175 if (shouldAddFullLevel(level)) {
2182 std::string cmGeneratorTarget::GetFrameworkDirectory(
2183 const std::string& config, BundleDirectoryLevel level) const
2185 std::string fpath = cmStrCat(
2186 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
2187 cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
2188 fpath += (ext ? *ext : "framework");
2189 if (shouldAddFullLevel(level) &&
2190 !this->Makefile->PlatformIsAppleEmbedded()) {
2191 fpath += "/Versions/";
2192 fpath += this->GetFrameworkVersion();
2197 std::string cmGeneratorTarget::GetFullName(
2198 const std::string& config, cmStateEnums::ArtifactType artifact) const
2200 if (this->IsImported()) {
2201 return this->GetFullNameImported(config, artifact);
2203 return this->GetFullNameInternal(config, artifact);
2206 std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
2207 const std::string& config) const
2209 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2211 // If building directly for installation then the build tree install_name
2212 // is the same as the install tree.
2213 if (this->MacOSXUseInstallNameDir()) {
2214 std::string installPrefix =
2215 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2216 return this->GetInstallNameDirForInstallTree(config, installPrefix);
2219 // Use the build tree directory for the target.
2220 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD)) {
2222 if (this->MacOSXRpathInstallNameDirDefault()) {
2225 dir = this->GetDirectory(config);
2234 std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
2235 const std::string& config, const std::string& installPrefix) const
2237 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2239 cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
2241 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
2242 if (install_name_dir && !install_name_dir->empty()) {
2243 dir = *install_name_dir;
2244 cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
2246 cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
2248 dir = cmStrCat(dir, '/');
2252 if (!install_name_dir) {
2253 if (this->MacOSXRpathInstallNameDirDefault()) {
2262 cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
2264 return this->Target->GetBacktrace();
2267 const std::set<BT<std::pair<std::string, bool>>>&
2268 cmGeneratorTarget::GetUtilities() const
2270 return this->Target->GetUtilities();
2273 bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
2275 return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
2276 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2277 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2278 this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
2279 this->GetType() == cmStateEnums::EXECUTABLE;
2282 const std::string* cmGeneratorTarget::GetExportMacro() const
2284 // Define the symbol for targets that export symbols.
2285 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
2286 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
2287 this->IsExecutableWithExports()) {
2288 if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
2289 this->ExportMacro = *custom_export_name;
2291 std::string in = cmStrCat(this->GetName(), "_EXPORTS");
2292 this->ExportMacro = cmSystemTools::MakeCidentifier(in);
2294 return &this->ExportMacro;
2299 class cmTargetCollectLinkLanguages
2302 cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
2304 std::unordered_set<std::string>& languages,
2305 cmGeneratorTarget const* head, bool secondPass)
2306 : Config(std::move(config))
2307 , Languages(languages)
2310 , SecondPass(secondPass)
2312 this->Visited.insert(target);
2315 void Visit(cmLinkItem const& item)
2318 if (item.AsStr().find("::") != std::string::npos) {
2319 bool noMessage = false;
2320 MessageType messageType = MessageType::FATAL_ERROR;
2321 std::ostringstream e;
2322 switch (this->Target->GetLocalGenerator()->GetPolicyStatus(
2323 cmPolicies::CMP0028)) {
2324 case cmPolicies::WARN: {
2325 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
2326 messageType = MessageType::AUTHOR_WARNING;
2328 case cmPolicies::OLD:
2330 case cmPolicies::REQUIRED_IF_USED:
2331 case cmPolicies::REQUIRED_ALWAYS:
2332 case cmPolicies::NEW:
2333 // Issue the fatal message.
2338 e << "Target \"" << this->Target->GetName()
2339 << "\" links to target \"" << item.AsStr()
2340 << "\" but the target was not found. Perhaps a find_package() "
2341 "call is missing for an IMPORTED target, or an ALIAS target is "
2343 this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
2344 messageType, e.str(), this->Target->GetBacktrace());
2349 if (!this->Visited.insert(item.Target).second) {
2352 cmLinkInterface const* iface = item.Target->GetLinkInterface(
2353 this->Config, this->HeadTarget, this->SecondPass);
2357 if (iface->HadLinkLanguageSensitiveCondition) {
2358 this->HadLinkLanguageSensitiveCondition = true;
2361 for (std::string const& language : iface->Languages) {
2362 this->Languages.insert(language);
2365 for (cmLinkItem const& lib : iface->Libraries) {
2370 bool GetHadLinkLanguageSensitiveCondition()
2372 return HadLinkLanguageSensitiveCondition;
2377 std::unordered_set<std::string>& Languages;
2378 cmGeneratorTarget const* HeadTarget;
2379 const cmGeneratorTarget* Target;
2380 std::set<cmGeneratorTarget const*> Visited;
2382 bool HadLinkLanguageSensitiveCondition = false;
2385 cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure(
2386 const std::string& config) const
2388 std::string key(cmSystemTools::UpperCase(config));
2389 auto i = this->LinkClosureMap.find(key);
2390 if (i == this->LinkClosureMap.end()) {
2392 this->ComputeLinkClosure(config, lc);
2393 LinkClosureMapType::value_type entry(key, lc);
2394 i = this->LinkClosureMap.insert(entry).first;
2399 class cmTargetSelectLinker
2402 cmGeneratorTarget const* Target;
2403 cmGlobalGenerator* GG;
2404 std::set<std::string> Preferred;
2407 cmTargetSelectLinker(cmGeneratorTarget const* target)
2411 this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator();
2413 void Consider(const std::string& lang)
2415 int preference = this->GG->GetLinkerPreference(lang);
2416 if (preference > this->Preference) {
2417 this->Preference = preference;
2418 this->Preferred.clear();
2420 if (preference == this->Preference) {
2421 this->Preferred.insert(lang);
2424 std::string Choose()
2426 if (this->Preferred.empty()) {
2429 if (this->Preferred.size() > 1) {
2430 std::ostringstream e;
2431 e << "Target " << this->Target->GetName()
2432 << " contains multiple languages with the highest linker preference"
2433 << " (" << this->Preference << "):\n";
2434 for (std::string const& li : this->Preferred) {
2435 e << " " << li << "\n";
2437 e << "Set the LINKER_LANGUAGE property for this target.";
2438 cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance();
2439 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2440 this->Target->GetBacktrace());
2442 return *this->Preferred.begin();
2446 bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2448 bool secondPass) const
2450 // Get languages built in this target.
2451 std::unordered_set<std::string> languages;
2452 cmLinkImplementation const* impl =
2453 this->GetLinkImplementation(config, secondPass);
2455 languages.insert(impl->Languages.cbegin(), impl->Languages.cend());
2457 // Add interface languages from linked targets.
2458 // cmTargetCollectLinkLanguages cll(this, config, languages, this,
2460 cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass);
2461 for (cmLinkImplItem const& lib : impl->Libraries) {
2465 // Store the transitive closure of languages.
2466 cm::append(lc.Languages, languages);
2468 // Choose the language whose linker should be used.
2469 if (secondPass || lc.LinkerLanguage.empty()) {
2470 // Find the language with the highest preference value.
2471 cmTargetSelectLinker tsl(this);
2473 // First select from the languages compiled directly in this target.
2474 for (std::string const& l : impl->Languages) {
2478 // Now consider languages that propagate from linked targets.
2479 for (std::string const& lang : languages) {
2480 std::string propagates =
2481 "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES";
2482 if (this->Makefile->IsOn(propagates)) {
2487 lc.LinkerLanguage = tsl.Choose();
2490 return impl->HadLinkLanguageSensitiveCondition ||
2491 cll.GetHadLinkLanguageSensitiveCondition();
2494 void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
2495 LinkClosure& lc) const
2497 bool secondPass = false;
2500 LinkClosure linkClosure;
2501 linkClosure.LinkerLanguage = this->LinkerLanguage;
2503 // Get languages built in this target.
2504 secondPass = this->ComputeLinkClosure(config, linkClosure, false);
2505 this->LinkerLanguage = linkClosure.LinkerLanguage;
2507 lc = std::move(linkClosure);
2512 LinkClosure linkClosure;
2514 this->ComputeLinkClosure(config, linkClosure, secondPass);
2515 lc = std::move(linkClosure);
2517 // linker language must not be changed between the two passes
2518 if (this->LinkerLanguage != lc.LinkerLanguage) {
2519 std::ostringstream e;
2520 e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> "
2521 "changes\nthe linker language for target \""
2522 << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '"
2523 << lc.LinkerLanguage << "') which is invalid.";
2524 cmSystemTools::Error(e.str());
2529 void cmGeneratorTarget::GetFullNameComponents(
2530 std::string& prefix, std::string& base, std::string& suffix,
2531 const std::string& config, cmStateEnums::ArtifactType artifact) const
2533 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
2536 std::string cmGeneratorTarget::BuildBundleDirectory(
2537 const std::string& base, const std::string& config,
2538 BundleDirectoryLevel level) const
2540 std::string fpath = base;
2541 if (this->IsAppBundleOnApple()) {
2542 fpath += this->GetAppBundleDirectory(config, level);
2544 if (this->IsFrameworkOnApple()) {
2545 fpath += this->GetFrameworkDirectory(config, level);
2547 if (this->IsCFBundleOnApple()) {
2548 fpath += this->GetCFBundleDirectory(config, level);
2553 std::string cmGeneratorTarget::GetMacContentDirectory(
2554 const std::string& config, cmStateEnums::ArtifactType artifact) const
2556 // Start with the output directory for the target.
2557 std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
2558 BundleDirectoryLevel level = ContentLevel;
2559 if (this->IsFrameworkOnApple()) {
2560 // additional files with a framework go into the version specific
2564 fpath = this->BuildBundleDirectory(fpath, config, level);
2568 std::string cmGeneratorTarget::GetEffectiveFolderName() const
2570 std::string effectiveFolder;
2572 if (!this->GlobalGenerator->UseFolderProperty()) {
2573 return effectiveFolder;
2576 cmProp targetFolder = this->GetProperty("FOLDER");
2578 effectiveFolder += *targetFolder;
2581 return effectiveFolder;
2584 cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
2585 const std::string& config) const
2587 // There is no compile information for imported targets.
2588 if (this->IsImported()) {
2592 if (this->GetType() > cmStateEnums::OBJECT_LIBRARY) {
2593 std::string msg = cmStrCat("cmTarget::GetCompileInfo called for ",
2594 this->GetName(), " which has type ",
2595 cmState::GetTargetTypeName(this->GetType()));
2596 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
2600 // Lookup/compute/cache the compile information for this configuration.
2601 std::string config_upper;
2602 if (!config.empty()) {
2603 config_upper = cmSystemTools::UpperCase(config);
2605 auto i = this->CompileInfoMap.find(config_upper);
2606 if (i == this->CompileInfoMap.end()) {
2608 this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
2609 CompileInfoMapType::value_type entry(config_upper, info);
2610 i = this->CompileInfoMap.insert(entry).first;
2615 cmGeneratorTarget::ModuleDefinitionInfo const*
2616 cmGeneratorTarget::GetModuleDefinitionInfo(std::string const& config) const
2618 // A module definition file only makes sense on certain target types.
2619 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
2620 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
2621 !this->IsExecutableWithExports()) {
2625 // Lookup/compute/cache the compile information for this configuration.
2626 std::string config_upper;
2627 if (!config.empty()) {
2628 config_upper = cmSystemTools::UpperCase(config);
2630 auto i = this->ModuleDefinitionInfoMap.find(config_upper);
2631 if (i == this->ModuleDefinitionInfoMap.end()) {
2632 ModuleDefinitionInfo info;
2633 this->ComputeModuleDefinitionInfo(config, info);
2634 ModuleDefinitionInfoMapType::value_type entry(config_upper, info);
2635 i = this->ModuleDefinitionInfoMap.insert(entry).first;
2640 void cmGeneratorTarget::ComputeModuleDefinitionInfo(
2641 std::string const& config, ModuleDefinitionInfo& info) const
2643 this->GetModuleDefinitionSources(info.Sources, config);
2644 info.WindowsExportAllSymbols =
2645 this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
2646 this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
2647 #if !defined(CMAKE_BOOTSTRAP)
2648 info.DefFileGenerated =
2649 info.WindowsExportAllSymbols || info.Sources.size() > 1;
2651 // Our __create_def helper is not available during CMake bootstrap.
2652 info.DefFileGenerated = false;
2654 if (info.DefFileGenerated) {
2656 this->GetObjectDirectory(config) /* has slash */ + "exports.def";
2657 } else if (!info.Sources.empty()) {
2658 info.DefFile = info.Sources.front()->GetFullPath();
2662 bool cmGeneratorTarget::IsDLLPlatform() const
2664 return this->Target->IsDLLPlatform();
2667 void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
2668 const std::string& config) const
2671 this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
2676 cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
2678 cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
2679 config, this, &dagChecker),
2683 void processILibs(const std::string& config,
2684 cmGeneratorTarget const* headTarget, cmLinkItem const& item,
2685 cmGlobalGenerator* gg,
2686 std::vector<cmGeneratorTarget const*>& tgts,
2687 std::set<cmGeneratorTarget const*>& emitted)
2689 if (item.Target && emitted.insert(item.Target).second) {
2690 tgts.push_back(item.Target);
2691 if (cmLinkInterfaceLibraries const* iface =
2692 item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) {
2693 for (cmLinkItem const& lib : iface->Libraries) {
2694 processILibs(config, headTarget, lib, gg, tgts, emitted);
2700 const std::vector<const cmGeneratorTarget*>&
2701 cmGeneratorTarget::GetLinkImplementationClosure(
2702 const std::string& config) const
2704 LinkImplClosure& tgts = this->LinkImplClosureMap[config];
2707 std::set<cmGeneratorTarget const*> emitted;
2709 cmLinkImplementationLibraries const* impl =
2710 this->GetLinkImplementationLibraries(config);
2712 for (cmLinkImplItem const& lib : impl->Libraries) {
2713 processILibs(config, this, lib,
2714 this->LocalGenerator->GetGlobalGenerator(), tgts, emitted);
2720 class cmTargetTraceDependencies
2723 cmTargetTraceDependencies(cmGeneratorTarget* target);
2727 cmGeneratorTarget* GeneratorTarget;
2728 cmMakefile* Makefile;
2729 cmLocalGenerator* LocalGenerator;
2730 cmGlobalGenerator const* GlobalGenerator;
2731 using SourceEntry = cmGeneratorTarget::SourceEntry;
2732 SourceEntry* CurrentEntry;
2733 std::queue<cmSourceFile*> SourceQueue;
2734 std::set<cmSourceFile*> SourcesQueued;
2735 using NameMapType = std::map<std::string, cmSourcesWithOutput>;
2736 NameMapType NameMap;
2737 std::vector<std::string> NewSources;
2739 void QueueSource(cmSourceFile* sf);
2740 void FollowName(std::string const& name);
2741 void FollowNames(std::vector<std::string> const& names);
2742 bool IsUtility(std::string const& dep);
2743 void CheckCustomCommand(cmCustomCommand const& cc);
2744 void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
2745 void FollowCommandDepends(cmCustomCommand const& cc,
2746 const std::string& config,
2747 std::set<std::string>& emitted);
2750 cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
2751 : GeneratorTarget(target)
2754 this->Makefile = target->Target->GetMakefile();
2755 this->LocalGenerator = target->GetLocalGenerator();
2756 this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
2757 this->CurrentEntry = nullptr;
2759 // Queue all the source files already specified for the target.
2760 if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
2761 std::set<cmSourceFile*> emitted;
2762 std::vector<std::string> const& configs =
2763 this->Makefile->GetGeneratorConfigs();
2764 for (std::string const& c : configs) {
2765 std::vector<cmSourceFile*> sources;
2766 this->GeneratorTarget->GetSourceFiles(sources, c);
2767 for (cmSourceFile* sf : sources) {
2768 const std::set<cmGeneratorTarget const*> tgts =
2769 this->GlobalGenerator->GetFilenameTargetDepends(sf);
2770 if (cm::contains(tgts, this->GeneratorTarget)) {
2771 std::ostringstream e;
2772 e << "Evaluation output file\n \"" << sf->ResolveFullPath()
2773 << "\"\ndepends on the sources of a target it is used in. This "
2774 "is a dependency loop and is not allowed.";
2775 this->GeneratorTarget->LocalGenerator->IssueMessage(
2776 MessageType::FATAL_ERROR, e.str());
2779 if (emitted.insert(sf).second &&
2780 this->SourcesQueued.insert(sf).second) {
2781 this->SourceQueue.push(sf);
2787 // Queue pre-build, pre-link, and post-build rule dependencies.
2788 this->CheckCustomCommands(this->GeneratorTarget->GetPreBuildCommands());
2789 this->CheckCustomCommands(this->GeneratorTarget->GetPreLinkCommands());
2790 this->CheckCustomCommands(this->GeneratorTarget->GetPostBuildCommands());
2793 void cmTargetTraceDependencies::Trace()
2795 // Process one dependency at a time until the queue is empty.
2796 while (!this->SourceQueue.empty()) {
2797 // Get the next source from the queue.
2798 cmSourceFile* sf = this->SourceQueue.front();
2799 this->SourceQueue.pop();
2800 this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
2802 // Queue dependencies added explicitly by the user.
2803 if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
2804 std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
2805 for (std::string& objDep : objDeps) {
2806 if (cmSystemTools::FileIsFullPath(objDep)) {
2807 objDep = cmSystemTools::CollapseFullPath(objDep);
2810 this->FollowNames(objDeps);
2813 // Queue the source needed to generate this file, if any.
2814 this->FollowName(sf->ResolveFullPath());
2816 // Queue dependencies added programmatically by commands.
2817 this->FollowNames(sf->GetDepends());
2819 // Queue custom command dependencies.
2820 if (cmCustomCommand const* cc = sf->GetCustomCommand()) {
2821 this->CheckCustomCommand(*cc);
2824 this->CurrentEntry = nullptr;
2826 this->GeneratorTarget->AddTracedSources(this->NewSources);
2829 void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
2831 if (this->SourcesQueued.insert(sf).second) {
2832 this->SourceQueue.push(sf);
2834 // Make sure this file is in the target at the end.
2835 this->NewSources.push_back(sf->ResolveFullPath());
2839 void cmTargetTraceDependencies::FollowName(std::string const& name)
2841 // Use lower bound with key comparison to not repeat the search for the
2842 // insert position if the name could not be found (which is the common case).
2843 auto i = this->NameMap.lower_bound(name);
2844 if (i == this->NameMap.end() || i->first != name) {
2845 // Check if we know how to generate this file.
2846 cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
2847 // If we failed to find a target or source and we have a relative path, it
2848 // might be a valid source if made relative to the current binary
2850 if (!sources.Target && !sources.Source &&
2851 !cmSystemTools::FileIsFullPath(name)) {
2853 cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
2854 fullname = cmSystemTools::CollapseFullPath(
2855 fullname, this->Makefile->GetHomeOutputDirectory());
2856 sources = this->Makefile->GetSourcesWithOutput(fullname);
2858 i = this->NameMap.emplace_hint(i, name, sources);
2860 if (cmTarget* t = i->second.Target) {
2861 // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
2862 // POST_BUILD command.
2863 this->GeneratorTarget->Target->AddUtility(t->GetName(), false);
2865 if (cmSourceFile* sf = i->second.Source) {
2866 // For now only follow the dependency if the source file is not a
2867 // byproduct. Semantics of byproducts in a non-Ninja context will have to
2868 // be defined first.
2869 if (!i->second.SourceIsByproduct) {
2870 // Record the dependency we just followed.
2871 if (this->CurrentEntry) {
2872 this->CurrentEntry->Depends.push_back(sf);
2874 this->QueueSource(sf);
2879 void cmTargetTraceDependencies::FollowNames(
2880 std::vector<std::string> const& names)
2882 for (std::string const& name : names) {
2883 this->FollowName(name);
2887 bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
2889 // Dependencies on targets (utilities) are supposed to be named by
2890 // just the target name. However for compatibility we support
2891 // naming the output file generated by the target (assuming there is
2892 // no output-name property which old code would not have set). In
2893 // that case the target name will be the file basename of the
2895 std::string util = cmSystemTools::GetFilenameName(dep);
2896 if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
2897 util = cmSystemTools::GetFilenameWithoutLastExtension(util);
2900 // Check for a target with this name.
2901 if (cmGeneratorTarget* t =
2902 this->GeneratorTarget->GetLocalGenerator()->FindGeneratorTargetToUse(
2904 // If we find the target and the dep was given as a full path,
2905 // then make sure it was not a full path to something else, and
2906 // the fact that the name matched a target was just a coincidence.
2907 if (cmSystemTools::FileIsFullPath(dep)) {
2908 if (t->GetType() >= cmStateEnums::EXECUTABLE &&
2909 t->GetType() <= cmStateEnums::MODULE_LIBRARY) {
2910 // This is really only for compatibility so we do not need to
2911 // worry about configuration names and output names.
2912 std::string tLocation = t->GetLocationForBuild();
2913 tLocation = cmSystemTools::GetFilenamePath(tLocation);
2914 std::string depLocation = cmSystemTools::GetFilenamePath(dep);
2915 depLocation = cmSystemTools::CollapseFullPath(depLocation);
2916 tLocation = cmSystemTools::CollapseFullPath(tLocation);
2917 if (depLocation == tLocation) {
2918 this->GeneratorTarget->Target->AddUtility(util, false);
2923 // The original name of the dependency was not a full path. It
2924 // must name a target, so add the target-level dependency.
2925 this->GeneratorTarget->Target->AddUtility(util, false);
2930 // The dependency does not name a target built in this project.
2934 void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
2936 // Transform command names that reference targets built in this
2937 // project to corresponding target-level dependencies.
2938 cmGeneratorExpression ge(cc.GetBacktrace());
2940 // Add target-level dependencies referenced by generator expressions.
2941 std::set<cmGeneratorTarget*> targets;
2943 for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) {
2944 std::string const& command = cCmdLine.front();
2945 // Check for a target with this name.
2946 if (cmGeneratorTarget* t =
2947 this->LocalGenerator->FindGeneratorTargetToUse(command)) {
2948 if (t->GetType() == cmStateEnums::EXECUTABLE) {
2949 // The command refers to an executable target built in
2950 // this project. Add the target-level dependency to make
2951 // sure the executable is up to date before this custom
2952 // command possibly runs.
2953 this->GeneratorTarget->Target->AddUtility(command, true);
2957 // Check for target references in generator expressions.
2958 for (std::string const& cl : cCmdLine) {
2959 const std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cl);
2960 cge->SetQuiet(true);
2961 cge->Evaluate(this->GeneratorTarget->GetLocalGenerator(), "");
2962 std::set<cmGeneratorTarget*> geTargets = cge->GetTargets();
2963 targets.insert(geTargets.begin(), geTargets.end());
2967 for (cmGeneratorTarget* target : targets) {
2968 this->GeneratorTarget->Target->AddUtility(target->GetName(), true);
2971 // Queue the custom command dependencies.
2972 std::set<std::string> emitted;
2973 std::vector<std::string> const& configs =
2974 this->Makefile->GetGeneratorConfigs();
2975 for (std::string const& conf : configs) {
2976 this->FollowCommandDepends(cc, conf, emitted);
2980 void cmTargetTraceDependencies::FollowCommandDepends(
2981 cmCustomCommand const& cc, const std::string& config,
2982 std::set<std::string>& emitted)
2984 cmCustomCommandGenerator ccg(cc, config,
2985 this->GeneratorTarget->LocalGenerator);
2987 const std::vector<std::string>& depends = ccg.GetDepends();
2989 for (std::string const& dep : depends) {
2990 if (emitted.insert(dep).second) {
2991 if (!this->IsUtility(dep)) {
2992 // The dependency does not name a target and may be a file we
2993 // know how to generate. Queue it.
2994 this->FollowName(dep);
3000 void cmTargetTraceDependencies::CheckCustomCommands(
3001 const std::vector<cmCustomCommand>& commands)
3003 for (cmCustomCommand const& command : commands) {
3004 this->CheckCustomCommand(command);
3008 void cmGeneratorTarget::TraceDependencies()
3010 // CMake-generated targets have no dependencies to trace. Normally tracing
3011 // would find nothing anyway, but when building CMake itself the "install"
3012 // target command ends up referencing the "cmake" target but we do not
3013 // really want the dependency because "install" depend on "all" anyway.
3014 if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
3018 // Use a helper object to trace the dependencies.
3019 cmTargetTraceDependencies tracer(this);
3023 std::string cmGeneratorTarget::GetCompilePDBDirectory(
3024 const std::string& config) const
3026 if (CompileInfo const* info = this->GetCompileInfo(config)) {
3027 return info->CompilePdbDir;
3032 void cmGeneratorTarget::GetAppleArchs(const std::string& config,
3033 std::vector<std::string>& archVec) const
3035 if (!this->Makefile->IsOn("APPLE")) {
3038 cmProp archs = nullptr;
3039 if (!config.empty()) {
3040 std::string defVarName =
3041 cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
3042 archs = this->GetProperty(defVarName);
3045 archs = this->GetProperty("OSX_ARCHITECTURES");
3048 cmExpandList(*archs, archVec);
3052 void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
3054 const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES");
3056 if (property.empty()) {
3057 switch (this->GetPolicyStatusCMP0104()) {
3058 case cmPolicies::WARN:
3059 if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
3060 this->Makefile->IssueMessage(
3061 MessageType::AUTHOR_WARNING,
3062 cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
3063 "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3067 case cmPolicies::OLD:
3070 this->Makefile->IssueMessage(
3071 MessageType::FATAL_ERROR,
3072 "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3077 // If CUDA_ARCHITECTURES is false we don't add any architectures.
3078 if (cmIsOff(property)) {
3082 struct CudaArchitecture
3086 bool virtual_{ true };
3088 std::vector<CudaArchitecture> architectures;
3091 std::vector<std::string> options;
3092 cmExpandList(property, options);
3094 for (std::string& option : options) {
3095 CudaArchitecture architecture;
3097 // Architecture name is up to the first specifier.
3098 std::size_t pos = option.find_first_of('-');
3099 architecture.name = option.substr(0, pos);
3101 if (pos != std::string::npos) {
3102 cm::string_view specifier{ option.c_str() + pos + 1,
3103 option.length() - pos - 1 };
3105 if (specifier == "real") {
3106 architecture.real = true;
3107 architecture.virtual_ = false;
3108 } else if (specifier == "virtual") {
3109 architecture.real = false;
3110 architecture.virtual_ = true;
3112 this->Makefile->IssueMessage(
3113 MessageType::FATAL_ERROR,
3114 "Uknown CUDA architecture specifier \"" + std::string(specifier) +
3119 architectures.emplace_back(architecture);
3123 std::string const& compiler =
3124 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3126 if (compiler == "NVIDIA") {
3127 for (CudaArchitecture& architecture : architectures) {
3129 " --generate-code=arch=compute_" + architecture.name + ",code=[";
3131 if (architecture.virtual_) {
3132 flags += "compute_" + architecture.name;
3134 if (architecture.real) {
3139 if (architecture.real) {
3140 flags += "sm_" + architecture.name;
3145 } else if (compiler == "Clang") {
3146 for (CudaArchitecture& architecture : architectures) {
3147 flags += " --cuda-gpu-arch=sm_" + architecture.name;
3149 if (!architecture.real) {
3150 Makefile->IssueMessage(
3151 MessageType::WARNING,
3152 "Clang doesn't support disabling CUDA real code generation.");
3155 if (!architecture.virtual_) {
3156 flags += " --no-cuda-include-ptx=sm_" + architecture.name;
3162 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
3164 std::string const& compiler =
3165 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3167 if (compiler == "Clang") {
3168 // Pass CUDA toolkit explicitly to Clang.
3169 // Clang's searching for the system CUDA toolkit isn't very good and it's
3170 // expected the user will explicitly pass the toolkit path.
3171 // This also avoids Clang having to search for the toolkit on every
3173 std::string toolkitRoot =
3174 this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
3176 if (!toolkitRoot.empty()) {
3177 flags += " --cuda-path=" +
3178 this->LocalGenerator->ConvertToOutputFormat(toolkitRoot,
3179 cmOutputConverter::SHELL);
3184 //----------------------------------------------------------------------------
3185 std::string cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
3186 std::string const& var, std::string const& lang,
3187 std::string const& config) const
3189 if (this->IsIPOEnabled(lang, config)) {
3190 std::string varIPO = var + "_IPO";
3191 if (this->Makefile->IsDefinitionSet(varIPO)) {
3199 //----------------------------------------------------------------------------
3200 std::string cmGeneratorTarget::GetCreateRuleVariable(
3201 std::string const& lang, std::string const& config) const
3203 switch (this->GetType()) {
3204 case cmStateEnums::STATIC_LIBRARY: {
3205 std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
3206 return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
3208 case cmStateEnums::SHARED_LIBRARY:
3209 return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
3210 case cmStateEnums::MODULE_LIBRARY:
3211 return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
3212 case cmStateEnums::EXECUTABLE:
3213 if (this->IsExecutableWithExports()) {
3214 std::string linkExeWithExports =
3215 "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
3216 if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
3217 return linkExeWithExports;
3220 return "CMAKE_" + lang + "_LINK_EXECUTABLE";
3228 void processIncludeDirectories(cmGeneratorTarget const* tgt,
3229 EvaluatedTargetPropertyEntries& entries,
3230 std::vector<BT<std::string>>& includes,
3231 std::unordered_set<std::string>& uniqueIncludes,
3234 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
3235 cmLinkImplItem const& item = entry.LinkImplItem;
3236 std::string const& targetName = item.AsStr();
3237 bool const fromImported = item.Target && item.Target->IsImported();
3238 bool const checkCMP0027 = item.FromGenex;
3240 std::string usedIncludes;
3241 for (std::string& entryInclude : entry.Values) {
3242 if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
3243 std::ostringstream e;
3244 MessageType messageType = MessageType::FATAL_ERROR;
3246 switch (tgt->GetPolicyStatusCMP0027()) {
3247 case cmPolicies::WARN:
3248 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
3250 case cmPolicies::OLD:
3251 messageType = MessageType::AUTHOR_WARNING;
3253 case cmPolicies::REQUIRED_ALWAYS:
3254 case cmPolicies::REQUIRED_IF_USED:
3255 case cmPolicies::NEW:
3259 /* clang-format off */
3260 e << "Imported target \"" << targetName << "\" includes "
3261 "non-existent path\n \"" << entryInclude << "\"\nin its "
3262 "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
3263 "* The path was deleted, renamed, or moved to another "
3265 "* An install or uninstall procedure did not complete "
3267 "* The installation package was faulty and references files it "
3268 "does not provide.\n";
3269 /* clang-format on */
3270 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3274 if (!cmSystemTools::FileIsFullPath(entryInclude)) {
3275 std::ostringstream e;
3276 bool noMessage = false;
3277 MessageType messageType = MessageType::FATAL_ERROR;
3278 if (!targetName.empty()) {
3279 /* clang-format off */
3280 e << "Target \"" << targetName << "\" contains relative "
3281 "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
3282 " \"" << entryInclude << "\"";
3283 /* clang-format on */
3285 switch (tgt->GetPolicyStatusCMP0021()) {
3286 case cmPolicies::WARN: {
3287 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
3288 messageType = MessageType::AUTHOR_WARNING;
3290 case cmPolicies::OLD:
3292 case cmPolicies::REQUIRED_IF_USED:
3293 case cmPolicies::REQUIRED_ALWAYS:
3294 case cmPolicies::NEW:
3295 // Issue the fatal message.
3298 e << "Found relative path while evaluating include directories of "
3300 << tgt->GetName() << "\":\n \"" << entryInclude << "\"\n";
3303 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
3304 if (messageType == MessageType::FATAL_ERROR) {
3310 if (!cmIsOff(entryInclude)) {
3311 cmSystemTools::ConvertToUnixSlashes(entryInclude);
3314 if (uniqueIncludes.insert(entryInclude).second) {
3315 includes.emplace_back(entryInclude, entry.Backtrace);
3316 if (debugIncludes) {
3317 usedIncludes += " * " + entryInclude + "\n";
3321 if (!usedIncludes.empty()) {
3322 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3324 std::string("Used includes for target ") + tgt->GetName() + ":\n" +
3332 std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
3333 const std::string& config, const std::string& lang) const
3335 std::vector<BT<std::string>> includes;
3336 std::unordered_set<std::string> uniqueIncludes;
3338 cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
3341 std::vector<std::string> debugProperties;
3342 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3345 bool debugIncludes = !this->DebugIncludesDone &&
3346 cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
3348 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3349 this->DebugIncludesDone = true;
3352 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3353 this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
3355 if (lang == "Swift") {
3356 AddSwiftImplicitIncludeDirectories(this, config, entries);
3359 AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
3360 &dagChecker, entries);
3362 if (this->Makefile->IsOn("APPLE")) {
3363 cmLinkImplementationLibraries const* impl =
3364 this->GetLinkImplementationLibraries(config);
3365 for (cmLinkImplItem const& lib : impl->Libraries) {
3366 std::string libDir = cmSystemTools::CollapseFullPath(
3367 lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
3369 static cmsys::RegularExpression frameworkCheck(
3370 "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
3371 if (!frameworkCheck.find(libDir)) {
3375 libDir = frameworkCheck.match(1);
3377 EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace());
3378 ee.Values.emplace_back(std::move(libDir));
3379 entries.Entries.emplace_back(std::move(ee));
3383 processIncludeDirectories(this, entries, includes, uniqueIncludes,
3389 enum class OptionsParse
3396 const auto DL_BEGIN = "<DEVICE_LINK>"_s;
3397 const auto DL_END = "</DEVICE_LINK>"_s;
3399 void processOptions(cmGeneratorTarget const* tgt,
3400 EvaluatedTargetPropertyEntries const& entries,
3401 std::vector<BT<std::string>>& options,
3402 std::unordered_set<std::string>& uniqueOptions,
3403 bool debugOptions, const char* logName, OptionsParse parse,
3404 bool processDeviceOptions = false)
3406 bool splitOption = !processDeviceOptions;
3407 for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
3408 std::string usedOptions;
3409 for (std::string const& opt : entry.Values) {
3410 if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
3411 options.emplace_back(opt, entry.Backtrace);
3412 splitOption = opt == DL_BEGIN;
3416 if (uniqueOptions.insert(opt).second) {
3417 if (parse == OptionsParse::Shell &&
3418 cmHasLiteralPrefix(opt, "SHELL:")) {
3420 std::vector<std::string> tmp;
3421 cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
3422 for (std::string& o : tmp) {
3423 options.emplace_back(std::move(o), entry.Backtrace);
3426 options.emplace_back(std::string(opt.c_str() + 6),
3430 options.emplace_back(opt, entry.Backtrace);
3433 usedOptions += " * " + opt + "\n";
3437 if (!usedOptions.empty()) {
3438 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3440 std::string("Used ") + logName + std::string(" for target ") +
3441 tgt->GetName() + ":\n" + usedOptions,
3447 std::vector<BT<std::string>> wrapOptions(
3448 std::vector<std::string>& options, const cmListFileBacktrace& bt,
3449 const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
3450 bool concatFlagAndArgs)
3452 std::vector<BT<std::string>> result;
3454 if (options.empty()) {
3458 if (wrapperFlag.empty() || cmHasLiteralPrefix(options.front(), "LINKER:")) {
3459 // nothing specified or LINKER wrapper, insert elements as is
3460 result.reserve(options.size());
3461 for (std::string& o : options) {
3462 result.emplace_back(std::move(o), bt);
3465 if (!wrapperSep.empty()) {
3466 if (concatFlagAndArgs) {
3467 // insert flag elements except last one
3468 for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
3469 result.emplace_back(*i, bt);
3471 // concatenate last flag element and all list values
3473 result.emplace_back(wrapperFlag.back() + cmJoin(options, wrapperSep),
3476 for (std::string const& i : wrapperFlag) {
3477 result.emplace_back(i, bt);
3479 // concatenate all list values in one option
3480 result.emplace_back(cmJoin(options, wrapperSep), bt);
3483 // prefix each element of list with wrapper
3484 if (concatFlagAndArgs) {
3485 std::transform(options.begin(), options.end(), options.begin(),
3486 [&wrapperFlag](std::string const& o) -> std::string {
3487 return wrapperFlag.back() + o;
3490 for (std::string& o : options) {
3491 for (auto i = wrapperFlag.begin(),
3492 e = concatFlagAndArgs ? wrapperFlag.end() - 1
3493 : wrapperFlag.end();
3495 result.emplace_back(*i, bt);
3497 result.emplace_back(std::move(o), bt);
3505 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
3506 const std::string& config,
3507 const std::string& language) const
3509 std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language);
3510 result.reserve(tmp.size());
3511 for (BT<std::string>& v : tmp) {
3512 result.emplace_back(std::move(v.Value));
3516 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
3517 std::string const& config, std::string const& language) const
3519 std::vector<BT<std::string>> result;
3520 std::unordered_set<std::string> uniqueOptions;
3522 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
3525 std::vector<std::string> debugProperties;
3526 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3529 bool debugOptions = !this->DebugCompileOptionsDone &&
3530 cm::contains(debugProperties, "COMPILE_OPTIONS");
3532 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3533 this->DebugCompileOptionsDone = true;
3536 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3537 this, config, language, &dagChecker, this->CompileOptionsEntries);
3539 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language,
3540 &dagChecker, entries);
3542 processOptions(this, entries, result, uniqueOptions, debugOptions,
3543 "compile options", OptionsParse::Shell);
3548 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
3549 const std::string& config) const
3551 std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config);
3552 result.reserve(tmp.size());
3553 for (BT<std::string>& v : tmp) {
3554 result.emplace_back(std::move(v.Value));
3558 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
3559 std::string const& config) const
3561 std::vector<BT<std::string>> result;
3562 std::unordered_set<std::string> uniqueFeatures;
3564 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
3567 std::vector<std::string> debugProperties;
3568 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3571 bool debugFeatures = !this->DebugCompileFeaturesDone &&
3572 cm::contains(debugProperties, "COMPILE_FEATURES");
3574 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3575 this->DebugCompileFeaturesDone = true;
3578 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3579 this, config, std::string(), &dagChecker, this->CompileFeaturesEntries);
3581 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES",
3582 std::string(), &dagChecker, entries);
3584 processOptions(this, entries, result, uniqueFeatures, debugFeatures,
3585 "compile features", OptionsParse::None);
3590 void cmGeneratorTarget::GetCompileDefinitions(
3591 std::vector<std::string>& result, const std::string& config,
3592 const std::string& language) const
3594 std::vector<BT<std::string>> tmp =
3595 this->GetCompileDefinitions(config, language);
3596 result.reserve(tmp.size());
3597 for (BT<std::string>& v : tmp) {
3598 result.emplace_back(std::move(v.Value));
3602 std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
3603 std::string const& config, std::string const& language) const
3605 std::vector<BT<std::string>> list;
3606 std::unordered_set<std::string> uniqueOptions;
3608 cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
3611 std::vector<std::string> debugProperties;
3612 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3615 bool debugDefines = !this->DebugCompileDefinitionsDone &&
3616 cm::contains(debugProperties, "COMPILE_DEFINITIONS");
3618 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3619 this->DebugCompileDefinitionsDone = true;
3622 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3623 this, config, language, &dagChecker, this->CompileDefinitionsEntries);
3625 AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language,
3626 &dagChecker, entries);
3628 if (!config.empty()) {
3629 std::string configPropName =
3630 "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
3631 cmProp configProp = this->GetProperty(configPropName);
3633 switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
3634 case cmPolicies::WARN: {
3635 this->LocalGenerator->IssueMessage(
3636 MessageType::AUTHOR_WARNING,
3637 cmPolicies::GetPolicyWarning(cmPolicies::CMP0043));
3640 case cmPolicies::OLD: {
3641 std::unique_ptr<TargetPropertyEntry> entry =
3642 CreateTargetPropertyEntry(*configProp);
3643 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
3644 this, config, language, &dagChecker, *entry));
3646 case cmPolicies::NEW:
3647 case cmPolicies::REQUIRED_ALWAYS:
3648 case cmPolicies::REQUIRED_IF_USED:
3654 processOptions(this, entries, list, uniqueOptions, debugDefines,
3655 "compile definitions", OptionsParse::None);
3660 std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
3661 const std::string& config, const std::string& language) const
3663 std::unordered_set<std::string> uniqueOptions;
3665 cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
3668 std::vector<std::string> debugProperties;
3669 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
3672 bool debugDefines = !this->DebugPrecompileHeadersDone &&
3673 std::find(debugProperties.begin(), debugProperties.end(),
3674 "PRECOMPILE_HEADERS") != debugProperties.end();
3676 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
3677 this->DebugPrecompileHeadersDone = true;
3680 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
3681 this, config, language, &dagChecker, this->PrecompileHeadersEntries);
3683 AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language,
3684 &dagChecker, entries);
3686 std::vector<BT<std::string>> list;
3687 processOptions(this, entries, list, uniqueOptions, debugDefines,
3688 "precompile headers", OptionsParse::None);
3693 std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
3694 const std::string& language,
3695 const std::string& arch) const
3697 if (language != "C" && language != "CXX" && language != "OBJC" &&
3698 language != "OBJCXX") {
3699 return std::string();
3702 if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
3703 return std::string();
3705 const cmGeneratorTarget* generatorTarget = this;
3706 cmProp pchReuseFrom =
3707 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
3709 const auto inserted =
3710 this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
3711 if (inserted.second) {
3712 const std::vector<BT<std::string>> headers =
3713 this->GetPrecompileHeaders(config, language);
3714 if (headers.empty() && !pchReuseFrom) {
3715 return std::string();
3717 std::string& filename = inserted.first->second;
3721 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
3724 filename = cmStrCat(
3725 generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
3727 const std::map<std::string, std::string> languageToExtension = {
3730 { "OBJC", ".objc.h" },
3731 { "OBJCXX", ".objcxx.hxx" }
3735 cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
3737 if (this->GetGlobalGenerator()->IsMultiConfig()) {
3738 filename = cmStrCat(filename, "/", config);
3742 cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch),
3743 languageToExtension.at(language));
3745 const std::string filename_tmp = cmStrCat(filename, ".tmp");
3746 if (!pchReuseFrom) {
3747 auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
3748 auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
3750 std::string firstHeaderOnDisk;
3752 cmGeneratedFileStream file(
3753 filename_tmp, false,
3754 this->GetGlobalGenerator()->GetMakefileEncoding());
3755 file << "/* generated by CMake */\n\n";
3757 file << pchPrologue << "\n";
3759 if (this->GetGlobalGenerator()->IsXcode()) {
3760 file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
3762 if (language == "CXX") {
3763 file << "#ifdef __cplusplus\n";
3765 for (auto const& header_bt : headers) {
3766 if (header_bt.Value.empty()) {
3769 if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
3770 file << "#include " << header_bt.Value << "\n";
3772 file << "#include \"" << header_bt.Value << "\"\n";
3775 if (cmSystemTools::FileExists(header_bt.Value) &&
3776 firstHeaderOnDisk.empty()) {
3777 firstHeaderOnDisk = header_bt.Value;
3780 if (language == "CXX") {
3781 file << "#endif // __cplusplus\n";
3783 if (this->GetGlobalGenerator()->IsXcode()) {
3784 file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
3787 file << pchEpilogue << "\n";
3791 if (!firstHeaderOnDisk.empty()) {
3792 cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
3795 cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
3798 return inserted.first->second;
3801 std::string cmGeneratorTarget::GetPchSource(const std::string& config,
3802 const std::string& language,
3803 const std::string& arch) const
3805 if (language != "C" && language != "CXX" && language != "OBJC" &&
3806 language != "OBJCXX") {
3807 return std::string();
3809 const auto inserted =
3810 this->PchSources.insert(std::make_pair(language + config + arch, ""));
3811 if (inserted.second) {
3812 const std::string pchHeader = this->GetPchHeader(config, language, arch);
3813 if (pchHeader.empty()) {
3814 return std::string();
3816 std::string& filename = inserted.first->second;
3818 const cmGeneratorTarget* generatorTarget = this;
3819 cmProp pchReuseFrom =
3820 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
3823 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
3827 cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(),
3828 "/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch");
3830 // For GCC the source extension will be tranformed into .h[xx].gch
3831 if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
3832 const std::map<std::string, std::string> languageToExtension = {
3834 { "CXX", ".hxx.cxx" },
3835 { "OBJC", ".objc.h.m" },
3836 { "OBJCXX", ".objcxx.hxx.mm" }
3839 filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
3840 languageToExtension.at(language));
3842 const std::map<std::string, std::string> languageToExtension = {
3843 { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
3846 filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
3847 languageToExtension.at(language));
3850 const std::string filename_tmp = cmStrCat(filename, ".tmp");
3851 if (!pchReuseFrom) {
3853 cmGeneratedFileStream file(filename_tmp);
3854 file << "/* generated by CMake */\n";
3856 cmFileTimes::Copy(pchHeader, filename_tmp);
3857 cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
3860 return inserted.first->second;
3863 std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
3864 const std::string& language,
3865 const std::string& arch)
3867 if (language != "C" && language != "CXX" && language != "OBJC" &&
3868 language != "OBJCXX") {
3869 return std::string();
3871 const auto inserted =
3872 this->PchObjectFiles.insert(std::make_pair(language + config + arch, ""));
3873 if (inserted.second) {
3874 const std::string pchSource = this->GetPchSource(config, language, arch);
3875 if (pchSource.empty()) {
3876 return std::string();
3878 std::string& filename = inserted.first->second;
3880 auto pchSf = this->Makefile->GetOrCreateSource(
3881 pchSource, false, cmSourceFileLocationKind::Known);
3883 filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
3884 if (this->GetGlobalGenerator()->IsMultiConfig()) {
3885 cmSystemTools::ReplaceString(
3886 filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
3889 return inserted.first->second;
3892 std::string cmGeneratorTarget::GetPchFile(const std::string& config,
3893 const std::string& language,
3894 const std::string& arch)
3896 const auto inserted =
3897 this->PchFiles.insert(std::make_pair(language + config + arch, ""));
3898 if (inserted.second) {
3899 std::string& pchFile = inserted.first->second;
3901 const std::string pchExtension =
3902 this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
3904 if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
3905 auto replaceExtension = [](const std::string& str,
3906 const std::string& ext) -> std::string {
3907 auto dot_pos = str.rfind('.');
3909 if (dot_pos != std::string::npos) {
3910 result = str.substr(0, dot_pos);
3916 cmGeneratorTarget* generatorTarget = this;
3917 cmProp pchReuseFrom =
3918 generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
3921 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
3924 const std::string pchFileObject =
3925 generatorTarget->GetPchFileObject(config, language, arch);
3926 if (!pchExtension.empty()) {
3927 pchFile = replaceExtension(pchFileObject, pchExtension);
3930 pchFile = this->GetPchHeader(config, language, arch);
3931 pchFile += pchExtension;
3934 return inserted.first->second;
3937 std::string cmGeneratorTarget::GetPchCreateCompileOptions(
3938 const std::string& config, const std::string& language,
3939 const std::string& arch)
3941 const auto inserted = this->PchCreateCompileOptions.insert(
3942 std::make_pair(language + config + arch, ""));
3943 if (inserted.second) {
3944 std::string& createOptionList = inserted.first->second;
3946 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
3947 createOptionList = this->Makefile->GetSafeDefinition(
3948 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
3951 const std::string createOptVar =
3952 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
3954 createOptionList = cmStrCat(
3955 createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar));
3957 const std::string pchHeader = this->GetPchHeader(config, language, arch);
3958 const std::string pchFile = this->GetPchFile(config, language, arch);
3960 cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader);
3961 cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile);
3963 return inserted.first->second;
3966 std::string cmGeneratorTarget::GetPchUseCompileOptions(
3967 const std::string& config, const std::string& language,
3968 const std::string& arch)
3970 const auto inserted = this->PchUseCompileOptions.insert(
3971 std::make_pair(language + config + arch, ""));
3972 if (inserted.second) {
3973 std::string& useOptionList = inserted.first->second;
3975 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
3976 useOptionList = this->Makefile->GetSafeDefinition(
3977 cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
3980 const std::string useOptVar =
3981 cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH");
3983 std::string const& useOptionListProperty =
3984 this->GetSafeProperty(useOptVar);
3986 useOptionList = cmStrCat(
3988 useOptionListProperty.empty()
3989 ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar))
3990 : useOptionListProperty);
3992 const std::string pchHeader = this->GetPchHeader(config, language, arch);
3993 const std::string pchFile = this->GetPchFile(config, language, arch);
3995 cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
3996 cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
3998 return inserted.first->second;
4001 void cmGeneratorTarget::AddSourceFileToUnityBatch(
4002 const std::string& sourceFilename)
4004 this->UnityBatchedSourceFiles.insert(sourceFilename);
4007 bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
4008 const std::string& sourceFilename) const
4010 if (!this->GetPropertyAsBool("UNITY_BUILD")) {
4014 return this->UnityBatchedSourceFiles.find(sourceFilename) !=
4015 this->UnityBatchedSourceFiles.end();
4018 void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
4019 const std::string& config,
4020 const std::string& language) const
4022 if (this->IsDeviceLink() &&
4023 this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
4024 // link options are not propagated to the device link step
4028 std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
4029 result.reserve(tmp.size());
4030 for (BT<std::string>& v : tmp) {
4031 result.emplace_back(std::move(v.Value));
4035 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
4036 std::string const& config, std::string const& language) const
4038 std::vector<BT<std::string>> result;
4039 std::unordered_set<std::string> uniqueOptions;
4041 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
4044 std::vector<std::string> debugProperties;
4045 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4048 bool debugOptions = !this->DebugLinkOptionsDone &&
4049 cm::contains(debugProperties, "LINK_OPTIONS");
4051 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4052 this->DebugLinkOptionsDone = true;
4055 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4056 this, config, language, &dagChecker, this->LinkOptionsEntries);
4058 AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
4059 &dagChecker, entries,
4060 this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
4062 processOptions(this, entries, result, uniqueOptions, debugOptions,
4063 "link options", OptionsParse::Shell, this->IsDeviceLink());
4065 if (this->IsDeviceLink()) {
4066 // wrap host link options
4067 const std::string wrapper(this->Makefile->GetSafeDefinition(
4068 "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
4069 std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4070 const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4071 "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
4072 bool concatFlagAndArgs = true;
4073 if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4074 concatFlagAndArgs = false;
4075 wrapperFlag.pop_back();
4078 auto it = result.begin();
4079 while (it != result.end()) {
4080 if (it->Value == DL_BEGIN) {
4081 // device link options, no treatment
4082 it = result.erase(it);
4083 it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
4084 return item.Value == DL_END;
4086 if (it != result.end()) {
4087 it = result.erase(it);
4090 // host link options must be wrapped
4091 std::vector<std::string> options;
4092 cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
4093 auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
4094 wrapperSep, concatFlagAndArgs);
4095 it = result.erase(it);
4096 // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
4097 // C++11 standard: 'std::vector::insert()' do not returns an iterator,
4098 // so need to recompute the iterator after insertion.
4099 if (it == result.end()) {
4100 cm::append(result, hostOptions);
4103 auto index = it - result.begin();
4104 result.insert(it, hostOptions.begin(), hostOptions.end());
4105 it = result.begin() + index + hostOptions.size();
4111 // Last step: replace "LINKER:" prefixed elements by
4112 // actual linker wrapper
4113 const std::string wrapper(this->Makefile->GetSafeDefinition(
4114 "CMAKE_" + language +
4115 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
4116 : "_LINKER_WRAPPER_FLAG")));
4117 std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
4118 const std::string wrapperSep(this->Makefile->GetSafeDefinition(
4119 "CMAKE_" + language +
4120 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
4121 : "_LINKER_WRAPPER_FLAG_SEP")));
4122 bool concatFlagAndArgs = true;
4123 if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
4124 concatFlagAndArgs = false;
4125 wrapperFlag.pop_back();
4128 const std::string LINKER{ "LINKER:" };
4129 const std::string SHELL{ "SHELL:" };
4130 const std::string LINKER_SHELL = LINKER + SHELL;
4132 std::vector<BT<std::string>>::iterator entry;
4133 while ((entry = std::find_if(result.begin(), result.end(),
4134 [&LINKER](BT<std::string> const& item) -> bool {
4135 return item.Value.compare(0, LINKER.length(),
4137 })) != result.end()) {
4138 std::string value = std::move(entry->Value);
4139 cmListFileBacktrace bt = std::move(entry->Backtrace);
4140 entry = result.erase(entry);
4142 std::vector<std::string> linkerOptions;
4143 if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
4144 cmSystemTools::ParseUnixCommandLine(
4145 value.c_str() + LINKER_SHELL.length(), linkerOptions);
4147 linkerOptions = cmTokenize(value.substr(LINKER.length()), ",");
4150 if (linkerOptions.empty() ||
4151 (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
4155 // for now, raise an error if prefix SHELL: is part of arguments
4156 if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
4157 [&SHELL](const std::string& item) -> bool {
4158 return item.find(SHELL) != std::string::npos;
4159 }) != linkerOptions.end()) {
4160 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
4161 MessageType::FATAL_ERROR,
4162 "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
4163 this->GetBacktrace());
4167 std::vector<BT<std::string>> options = wrapOptions(
4168 linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
4169 result.insert(entry, options.begin(), options.end());
4174 void cmGeneratorTarget::GetStaticLibraryLinkOptions(
4175 std::vector<std::string>& result, const std::string& config,
4176 const std::string& language) const
4178 std::vector<BT<std::string>> tmp =
4179 this->GetStaticLibraryLinkOptions(config, language);
4180 result.reserve(tmp.size());
4181 for (BT<std::string>& v : tmp) {
4182 result.emplace_back(std::move(v.Value));
4186 std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
4187 std::string const& config, std::string const& language) const
4189 std::vector<BT<std::string>> result;
4190 std::unordered_set<std::string> uniqueOptions;
4192 cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
4195 EvaluatedTargetPropertyEntries entries;
4196 if (cmProp linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
4197 std::vector<std::string> options = cmExpandedList(*linkOptions);
4198 for (const auto& option : options) {
4199 std::unique_ptr<TargetPropertyEntry> entry =
4200 CreateTargetPropertyEntry(option);
4201 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4202 this, config, language, &dagChecker, *entry));
4205 processOptions(this, entries, result, uniqueOptions, false,
4206 "static library link options", OptionsParse::Shell);
4212 void processLinkDirectories(cmGeneratorTarget const* tgt,
4213 EvaluatedTargetPropertyEntries& entries,
4214 std::vector<BT<std::string>>& directories,
4215 std::unordered_set<std::string>& uniqueDirectories,
4216 bool debugDirectories)
4218 for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
4219 cmLinkImplItem const& item = entry.LinkImplItem;
4220 std::string const& targetName = item.AsStr();
4222 std::string usedDirectories;
4223 for (std::string& entryDirectory : entry.Values) {
4224 if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
4225 std::ostringstream e;
4226 bool noMessage = false;
4227 MessageType messageType = MessageType::FATAL_ERROR;
4228 if (!targetName.empty()) {
4229 /* clang-format off */
4230 e << "Target \"" << targetName << "\" contains relative "
4231 "path in its INTERFACE_LINK_DIRECTORIES:\n"
4232 " \"" << entryDirectory << "\"";
4233 /* clang-format on */
4235 switch (tgt->GetPolicyStatusCMP0081()) {
4236 case cmPolicies::WARN: {
4237 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
4238 messageType = MessageType::AUTHOR_WARNING;
4240 case cmPolicies::OLD:
4243 case cmPolicies::REQUIRED_IF_USED:
4244 case cmPolicies::REQUIRED_ALWAYS:
4245 case cmPolicies::NEW:
4246 // Issue the fatal message.
4249 e << "Found relative path while evaluating link directories of "
4251 << tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
4254 tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
4255 if (messageType == MessageType::FATAL_ERROR) {
4261 // Sanitize the path the same way the link_directories command does
4262 // in case projects set the LINK_DIRECTORIES property directly.
4263 cmSystemTools::ConvertToUnixSlashes(entryDirectory);
4264 if (uniqueDirectories.insert(entryDirectory).second) {
4265 directories.emplace_back(entryDirectory, entry.Backtrace);
4266 if (debugDirectories) {
4267 usedDirectories += " * " + entryDirectory + "\n";
4271 if (!usedDirectories.empty()) {
4272 tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
4274 std::string("Used link directories for target ") + tgt->GetName() +
4275 ":\n" + usedDirectories,
4282 void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
4283 const std::string& config,
4284 const std::string& language) const
4286 std::vector<BT<std::string>> tmp =
4287 this->GetLinkDirectories(config, language);
4288 result.reserve(tmp.size());
4289 for (BT<std::string>& v : tmp) {
4290 result.emplace_back(std::move(v.Value));
4294 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
4295 std::string const& config, std::string const& language) const
4297 std::vector<BT<std::string>> result;
4298 std::unordered_set<std::string> uniqueDirectories;
4300 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
4303 std::vector<std::string> debugProperties;
4304 this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
4307 bool debugDirectories = !this->DebugLinkDirectoriesDone &&
4308 cm::contains(debugProperties, "LINK_DIRECTORIES");
4310 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
4311 this->DebugLinkDirectoriesDone = true;
4314 EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
4315 this, config, language, &dagChecker, this->LinkDirectoriesEntries);
4317 AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
4318 &dagChecker, entries,
4319 this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
4321 processLinkDirectories(this, entries, result, uniqueDirectories,
4327 void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
4328 const std::string& config,
4329 const std::string& language) const
4331 std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language);
4332 result.reserve(tmp.size());
4333 for (BT<std::string>& v : tmp) {
4334 result.emplace_back(std::move(v.Value));
4338 std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
4339 std::string const& config, std::string const& language) const
4341 std::vector<BT<std::string>> result;
4342 std::unordered_set<std::string> uniqueOptions;
4343 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
4346 EvaluatedTargetPropertyEntries entries;
4347 if (cmProp linkDepends = this->GetProperty("LINK_DEPENDS")) {
4348 std::vector<std::string> depends = cmExpandedList(*linkDepends);
4349 for (const auto& depend : depends) {
4350 std::unique_ptr<TargetPropertyEntry> entry =
4351 CreateTargetPropertyEntry(depend);
4352 entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
4353 this, config, language, &dagChecker, *entry));
4356 AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
4357 &dagChecker, entries,
4358 this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
4360 processOptions(this, entries, result, uniqueOptions, false, "link depends",
4361 OptionsParse::None);
4366 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
4368 if (this->IsImported()) {
4371 cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
4374 cmGeneratorTarget::Names targetNames;
4375 if (this->GetType() == cmStateEnums::EXECUTABLE) {
4376 targetNames = this->GetExecutableNames(config);
4377 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
4378 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4379 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
4380 targetNames = this->GetLibraryNames(config);
4385 // Get the directory.
4387 this->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
4391 if (!targetNames.Output.empty()) {
4392 f = cmStrCat(dir, '/', targetNames.Output);
4393 gg->AddToManifest(f);
4395 if (!targetNames.SharedObject.empty()) {
4396 f = cmStrCat(dir, '/', targetNames.SharedObject);
4397 gg->AddToManifest(f);
4399 if (!targetNames.Real.empty()) {
4400 f = cmStrCat(dir, '/', targetNames.Real);
4401 gg->AddToManifest(f);
4403 if (!targetNames.PDB.empty()) {
4404 f = cmStrCat(dir, '/', targetNames.PDB);
4405 gg->AddToManifest(f);
4407 if (!targetNames.ImportLibrary.empty()) {
4409 cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact),
4410 '/', targetNames.ImportLibrary);
4411 gg->AddToManifest(f);
4415 bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
4417 std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
4418 for (BT<std::string> const& f : features) {
4419 if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) {
4426 std::string cmGeneratorTarget::GetImportedLibName(
4427 std::string const& config) const
4429 if (cmGeneratorTarget::ImportInfo const* info =
4430 this->GetImportInfo(config)) {
4431 return info->LibName;
4433 return std::string();
4436 std::string cmGeneratorTarget::GetFullPath(const std::string& config,
4437 cmStateEnums::ArtifactType artifact,
4438 bool realname) const
4440 if (this->IsImported()) {
4441 return this->Target->ImportedGetFullPath(config, artifact);
4443 return this->NormalGetFullPath(config, artifact, realname);
4446 std::string cmGeneratorTarget::NormalGetFullPath(
4447 const std::string& config, cmStateEnums::ArtifactType artifact,
4448 bool realname) const
4450 std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
4451 if (this->IsAppBundleOnApple()) {
4453 cmStrCat(this->BuildBundleDirectory(fpath, config, FullLevel), '/');
4456 // Add the full name of the target.
4458 case cmStateEnums::RuntimeBinaryArtifact:
4460 fpath += this->NormalGetRealName(config);
4463 this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact);
4466 case cmStateEnums::ImportLibraryArtifact:
4467 fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
4473 std::string cmGeneratorTarget::NormalGetRealName(
4474 const std::string& config) const
4476 // This should not be called for imported targets.
4477 // TODO: Split cmTarget into a class hierarchy to get compile-time
4478 // enforcement of the limited imported target API.
4479 if (this->IsImported()) {
4480 std::string msg = cmStrCat("NormalGetRealName called on imported target: ",
4482 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
4485 if (this->GetType() == cmStateEnums::EXECUTABLE) {
4486 // Compute the real name that will be built.
4487 return this->GetExecutableNames(config).Real;
4489 // Compute the real name that will be built.
4490 return this->GetLibraryNames(config).Real;
4493 cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
4494 const std::string& config) const
4496 cmGeneratorTarget::Names targetNames;
4498 // This should not be called for imported targets.
4499 // TODO: Split cmTarget into a class hierarchy to get compile-time
4500 // enforcement of the limited imported target API.
4501 if (this->IsImported()) {
4503 cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
4504 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
4507 // Check for library version properties.
4508 cmProp version = this->GetProperty("VERSION");
4509 cmProp soversion = this->GetProperty("SOVERSION");
4510 if (!this->HasSOName(config) ||
4511 this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
4512 this->IsFrameworkOnApple()) {
4513 // Versioning is supported only for shared libraries and modules,
4514 // and then only when the platform supports an soname flag.
4516 soversion = nullptr;
4518 if (version && !soversion) {
4519 // The soversion must be set if the library version is set. Use
4520 // the library version as the soversion.
4521 soversion = version;
4523 if (!version && soversion) {
4524 // Use the soversion as the library version.
4525 version = soversion;
4528 // Get the components of the library name.
4531 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
4532 prefix, targetNames.Base, suffix);
4534 // The library name.
4535 targetNames.Output = prefix + targetNames.Base + suffix;
4537 if (this->IsFrameworkOnApple()) {
4538 targetNames.Real = prefix;
4539 if (!this->Makefile->PlatformIsAppleEmbedded()) {
4540 targetNames.Real += "Versions/";
4541 targetNames.Real += this->GetFrameworkVersion();
4542 targetNames.Real += "/";
4544 targetNames.Real += targetNames.Base + suffix;
4545 targetNames.SharedObject = targetNames.Real + suffix;
4547 // The library's soname.
4548 this->ComputeVersionedName(targetNames.SharedObject, prefix,
4549 targetNames.Base, suffix, targetNames.Output,
4550 (soversion ? soversion->c_str() : nullptr));
4552 // The library's real name on disk.
4553 this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
4554 suffix, targetNames.Output,
4555 (version ? version->c_str() : nullptr));
4558 // The import library name.
4559 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4560 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
4561 targetNames.ImportLibrary =
4562 this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
4565 // The program database file name.
4566 targetNames.PDB = this->GetPDBName(config);
4571 cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
4572 const std::string& config) const
4574 cmGeneratorTarget::Names targetNames;
4576 // This should not be called for imported targets.
4577 // TODO: Split cmTarget into a class hierarchy to get compile-time
4578 // enforcement of the limited imported target API.
4579 if (this->IsImported()) {
4580 std::string msg = cmStrCat(
4581 "GetExecutableNames called on imported target: ", this->GetName());
4582 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
4585 // This versioning is supported only for executables and then only
4586 // when the platform supports symbolic links.
4587 #if defined(_WIN32) && !defined(__CYGWIN__)
4588 const char* version = nullptr;
4590 // Check for executable version properties.
4591 const char* version = nullptr;
4592 if (cmProp p = this->GetProperty("VERSION")) {
4593 version = p->c_str();
4595 if (this->GetType() != cmStateEnums::EXECUTABLE ||
4596 this->Makefile->IsOn("XCODE")) {
4601 // Get the components of the executable name.
4604 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
4605 prefix, targetNames.Base, suffix);
4607 // The executable name.
4608 targetNames.Output = prefix + targetNames.Base + suffix;
4610 // The executable's real name on disk.
4611 #if defined(__CYGWIN__)
4612 targetNames.Real = prefix + targetNames.Base;
4614 targetNames.Real = targetNames.Output;
4617 targetNames.Real += "-";
4618 targetNames.Real += version;
4620 #if defined(__CYGWIN__)
4621 targetNames.Real += suffix;
4624 // The import library name.
4625 targetNames.ImportLibrary =
4626 this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
4628 // The program database file name.
4629 targetNames.PDB = this->GetPDBName(config);
4634 std::string cmGeneratorTarget::GetFullNameInternal(
4635 const std::string& config, cmStateEnums::ArtifactType artifact) const
4640 this->GetFullNameInternal(config, artifact, prefix, base, suffix);
4641 return prefix + base + suffix;
4644 std::string cmGeneratorTarget::ImportedGetLocation(
4645 const std::string& config) const
4647 assert(this->IsImported());
4648 return this->Target->ImportedGetFullPath(
4649 config, cmStateEnums::RuntimeBinaryArtifact);
4652 std::string cmGeneratorTarget::GetFullNameImported(
4653 const std::string& config, cmStateEnums::ArtifactType artifact) const
4655 return cmSystemTools::GetFilenameName(
4656 this->Target->ImportedGetFullPath(config, artifact));
4659 void cmGeneratorTarget::GetFullNameInternal(
4660 const std::string& config, cmStateEnums::ArtifactType artifact,
4661 std::string& outPrefix, std::string& outBase, std::string& outSuffix) const
4663 // Use just the target name for non-main target types.
4664 if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
4665 this->GetType() != cmStateEnums::SHARED_LIBRARY &&
4666 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
4667 this->GetType() != cmStateEnums::EXECUTABLE) {
4669 outBase = this->GetName();
4674 const bool isImportedLibraryArtifact =
4675 (artifact == cmStateEnums::ImportLibraryArtifact);
4677 // Return an empty name for the import library if this platform
4678 // does not support import libraries.
4679 if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
4686 // retrieve prefix and suffix
4687 std::string ll = this->GetLinkerLanguage(config);
4688 const char* targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
4689 const char* targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
4691 // The implib option is only allowed for shared libraries, module
4692 // libraries, and executables.
4693 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
4694 this->GetType() != cmStateEnums::MODULE_LIBRARY &&
4695 this->GetType() != cmStateEnums::EXECUTABLE) {
4696 artifact = cmStateEnums::RuntimeBinaryArtifact;
4699 // Compute the full name for main target types.
4700 const std::string configPostfix = this->GetFilePostfix(config);
4702 // frameworks have directory prefix but no suffix
4703 std::string fw_prefix;
4704 if (this->IsFrameworkOnApple()) {
4706 cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
4707 targetPrefix = fw_prefix.c_str();
4708 targetSuffix = nullptr;
4711 if (this->IsCFBundleOnApple()) {
4712 fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
4713 targetPrefix = fw_prefix.c_str();
4714 targetSuffix = nullptr;
4717 // Begin the final name with the prefix.
4718 outPrefix = targetPrefix ? targetPrefix : "";
4720 // Append the target name or property-specified name.
4721 outBase += this->GetOutputName(config, artifact);
4723 // Append the per-configuration postfix.
4724 // When using Xcode, the postfix should be part of the suffix rather than
4725 // the base, because the suffix ends up being used in Xcode's
4726 // EXECUTABLE_SUFFIX attribute.
4727 if (this->IsFrameworkOnApple() &&
4728 GetGlobalGenerator()->GetName() == "Xcode") {
4729 targetSuffix = configPostfix.c_str();
4731 outBase += configPostfix;
4734 // Name shared libraries with their version number on some platforms.
4735 if (cmProp soversion = this->GetProperty("SOVERSION")) {
4736 if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
4737 !isImportedLibraryArtifact &&
4738 this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
4740 outBase += *soversion;
4744 // Append the suffix.
4745 outSuffix = targetSuffix ? targetSuffix : "";
4748 std::string cmGeneratorTarget::GetLinkerLanguage(
4749 const std::string& config) const
4751 return this->GetLinkClosure(config)->LinkerLanguage;
4754 std::string cmGeneratorTarget::GetPDBOutputName(
4755 const std::string& config) const
4758 this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
4760 std::vector<std::string> props;
4761 std::string configUpper = cmSystemTools::UpperCase(config);
4762 if (!configUpper.empty()) {
4763 // PDB_NAME_<CONFIG>
4764 props.push_back("PDB_NAME_" + configUpper);
4768 props.emplace_back("PDB_NAME");
4770 for (std::string const& p : props) {
4771 if (cmProp outName = this->GetProperty(p)) {
4779 std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
4784 this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
4785 prefix, base, suffix);
4787 std::vector<std::string> props;
4788 std::string configUpper = cmSystemTools::UpperCase(config);
4789 if (!configUpper.empty()) {
4790 // PDB_NAME_<CONFIG>
4791 props.push_back("PDB_NAME_" + configUpper);
4795 props.emplace_back("PDB_NAME");
4797 for (std::string const& p : props) {
4798 if (cmProp outName = this->GetProperty(p)) {
4803 return prefix + base + ".pdb";
4806 std::string cmGeneratorTarget::GetObjectDirectory(
4807 std::string const& config) const
4809 std::string obj_dir =
4810 this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
4811 #if defined(__APPLE__)
4812 // find and replace $(PROJECT_NAME) xcode placeholder
4813 const std::string projectName = this->LocalGenerator->GetProjectName();
4814 cmSystemTools::ReplaceString(obj_dir, "$(PROJECT_NAME)", projectName);
4815 // Replace Xcode's placeholder for the object file directory since
4816 // installation and export scripts need to know the real directory.
4817 // Xcode has build-time settings (e.g. for sanitizers) that affect this,
4818 // but we use the default here. Users that want to enable sanitizers
4819 // will do so at the cost of object library installation and export.
4820 cmSystemTools::ReplaceString(obj_dir, "$(OBJECT_FILE_DIR_normal:base)",
4826 void cmGeneratorTarget::GetTargetObjectNames(
4827 std::string const& config, std::vector<std::string>& objects) const
4829 std::vector<cmSourceFile const*> objectSources;
4830 this->GetObjectSources(objectSources, config);
4831 std::map<cmSourceFile const*, std::string> mapping;
4833 for (cmSourceFile const* sf : objectSources) {
4837 this->LocalGenerator->ComputeObjectFilenames(mapping, this);
4839 for (cmSourceFile const* src : objectSources) {
4840 // Find the object file name corresponding to this source file.
4841 auto map_it = mapping.find(src);
4842 // It must exist because we populated the mapping just above.
4843 assert(!map_it->second.empty());
4844 objects.push_back(map_it->second);
4848 bool cmGeneratorTarget::StrictTargetComparison::operator()(
4849 cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
4851 int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
4852 if (nameResult == 0) {
4854 t1->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
4855 t2->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
4857 return nameResult < 0;
4860 struct cmGeneratorTarget::SourceFileFlags
4861 cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
4863 struct SourceFileFlags flags;
4864 this->ConstructSourceFileFlags();
4865 auto si = this->SourceFlagsMap.find(sf);
4866 if (si != this->SourceFlagsMap.end()) {
4869 // Handle the MACOSX_PACKAGE_LOCATION property on source files that
4870 // were not listed in one of the other lists.
4871 if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
4872 flags.MacFolder = location->c_str();
4873 const bool stripResources =
4874 this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
4875 if (*location == "Resources") {
4876 flags.Type = cmGeneratorTarget::SourceFileTypeResource;
4877 if (stripResources) {
4878 flags.MacFolder = "";
4880 } else if (cmHasLiteralPrefix(*location, "Resources/")) {
4881 flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
4882 if (stripResources) {
4883 flags.MacFolder += strlen("Resources/");
4886 flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
4893 void cmGeneratorTarget::ConstructSourceFileFlags() const
4895 if (this->SourceFileFlagsConstructed) {
4898 this->SourceFileFlagsConstructed = true;
4900 // Process public headers to mark the source files.
4901 if (cmProp files = this->GetProperty("PUBLIC_HEADER")) {
4902 std::vector<std::string> relFiles = cmExpandedList(*files);
4903 for (std::string const& relFile : relFiles) {
4904 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4905 SourceFileFlags& flags = this->SourceFlagsMap[sf];
4906 flags.MacFolder = "Headers";
4907 flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
4912 // Process private headers after public headers so that they take
4913 // precedence if a file is listed in both.
4914 if (cmProp files = this->GetProperty("PRIVATE_HEADER")) {
4915 std::vector<std::string> relFiles = cmExpandedList(*files);
4916 for (std::string const& relFile : relFiles) {
4917 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4918 SourceFileFlags& flags = this->SourceFlagsMap[sf];
4919 flags.MacFolder = "PrivateHeaders";
4920 flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
4925 // Mark sources listed as resources.
4926 if (cmProp files = this->GetProperty("RESOURCE")) {
4927 std::vector<std::string> relFiles = cmExpandedList(*files);
4928 for (std::string const& relFile : relFiles) {
4929 if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4930 SourceFileFlags& flags = this->SourceFlagsMap[sf];
4931 flags.MacFolder = "";
4932 if (!this->GlobalGenerator->ShouldStripResourcePath(this->Makefile)) {
4933 flags.MacFolder = "Resources";
4935 flags.Type = cmGeneratorTarget::SourceFileTypeResource;
4941 const cmGeneratorTarget::CompatibleInterfacesBase&
4942 cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
4944 cmGeneratorTarget::CompatibleInterfaces& compat =
4945 this->CompatibleInterfacesMap[config];
4948 compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
4949 compat.PropsString.insert("AUTOUIC_OPTIONS");
4950 std::vector<cmGeneratorTarget const*> const& deps =
4951 this->GetLinkImplementationClosure(config);
4952 for (cmGeneratorTarget const* li : deps) {
4953 #define CM_READ_COMPATIBLE_INTERFACE(X, x) \
4954 if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
4955 std::vector<std::string> props; \
4956 cmExpandList(*prop, props); \
4957 compat.Props##x.insert(props.begin(), props.end()); \
4959 CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
4960 CM_READ_COMPATIBLE_INTERFACE(STRING, String)
4961 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
4962 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
4963 #undef CM_READ_COMPATIBLE_INTERFACE
4969 bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
4970 const std::string& p, const std::string& config) const
4972 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
4973 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
4976 return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
4979 bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
4980 const std::string& p, const std::string& config) const
4982 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
4983 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
4986 return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
4989 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
4990 const std::string& p, const std::string& config) const
4992 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
4993 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
4996 return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
4999 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
5000 const std::string& p, const std::string& config) const
5002 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5003 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5006 return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
5017 template <typename PropertyType>
5018 PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5019 const std::string& prop,
5020 const std::string& config,
5021 CompatibleType, PropertyType*);
5024 bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5025 const std::string& prop,
5026 const std::string& config,
5027 CompatibleType /*unused*/,
5030 return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
5034 const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
5035 const std::string& prop,
5036 const std::string& config,
5038 const char** /*unused*/)
5043 "String compatibility check function called for boolean");
5046 return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
5048 return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
5050 return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
5052 assert(false && "Unreachable!");
5056 template <typename PropertyType>
5057 void checkPropertyConsistency(cmGeneratorTarget const* depender,
5058 cmGeneratorTarget const* dependee,
5059 const std::string& propName,
5060 std::set<std::string>& emitted,
5061 const std::string& config, CompatibleType t,
5062 PropertyType* /*unused*/)
5064 cmProp prop = dependee->GetProperty(propName);
5069 std::vector<std::string> props = cmExpandedList(*prop);
5071 cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
5073 for (std::string const& p : props) {
5074 std::string pname = cmSystemTools::HelpFileName(p);
5075 std::string pfile = pdir + pname + ".rst";
5076 if (cmSystemTools::FileExists(pfile, true)) {
5077 std::ostringstream e;
5078 e << "Target \"" << dependee->GetName() << "\" has property \"" << p
5079 << "\" listed in its " << propName
5081 "This is not allowed. Only user-defined properties may appear "
5083 << propName << " property.";
5084 depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
5088 if (emitted.insert(p).second) {
5089 getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
5091 if (cmSystemTools::GetErrorOccuredFlag()) {
5099 std::string intersect(const std::set<std::string>& s1,
5100 const std::set<std::string>& s2)
5102 std::set<std::string> intersect;
5103 std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
5104 std::inserter(intersect, intersect.begin()));
5105 if (!intersect.empty()) {
5106 return *intersect.begin();
5111 std::string intersect(const std::set<std::string>& s1,
5112 const std::set<std::string>& s2,
5113 const std::set<std::string>& s3)
5116 result = intersect(s1, s2);
5117 if (!result.empty()) {
5120 result = intersect(s1, s3);
5121 if (!result.empty()) {
5124 return intersect(s2, s3);
5127 std::string intersect(const std::set<std::string>& s1,
5128 const std::set<std::string>& s2,
5129 const std::set<std::string>& s3,
5130 const std::set<std::string>& s4)
5133 result = intersect(s1, s2);
5134 if (!result.empty()) {
5137 result = intersect(s1, s3);
5138 if (!result.empty()) {
5141 result = intersect(s1, s4);
5142 if (!result.empty()) {
5145 return intersect(s2, s3, s4);
5149 void cmGeneratorTarget::CheckPropertyCompatibility(
5150 cmComputeLinkInformation& info, const std::string& config) const
5152 const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
5154 std::set<std::string> emittedBools;
5155 static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
5156 std::set<std::string> emittedStrings;
5157 static const std::string strString = "COMPATIBLE_INTERFACE_STRING";
5158 std::set<std::string> emittedMinNumbers;
5159 static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
5160 std::set<std::string> emittedMaxNumbers;
5161 static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
5163 for (auto const& dep : deps) {
5168 checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
5169 config, BoolType, nullptr);
5170 if (cmSystemTools::GetErrorOccuredFlag()) {
5173 checkPropertyConsistency<const char*>(this, dep.Target, strString,
5174 emittedStrings, config, StringType,
5176 if (cmSystemTools::GetErrorOccuredFlag()) {
5179 checkPropertyConsistency<const char*>(this, dep.Target, strNumMin,
5180 emittedMinNumbers, config,
5181 NumberMinType, nullptr);
5182 if (cmSystemTools::GetErrorOccuredFlag()) {
5185 checkPropertyConsistency<const char*>(this, dep.Target, strNumMax,
5186 emittedMaxNumbers, config,
5187 NumberMaxType, nullptr);
5188 if (cmSystemTools::GetErrorOccuredFlag()) {
5193 std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
5196 if (!prop.empty()) {
5197 // Use a sorted std::vector to keep the error message sorted.
5198 std::vector<std::string> props;
5199 auto i = emittedBools.find(prop);
5200 if (i != emittedBools.end()) {
5201 props.push_back(strBool);
5203 i = emittedStrings.find(prop);
5204 if (i != emittedStrings.end()) {
5205 props.push_back(strString);
5207 i = emittedMinNumbers.find(prop);
5208 if (i != emittedMinNumbers.end()) {
5209 props.push_back(strNumMin);
5211 i = emittedMaxNumbers.find(prop);
5212 if (i != emittedMaxNumbers.end()) {
5213 props.push_back(strNumMax);
5215 std::sort(props.begin(), props.end());
5217 std::string propsString = cmStrCat(
5218 cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
5220 std::ostringstream e;
5221 e << "Property \"" << prop << "\" appears in both the " << propsString
5222 << " property in the dependencies of target \"" << this->GetName()
5223 << "\". This is not allowed. A property may only require "
5225 "in a boolean interpretation, a numeric minimum, a numeric maximum "
5227 "string interpretation, but not a mixture.";
5228 this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
5232 template <typename PropertyType>
5233 std::string valueAsString(PropertyType);
5235 std::string valueAsString<bool>(bool value)
5237 return value ? "TRUE" : "FALSE";
5240 std::string valueAsString<const char*>(const char* value)
5242 return value ? value : "(unset)";
5245 std::string valueAsString<std::string>(std::string value)
5250 std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
5255 std::string compatibilityType(CompatibleType t)
5259 return "Boolean compatibility";
5261 return "String compatibility";
5263 return "Numeric maximum compatibility";
5265 return "Numeric minimum compatibility";
5267 assert(false && "Unreachable!");
5271 std::string compatibilityAgree(CompatibleType t, bool dominant)
5276 return dominant ? "(Disagree)\n" : "(Agree)\n";
5279 return dominant ? "(Dominant)\n" : "(Ignored)\n";
5281 assert(false && "Unreachable!");
5285 template <typename PropertyType>
5286 PropertyType getTypedProperty(
5287 cmGeneratorTarget const* tgt, const std::string& prop,
5288 cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
5291 bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
5292 const std::string& prop,
5293 cmGeneratorExpressionInterpreter* genexInterpreter)
5295 if (genexInterpreter == nullptr) {
5296 return tgt->GetPropertyAsBool(prop);
5299 cmProp value = tgt->GetProperty(prop);
5301 genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop));
5305 const char* getTypedProperty<const char*>(
5306 cmGeneratorTarget const* tgt, const std::string& prop,
5307 cmGeneratorExpressionInterpreter* genexInterpreter)
5309 cmProp value = tgt->GetProperty(prop);
5311 if (genexInterpreter == nullptr) {
5312 return value ? value->c_str() : nullptr;
5315 return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop)
5320 std::string getTypedProperty<std::string>(
5321 cmGeneratorTarget const* tgt, const std::string& prop,
5322 cmGeneratorExpressionInterpreter* genexInterpreter)
5324 cmProp value = tgt->GetProperty(prop);
5326 if (genexInterpreter == nullptr) {
5327 return valueAsString(value ? value->c_str() : nullptr);
5330 return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop);
5333 template <typename PropertyType>
5334 PropertyType impliedValue(PropertyType);
5336 bool impliedValue<bool>(bool /*unused*/)
5341 const char* impliedValue<const char*>(const char* /*unused*/)
5346 std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
5348 return std::string();
5351 template <typename PropertyType>
5352 std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
5357 std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
5358 CompatibleType /*unused*/)
5360 return { lhs == rhs, lhs };
5363 std::pair<bool, const char*> consistentStringProperty(const char* lhs,
5366 const bool b = strcmp(lhs, rhs) == 0;
5367 return { b, b ? lhs : nullptr };
5370 std::pair<bool, std::string> consistentStringProperty(const std::string& lhs,
5371 const std::string& rhs)
5373 const bool b = lhs == rhs;
5374 return { b, b ? lhs : valueAsString(nullptr) };
5377 std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
5383 long lnum = strtol(lhs, &pEnd, 0);
5384 if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
5385 return { false, nullptr };
5388 long rnum = strtol(rhs, &pEnd, 0);
5389 if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
5390 return { false, nullptr };
5393 if (t == NumberMaxType) {
5394 return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
5397 return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
5401 std::pair<bool, const char*> consistentProperty(const char* lhs,
5406 return { true, lhs };
5409 return { true, rhs };
5412 return { true, lhs };
5417 bool same = cmIsOn(lhs) == cmIsOn(rhs);
5418 return { same, same ? lhs : nullptr };
5421 return consistentStringProperty(lhs, rhs);
5424 return consistentNumberProperty(lhs, rhs, t);
5426 assert(false && "Unreachable!");
5427 return { false, nullptr };
5430 std::pair<bool, std::string> consistentProperty(const std::string& lhs,
5431 const std::string& rhs,
5434 const std::string null_ptr = valueAsString(nullptr);
5436 if (lhs == null_ptr && rhs == null_ptr) {
5437 return { true, lhs };
5439 if (lhs == null_ptr) {
5440 return { true, rhs };
5442 if (rhs == null_ptr) {
5443 return { true, lhs };
5448 bool same = cmIsOn(lhs) == cmIsOn(rhs);
5449 return { same, same ? lhs : null_ptr };
5452 return consistentStringProperty(lhs, rhs);
5454 case NumberMaxType: {
5455 auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
5456 return { value.first,
5457 value.first ? std::string(value.second) : null_ptr };
5460 assert(false && "Unreachable!");
5461 return { false, null_ptr };
5464 template <typename PropertyType>
5465 PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
5466 const std::string& p,
5467 const std::string& config,
5468 const char* defaultValue,
5470 PropertyType* /*unused*/)
5472 PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
5474 std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
5475 const bool explicitlySet = cm::contains(headPropKeys, p);
5477 const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
5478 assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
5480 std::vector<cmGeneratorTarget const*> const& deps =
5481 tgt->GetLinkImplementationClosure(config);
5486 bool propInitialized = explicitlySet;
5488 std::string report = cmStrCat(" * Target \"", tgt->GetName());
5489 if (explicitlySet) {
5490 report += "\" has property content \"";
5491 report += valueAsString<PropertyType>(propContent);
5493 } else if (impliedByUse) {
5494 report += "\" property is implied by use.\n";
5496 report += "\" property not set.\n";
5499 std::string interfaceProperty = "INTERFACE_" + p;
5500 std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
5501 if (p == "POSITION_INDEPENDENT_CODE") {
5502 genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
5503 tgt->GetLocalGenerator(), config, tgt);
5506 for (cmGeneratorTarget const* theTarget : deps) {
5507 // An error should be reported if one dependency
5508 // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
5509 // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
5510 // target itself has a POSITION_INDEPENDENT_CODE which disagrees
5511 // with a dependency.
5513 std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
5515 const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty);
5516 PropertyType ifacePropContent = getTypedProperty<PropertyType>(
5517 theTarget, interfaceProperty, genexInterpreter.get());
5519 std::string reportEntry;
5521 reportEntry += " * Target \"";
5522 reportEntry += theTarget->GetName();
5523 reportEntry += "\" property value \"";
5524 reportEntry += valueAsString<PropertyType>(ifacePropContent);
5525 reportEntry += "\" ";
5528 if (explicitlySet) {
5530 std::pair<bool, PropertyType> consistent =
5531 consistentProperty(propContent, ifacePropContent, t);
5532 report += reportEntry;
5533 report += compatibilityAgree(t, propContent != consistent.second);
5534 if (!consistent.first) {
5535 std::ostringstream e;
5536 e << "Property " << p << " on target \"" << tgt->GetName()
5537 << "\" does\nnot match the "
5540 << " property requirement\nof "
5542 << theTarget->GetName() << "\".\n";
5543 cmSystemTools::Error(e.str());
5546 propContent = consistent.second;
5549 // Explicitly set on target and not set in iface. Can't disagree.
5553 propContent = impliedValue<PropertyType>(propContent);
5556 std::pair<bool, PropertyType> consistent =
5557 consistentProperty(propContent, ifacePropContent, t);
5558 report += reportEntry;
5559 report += compatibilityAgree(t, propContent != consistent.second);
5560 if (!consistent.first) {
5561 std::ostringstream e;
5562 e << "Property " << p << " on target \"" << tgt->GetName()
5563 << "\" is\nimplied to be " << defaultValue
5564 << " because it was used to determine the link libraries\n"
5565 "already. The INTERFACE_"
5566 << p << " property on\ndependency \"" << theTarget->GetName()
5567 << "\" is in conflict.\n";
5568 cmSystemTools::Error(e.str());
5571 propContent = consistent.second;
5574 // Implicitly set on target and not set in iface. Can't disagree.
5578 if (propInitialized) {
5579 std::pair<bool, PropertyType> consistent =
5580 consistentProperty(propContent, ifacePropContent, t);
5581 report += reportEntry;
5582 report += compatibilityAgree(t, propContent != consistent.second);
5583 if (!consistent.first) {
5584 std::ostringstream e;
5585 e << "The INTERFACE_" << p << " property of \""
5586 << theTarget->GetName() << "\" does\nnot agree with the value of "
5587 << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
5588 cmSystemTools::Error(e.str());
5591 propContent = consistent.second;
5594 report += reportEntry + "(Interface set)\n";
5595 propContent = ifacePropContent;
5596 propInitialized = true;
5598 // Not set. Nothing to agree on.
5603 tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
5604 report, compatibilityType(t));
5608 bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
5610 bool previous = this->DeviceLink;
5611 this->DeviceLink = deviceLink;
5615 bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
5616 const std::string& p, const std::string& config) const
5618 return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
5622 std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
5623 const std::string& p, const std::string& config) const
5625 return checkInterfacePropertyCompatibility<std::string>(
5626 this, p, config, "FALSE", BoolType, nullptr);
5629 const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
5630 const std::string& p, const std::string& config) const
5632 return checkInterfacePropertyCompatibility<const char*>(
5633 this, p, config, "empty", StringType, nullptr);
5636 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
5637 const std::string& p, const std::string& config) const
5639 return checkInterfacePropertyCompatibility<const char*>(
5640 this, p, config, "empty", NumberMinType, nullptr);
5643 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
5644 const std::string& p, const std::string& config) const
5646 return checkInterfacePropertyCompatibility<const char*>(
5647 this, p, config, "empty", NumberMaxType, nullptr);
5650 cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
5651 const std::string& config) const
5653 // Lookup any existing information for this configuration.
5654 std::string key(cmSystemTools::UpperCase(config));
5655 auto i = this->LinkInformation.find(key);
5656 if (i == this->LinkInformation.end()) {
5657 // Compute information for this configuration.
5658 auto info = cm::make_unique<cmComputeLinkInformation>(this, config);
5659 if (info && !info->Compute()) {
5663 // Store the information for this configuration.
5664 i = this->LinkInformation.emplace(key, std::move(info)).first;
5667 this->CheckPropertyCompatibility(*i->second, config);
5670 return i->second.get();
5673 void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
5676 this->GetTargetVersion("VERSION", major, minor, patch);
5679 void cmGeneratorTarget::GetTargetVersionFallback(
5680 const std::string& property, const std::string& fallback_property,
5681 int& major, int& minor, int& patch) const
5683 if (this->GetProperty(property)) {
5684 this->GetTargetVersion(property, major, minor, patch);
5686 this->GetTargetVersion(fallback_property, major, minor, patch);
5690 void cmGeneratorTarget::GetTargetVersion(const std::string& property,
5691 int& major, int& minor,
5694 // Set the default values.
5699 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
5701 if (cmProp version = this->GetProperty(property)) {
5702 // Try to parse the version number and store the results that were
5703 // successfully parsed.
5707 switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor,
5710 patch = parsed_patch;
5713 minor = parsed_minor;
5716 major = parsed_major;
5724 std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
5725 std::string const& lang, std::string const& config) const
5727 // This is activated by the presence of a default selection whether or
5728 // not it is overridden by a property.
5729 cmProp runtimeLibraryDefault = this->Makefile->GetDef(
5730 cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
5731 if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) {
5732 return std::string();
5734 cmProp runtimeLibraryValue =
5735 this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
5736 if (!runtimeLibraryValue) {
5737 runtimeLibraryValue = runtimeLibraryDefault;
5739 return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
5740 *runtimeLibraryValue, this->LocalGenerator, config, this));
5743 std::string cmGeneratorTarget::GetFortranModuleDirectory(
5744 std::string const& working_dir) const
5746 if (!this->FortranModuleDirectoryCreated) {
5747 this->FortranModuleDirectory =
5748 this->CreateFortranModuleDirectory(working_dir);
5749 this->FortranModuleDirectoryCreated = true;
5752 return this->FortranModuleDirectory;
5755 std::string cmGeneratorTarget::CreateFortranModuleDirectory(
5756 std::string const& working_dir) const
5758 std::string mod_dir;
5759 std::string target_mod_dir;
5760 if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
5761 target_mod_dir = *prop;
5763 std::string const& default_mod_dir =
5764 this->LocalGenerator->GetCurrentBinaryDirectory();
5765 if (default_mod_dir != working_dir) {
5766 target_mod_dir = default_mod_dir;
5769 const char* moddir_flag =
5770 this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
5771 if (!target_mod_dir.empty() && moddir_flag) {
5772 // Compute the full path to the module directory.
5773 if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
5774 // Already a full path.
5775 mod_dir = target_mod_dir;
5777 // Interpret relative to the current output directory.
5778 mod_dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
5779 '/', target_mod_dir);
5782 // Make sure the module output directory exists.
5783 cmSystemTools::MakeDirectory(mod_dir);
5788 std::string cmGeneratorTarget::GetFrameworkVersion() const
5790 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
5792 if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) {
5795 if (cmProp tversion = this->GetProperty("VERSION")) {
5801 void cmGeneratorTarget::ComputeVersionedName(std::string& vName,
5802 std::string const& prefix,
5803 std::string const& base,
5804 std::string const& suffix,
5805 std::string const& name,
5806 const char* version) const
5808 vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
5813 vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
5816 std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
5818 return this->Target->GetProperties().GetKeys();
5821 void cmGeneratorTarget::ReportPropertyOrigin(
5822 const std::string& p, const std::string& result, const std::string& report,
5823 const std::string& compatibilityType) const
5825 std::vector<std::string> debugProperties;
5826 this->Target->GetMakefile()->GetDefExpandList(
5827 "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties);
5829 bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
5830 cm::contains(debugProperties, p);
5832 if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
5833 this->DebugCompatiblePropertiesDone[p] = true;
5839 std::string areport =
5840 cmStrCat(compatibilityType, " of property \"", p, "\" for target \"",
5841 this->GetName(), "\" (result: \"", result, "\"):\n", report);
5843 this->LocalGenerator->GetCMakeInstance()->IssueMessage(MessageType::LOG,
5847 bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
5848 cmLocalGenerator const*& lg) const
5850 if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
5851 cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
5852 if (dirId.String.empty()) {
5853 lg = this->LocalGenerator;
5856 if (cmLocalGenerator const* otherLG =
5857 this->GlobalGenerator->FindLocalGenerator(dirId)) {
5865 void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
5866 cmListFileBacktrace const& bt,
5867 std::vector<cmLinkItem>& items) const
5869 cmLocalGenerator const* lg = this->LocalGenerator;
5870 for (std::string const& n : names) {
5871 if (this->IsLinkLookupScope(n, lg)) {
5875 std::string name = this->CheckCMP0004(n);
5876 if (name == this->GetName() || name.empty()) {
5879 items.push_back(this->ResolveLinkItem(name, bt, lg));
5883 void cmGeneratorTarget::ExpandLinkItems(
5884 std::string const& prop, std::string const& value, std::string const& config,
5885 cmGeneratorTarget const* headTarget, bool usage_requirements_only,
5886 std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition,
5887 bool& hadContextSensitiveCondition,
5888 bool& hadLinkLanguageSensitiveCondition) const
5890 // Keep this logic in sync with ComputeLinkImplementationLibraries.
5891 cmGeneratorExpression ge;
5892 cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
5893 // The $<LINK_ONLY> expression may be in a link interface to specify
5894 // private link dependencies that are otherwise excluded from usage
5896 if (usage_requirements_only) {
5897 dagChecker.SetTransitivePropertiesOnly();
5899 std::vector<std::string> libs;
5900 std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
5901 cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget,
5902 &dagChecker, this, headTarget->LinkerLanguage),
5904 this->LookupLinkItems(libs, cge->GetBacktrace(), items);
5905 hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
5906 hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition();
5907 hadLinkLanguageSensitiveCondition =
5908 cge->GetHadLinkLanguageSensitiveCondition();
5911 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
5912 const std::string& config, cmGeneratorTarget const* head) const
5914 return this->GetLinkInterface(config, head, false);
5917 cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
5918 const std::string& config, cmGeneratorTarget const* head,
5919 bool secondPass) const
5921 // Imported targets have their own link interface.
5922 if (this->IsImported()) {
5923 return this->GetImportLinkInterface(config, head, false, secondPass);
5926 // Link interfaces are not supported for executables that do not
5928 if (this->GetType() == cmStateEnums::EXECUTABLE &&
5929 !this->IsExecutableWithExports()) {
5933 // Lookup any existing link interface for this configuration.
5934 cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
5940 // If the link interface does not depend on the head target
5941 // then return the one we computed first.
5942 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
5943 return &hm.begin()->second;
5946 cmOptionalLinkInterface& iface = hm[head];
5947 if (!iface.LibrariesDone) {
5948 iface.LibrariesDone = true;
5949 this->ComputeLinkInterfaceLibraries(config, iface, head, false);
5951 if (!iface.AllDone) {
5952 iface.AllDone = true;
5954 this->ComputeLinkInterface(config, iface, head, secondPass);
5958 return iface.Exists ? &iface : nullptr;
5961 void cmGeneratorTarget::ComputeLinkInterface(
5962 const std::string& config, cmOptionalLinkInterface& iface,
5963 cmGeneratorTarget const* headTarget) const
5965 this->ComputeLinkInterface(config, iface, headTarget, false);
5968 void cmGeneratorTarget::ComputeLinkInterface(
5969 const std::string& config, cmOptionalLinkInterface& iface,
5970 cmGeneratorTarget const* headTarget, bool secondPass) const
5972 if (iface.Explicit) {
5973 if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5974 this->GetType() == cmStateEnums::STATIC_LIBRARY ||
5975 this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
5976 // Shared libraries may have runtime implementation dependencies
5977 // on other shared libraries that are not in the interface.
5978 std::set<cmLinkItem> emitted;
5979 for (cmLinkItem const& lib : iface.Libraries) {
5980 emitted.insert(lib);
5982 if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
5983 cmLinkImplementation const* impl =
5984 this->GetLinkImplementation(config, secondPass);
5985 for (cmLinkImplItem const& lib : impl->Libraries) {
5986 if (emitted.insert(lib).second) {
5988 // This is a runtime dependency on another shared library.
5989 if (lib.Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
5990 iface.SharedDeps.push_back(lib);
5993 // TODO: Recognize shared library file names. Perhaps this
5994 // should be moved to cmComputeLinkInformation, but that
5995 // creates a chicken-and-egg problem since this list is needed
5996 // for its construction.
6002 } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
6003 this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
6004 // The link implementation is the default link interface.
6005 cmLinkImplementationLibraries const* impl =
6006 this->GetLinkImplementationLibrariesInternal(config, headTarget);
6007 iface.ImplementationIsInterface = true;
6008 iface.WrongConfigLibraries = impl->WrongConfigLibraries;
6011 if (this->LinkLanguagePropagatesToDependents()) {
6012 // Targets using this archive need its language runtime libraries.
6013 if (cmLinkImplementation const* impl =
6014 this->GetLinkImplementation(config, secondPass)) {
6015 iface.Languages = impl->Languages;
6019 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
6020 // Construct the property name suffix for this configuration.
6021 std::string suffix = "_";
6022 if (!config.empty()) {
6023 suffix += cmSystemTools::UpperCase(config);
6025 suffix += "NOCONFIG";
6028 // How many repetitions are needed if this library has cyclic
6030 std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix);
6031 if (cmProp config_reps = this->GetProperty(propName)) {
6032 sscanf(config_reps->c_str(), "%u", &iface.Multiplicity);
6033 } else if (cmProp reps =
6034 this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
6035 sscanf(reps->c_str(), "%u", &iface.Multiplicity);
6040 const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
6041 const std::string& config, cmGeneratorTarget const* head,
6042 bool usage_requirements_only) const
6044 // Imported targets have their own link interface.
6045 if (this->IsImported()) {
6046 return this->GetImportLinkInterface(config, head, usage_requirements_only);
6049 // Link interfaces are not supported for executables that do not
6051 if (this->GetType() == cmStateEnums::EXECUTABLE &&
6052 !this->IsExecutableWithExports()) {
6056 // Lookup any existing link interface for this configuration.
6057 cmHeadToLinkInterfaceMap& hm =
6058 (usage_requirements_only
6059 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
6060 : this->GetHeadToLinkInterfaceMap(config));
6062 // If the link interface does not depend on the head target
6063 // then return the one we computed first.
6064 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6065 return &hm.begin()->second;
6068 cmOptionalLinkInterface& iface = hm[head];
6069 if (!iface.LibrariesDone) {
6070 iface.LibrariesDone = true;
6071 this->ComputeLinkInterfaceLibraries(config, iface, head,
6072 usage_requirements_only);
6075 return iface.Exists ? &iface : nullptr;
6078 std::string cmGeneratorTarget::GetDirectory(
6079 const std::string& config, cmStateEnums::ArtifactType artifact) const
6081 if (this->IsImported()) {
6082 // Return the directory from which the target is imported.
6083 return cmSystemTools::GetFilenamePath(
6084 this->Target->ImportedGetFullPath(config, artifact));
6086 if (OutputInfo const* info = this->GetOutputInfo(config)) {
6087 // Return the directory in which the target will be built.
6089 case cmStateEnums::RuntimeBinaryArtifact:
6090 return info->OutDir;
6091 case cmStateEnums::ImportLibraryArtifact:
6092 return info->ImpDir;
6098 bool cmGeneratorTarget::UsesDefaultOutputDir(
6099 const std::string& config, cmStateEnums::ArtifactType artifact) const
6102 return this->ComputeOutputDir(config, artifact, dir);
6105 cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
6106 const std::string& config) const
6108 // There is no output information for imported targets.
6109 if (this->IsImported()) {
6113 // Only libraries and executables have well-defined output files.
6114 if (!this->HaveWellDefinedOutputFiles()) {
6115 std::string msg = cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
6116 this->GetName(), " which has type ",
6117 cmState::GetTargetTypeName(this->GetType()));
6118 this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
6122 // Lookup/compute/cache the output information for this configuration.
6123 std::string config_upper;
6124 if (!config.empty()) {
6125 config_upper = cmSystemTools::UpperCase(config);
6127 auto i = this->OutputInfoMap.find(config_upper);
6128 if (i == this->OutputInfoMap.end()) {
6129 // Add empty info in map to detect potential recursion.
6131 OutputInfoMapType::value_type entry(config_upper, info);
6132 i = this->OutputInfoMap.insert(entry).first;
6134 // Compute output directories.
6135 this->ComputeOutputDir(config, cmStateEnums::RuntimeBinaryArtifact,
6137 this->ComputeOutputDir(config, cmStateEnums::ImportLibraryArtifact,
6139 if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
6140 info.PdbDir = info.OutDir;
6143 // Now update the previously-prepared map entry.
6145 } else if (i->second.empty()) {
6146 // An empty map entry indicates we have been called recursively
6147 // from the above block.
6148 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
6149 MessageType::FATAL_ERROR,
6150 "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
6151 this->GetBacktrace());
6157 bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
6158 cmStateEnums::ArtifactType artifact,
6159 std::string& out) const
6161 bool usesDefaultOutputDir = false;
6162 std::string conf = config;
6164 // Look for a target property defining the target output directory
6165 // based on the target type.
6166 std::string targetTypeName = this->GetOutputTargetType(artifact);
6167 const char* propertyName = nullptr;
6168 std::string propertyNameStr = targetTypeName;
6169 if (!propertyNameStr.empty()) {
6170 propertyNameStr += "_OUTPUT_DIRECTORY";
6171 propertyName = propertyNameStr.c_str();
6174 // Check for a per-configuration output directory target property.
6175 std::string configUpper = cmSystemTools::UpperCase(conf);
6176 const char* configProp = nullptr;
6177 std::string configPropStr = targetTypeName;
6178 if (!configPropStr.empty()) {
6179 configPropStr += "_OUTPUT_DIRECTORY_";
6180 configPropStr += configUpper;
6181 configProp = configPropStr.c_str();
6184 // Select an output directory.
6185 if (cmProp config_outdir = this->GetProperty(configProp)) {
6186 // Use the user-specified per-configuration output directory.
6187 out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
6190 // Skip per-configuration subdirectory.
6192 } else if (cmProp outdir = this->GetProperty(propertyName)) {
6193 // Use the user-specified output directory.
6195 cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
6197 // Skip per-configuration subdirectory if the value contained a
6198 // generator expression.
6199 if (out != *outdir) {
6202 } else if (this->GetType() == cmStateEnums::EXECUTABLE) {
6203 // Lookup the output path for executables.
6204 out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
6205 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
6206 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6207 this->GetType() == cmStateEnums::MODULE_LIBRARY) {
6208 // Lookup the output path for libraries.
6209 out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
6212 // Default to the current output directory.
6213 usesDefaultOutputDir = true;
6217 // Convert the output path to a full path in case it is
6218 // specified as a relative path. Treat a relative path as
6219 // relative to the current output directory for this makefile.
6220 out = (cmSystemTools::CollapseFullPath(
6221 out, this->LocalGenerator->GetCurrentBinaryDirectory()));
6223 // The generator may add the configuration's subdirectory.
6224 if (!conf.empty()) {
6226 this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
6227 std::string suffix =
6228 usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
6229 this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
6230 "/", conf, suffix, out);
6233 return usesDefaultOutputDir;
6236 bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
6237 const std::string& config,
6238 std::string& out) const
6240 // Look for a target property defining the target output directory
6241 // based on the target type.
6242 const char* propertyName = nullptr;
6243 std::string propertyNameStr = kind;
6244 if (!propertyNameStr.empty()) {
6245 propertyNameStr += "_OUTPUT_DIRECTORY";
6246 propertyName = propertyNameStr.c_str();
6248 std::string conf = config;
6250 // Check for a per-configuration output directory target property.
6251 std::string configUpper = cmSystemTools::UpperCase(conf);
6252 const char* configProp = nullptr;
6253 std::string configPropStr = kind;
6254 if (!configPropStr.empty()) {
6255 configPropStr += "_OUTPUT_DIRECTORY_";
6256 configPropStr += configUpper;
6257 configProp = configPropStr.c_str();
6260 // Select an output directory.
6261 if (cmProp config_outdir = this->GetProperty(configProp)) {
6262 // Use the user-specified per-configuration output directory.
6263 out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
6266 // Skip per-configuration subdirectory.
6268 } else if (cmProp outdir = this->GetProperty(propertyName)) {
6269 // Use the user-specified output directory.
6271 cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
6273 // Skip per-configuration subdirectory if the value contained a
6274 // generator expression.
6275 if (out != *outdir) {
6283 // Convert the output path to a full path in case it is
6284 // specified as a relative path. Treat a relative path as
6285 // relative to the current output directory for this makefile.
6286 out = (cmSystemTools::CollapseFullPath(
6287 out, this->LocalGenerator->GetCurrentBinaryDirectory()));
6289 // The generator may add the configuration's subdirectory.
6290 if (!conf.empty()) {
6291 this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
6292 "/", conf, "", out);
6297 bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string& config) const
6299 std::string install_rpath;
6300 this->GetInstallRPATH(config, install_rpath);
6301 return !install_rpath.empty() &&
6302 !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
6305 bool cmGeneratorTarget::GetBuildRPATH(const std::string& config,
6306 std::string& rpath) const
6308 return this->GetRPATH(config, "BUILD_RPATH", rpath);
6311 bool cmGeneratorTarget::GetInstallRPATH(const std::string& config,
6312 std::string& rpath) const
6314 return this->GetRPATH(config, "INSTALL_RPATH", rpath);
6317 bool cmGeneratorTarget::GetRPATH(const std::string& config,
6318 const std::string& prop,
6319 std::string& rpath) const
6321 cmProp value = this->GetProperty(prop);
6327 cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config);
6332 void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
6333 const std::string& config, cmOptionalLinkInterface& iface,
6334 cmGeneratorTarget const* headTarget, bool usage_requirements_only) const
6336 // Construct the property name suffix for this configuration.
6337 std::string suffix = "_";
6338 if (!config.empty()) {
6339 suffix += cmSystemTools::UpperCase(config);
6341 suffix += "NOCONFIG";
6344 // An explicit list of interface libraries may be set for shared
6345 // libraries and executables that export symbols.
6346 cmProp explicitLibraries = nullptr;
6347 std::string linkIfaceProp;
6348 bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
6349 this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
6351 // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
6352 linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
6353 explicitLibraries = this->GetProperty(linkIfaceProp);
6354 } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6355 this->IsExecutableWithExports()) {
6356 // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
6357 // shared lib or executable.
6359 // Lookup the per-configuration property.
6360 linkIfaceProp = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
6361 explicitLibraries = this->GetProperty(linkIfaceProp);
6363 // If not set, try the generic property.
6364 if (!explicitLibraries) {
6365 linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
6366 explicitLibraries = this->GetProperty(linkIfaceProp);
6370 if (explicitLibraries &&
6371 this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
6372 !this->PolicyWarnedCMP0022) {
6373 // Compare the explicitly set old link interface properties to the
6374 // preferred new link interface property one and warn if different.
6375 cmProp newExplicitLibraries =
6376 this->GetProperty("INTERFACE_LINK_LIBRARIES");
6377 if (newExplicitLibraries &&
6378 (*newExplicitLibraries != *explicitLibraries)) {
6379 std::ostringstream w;
6380 /* clang-format off */
6381 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
6382 "Target \"" << this->GetName() << "\" has an "
6383 "INTERFACE_LINK_LIBRARIES property which differs from its " <<
6384 linkIfaceProp << " properties."
6386 "INTERFACE_LINK_LIBRARIES:\n"
6387 " " << *newExplicitLibraries << "\n" <<
6388 linkIfaceProp << ":\n"
6389 " " << *explicitLibraries << "\n";
6390 /* clang-format on */
6391 this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
6392 this->PolicyWarnedCMP0022 = true;
6396 // There is no implicit link interface for executables or modules
6397 // so if none was explicitly set then there is no link interface.
6398 if (!explicitLibraries &&
6399 (this->GetType() == cmStateEnums::EXECUTABLE ||
6400 (this->GetType() == cmStateEnums::MODULE_LIBRARY))) {
6403 iface.Exists = true;
6404 iface.Explicit = cmp0022NEW || explicitLibraries != nullptr;
6406 if (explicitLibraries) {
6407 // The interface libraries have been explicitly set.
6408 this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config,
6409 headTarget, usage_requirements_only, iface.Libraries,
6410 iface.HadHeadSensitiveCondition,
6411 iface.HadContextSensitiveCondition,
6412 iface.HadLinkLanguageSensitiveCondition);
6413 } else if (!cmp0022NEW)
6414 // If CMP0022 is NEW then the plain tll signature sets the
6415 // INTERFACE_LINK_LIBRARIES, so if we get here then the project
6416 // cleared the property explicitly and we should not fall back
6417 // to the link implementation.
6419 // The link implementation is the default link interface.
6420 cmLinkImplementationLibraries const* impl =
6421 this->GetLinkImplementationLibrariesInternal(config, headTarget);
6422 iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
6423 impl->Libraries.end());
6424 if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
6425 !this->PolicyWarnedCMP0022 && !usage_requirements_only) {
6426 // Compare the link implementation fallback link interface to the
6427 // preferred new link interface property and warn if different.
6428 std::vector<cmLinkItem> ifaceLibs;
6429 static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
6430 if (cmProp newExplicitLibraries = this->GetProperty(newProp)) {
6431 bool hadHeadSensitiveConditionDummy = false;
6432 bool hadContextSensitiveConditionDummy = false;
6433 bool hadLinkLanguageSensitiveConditionDummy = false;
6434 this->ExpandLinkItems(newProp, *newExplicitLibraries, config,
6435 headTarget, usage_requirements_only, ifaceLibs,
6436 hadHeadSensitiveConditionDummy,
6437 hadContextSensitiveConditionDummy,
6438 hadLinkLanguageSensitiveConditionDummy);
6440 if (ifaceLibs != iface.Libraries) {
6441 std::string oldLibraries = cmJoin(impl->Libraries, ";");
6442 std::string newLibraries = cmJoin(ifaceLibs, ";");
6443 if (oldLibraries.empty()) {
6444 oldLibraries = "(empty)";
6446 if (newLibraries.empty()) {
6447 newLibraries = "(empty)";
6450 std::ostringstream w;
6451 /* clang-format off */
6452 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
6453 "Target \"" << this->GetName() << "\" has an "
6454 "INTERFACE_LINK_LIBRARIES property. "
6455 "This should be preferred as the source of the link interface "
6456 "for this library but because CMP0022 is not set CMake is "
6457 "ignoring the property and using the link implementation "
6458 "as the link interface instead."
6460 "INTERFACE_LINK_LIBRARIES:\n"
6461 " " << newLibraries << "\n"
6462 "Link implementation:\n"
6463 " " << oldLibraries << "\n";
6464 /* clang-format on */
6465 this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
6467 this->PolicyWarnedCMP0022 = true;
6473 const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
6474 const std::string& config, cmGeneratorTarget const* headTarget,
6475 bool usage_requirements_only, bool secondPass) const
6477 cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config);
6482 cmHeadToLinkInterfaceMap& hm =
6483 (usage_requirements_only
6484 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
6485 : this->GetHeadToLinkInterfaceMap(config));
6488 hm.erase(headTarget);
6491 // If the link interface does not depend on the head target
6492 // then return the one we computed first.
6493 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6494 return &hm.begin()->second;
6497 cmOptionalLinkInterface& iface = hm[headTarget];
6498 if (!iface.AllDone) {
6499 iface.AllDone = true;
6500 iface.Multiplicity = info->Multiplicity;
6501 cmExpandList(info->Languages, iface.Languages);
6502 this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config,
6503 headTarget, usage_requirements_only, iface.Libraries,
6504 iface.HadHeadSensitiveCondition,
6505 iface.HadContextSensitiveCondition,
6506 iface.HadLinkLanguageSensitiveCondition);
6507 std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
6508 this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps);
6514 cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
6515 const std::string& config) const
6517 // There is no imported information for non-imported targets.
6518 if (!this->IsImported()) {
6522 // Lookup/compute/cache the import information for this
6524 std::string config_upper;
6525 if (!config.empty()) {
6526 config_upper = cmSystemTools::UpperCase(config);
6528 config_upper = "NOCONFIG";
6531 auto i = this->ImportInfoMap.find(config_upper);
6532 if (i == this->ImportInfoMap.end()) {
6534 this->ComputeImportInfo(config_upper, info);
6535 ImportInfoMapType::value_type entry(config_upper, info);
6536 i = this->ImportInfoMap.insert(entry).first;
6539 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
6542 // If the location is empty then the target is not available for
6543 // this configuration.
6544 if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
6548 // Return the import information.
6552 void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
6553 ImportInfo& info) const
6555 // This method finds information about an imported target from its
6556 // properties. The "IMPORTED_" namespace is reserved for properties
6557 // defined by the project exporting the target.
6559 // Initialize members.
6560 info.NoSOName = false;
6562 cmProp loc = nullptr;
6563 cmProp imp = nullptr;
6565 if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
6569 // Get the link interface.
6571 std::string linkProp = "INTERFACE_LINK_LIBRARIES";
6572 cmProp propertyLibs = this->GetProperty(linkProp);
6574 if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
6575 if (!propertyLibs) {
6576 linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix);
6577 propertyLibs = this->GetProperty(linkProp);
6580 if (!propertyLibs) {
6581 linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
6582 propertyLibs = this->GetProperty(linkProp);
6586 info.LibrariesProp = linkProp;
6587 info.Libraries = *propertyLibs;
6590 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
6592 info.LibName = *loc;
6597 // A provided configuration has been chosen. Load the
6598 // configuration's properties.
6600 // Get the location.
6602 info.Location = *loc;
6604 std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
6605 if (cmProp config_location = this->GetProperty(impProp)) {
6606 info.Location = *config_location;
6607 } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) {
6608 info.Location = *location;
6613 if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
6614 std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
6615 if (cmProp config_soname = this->GetProperty(soProp)) {
6616 info.SOName = *config_soname;
6617 } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) {
6618 info.SOName = *soname;
6622 // Get the "no-soname" mark.
6623 if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
6624 std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
6625 if (cmProp config_no_soname = this->GetProperty(soProp)) {
6626 info.NoSOName = cmIsOn(*config_no_soname);
6627 } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
6628 info.NoSOName = cmIsOn(*no_soname);
6632 // Get the import library.
6634 info.ImportLibrary = *imp;
6635 } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6636 this->IsExecutableWithExports()) {
6637 std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
6638 if (cmProp config_implib = this->GetProperty(impProp)) {
6639 info.ImportLibrary = *config_implib;
6640 } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) {
6641 info.ImportLibrary = *implib;
6645 // Get the link dependencies.
6647 std::string linkProp =
6648 cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
6649 if (cmProp config_libs = this->GetProperty(linkProp)) {
6650 info.SharedDeps = *config_libs;
6651 } else if (cmProp libs =
6652 this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
6653 info.SharedDeps = *libs;
6657 // Get the link languages.
6658 if (this->LinkLanguagePropagatesToDependents()) {
6659 std::string linkProp =
6660 cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
6661 if (cmProp config_libs = this->GetProperty(linkProp)) {
6662 info.Languages = *config_libs;
6663 } else if (cmProp libs =
6664 this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
6665 info.Languages = *libs;
6669 // Get information if target is managed assembly.
6671 std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
6672 if (cmProp pc = this->GetProperty(linkProp + suffix)) {
6673 info.Managed = this->CheckManagedType(*pc);
6674 } else if (cmProp p = this->GetProperty(linkProp)) {
6675 info.Managed = this->CheckManagedType(*p);
6679 // Get the cyclic repetition count.
6680 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
6681 std::string linkProp =
6682 cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
6683 if (cmProp config_reps = this->GetProperty(linkProp)) {
6684 sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
6685 } else if (cmProp reps =
6686 this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
6687 sscanf(reps->c_str(), "%u", &info.Multiplicity);
6692 cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
6693 const std::string& config) const
6695 return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)];
6698 cmHeadToLinkInterfaceMap&
6699 cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
6700 const std::string& config) const
6703 ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
6706 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
6707 const std::string& config) const
6709 return this->GetLinkImplementation(config, false);
6712 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
6713 const std::string& config, bool secondPass) const
6715 // There is no link implementation for imported targets.
6716 if (this->IsImported()) {
6720 cmOptionalLinkImplementation& impl =
6721 this->LinkImplMap[cmSystemTools::UpperCase(config)][this];
6723 impl = cmOptionalLinkImplementation();
6725 if (!impl.LibrariesDone) {
6726 impl.LibrariesDone = true;
6727 this->ComputeLinkImplementationLibraries(config, impl, this);
6729 if (!impl.LanguagesDone) {
6730 impl.LanguagesDone = true;
6731 this->ComputeLinkImplementationLanguages(config, impl);
6736 bool cmGeneratorTarget::GetConfigCommonSourceFiles(
6737 std::vector<cmSourceFile*>& files) const
6739 std::vector<std::string> const& configs =
6740 this->Makefile->GetGeneratorConfigs();
6742 auto it = configs.begin();
6743 const std::string& firstConfig = *it;
6744 this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
6746 for (; it != configs.end(); ++it) {
6747 std::vector<cmSourceFile*> configFiles;
6748 this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
6749 if (configFiles != files) {
6750 std::string firstConfigFiles;
6751 const char* sep = "";
6752 for (cmSourceFile* f : files) {
6753 firstConfigFiles += sep;
6754 firstConfigFiles += f->ResolveFullPath();
6758 std::string thisConfigFiles;
6760 for (cmSourceFile* f : configFiles) {
6761 thisConfigFiles += sep;
6762 thisConfigFiles += f->ResolveFullPath();
6765 std::ostringstream e;
6766 /* clang-format off */
6767 e << "Target \"" << this->GetName()
6768 << "\" has source files which vary by "
6769 "configuration. This is not supported by the \""
6770 << this->GlobalGenerator->GetName()
6771 << "\" generator.\n"
6772 "Config \"" << firstConfig << "\":\n"
6773 " " << firstConfigFiles << "\n"
6774 "Config \"" << *it << "\":\n"
6775 " " << thisConfigFiles << "\n";
6776 /* clang-format on */
6777 this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
6784 void cmGeneratorTarget::GetObjectLibrariesCMP0026(
6785 std::vector<cmGeneratorTarget*>& objlibs) const
6787 // At configure-time, this method can be called as part of getting the
6788 // LOCATION property or to export() a file to be include()d. However
6789 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
6790 // for TARGET_OBJECTS instead for backwards compatibility with OLD
6791 // behavior of CMP0024 and CMP0026 only.
6792 cmStringRange rng = this->Target->GetSourceEntries();
6793 for (std::string const& entry : rng) {
6794 std::vector<std::string> files = cmExpandedList(entry);
6795 for (std::string const& li : files) {
6796 if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
6797 std::string objLibName = li.substr(17, li.size() - 18);
6799 if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
6802 cmGeneratorTarget* objLib =
6803 this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
6805 objlibs.push_back(objLib);
6812 std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
6814 // Strip whitespace off the library names because we used to do this
6815 // in case variables were expanded at generate time. We no longer
6816 // do the expansion but users link to libraries like " ${VAR} ".
6817 std::string lib = item;
6818 std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
6819 if (pos != std::string::npos) {
6820 lib = lib.substr(pos);
6822 pos = lib.find_last_not_of(" \t\r\n");
6823 if (pos != std::string::npos) {
6824 lib = lib.substr(0, pos + 1);
6827 cmake* cm = this->LocalGenerator->GetCMakeInstance();
6828 switch (this->GetPolicyStatusCMP0004()) {
6829 case cmPolicies::WARN: {
6830 std::ostringstream w;
6831 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
6832 << "Target \"" << this->GetName() << "\" links to item \"" << item
6833 << "\" which has leading or trailing whitespace.";
6834 cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
6835 this->GetBacktrace());
6837 case cmPolicies::OLD:
6839 case cmPolicies::NEW: {
6840 std::ostringstream e;
6841 e << "Target \"" << this->GetName() << "\" links to item \"" << item
6842 << "\" which has leading or trailing whitespace. "
6843 << "This is now an error according to policy CMP0004.";
6844 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
6845 this->GetBacktrace());
6847 case cmPolicies::REQUIRED_IF_USED:
6848 case cmPolicies::REQUIRED_ALWAYS: {
6849 std::ostringstream e;
6850 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
6851 << "Target \"" << this->GetName() << "\" links to item \"" << item
6852 << "\" which has leading or trailing whitespace.";
6853 cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
6854 this->GetBacktrace());
6861 bool cmGeneratorTarget::IsDeprecated() const
6863 cmProp deprecation = this->GetProperty("DEPRECATION");
6864 return deprecation && !deprecation->empty();
6867 std::string cmGeneratorTarget::GetDeprecation() const
6869 // find DEPRECATION property
6870 if (cmProp deprecation = this->GetProperty("DEPRECATION")) {
6871 return *deprecation;
6873 return std::string();
6876 void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
6877 const std::string& config) const
6879 std::vector<cmSourceFile*> sourceFiles;
6880 this->GetSourceFiles(sourceFiles, config);
6881 for (cmSourceFile* src : sourceFiles) {
6882 const std::string& lang = src->GetOrDetermineLanguage();
6883 if (!lang.empty()) {
6884 languages.insert(lang);
6888 std::vector<cmGeneratorTarget*> objectLibraries;
6889 std::vector<cmSourceFile const*> externalObjects;
6890 if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
6891 std::vector<cmGeneratorTarget*> objectTargets;
6892 this->GetObjectLibrariesCMP0026(objectTargets);
6893 objectLibraries.reserve(objectTargets.size());
6894 for (cmGeneratorTarget* gt : objectTargets) {
6895 objectLibraries.push_back(gt);
6898 this->GetExternalObjects(externalObjects, config);
6899 for (cmSourceFile const* extObj : externalObjects) {
6900 std::string objLib = extObj->GetObjectLibrary();
6901 if (cmGeneratorTarget* tgt =
6902 this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
6903 auto const objLibIt =
6904 std::find_if(objectLibraries.cbegin(), objectLibraries.cend(),
6905 [tgt](cmGeneratorTarget* t) { return t == tgt; });
6906 if (objectLibraries.cend() == objLibIt) {
6907 objectLibraries.push_back(tgt);
6912 for (cmGeneratorTarget* objLib : objectLibraries) {
6913 objLib->GetLanguages(languages, config);
6917 bool cmGeneratorTarget::IsCSharpOnly() const
6919 // Only certain target types may compile CSharp.
6920 if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
6921 this->GetType() != cmStateEnums::STATIC_LIBRARY &&
6922 this->GetType() != cmStateEnums::EXECUTABLE) {
6925 std::set<std::string> languages = this->GetAllConfigCompileLanguages();
6926 // Consider an explicit linker language property, but *not* the
6927 // computed linker language that may depend on linked targets.
6928 cmProp linkLang = this->GetProperty("LINKER_LANGUAGE");
6929 if (linkLang && !linkLang->empty()) {
6930 languages.insert(*linkLang);
6932 return languages.size() == 1 && languages.count("CSharp") > 0;
6935 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
6936 const std::string& config, cmOptionalLinkImplementation& impl) const
6938 // This target needs runtime libraries for its source languages.
6939 std::set<std::string> languages;
6940 // Get languages used in our source files.
6941 this->GetLanguages(languages, config);
6942 // Copy the set of languages to the link implementation.
6943 impl.Languages.insert(impl.Languages.begin(), languages.begin(),
6947 bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
6949 if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
6952 std::string build_rpath;
6953 if (this->GetBuildRPATH(config, build_rpath)) {
6956 if (cmLinkImplementationLibraries const* impl =
6957 this->GetLinkImplementationLibraries(config)) {
6958 return !impl->Libraries.empty();
6963 cmLinkImplementationLibraries const*
6964 cmGeneratorTarget::GetLinkImplementationLibraries(
6965 const std::string& config) const
6967 return this->GetLinkImplementationLibrariesInternal(config, this);
6970 cmLinkImplementationLibraries const*
6971 cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
6972 const std::string& config, cmGeneratorTarget const* head) const
6974 // There is no link implementation for imported targets.
6975 if (this->IsImported()) {
6979 // Populate the link implementation libraries for this configuration.
6980 HeadToLinkImplementationMap& hm =
6981 this->LinkImplMap[cmSystemTools::UpperCase(config)];
6983 // If the link implementation does not depend on the head target
6984 // then return the one we computed first.
6985 if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
6986 return &hm.begin()->second;
6989 cmOptionalLinkImplementation& impl = hm[head];
6990 if (!impl.LibrariesDone) {
6991 impl.LibrariesDone = true;
6992 this->ComputeLinkImplementationLibraries(config, impl, head);
6997 bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
6998 const std::string& p) const
7000 return cm::contains(this->LinkImplicitNullProperties, p);
7003 void cmGeneratorTarget::ComputeLinkImplementationLibraries(
7004 const std::string& config, cmOptionalLinkImplementation& impl,
7005 cmGeneratorTarget const* head) const
7007 cmLocalGenerator const* lg = this->LocalGenerator;
7008 cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
7009 cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
7010 cmBacktraceRange::const_iterator btIt = btRange.begin();
7011 // Collect libraries directly linked in this configuration.
7012 for (cmStringRange::const_iterator le = entryRange.begin(),
7013 end = entryRange.end();
7014 le != end; ++le, ++btIt) {
7015 std::vector<std::string> llibs;
7016 // Keep this logic in sync with ExpandLinkItems.
7017 cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
7019 cmGeneratorExpression ge(*btIt);
7020 std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le);
7021 std::string const& evaluated =
7022 cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
7023 this->LinkerLanguage);
7024 cmExpandList(evaluated, llibs);
7025 if (cge->GetHadHeadSensitiveCondition()) {
7026 impl.HadHeadSensitiveCondition = true;
7028 if (cge->GetHadContextSensitiveCondition()) {
7029 impl.HadContextSensitiveCondition = true;
7031 if (cge->GetHadLinkLanguageSensitiveCondition()) {
7032 impl.HadLinkLanguageSensitiveCondition = true;
7035 for (std::string const& lib : llibs) {
7036 if (this->IsLinkLookupScope(lib, lg)) {
7040 // Skip entries that resolve to the target itself or are empty.
7041 std::string name = this->CheckCMP0004(lib);
7042 if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) {
7043 // resolve alias name
7044 auto target = this->Makefile->FindTargetToUse(name);
7046 name = target->GetName();
7049 if (name == this->GetName() || name.empty()) {
7050 if (name == this->GetName()) {
7051 bool noMessage = false;
7052 MessageType messageType = MessageType::FATAL_ERROR;
7053 std::ostringstream e;
7054 switch (this->GetPolicyStatusCMP0038()) {
7055 case cmPolicies::WARN: {
7056 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
7057 messageType = MessageType::AUTHOR_WARNING;
7059 case cmPolicies::OLD:
7061 case cmPolicies::REQUIRED_IF_USED:
7062 case cmPolicies::REQUIRED_ALWAYS:
7063 case cmPolicies::NEW:
7064 // Issue the fatal message.
7069 e << "Target \"" << this->GetName() << "\" links to itself.";
7070 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
7071 messageType, e.str(), this->GetBacktrace());
7072 if (messageType == MessageType::FATAL_ERROR) {
7080 // The entry is meant for this configuration.
7081 impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg),
7085 std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
7086 for (std::string const& sp : seenProps) {
7087 if (!this->GetProperty(sp)) {
7088 this->LinkImplicitNullProperties.insert(sp);
7091 cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
7094 // Get the list of configurations considered to be DEBUG.
7095 std::vector<std::string> debugConfigs =
7096 this->Makefile->GetCMakeInstance()->GetDebugConfigs();
7098 cmTargetLinkLibraryType linkType =
7099 CMP0003_ComputeLinkType(config, debugConfigs);
7100 cmTarget::LinkLibraryVectorType const& oldllibs =
7101 this->Target->GetOriginalLinkLibraries();
7102 for (cmTarget::LibraryID const& oldllib : oldllibs) {
7103 if (oldllib.second != GENERAL_LibraryType && oldllib.second != linkType) {
7104 std::string name = this->CheckCMP0004(oldllib.first);
7105 if (name == this->GetName() || name.empty()) {
7108 // Support OLD behavior for CMP0003.
7109 impl.WrongConfigLibraries.push_back(
7110 this->ResolveLinkItem(name, cmListFileBacktrace()));
7115 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
7116 std::string const& name) const
7118 return this->ResolveTargetReference(name, this->LocalGenerator);
7121 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
7122 std::string const& name, cmLocalGenerator const* lg) const
7124 TargetOrString resolved;
7126 if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
7127 resolved.Target = tgt;
7129 resolved.String = name;
7135 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
7136 std::string const& name, cmListFileBacktrace const& bt) const
7138 return this->ResolveLinkItem(name, bt, this->LocalGenerator);
7141 cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name,
7142 cmListFileBacktrace const& bt,
7143 cmLocalGenerator const* lg) const
7145 TargetOrString resolved = this->ResolveTargetReference(name, lg);
7147 if (!resolved.Target) {
7148 return cmLinkItem(resolved.String, false, bt);
7151 // Check deprecation, issue message with `bt` backtrace.
7152 if (resolved.Target->IsDeprecated()) {
7153 std::ostringstream w;
7154 /* clang-format off */
7156 "The library that is being linked to, " << resolved.Target->GetName() <<
7157 ", is marked as being deprecated by the owner. The message provided by "
7158 "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
7159 /* clang-format on */
7160 this->LocalGenerator->GetCMakeInstance()->IssueMessage(
7161 MessageType::AUTHOR_WARNING, w.str(), bt);
7164 // Skip targets that will not really be linked. This is probably a
7165 // name conflict between an external library and an executable
7166 // within the project.
7167 if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
7168 !resolved.Target->IsExecutableWithExports()) {
7169 return cmLinkItem(resolved.Target->GetName(), false, bt);
7172 return cmLinkItem(resolved.Target, false, bt);
7175 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
7177 if (OutputInfo const* info = this->GetOutputInfo(config)) {
7178 // Return the directory in which the target will be built.
7179 return info->PdbDir;
7184 bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
7186 return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
7189 bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
7190 std::string const& gnuName,
7192 const char* newExt) const
7194 if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
7195 gnuName.substr(gnuName.size() - 6) == ".dll.a") {
7196 out = cmStrCat(cm::string_view(gnuName).substr(0, gnuName.size() - 6),
7197 newExt ? newExt : ".lib");
7203 bool cmGeneratorTarget::IsExecutableWithExports() const
7205 return (this->GetType() == cmStateEnums::EXECUTABLE &&
7206 this->GetPropertyAsBool("ENABLE_EXPORTS"));
7209 bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
7211 return (this->IsDLLPlatform() &&
7212 (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7213 this->IsExecutableWithExports()) &&
7214 // Assemblies which have only managed code do not have
7215 // import libraries.
7216 this->GetManagedType(config) != ManagedType::Managed) ||
7217 (this->Target->IsAIX() && this->IsExecutableWithExports());
7220 bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
7222 return this->HasImportLibrary(config) ||
7223 // On DLL platforms we always generate the import library name
7224 // just in case the sources have export markup.
7225 (this->IsDLLPlatform() &&
7226 (this->GetType() == cmStateEnums::EXECUTABLE ||
7227 this->GetType() == cmStateEnums::MODULE_LIBRARY));
7230 std::string cmGeneratorTarget::GetSupportDirectory() const
7232 std::string dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
7233 "/CMakeFiles/", this->GetName());
7242 bool cmGeneratorTarget::IsLinkable() const
7244 return (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
7245 this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7246 this->GetType() == cmStateEnums::MODULE_LIBRARY ||
7247 this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
7248 this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
7249 this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
7250 this->IsExecutableWithExports());
7253 bool cmGeneratorTarget::IsFrameworkOnApple() const
7255 return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
7256 this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
7257 this->Makefile->IsOn("APPLE") &&
7258 this->GetPropertyAsBool("FRAMEWORK"));
7261 bool cmGeneratorTarget::IsAppBundleOnApple() const
7263 return (this->GetType() == cmStateEnums::EXECUTABLE &&
7264 this->Makefile->IsOn("APPLE") &&
7265 this->GetPropertyAsBool("MACOSX_BUNDLE"));
7268 bool cmGeneratorTarget::IsXCTestOnApple() const
7270 return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
7273 bool cmGeneratorTarget::IsCFBundleOnApple() const
7275 return (this->GetType() == cmStateEnums::MODULE_LIBRARY &&
7276 this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
7279 cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
7280 std::string const& propval) const
7282 // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
7283 // or only C++/CLI) does only depend on whether the property is an empty
7284 // string or contains any value at all. In Visual Studio generators
7285 // this propval is prepended with /clr[:] which results in:
7287 // 1. propval does not exist: no /clr flag, unmanaged target, has import
7289 // 2. empty propval: add /clr as flag, mixed unmanaged/managed
7290 // target, has import lib
7291 // 3. any value (safe,pure): add /clr:[propval] as flag, target with
7292 // managed code only, no import lib
7293 return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
7296 cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
7297 const std::string& config) const
7299 // Only libraries and executables can be managed targets.
7300 if (this->GetType() > cmStateEnums::SHARED_LIBRARY) {
7301 return ManagedType::Undefined;
7304 if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
7305 return ManagedType::Native;
7308 // Check imported target.
7309 if (this->IsImported()) {
7310 if (cmGeneratorTarget::ImportInfo const* info =
7311 this->GetImportInfo(config)) {
7312 return info->Managed;
7314 return ManagedType::Undefined;
7317 // Check for explicitly set clr target property.
7318 if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
7319 return this->CheckManagedType(*clr);
7322 // C# targets are always managed. This language specific check
7323 // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
7324 // has to be set manually for C# targets.
7325 return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;