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"
17 #include <type_traits>
18 #include <unordered_set>
22 #include <cm/optional>
23 #include <cm/string_view>
24 #include <cmext/algorithm>
25 #include <cmext/string_view>
27 #include "cmsys/RegularExpression.hxx"
29 #include "cmAlgorithms.h"
30 #include "cmComputeLinkInformation.h"
31 #include "cmCryptoHash.h"
32 #include "cmCustomCommandGenerator.h"
33 #include "cmCxxModuleUsageEffects.h"
34 #include "cmEvaluatedTargetProperty.h"
35 #include "cmFileSet.h"
36 #include "cmFileTimes.h"
37 #include "cmGeneratedFileStream.h"
38 #include "cmGeneratorExpression.h"
39 #include "cmGeneratorExpressionContext.h"
40 #include "cmGeneratorExpressionDAGChecker.h"
41 #include "cmGeneratorExpressionNode.h"
42 #include "cmGlobalGenerator.h"
44 #include "cmLocalGenerator.h"
45 #include "cmMakefile.h"
46 #include "cmMessageType.h"
47 #include "cmOutputConverter.h"
48 #include "cmPropertyMap.h"
50 #include "cmSourceFile.h"
51 #include "cmSourceFileLocation.h"
52 #include "cmSourceFileLocationKind.h"
53 #include "cmSourceGroup.h"
54 #include "cmStandardLevel.h"
55 #include "cmStandardLevelResolver.h"
57 #include "cmStringAlgorithms.h"
58 #include "cmSyntheticTargetCache.h"
59 #include "cmSystemTools.h"
61 #include "cmTargetLinkLibraryType.h"
62 #include "cmTargetPropertyComputer.h"
66 using LinkInterfaceFor
= cmGeneratorTarget::LinkInterfaceFor
;
68 const std::string kINTERFACE_LINK_LIBRARIES
= "INTERFACE_LINK_LIBRARIES";
69 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT
=
70 "INTERFACE_LINK_LIBRARIES_DIRECT";
71 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE
=
72 "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
76 cmValue
cmTargetPropertyComputer::GetSources
<cmGeneratorTarget
>(
77 cmGeneratorTarget
const* tgt
, cmMakefile
const& /* mf */)
79 return tgt
->GetSourcesProperty();
84 cmTargetPropertyComputer::ComputeLocationForBuild
<cmGeneratorTarget
>(
85 cmGeneratorTarget
const* tgt
)
87 return tgt
->GetLocation("");
92 cmTargetPropertyComputer::ComputeLocation
<cmGeneratorTarget
>(
93 cmGeneratorTarget
const* tgt
, const std::string
& config
)
95 return tgt
->GetLocation(config
);
98 cmLinkImplItem
cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem
;
100 class TargetPropertyEntryString
: public cmGeneratorTarget::TargetPropertyEntry
103 TargetPropertyEntryString(BT
<std::string
> propertyValue
,
104 cmLinkImplItem
const& item
= NoLinkImplItem
)
105 : cmGeneratorTarget::TargetPropertyEntry(item
)
106 , PropertyValue(std::move(propertyValue
))
110 const std::string
& Evaluate(cmLocalGenerator
*, const std::string
&,
111 cmGeneratorTarget
const*,
112 cmGeneratorExpressionDAGChecker
*,
113 std::string
const&) const override
115 return this->PropertyValue
.Value
;
118 cmListFileBacktrace
GetBacktrace() const override
120 return this->PropertyValue
.Backtrace
;
122 std::string
const& GetInput() const override
124 return this->PropertyValue
.Value
;
128 BT
<std::string
> PropertyValue
;
131 class TargetPropertyEntryGenex
: public cmGeneratorTarget::TargetPropertyEntry
134 TargetPropertyEntryGenex(std::unique_ptr
<cmCompiledGeneratorExpression
> cge
,
135 cmLinkImplItem
const& item
= NoLinkImplItem
)
136 : cmGeneratorTarget::TargetPropertyEntry(item
)
141 const std::string
& Evaluate(cmLocalGenerator
* lg
, const std::string
& config
,
142 cmGeneratorTarget
const* headTarget
,
143 cmGeneratorExpressionDAGChecker
* dagChecker
,
144 std::string
const& language
) const override
146 return this->ge
->Evaluate(lg
, config
, headTarget
, dagChecker
, nullptr,
150 cmListFileBacktrace
GetBacktrace() const override
152 return this->ge
->GetBacktrace();
155 std::string
const& GetInput() const override
{ return this->ge
->GetInput(); }
157 bool GetHadContextSensitiveCondition() const override
159 return this->ge
->GetHadContextSensitiveCondition();
163 const std::unique_ptr
<cmCompiledGeneratorExpression
> ge
;
166 class TargetPropertyEntryFileSet
167 : public cmGeneratorTarget::TargetPropertyEntry
170 TargetPropertyEntryFileSet(
171 std::vector
<std::string
> dirs
, bool contextSensitiveDirs
,
172 std::unique_ptr
<cmCompiledGeneratorExpression
> entryCge
,
173 const cmFileSet
* fileSet
, cmLinkImplItem
const& item
= NoLinkImplItem
)
174 : cmGeneratorTarget::TargetPropertyEntry(item
)
175 , BaseDirs(std::move(dirs
))
176 , ContextSensitiveDirs(contextSensitiveDirs
)
177 , EntryCge(std::move(entryCge
))
182 const std::string
& Evaluate(cmLocalGenerator
* lg
, const std::string
& config
,
183 cmGeneratorTarget
const* headTarget
,
184 cmGeneratorExpressionDAGChecker
* dagChecker
,
185 std::string
const& /*lang*/) const override
187 std::map
<std::string
, std::vector
<std::string
>> filesPerDir
;
188 this->FileSet
->EvaluateFileEntry(this->BaseDirs
, filesPerDir
,
189 this->EntryCge
, lg
, config
, headTarget
,
192 std::vector
<std::string
> files
;
193 for (auto const& it
: filesPerDir
) {
194 files
.insert(files
.end(), it
.second
.begin(), it
.second
.end());
197 static std::string filesStr
;
198 filesStr
= cmList::to_string(files
);
202 cmListFileBacktrace
GetBacktrace() const override
204 return this->EntryCge
->GetBacktrace();
207 std::string
const& GetInput() const override
209 return this->EntryCge
->GetInput();
212 bool GetHadContextSensitiveCondition() const override
214 return this->ContextSensitiveDirs
||
215 this->EntryCge
->GetHadContextSensitiveCondition();
219 const std::vector
<std::string
> BaseDirs
;
220 const bool ContextSensitiveDirs
;
221 const std::unique_ptr
<cmCompiledGeneratorExpression
> EntryCge
;
222 const cmFileSet
* FileSet
;
227 TargetPropertyEntry
> static CreateTargetPropertyEntry(cmake
& cmakeInstance
,
232 evaluateForBuildsystem
=
235 if (cmGeneratorExpression::Find(propertyValue
.Value
) != std::string::npos
) {
236 cmGeneratorExpression
ge(cmakeInstance
, propertyValue
.Backtrace
);
237 std::unique_ptr
<cmCompiledGeneratorExpression
> cge
=
238 ge
.Parse(propertyValue
.Value
);
239 cge
->SetEvaluateForBuildsystem(evaluateForBuildsystem
);
240 return std::unique_ptr
<cmGeneratorTarget::TargetPropertyEntry
>(
241 cm::make_unique
<TargetPropertyEntryGenex
>(std::move(cge
)));
244 return std::unique_ptr
<cmGeneratorTarget::TargetPropertyEntry
>(
245 cm::make_unique
<TargetPropertyEntryString
>(propertyValue
));
248 cmGeneratorTarget::TargetPropertyEntry::TargetPropertyEntry(
249 cmLinkImplItem
const& item
)
254 bool cmGeneratorTarget::TargetPropertyEntry::GetHadContextSensitiveCondition()
260 static void CreatePropertyGeneratorExpressions(
261 cmake
& cmakeInstance
, cmBTStringRange entries
,
262 std::vector
<std::unique_ptr
<cmGeneratorTarget::TargetPropertyEntry
>>& items
,
263 bool evaluateForBuildsystem
= false)
265 for (auto const& entry
: entries
) {
267 CreateTargetPropertyEntry(cmakeInstance
, entry
, evaluateForBuildsystem
));
271 cmGeneratorTarget::cmGeneratorTarget(cmTarget
* t
, cmLocalGenerator
* lg
)
274 this->Makefile
= this->Target
->GetMakefile();
275 this->LocalGenerator
= lg
;
276 this->GlobalGenerator
= this->LocalGenerator
->GetGlobalGenerator();
278 this->GlobalGenerator
->ComputeTargetObjectDirectory(this);
280 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
281 t
->GetIncludeDirectoriesEntries(),
282 this->IncludeDirectoriesEntries
);
284 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
285 t
->GetCompileOptionsEntries(),
286 this->CompileOptionsEntries
);
288 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
289 t
->GetCompileFeaturesEntries(),
290 this->CompileFeaturesEntries
);
292 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
293 t
->GetCompileDefinitionsEntries(),
294 this->CompileDefinitionsEntries
);
296 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
297 t
->GetLinkOptionsEntries(),
298 this->LinkOptionsEntries
);
300 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
301 t
->GetLinkDirectoriesEntries(),
302 this->LinkDirectoriesEntries
);
304 CreatePropertyGeneratorExpressions(*lg
->GetCMakeInstance(),
305 t
->GetPrecompileHeadersEntries(),
306 this->PrecompileHeadersEntries
);
308 CreatePropertyGeneratorExpressions(
309 *lg
->GetCMakeInstance(), t
->GetSourceEntries(), this->SourceEntries
, true);
311 this->PolicyMap
= t
->GetPolicyMap();
313 // Get hard-coded linker language
314 if (this->Target
->GetProperty("HAS_CXX")) {
315 this->LinkerLanguage
= "CXX";
317 this->LinkerLanguage
= this->Target
->GetSafeProperty("LINKER_LANGUAGE");
321 cmGeneratorTarget::~cmGeneratorTarget() = default;
323 cmValue
cmGeneratorTarget::GetSourcesProperty() const
325 std::vector
<std::string
> values
;
326 for (auto const& se
: this->SourceEntries
) {
327 values
.push_back(se
->GetInput());
329 static std::string value
;
330 value
= cmList::to_string(values
);
331 return cmValue(value
);
334 cmGlobalGenerator
* cmGeneratorTarget::GetGlobalGenerator() const
336 return this->GetLocalGenerator()->GetGlobalGenerator();
339 cmLocalGenerator
* cmGeneratorTarget::GetLocalGenerator() const
341 return this->LocalGenerator
;
344 cmStateEnums::TargetType
cmGeneratorTarget::GetType() const
346 return this->Target
->GetType();
349 const std::string
& cmGeneratorTarget::GetName() const
351 return this->Target
->GetName();
354 std::string
cmGeneratorTarget::GetExportName() const
356 cmValue exportName
= this->GetProperty("EXPORT_NAME");
358 if (cmNonempty(exportName
)) {
359 if (!cmGeneratorExpression::IsValidTargetName(*exportName
)) {
360 std::ostringstream e
;
361 e
<< "EXPORT_NAME property \"" << *exportName
<< "\" for \""
362 << this->GetName() << "\": is not valid.";
363 cmSystemTools::Error(e
.str());
368 return this->GetName();
371 std::string
cmGeneratorTarget::GetFilesystemExportName() const
373 auto fs_safe
= this->GetExportName();
374 // First escape any `_` characters to avoid collisions.
375 cmSystemTools::ReplaceString(fs_safe
, "_", "__");
376 // Escape other characters that are not generally filesystem-safe.
377 cmSystemTools::ReplaceString(fs_safe
, ":", "_c");
381 cmValue
cmGeneratorTarget::GetProperty(const std::string
& prop
) const
384 cmTargetPropertyComputer::GetProperty(this, prop
, *this->Makefile
)) {
387 if (cmSystemTools::GetFatalErrorOccurred()) {
390 return this->Target
->GetProperty(prop
);
393 std::string
const& cmGeneratorTarget::GetSafeProperty(
394 std::string
const& prop
) const
396 return this->GetProperty(prop
);
399 const char* cmGeneratorTarget::GetOutputTargetType(
400 cmStateEnums::ArtifactType artifact
) const
402 if (this->IsFrameworkOnApple() || this->GetGlobalGenerator()->IsXcode()) {
403 // import file (i.e. .tbd file) is always in same location as library
404 artifact
= cmStateEnums::RuntimeBinaryArtifact
;
407 switch (this->GetType()) {
408 case cmStateEnums::SHARED_LIBRARY
:
409 if (this->IsDLLPlatform()) {
411 case cmStateEnums::RuntimeBinaryArtifact
:
412 // A DLL shared library is treated as a runtime target.
414 case cmStateEnums::ImportLibraryArtifact
:
415 // A DLL import library is treated as an archive target.
420 case cmStateEnums::RuntimeBinaryArtifact
:
421 // For non-DLL platforms shared libraries are treated as
424 case cmStateEnums::ImportLibraryArtifact
:
425 // Library import libraries are treated as archive targets.
430 case cmStateEnums::STATIC_LIBRARY
:
431 // Static libraries are always treated as archive targets.
433 case cmStateEnums::MODULE_LIBRARY
:
435 case cmStateEnums::RuntimeBinaryArtifact
:
436 // Module libraries are always treated as library targets.
438 case cmStateEnums::ImportLibraryArtifact
:
439 // Module import libraries are treated as archive targets.
443 case cmStateEnums::OBJECT_LIBRARY
:
444 // Object libraries are always treated as object targets.
446 case cmStateEnums::EXECUTABLE
:
448 case cmStateEnums::RuntimeBinaryArtifact
:
449 // Executables are always treated as runtime targets.
451 case cmStateEnums::ImportLibraryArtifact
:
452 // Executable import libraries are treated as archive targets.
462 std::string
cmGeneratorTarget::GetOutputName(
463 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
465 // Lookup/compute/cache the output name for this configuration.
466 OutputNameKey
key(config
, artifact
);
467 auto i
= this->OutputNameMap
.find(key
);
468 if (i
== this->OutputNameMap
.end()) {
469 // Add empty name in map to detect potential recursion.
470 OutputNameMapType::value_type
entry(key
, "");
471 i
= this->OutputNameMap
.insert(entry
).first
;
473 // Compute output name.
474 std::vector
<std::string
> props
;
475 std::string type
= this->GetOutputTargetType(artifact
);
476 std::string configUpper
= cmSystemTools::UpperCase(config
);
477 if (!type
.empty() && !configUpper
.empty()) {
478 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
479 props
.push_back(type
+ "_OUTPUT_NAME_" + configUpper
);
482 // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
483 props
.push_back(type
+ "_OUTPUT_NAME");
485 if (!configUpper
.empty()) {
486 // OUTPUT_NAME_<CONFIG>
487 props
.push_back("OUTPUT_NAME_" + configUpper
);
488 // <CONFIG>_OUTPUT_NAME
489 props
.push_back(configUpper
+ "_OUTPUT_NAME");
492 props
.emplace_back("OUTPUT_NAME");
495 for (std::string
const& p
: props
) {
496 if (cmValue outNameProp
= this->GetProperty(p
)) {
497 outName
= *outNameProp
;
502 if (outName
.empty()) {
503 outName
= this->GetName();
506 // Now evaluate genex and update the previously-prepared map entry.
508 cmGeneratorExpression::Evaluate(outName
, this->LocalGenerator
, config
);
509 } else if (i
->second
.empty()) {
510 // An empty map entry indicates we have been called recursively
511 // from the above block.
512 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
513 MessageType::FATAL_ERROR
,
514 "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
515 this->GetBacktrace());
520 std::string
cmGeneratorTarget::GetFilePrefix(
521 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
523 if (this->IsImported()) {
524 cmValue prefix
= this->GetFilePrefixInternal(config
, artifact
);
525 return prefix
? *prefix
: std::string();
527 return this->GetFullNameInternalComponents(config
, artifact
).prefix
;
529 std::string
cmGeneratorTarget::GetFileSuffix(
530 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
532 if (this->IsImported()) {
533 cmValue suffix
= this->GetFileSuffixInternal(config
, artifact
);
534 return suffix
? *suffix
: std::string();
536 return this->GetFullNameInternalComponents(config
, artifact
).suffix
;
539 std::string
cmGeneratorTarget::GetFilePostfix(const std::string
& config
) const
541 cmValue postfix
= nullptr;
542 std::string frameworkPostfix
;
543 if (!config
.empty()) {
544 std::string configProp
=
545 cmStrCat(cmSystemTools::UpperCase(config
), "_POSTFIX");
546 postfix
= this->GetProperty(configProp
);
548 // Mac application bundles and frameworks have no regular postfix like
550 if (!this->IsImported() && postfix
&&
551 (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
555 // Frameworks created by multi config generators can have a special
556 // framework postfix.
557 frameworkPostfix
= this->GetFrameworkMultiConfigPostfix(config
);
558 if (!frameworkPostfix
.empty()) {
559 postfix
= cmValue(frameworkPostfix
);
562 return postfix
? *postfix
: std::string();
565 std::string
cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
566 const std::string
& config
) const
568 cmValue postfix
= nullptr;
569 if (!config
.empty()) {
570 std::string configProp
= cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
571 cmSystemTools::UpperCase(config
));
572 postfix
= this->GetProperty(configProp
);
574 if (!this->IsImported() && postfix
&&
575 (this->IsFrameworkOnApple() &&
576 !this->GetGlobalGenerator()->IsMultiConfig())) {
580 return postfix
? *postfix
: std::string();
583 cmValue
cmGeneratorTarget::GetFilePrefixInternal(
584 std::string
const& config
, cmStateEnums::ArtifactType artifact
,
585 const std::string
& language
) const
587 // no prefix for non-main target types.
588 if (this->GetType() != cmStateEnums::STATIC_LIBRARY
&&
589 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
590 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
591 this->GetType() != cmStateEnums::EXECUTABLE
) {
595 const bool isImportedLibraryArtifact
=
596 (artifact
== cmStateEnums::ImportLibraryArtifact
);
598 // Return an empty prefix for the import library if this platform
599 // does not support import libraries.
600 if (isImportedLibraryArtifact
&& !this->NeedImportLibraryName(config
)) {
604 // The implib option is only allowed for shared libraries, module
605 // libraries, and executables.
606 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
607 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
608 this->GetType() != cmStateEnums::EXECUTABLE
) {
609 artifact
= cmStateEnums::RuntimeBinaryArtifact
;
612 // Compute prefix value.
613 cmValue targetPrefix
=
614 (isImportedLibraryArtifact
? this->GetProperty("IMPORT_PREFIX")
615 : this->GetProperty("PREFIX"));
618 const char* prefixVar
= this->Target
->GetPrefixVariableInternal(artifact
);
619 if (!language
.empty() && cmNonempty(prefixVar
)) {
620 std::string langPrefix
= cmStrCat(prefixVar
, "_", language
);
621 targetPrefix
= this->Makefile
->GetDefinition(langPrefix
);
624 // if there is no prefix on the target nor specific language
625 // use the cmake definition.
626 if (!targetPrefix
&& prefixVar
) {
627 targetPrefix
= this->Makefile
->GetDefinition(prefixVar
);
634 cmValue
cmGeneratorTarget::GetFileSuffixInternal(
635 std::string
const& config
, cmStateEnums::ArtifactType artifact
,
636 const std::string
& language
) const
638 // no suffix for non-main target types.
639 if (this->GetType() != cmStateEnums::STATIC_LIBRARY
&&
640 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
641 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
642 this->GetType() != cmStateEnums::EXECUTABLE
) {
646 const bool isImportedLibraryArtifact
=
647 (artifact
== cmStateEnums::ImportLibraryArtifact
);
649 // Return an empty suffix for the import library if this platform
650 // does not support import libraries.
651 if (isImportedLibraryArtifact
&& !this->NeedImportLibraryName(config
)) {
655 // The implib option is only allowed for shared libraries, module
656 // libraries, and executables.
657 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
658 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
659 this->GetType() != cmStateEnums::EXECUTABLE
) {
660 artifact
= cmStateEnums::RuntimeBinaryArtifact
;
663 // Compute suffix value.
664 cmValue targetSuffix
=
665 (isImportedLibraryArtifact
? this->GetProperty("IMPORT_SUFFIX")
666 : this->GetProperty("SUFFIX"));
669 const char* suffixVar
= this->Target
->GetSuffixVariableInternal(artifact
);
670 if (!language
.empty() && cmNonempty(suffixVar
)) {
671 std::string langSuffix
= cmStrCat(suffixVar
, "_", language
);
672 targetSuffix
= this->Makefile
->GetDefinition(langSuffix
);
675 // if there is no suffix on the target nor specific language
676 // use the cmake definition.
677 if (!targetSuffix
&& suffixVar
) {
678 targetSuffix
= this->Makefile
->GetDefinition(suffixVar
);
685 void cmGeneratorTarget::ClearSourcesCache()
687 this->AllConfigSources
.clear();
688 this->KindedSourcesMap
.clear();
689 this->SourcesAreContextDependent
= Tribool::Indeterminate
;
690 this->Objects
.clear();
691 this->VisitedConfigsForObjects
.clear();
692 this->LinkImplMap
.clear();
693 this->LinkImplUsageRequirementsOnlyMap
.clear();
694 this->IncludeDirectoriesCache
.clear();
695 this->CompileOptionsCache
.clear();
696 this->CompileDefinitionsCache
.clear();
697 this->PrecompileHeadersCache
.clear();
698 this->LinkOptionsCache
.clear();
699 this->LinkDirectoriesCache
.clear();
700 this->RuntimeBinaryFullNameCache
.clear();
701 this->ImportLibraryFullNameCache
.clear();
704 void cmGeneratorTarget::ClearLinkInterfaceCache()
706 this->LinkInterfaceMap
.clear();
707 this->LinkInterfaceUsageRequirementsOnlyMap
.clear();
710 void cmGeneratorTarget::AddSourceCommon(const std::string
& src
, bool before
)
712 this->SourceEntries
.insert(
713 before
? this->SourceEntries
.begin() : this->SourceEntries
.end(),
714 CreateTargetPropertyEntry(
715 *this->LocalGenerator
->GetCMakeInstance(),
716 BT
<std::string
>(src
, this->Makefile
->GetBacktrace()), true));
717 this->ClearSourcesCache();
720 void cmGeneratorTarget::AddSource(const std::string
& src
, bool before
)
722 this->Target
->AddSource(src
, before
);
723 this->AddSourceCommon(src
, before
);
726 void cmGeneratorTarget::AddTracedSources(std::vector
<std::string
> const& srcs
)
728 this->Target
->AddTracedSources(srcs
);
730 this->AddSourceCommon(cmJoin(srcs
, ";"));
734 void cmGeneratorTarget::AddIncludeDirectory(const std::string
& src
,
737 this->Target
->InsertInclude(
738 BT
<std::string
>(src
, this->Makefile
->GetBacktrace()), before
);
739 this->IncludeDirectoriesEntries
.insert(
740 before
? this->IncludeDirectoriesEntries
.begin()
741 : this->IncludeDirectoriesEntries
.end(),
742 CreateTargetPropertyEntry(
743 *this->Makefile
->GetCMakeInstance(),
744 BT
<std::string
>(src
, this->Makefile
->GetBacktrace()), true));
747 void cmGeneratorTarget::AddSystemIncludeDirectory(std::string
const& inc
,
748 std::string
const& lang
)
750 std::string config_upper
;
751 auto const& configs
=
752 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
754 for (auto const& config
: configs
) {
755 std::string inc_with_config
= inc
;
756 if (!config
.empty()) {
757 cmSystemTools::ReplaceString(inc_with_config
, "$<CONFIG>", config
);
758 config_upper
= cmSystemTools::UpperCase(config
);
760 auto const& key
= cmStrCat(config_upper
, "/", lang
);
761 this->Target
->AddSystemIncludeDirectories({ inc_with_config
});
762 this->SystemIncludesCache
[key
].emplace_back(inc_with_config
);
764 // SystemIncludesCache should be sorted so that binary search can be used
765 std::sort(this->SystemIncludesCache
[key
].begin(),
766 this->SystemIncludesCache
[key
].end());
770 std::vector
<cmSourceFile
*> const* cmGeneratorTarget::GetSourceDepends(
771 cmSourceFile
const* sf
) const
773 auto i
= this->SourceDepends
.find(sf
);
774 if (i
!= this->SourceDepends
.end()) {
775 return &i
->second
.Depends
;
781 void handleSystemIncludesDep(cmLocalGenerator
* lg
,
782 cmGeneratorTarget
const* depTgt
,
783 const std::string
& config
,
784 cmGeneratorTarget
const* headTarget
,
785 cmGeneratorExpressionDAGChecker
* dagChecker
,
786 cmList
& result
, bool excludeImported
,
787 std::string
const& language
)
790 depTgt
->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
791 result
.append(cmGeneratorExpression::Evaluate(
792 *dirs
, lg
, config
, headTarget
, dagChecker
, depTgt
, language
));
794 if (!depTgt
->GetPropertyAsBool("SYSTEM")) {
797 if (depTgt
->IsImported()) {
798 if (excludeImported
) {
801 if (depTgt
->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
806 if (cmValue dirs
= depTgt
->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
807 result
.append(cmGeneratorExpression::Evaluate(
808 *dirs
, lg
, config
, headTarget
, dagChecker
, depTgt
, language
));
811 if (depTgt
->Target
->IsFrameworkOnApple() ||
812 depTgt
->IsImportedFrameworkFolderOnApple(config
)) {
813 if (auto fwDescriptor
= depTgt
->GetGlobalGenerator()->SplitFrameworkPath(
814 depTgt
->GetLocation(config
))) {
815 result
.push_back(fwDescriptor
->Directory
);
816 result
.push_back(fwDescriptor
->GetFrameworkPath());
822 /* clang-format off */
823 #define IMPLEMENT_VISIT(KIND) \
825 KindedSources const& kinded = this->GetKindedSources(config); \
826 for (SourceAndKind const& s : kinded.Sources) { \
827 if (s.Kind == KIND) { \
828 data.push_back(s.Source.Value); \
832 /* clang-format on */
834 void cmGeneratorTarget::GetObjectSources(
835 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
837 IMPLEMENT_VISIT(SourceKindObjectSource
);
839 if (this->VisitedConfigsForObjects
.count(config
)) {
843 for (cmSourceFile
const* it
: data
) {
847 this->LocalGenerator
->ComputeObjectFilenames(this->Objects
, this);
848 this->VisitedConfigsForObjects
.insert(config
);
851 void cmGeneratorTarget::ComputeObjectMapping()
853 auto const& configs
=
854 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
855 std::set
<std::string
> configSet(configs
.begin(), configs
.end());
856 if (configSet
== this->VisitedConfigsForObjects
) {
860 for (std::string
const& c
: configs
) {
861 std::vector
<cmSourceFile
const*> sourceFiles
;
862 this->GetObjectSources(sourceFiles
, c
);
866 cmValue
cmGeneratorTarget::GetFeature(const std::string
& feature
,
867 const std::string
& config
) const
869 if (!config
.empty()) {
870 std::string featureConfig
=
871 cmStrCat(feature
, '_', cmSystemTools::UpperCase(config
));
872 if (cmValue value
= this->GetProperty(featureConfig
)) {
876 if (cmValue value
= this->GetProperty(feature
)) {
879 return this->LocalGenerator
->GetFeature(feature
, config
);
882 std::string
cmGeneratorTarget::GetLinkerTypeProperty(
883 std::string
const& lang
, std::string
const& config
) const
885 std::string propName
{ "LINKER_TYPE" };
886 auto linkerType
= this->GetProperty(propName
);
887 if (!linkerType
.IsEmpty()) {
888 cmGeneratorExpressionDAGChecker
dagChecker(this, propName
, nullptr,
891 cmGeneratorExpression::Evaluate(*linkerType
, this->GetLocalGenerator(),
892 config
, this, &dagChecker
, this, lang
);
893 if (this->IsDeviceLink()) {
894 cmList list
{ ltype
};
895 const auto DL_BEGIN
= "<DEVICE_LINK>"_s
;
896 const auto DL_END
= "</DEVICE_LINK>"_s
;
897 cm::erase_if(list
, [&](const std::string
& item
) {
898 return item
== DL_BEGIN
|| item
== DL_END
;
900 return list
.to_string();
904 return std::string
{};
907 const char* cmGeneratorTarget::GetLinkPIEProperty(
908 const std::string
& config
) const
910 static std::string PICValue
;
912 PICValue
= this->GetLinkInterfaceDependentStringAsBoolProperty(
913 "POSITION_INDEPENDENT_CODE", config
);
915 if (PICValue
== "(unset)") {
916 // POSITION_INDEPENDENT_CODE is not set
920 auto status
= this->GetPolicyStatusCMP0083();
921 return (status
!= cmPolicies::WARN
&& status
!= cmPolicies::OLD
)
926 bool cmGeneratorTarget::IsIPOEnabled(std::string
const& lang
,
927 std::string
const& config
) const
929 cmValue feature
= this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config
);
931 if (!cmIsOn(feature
)) {
932 // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
936 if (lang
!= "C" && lang
!= "CXX" && lang
!= "CUDA" && lang
!= "Fortran") {
937 // We do not define IPO behavior for other languages.
941 if (lang
== "CUDA") {
942 // CUDA IPO requires both CUDA_ARCHITECTURES and CUDA_SEPARABLE_COMPILATION
943 if (cmIsOff(this->GetSafeProperty("CUDA_ARCHITECTURES")) ||
944 cmIsOff(this->GetSafeProperty("CUDA_SEPARABLE_COMPILATION"))) {
949 cmPolicies::PolicyStatus cmp0069
= this->GetPolicyStatusCMP0069();
951 if (cmp0069
== cmPolicies::OLD
|| cmp0069
== cmPolicies::WARN
) {
952 if (this->Makefile
->IsOn("_CMAKE_" + lang
+ "_IPO_LEGACY_BEHAVIOR")) {
955 if (this->PolicyReportedCMP0069
) {
956 // problem is already reported, no need to issue a message
959 const bool in_try_compile
=
960 this->LocalGenerator
->GetCMakeInstance()->GetIsInTryCompile();
961 if (cmp0069
== cmPolicies::WARN
&& !in_try_compile
) {
962 std::ostringstream w
;
963 w
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0069
) << "\n";
964 w
<< "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
965 << "'" << this->GetName() << "'.";
966 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
967 MessageType::AUTHOR_WARNING
, w
.str(), this->GetBacktrace());
969 this->PolicyReportedCMP0069
= true;
974 // Note: check consistency with messages from CheckIPOSupported
975 const char* message
= nullptr;
976 if (!this->Makefile
->IsOn("_CMAKE_" + lang
+ "_IPO_SUPPORTED_BY_CMAKE")) {
977 message
= "CMake doesn't support IPO for current compiler";
978 } else if (!this->Makefile
->IsOn("_CMAKE_" + lang
+
979 "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
980 message
= "Compiler doesn't support IPO";
981 } else if (!this->GlobalGenerator
->IsIPOSupported()) {
982 message
= "CMake doesn't support IPO for current generator";
986 // No error/warning messages
990 if (this->PolicyReportedCMP0069
) {
991 // problem is already reported, no need to issue a message
995 this->PolicyReportedCMP0069
= true;
997 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
998 MessageType::FATAL_ERROR
, message
, this->GetBacktrace());
1002 const std::string
& cmGeneratorTarget::GetObjectName(cmSourceFile
const* file
)
1004 this->ComputeObjectMapping();
1005 return this->Objects
[file
];
1008 const char* cmGeneratorTarget::GetCustomObjectExtension() const
1010 struct compiler_mode
1012 std::string variable
;
1013 std::string extension
;
1015 static std::array
<compiler_mode
, 4> const modes
{
1016 { { "CUDA_PTX_COMPILATION", ".ptx" },
1017 { "CUDA_CUBIN_COMPILATION", ".cubin" },
1018 { "CUDA_FATBIN_COMPILATION", ".fatbin" },
1019 { "CUDA_OPTIX_COMPILATION", ".optixir" } }
1022 std::string
const& compiler
=
1023 this->Makefile
->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
1024 if (!compiler
.empty()) {
1025 for (const auto& m
: modes
) {
1026 const bool has_extension
= this->GetPropertyAsBool(m
.variable
);
1027 if (has_extension
) {
1028 return m
.extension
.c_str();
1035 void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile
const* sf
)
1037 this->ExplicitObjectName
.insert(sf
);
1040 bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile
const* file
) const
1042 const_cast<cmGeneratorTarget
*>(this)->ComputeObjectMapping();
1043 auto it
= this->ExplicitObjectName
.find(file
);
1044 return it
!= this->ExplicitObjectName
.end();
1047 BTs
<std::string
> const* cmGeneratorTarget::GetLanguageStandardProperty(
1048 std::string
const& lang
, std::string
const& config
) const
1050 std::string key
= cmStrCat(cmSystemTools::UpperCase(config
), '-', lang
);
1051 auto langStandardIter
= this->LanguageStandardMap
.find(key
);
1052 if (langStandardIter
!= this->LanguageStandardMap
.end()) {
1053 return &langStandardIter
->second
;
1056 return this->Target
->GetLanguageStandardProperty(
1057 cmStrCat(lang
, "_STANDARD"));
1060 cmValue
cmGeneratorTarget::GetLanguageStandard(std::string
const& lang
,
1061 std::string
const& config
) const
1063 BTs
<std::string
> const* languageStandard
=
1064 this->GetLanguageStandardProperty(lang
, config
);
1066 if (languageStandard
) {
1067 return cmValue(languageStandard
->Value
);
1073 cmValue
cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
1074 std::string
const& lang
, const char* suffix
) const
1076 cmValue propertyValue
= this->Target
->GetProperty(cmStrCat(lang
, suffix
));
1077 if (!propertyValue
) {
1078 // Check if we should use the value set by another language.
1079 if (lang
== "OBJC") {
1080 propertyValue
= this->GetPropertyWithPairedLanguageSupport("C", suffix
);
1081 } else if (lang
== "OBJCXX" || lang
== "CUDA" || lang
== "HIP") {
1083 this->GetPropertyWithPairedLanguageSupport("CXX", suffix
);
1086 return propertyValue
;
1089 cmValue
cmGeneratorTarget::GetLanguageExtensions(std::string
const& lang
) const
1091 return this->GetPropertyWithPairedLanguageSupport(lang
, "_EXTENSIONS");
1094 bool cmGeneratorTarget::GetLanguageStandardRequired(
1095 std::string
const& lang
) const
1098 this->GetPropertyWithPairedLanguageSupport(lang
, "_STANDARD_REQUIRED"));
1101 void cmGeneratorTarget::GetModuleDefinitionSources(
1102 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
1104 IMPLEMENT_VISIT(SourceKindModuleDefinition
);
1107 void cmGeneratorTarget::GetHeaderSources(
1108 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
1110 IMPLEMENT_VISIT(SourceKindHeader
);
1113 void cmGeneratorTarget::GetCxxModuleSources(
1114 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
1116 IMPLEMENT_VISIT(SourceKindCxxModuleSource
);
1119 void cmGeneratorTarget::GetExtraSources(std::vector
<cmSourceFile
const*>& data
,
1120 const std::string
& config
) const
1122 IMPLEMENT_VISIT(SourceKindExtra
);
1125 void cmGeneratorTarget::GetCustomCommands(
1126 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
1128 IMPLEMENT_VISIT(SourceKindCustomCommand
);
1131 void cmGeneratorTarget::GetExternalObjects(
1132 std::vector
<cmSourceFile
const*>& data
, const std::string
& config
) const
1134 IMPLEMENT_VISIT(SourceKindExternalObject
);
1137 void cmGeneratorTarget::GetManifests(std::vector
<cmSourceFile
const*>& data
,
1138 const std::string
& config
) const
1140 IMPLEMENT_VISIT(SourceKindManifest
);
1143 std::set
<cmLinkItem
> const& cmGeneratorTarget::GetUtilityItems() const
1145 if (!this->UtilityItemsDone
) {
1146 this->UtilityItemsDone
= true;
1147 std::set
<BT
<std::pair
<std::string
, bool>>> const& utilities
=
1148 this->GetUtilities();
1149 for (BT
<std::pair
<std::string
, bool>> const& i
: utilities
) {
1150 if (cmGeneratorTarget
* gt
=
1151 this->LocalGenerator
->FindGeneratorTargetToUse(i
.Value
.first
)) {
1152 this->UtilityItems
.insert(cmLinkItem(gt
, i
.Value
.second
, i
.Backtrace
));
1154 this->UtilityItems
.insert(
1155 cmLinkItem(i
.Value
.first
, i
.Value
.second
, i
.Backtrace
));
1159 return this->UtilityItems
;
1162 const std::string
& cmGeneratorTarget::GetLocation(
1163 const std::string
& config
) const
1165 static std::string location
;
1166 if (this->IsImported()) {
1167 location
= this->Target
->ImportedGetFullPath(
1168 config
, cmStateEnums::RuntimeBinaryArtifact
);
1170 location
= this->GetFullPath(config
, cmStateEnums::RuntimeBinaryArtifact
);
1175 cm::optional
<std::string
> cmGeneratorTarget::MaybeGetLocation(
1176 std::string
const& config
) const
1178 cm::optional
<std::string
> location
;
1179 if (cmGeneratorTarget::ImportInfo
const* imp
= this->GetImportInfo(config
)) {
1180 if (!imp
->Location
.empty()) {
1181 location
= imp
->Location
;
1184 location
= this->GetFullPath(config
, cmStateEnums::RuntimeBinaryArtifact
);
1189 std::vector
<cmCustomCommand
> const& cmGeneratorTarget::GetPreBuildCommands()
1192 return this->Target
->GetPreBuildCommands();
1195 std::vector
<cmCustomCommand
> const& cmGeneratorTarget::GetPreLinkCommands()
1198 return this->Target
->GetPreLinkCommands();
1201 std::vector
<cmCustomCommand
> const& cmGeneratorTarget::GetPostBuildCommands()
1204 return this->Target
->GetPostBuildCommands();
1207 void cmGeneratorTarget::AppendCustomCommandSideEffects(
1208 std::set
<cmGeneratorTarget
const*>& sideEffects
) const
1210 if (!this->GetPreBuildCommands().empty() ||
1211 !this->GetPreLinkCommands().empty() ||
1212 !this->GetPostBuildCommands().empty()) {
1213 sideEffects
.insert(this);
1215 for (auto const& source
: this->GetAllConfigSources()) {
1216 if (source
.Source
->GetCustomCommand() != nullptr) {
1217 sideEffects
.insert(this);
1224 void cmGeneratorTarget::AppendLanguageSideEffects(
1225 std::map
<std::string
, std::set
<cmGeneratorTarget
const*>>& sideEffects
) const
1227 static const std::set
<cm::string_view
> LANGS_WITH_NO_SIDE_EFFECTS
= {
1228 "C"_s
, "CXX"_s
, "OBJC"_s
, "OBJCXX"_s
, "ASM"_s
, "CUDA"_s
, "HIP"_s
1231 for (auto const& lang
: this->GetAllConfigCompileLanguages()) {
1232 if (!LANGS_WITH_NO_SIDE_EFFECTS
.count(lang
)) {
1233 sideEffects
[lang
].insert(this);
1238 bool cmGeneratorTarget::IsInBuildSystem() const
1240 if (this->IsImported()) {
1243 switch (this->Target
->GetType()) {
1244 case cmStateEnums::EXECUTABLE
:
1245 case cmStateEnums::STATIC_LIBRARY
:
1246 case cmStateEnums::SHARED_LIBRARY
:
1247 case cmStateEnums::MODULE_LIBRARY
:
1248 case cmStateEnums::OBJECT_LIBRARY
:
1249 case cmStateEnums::UTILITY
:
1250 case cmStateEnums::GLOBAL_TARGET
:
1252 case cmStateEnums::INTERFACE_LIBRARY
:
1253 // An INTERFACE library is in the build system if it has SOURCES
1254 // or C++ module filesets.
1255 if (!this->SourceEntries
.empty() ||
1256 !this->Target
->GetHeaderSetsEntries().empty() ||
1257 !this->Target
->GetCxxModuleSetsEntries().empty()) {
1261 case cmStateEnums::UNKNOWN_LIBRARY
:
1267 bool cmGeneratorTarget::IsNormal() const
1269 return this->Target
->IsNormal();
1272 bool cmGeneratorTarget::IsRuntimeBinary() const
1274 return this->Target
->IsRuntimeBinary();
1277 bool cmGeneratorTarget::IsSynthetic() const
1279 return this->Target
->IsSynthetic();
1282 bool cmGeneratorTarget::IsImported() const
1284 return this->Target
->IsImported();
1287 bool cmGeneratorTarget::IsImportedGloballyVisible() const
1289 return this->Target
->IsImportedGloballyVisible();
1292 bool cmGeneratorTarget::CanCompileSources() const
1294 return this->Target
->CanCompileSources();
1297 bool cmGeneratorTarget::HasKnownRuntimeArtifactLocation(
1298 std::string
const& config
) const
1300 if (!this->IsRuntimeBinary()) {
1303 if (!this->IsImported()) {
1306 ImportInfo
const* info
= this->GetImportInfo(config
);
1307 return info
&& !info
->Location
.empty();
1310 const std::string
& cmGeneratorTarget::GetLocationForBuild() const
1312 static std::string location
;
1313 if (this->IsImported()) {
1314 location
= this->Target
->ImportedGetFullPath(
1315 "", cmStateEnums::RuntimeBinaryArtifact
);
1319 // Now handle the deprecated build-time configuration location.
1320 std::string
const noConfig
;
1321 location
= this->GetDirectory(noConfig
);
1322 cmValue cfgid
= this->Makefile
->GetDefinition("CMAKE_CFG_INTDIR");
1323 if (cfgid
&& (*cfgid
!= ".")) {
1328 if (this->IsAppBundleOnApple()) {
1329 std::string macdir
= this->BuildBundleDirectory("", "", FullLevel
);
1330 if (!macdir
.empty()) {
1336 location
+= this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact
);
1340 bool cmGeneratorTarget::IsSystemIncludeDirectory(
1341 const std::string
& dir
, const std::string
& config
,
1342 const std::string
& language
) const
1344 std::string config_upper
;
1345 if (!config
.empty()) {
1346 config_upper
= cmSystemTools::UpperCase(config
);
1349 std::string key
= cmStrCat(config_upper
, '/', language
);
1350 auto iter
= this->SystemIncludesCache
.find(key
);
1352 if (iter
== this->SystemIncludesCache
.end()) {
1353 cmGeneratorExpressionDAGChecker
dagChecker(
1354 this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
1356 bool excludeImported
= this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
1359 for (std::string
const& it
: this->Target
->GetSystemIncludeDirectories()) {
1360 result
.append(cmGeneratorExpression::Evaluate(it
, this->LocalGenerator
,
1361 config
, this, &dagChecker
,
1362 nullptr, language
));
1365 std::vector
<cmGeneratorTarget
const*> const& deps
=
1366 this->GetLinkImplementationClosure(config
);
1367 for (cmGeneratorTarget
const* dep
: deps
) {
1368 handleSystemIncludesDep(this->LocalGenerator
, dep
, config
, this,
1369 &dagChecker
, result
, excludeImported
, language
);
1372 cmLinkImplementation
const* impl
=
1373 this->GetLinkImplementation(config
, LinkInterfaceFor::Usage
);
1374 if (impl
!= nullptr) {
1375 auto runtimeEntries
= impl
->LanguageRuntimeLibraries
.find(language
);
1376 if (runtimeEntries
!= impl
->LanguageRuntimeLibraries
.end()) {
1377 for (auto const& lib
: runtimeEntries
->second
) {
1379 handleSystemIncludesDep(this->LocalGenerator
, lib
.Target
, config
,
1380 this, &dagChecker
, result
, excludeImported
,
1387 std::for_each(result
.begin(), result
.end(),
1388 cmSystemTools::ConvertToUnixSlashes
);
1389 std::sort(result
.begin(), result
.end());
1390 result
.erase(std::unique(result
.begin(), result
.end()), result
.end());
1392 iter
= this->SystemIncludesCache
.emplace(key
, result
).first
;
1395 return std::binary_search(iter
->second
.begin(), iter
->second
.end(), dir
);
1398 bool cmGeneratorTarget::GetPropertyAsBool(const std::string
& prop
) const
1400 return this->Target
->GetPropertyAsBool(prop
);
1403 bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
1404 std::string
const& prop
, cmGeneratorExpressionContext
* context
,
1405 LinkInterfaceFor interfaceFor
) const
1407 std::string
const key
= prop
+ '@' + context
->Config
;
1408 auto i
= this->MaybeInterfacePropertyExists
.find(key
);
1409 if (i
== this->MaybeInterfacePropertyExists
.end()) {
1410 // Insert an entry now in case there is a cycle.
1411 i
= this->MaybeInterfacePropertyExists
.emplace(key
, false).first
;
1412 bool& maybeInterfaceProp
= i
->second
;
1414 // If this target itself has a non-empty property value, we are done.
1415 maybeInterfaceProp
= cmNonempty(this->GetProperty(prop
));
1417 // Otherwise, recurse to interface dependencies.
1418 if (!maybeInterfaceProp
) {
1419 cmGeneratorTarget
const* headTarget
=
1420 context
->HeadTarget
? context
->HeadTarget
: this;
1421 if (cmLinkInterfaceLibraries
const* iface
=
1422 this->GetLinkInterfaceLibraries(context
->Config
, headTarget
,
1424 if (iface
->HadHeadSensitiveCondition
) {
1425 // With a different head target we may get to a library with
1426 // this interface property.
1427 maybeInterfaceProp
= true;
1429 // The transitive interface libraries do not depend on the
1430 // head target, so we can follow them.
1431 for (cmLinkItem
const& lib
: iface
->Libraries
) {
1433 lib
.Target
->MaybeHaveInterfaceProperty(prop
, context
,
1435 maybeInterfaceProp
= true;
1446 std::string
cmGeneratorTarget::EvaluateInterfaceProperty(
1447 std::string
const& prop
, cmGeneratorExpressionContext
* context
,
1448 cmGeneratorExpressionDAGChecker
* dagCheckerParent
,
1449 LinkInterfaceFor interfaceFor
) const
1453 // If the property does not appear transitively at all, we are done.
1454 if (!this->MaybeHaveInterfaceProperty(prop
, context
, interfaceFor
)) {
1458 // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is
1459 // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
1460 // but sufficient for transitive interface properties.
1461 cmGeneratorExpressionDAGChecker
dagChecker(context
->Backtrace
, this, prop
,
1462 nullptr, dagCheckerParent
);
1463 switch (dagChecker
.Check()) {
1464 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE
:
1465 dagChecker
.ReportError(
1466 context
, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop
+ ">");
1468 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE
:
1469 // No error. We just skip cyclic references.
1470 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN
:
1471 // No error. We have already seen this transitive property.
1473 case cmGeneratorExpressionDAGChecker::DAG
:
1477 cmGeneratorTarget
const* headTarget
=
1478 context
->HeadTarget
? context
->HeadTarget
: this;
1480 if (cmValue p
= this->GetProperty(prop
)) {
1481 result
= cmGeneratorExpressionNode::EvaluateDependentExpression(
1482 *p
, context
->LG
, context
, headTarget
, &dagChecker
, this);
1485 if (cmLinkInterfaceLibraries
const* iface
= this->GetLinkInterfaceLibraries(
1486 context
->Config
, headTarget
, interfaceFor
)) {
1487 context
->HadContextSensitiveCondition
=
1488 context
->HadContextSensitiveCondition
||
1489 iface
->HadContextSensitiveCondition
;
1490 for (cmLinkItem
const& lib
: iface
->Libraries
) {
1491 // Broken code can have a target in its own link interface.
1492 // Don't follow such link interface entries so as not to create a
1493 // self-referencing loop.
1494 if (lib
.Target
&& lib
.Target
!= this) {
1495 // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
1496 // above property and hand-evaluate it as if it were compiled.
1497 // Create a context as cmCompiledGeneratorExpression::Evaluate does.
1498 cmGeneratorExpressionContext
libContext(
1499 context
->LG
, context
->Config
, context
->Quiet
, headTarget
, this,
1500 context
->EvaluateForBuildsystem
, context
->Backtrace
,
1502 std::string libResult
= cmGeneratorExpression::StripEmptyListElements(
1503 lib
.Target
->EvaluateInterfaceProperty(prop
, &libContext
, &dagChecker
,
1505 if (!libResult
.empty()) {
1506 if (result
.empty()) {
1507 result
= std::move(libResult
);
1509 result
.reserve(result
.size() + 1 + libResult
.size());
1511 result
+= libResult
;
1514 context
->HadContextSensitiveCondition
=
1515 context
->HadContextSensitiveCondition
||
1516 libContext
.HadContextSensitiveCondition
;
1517 context
->HadHeadSensitiveCondition
=
1518 context
->HadHeadSensitiveCondition
||
1519 libContext
.HadHeadSensitiveCondition
;
1529 enum class IncludeDirectoryFallBack
1535 std::string
AddLangSpecificInterfaceIncludeDirectories(
1536 const cmGeneratorTarget
* root
, const cmGeneratorTarget
* target
,
1537 const std::string
& lang
, const std::string
& config
,
1538 const std::string
& propertyName
, IncludeDirectoryFallBack mode
,
1539 cmGeneratorExpressionDAGChecker
* context
)
1541 cmGeneratorExpressionDAGChecker dag
{ target
->GetBacktrace(), target
,
1542 propertyName
, nullptr, context
};
1543 switch (dag
.Check()) {
1544 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE
:
1546 nullptr, "$<TARGET_PROPERTY:" + target
->GetName() + ",propertyName");
1548 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE
:
1549 // No error. We just skip cyclic references.
1550 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN
:
1551 // No error. We have already seen this transitive property.
1553 case cmGeneratorExpressionDAGChecker::DAG
:
1557 std::string directories
;
1558 if (const auto* link_interface
= target
->GetLinkInterfaceLibraries(
1559 config
, root
, LinkInterfaceFor::Usage
)) {
1560 for (const cmLinkItem
& library
: link_interface
->Libraries
) {
1561 if (const cmGeneratorTarget
* dependency
= library
.Target
) {
1562 if (cm::contains(dependency
->GetAllConfigCompileLanguages(), lang
)) {
1563 auto* lg
= dependency
->GetLocalGenerator();
1564 std::string value
= dependency
->GetSafeProperty(propertyName
);
1565 if (value
.empty()) {
1566 if (mode
== IncludeDirectoryFallBack::BINARY
) {
1567 value
= lg
->GetCurrentBinaryDirectory();
1568 } else if (mode
== IncludeDirectoryFallBack::OBJECT
) {
1569 value
= cmStrCat(lg
->GetCurrentBinaryDirectory(), '/',
1570 lg
->GetTargetDirectory(dependency
));
1574 if (!directories
.empty()) {
1577 directories
+= value
;
1585 void AddLangSpecificImplicitIncludeDirectories(
1586 const cmGeneratorTarget
* target
, const std::string
& lang
,
1587 const std::string
& config
, const std::string
& propertyName
,
1588 IncludeDirectoryFallBack mode
, EvaluatedTargetPropertyEntries
& entries
)
1590 if (const auto* libraries
= target
->GetLinkImplementationLibraries(
1591 config
, LinkInterfaceFor::Usage
)) {
1592 cmGeneratorExpressionDAGChecker dag
{ target
->GetBacktrace(), target
,
1593 propertyName
, nullptr, nullptr };
1595 for (const cmLinkImplItem
& library
: libraries
->Libraries
) {
1596 if (const cmGeneratorTarget
* dependency
= library
.Target
) {
1597 if (!dependency
->IsInBuildSystem()) {
1600 if (cm::contains(dependency
->GetAllConfigCompileLanguages(), lang
)) {
1601 auto* lg
= dependency
->GetLocalGenerator();
1602 EvaluatedTargetPropertyEntry entry
{ library
, library
.Backtrace
};
1604 if (cmValue val
= dependency
->GetProperty(propertyName
)) {
1605 entry
.Values
.emplace_back(*val
);
1607 if (mode
== IncludeDirectoryFallBack::BINARY
) {
1608 entry
.Values
.emplace_back(lg
->GetCurrentBinaryDirectory());
1609 } else if (mode
== IncludeDirectoryFallBack::OBJECT
) {
1610 entry
.Values
.emplace_back(
1611 dependency
->GetObjectDirectory(config
));
1616 AddLangSpecificInterfaceIncludeDirectories(
1617 target
, dependency
, lang
, config
, propertyName
, mode
, &dag
),
1619 entries
.Entries
.emplace_back(std::move(entry
));
1626 void AddObjectEntries(cmGeneratorTarget
const* headTarget
,
1627 std::string
const& config
,
1628 cmGeneratorExpressionDAGChecker
* dagChecker
,
1629 EvaluatedTargetPropertyEntries
& entries
)
1631 if (cmLinkImplementationLibraries
const* impl
=
1632 headTarget
->GetLinkImplementationLibraries(config
,
1633 LinkInterfaceFor::Usage
)) {
1634 entries
.HadContextSensitiveCondition
= impl
->HadContextSensitiveCondition
;
1635 for (cmLinkImplItem
const& lib
: impl
->Libraries
) {
1637 lib
.Target
->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
1638 std::string uniqueName
=
1639 headTarget
->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
1641 std::string genex
= "$<TARGET_OBJECTS:" + std::move(uniqueName
) + ">";
1642 cmGeneratorExpression
ge(*headTarget
->Makefile
->GetCMakeInstance(),
1644 std::unique_ptr
<cmCompiledGeneratorExpression
> cge
= ge
.Parse(genex
);
1645 cge
->SetEvaluateForBuildsystem(true);
1647 EvaluatedTargetPropertyEntry
ee(lib
, lib
.Backtrace
);
1648 cmExpandList(cge
->Evaluate(headTarget
->GetLocalGenerator(), config
,
1649 headTarget
, dagChecker
),
1651 if (cge
->GetHadContextSensitiveCondition()) {
1652 ee
.ContextDependent
= true;
1654 entries
.Entries
.emplace_back(std::move(ee
));
1660 void addFileSetEntry(cmGeneratorTarget
const* headTarget
,
1661 std::string
const& config
,
1662 cmGeneratorExpressionDAGChecker
* dagChecker
,
1663 cmFileSet
const* fileSet
,
1664 EvaluatedTargetPropertyEntries
& entries
)
1666 auto dirCges
= fileSet
->CompileDirectoryEntries();
1667 auto dirs
= fileSet
->EvaluateDirectoryEntries(
1668 dirCges
, headTarget
->GetLocalGenerator(), config
, headTarget
, dagChecker
);
1669 bool contextSensitiveDirs
= false;
1670 for (auto const& dirCge
: dirCges
) {
1671 if (dirCge
->GetHadContextSensitiveCondition()) {
1672 contextSensitiveDirs
= true;
1676 cmake
* cm
= headTarget
->GetLocalGenerator()->GetCMakeInstance();
1677 for (auto& entryCge
: fileSet
->CompileFileEntries()) {
1678 TargetPropertyEntryFileSet
tpe(dirs
, contextSensitiveDirs
,
1679 std::move(entryCge
), fileSet
);
1680 entries
.Entries
.emplace_back(
1681 EvaluateTargetPropertyEntry(headTarget
, config
, "", dagChecker
, tpe
));
1682 EvaluatedTargetPropertyEntry
const& entry
= entries
.Entries
.back();
1683 for (auto const& file
: entry
.Values
) {
1684 auto* sf
= headTarget
->Makefile
->GetOrCreateSource(file
);
1685 if (fileSet
->GetType() == "HEADERS"_s
) {
1686 sf
->SetProperty("HEADER_FILE_ONLY", "TRUE");
1689 #ifndef CMAKE_BOOTSTRAP
1692 auto path
= sf
->ResolveFullPath(&e
, &w
);
1694 cm
->IssueMessage(MessageType::AUTHOR_WARNING
, w
, entry
.Backtrace
);
1698 cm
->IssueMessage(MessageType::FATAL_ERROR
, e
, entry
.Backtrace
);
1703 for (auto const& sg
: headTarget
->Makefile
->GetSourceGroups()) {
1704 if (sg
.MatchChildrenFiles(path
)) {
1710 if (fileSet
->GetType() == "HEADERS"_s
) {
1711 headTarget
->Makefile
->GetOrCreateSourceGroup("Header Files")
1712 ->AddGroupFile(path
);
1720 void AddFileSetEntries(cmGeneratorTarget
const* headTarget
,
1721 std::string
const& config
,
1722 cmGeneratorExpressionDAGChecker
* dagChecker
,
1723 EvaluatedTargetPropertyEntries
& entries
)
1725 for (auto const& entry
: headTarget
->Target
->GetHeaderSetsEntries()) {
1726 for (auto const& name
: cmList
{ entry
.Value
}) {
1727 auto const* headerSet
= headTarget
->Target
->GetFileSet(name
);
1728 addFileSetEntry(headTarget
, config
, dagChecker
, headerSet
, entries
);
1731 for (auto const& entry
: headTarget
->Target
->GetCxxModuleSetsEntries()) {
1732 for (auto const& name
: cmList
{ entry
.Value
}) {
1733 auto const* cxxModuleSet
= headTarget
->Target
->GetFileSet(name
);
1734 addFileSetEntry(headTarget
, config
, dagChecker
, cxxModuleSet
, entries
);
1739 bool processSources(cmGeneratorTarget
const* tgt
,
1740 EvaluatedTargetPropertyEntries
& entries
,
1741 std::vector
<BT
<std::string
>>& srcs
,
1742 std::unordered_set
<std::string
>& uniqueSrcs
,
1745 cmMakefile
* mf
= tgt
->Target
->GetMakefile();
1747 bool contextDependent
= entries
.HadContextSensitiveCondition
;
1749 for (EvaluatedTargetPropertyEntry
& entry
: entries
.Entries
) {
1750 if (entry
.ContextDependent
) {
1751 contextDependent
= true;
1754 cmLinkImplItem
const& item
= entry
.LinkImplItem
;
1755 std::string
const& targetName
= item
.AsStr();
1757 for (std::string
& src
: entry
.Values
) {
1758 cmSourceFile
* sf
= mf
->GetOrCreateSource(src
);
1761 std::string fullPath
= sf
->ResolveFullPath(&e
, &w
);
1762 cmake
* cm
= tgt
->GetLocalGenerator()->GetCMakeInstance();
1764 cm
->IssueMessage(MessageType::AUTHOR_WARNING
, w
, entry
.Backtrace
);
1766 if (fullPath
.empty()) {
1768 cm
->IssueMessage(MessageType::FATAL_ERROR
, e
, entry
.Backtrace
);
1770 return contextDependent
;
1773 if (!targetName
.empty() && !cmSystemTools::FileIsFullPath(src
)) {
1774 std::ostringstream err
;
1775 if (!targetName
.empty()) {
1776 err
<< "Target \"" << targetName
1777 << "\" contains relative path in its INTERFACE_SOURCES:\n \""
1780 err
<< "Found relative path while evaluating sources of \""
1781 << tgt
->GetName() << "\":\n \"" << src
<< "\"\n";
1783 tgt
->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR
,
1785 return contextDependent
;
1789 std::string usedSources
;
1790 for (std::string
const& src
: entry
.Values
) {
1791 if (uniqueSrcs
.insert(src
).second
) {
1792 srcs
.emplace_back(src
, entry
.Backtrace
);
1794 usedSources
+= " * " + src
+ "\n";
1798 if (!usedSources
.empty()) {
1799 tgt
->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
1801 std::string("Used sources for target ") + tgt
->GetName() + ":\n" +
1806 return contextDependent
;
1810 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetSourceFilePaths(
1811 std::string
const& config
) const
1813 std::vector
<BT
<std::string
>> files
;
1815 if (!this->LocalGenerator
->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1816 // At configure-time, this method can be called as part of getting the
1817 // LOCATION property or to export() a file to be include()d. However
1818 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
1819 // for TARGET_OBJECTS instead for backwards compatibility with OLD
1820 // behavior of CMP0024 and CMP0026 only.
1822 cmBTStringRange sourceEntries
= this->Target
->GetSourceEntries();
1823 for (auto const& entry
: sourceEntries
) {
1824 cmList items
{ entry
.Value
};
1825 for (auto const& item
: items
) {
1826 if (cmHasLiteralPrefix(item
, "$<TARGET_OBJECTS:") &&
1827 item
.back() == '>') {
1830 files
.emplace_back(item
);
1836 cmList debugProperties
{ this->Makefile
->GetDefinition(
1837 "CMAKE_DEBUG_TARGET_PROPERTIES") };
1839 !this->DebugSourcesDone
&& cm::contains(debugProperties
, "SOURCES");
1841 if (this->LocalGenerator
->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
1842 this->DebugSourcesDone
= true;
1845 cmGeneratorExpressionDAGChecker
dagChecker(this, "SOURCES", nullptr,
1848 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
1849 this, config
, std::string(), &dagChecker
, this->SourceEntries
);
1851 std::unordered_set
<std::string
> uniqueSrcs
;
1852 bool contextDependentDirectSources
=
1853 processSources(this, entries
, files
, uniqueSrcs
, debugSources
);
1855 // Collect INTERFACE_SOURCES of all direct link-dependencies.
1856 EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries
;
1857 AddInterfaceEntries(this, config
, "INTERFACE_SOURCES", std::string(),
1858 &dagChecker
, linkInterfaceSourcesEntries
,
1859 IncludeRuntimeInterface::No
, LinkInterfaceFor::Usage
);
1860 bool contextDependentInterfaceSources
= processSources(
1861 this, linkInterfaceSourcesEntries
, files
, uniqueSrcs
, debugSources
);
1863 // Collect TARGET_OBJECTS of direct object link-dependencies.
1864 bool contextDependentObjects
= false;
1865 if (this->GetType() != cmStateEnums::OBJECT_LIBRARY
) {
1866 EvaluatedTargetPropertyEntries linkObjectsEntries
;
1867 AddObjectEntries(this, config
, &dagChecker
, linkObjectsEntries
);
1868 contextDependentObjects
= processSources(this, linkObjectsEntries
, files
,
1869 uniqueSrcs
, debugSources
);
1870 // Note that for imported targets or multi-config generators supporting
1871 // cross-config builds the paths to the object files must be per-config,
1872 // so contextDependentObjects will be true here even if object libraries
1873 // are specified without per-config generator expressions.
1876 // Collect this target's file sets.
1877 EvaluatedTargetPropertyEntries fileSetEntries
;
1878 AddFileSetEntries(this, config
, &dagChecker
, fileSetEntries
);
1879 bool contextDependentFileSets
=
1880 processSources(this, fileSetEntries
, files
, uniqueSrcs
, debugSources
);
1882 // Determine if sources are context-dependent or not.
1883 if (!contextDependentDirectSources
&& !contextDependentInterfaceSources
&&
1884 !contextDependentObjects
&& !contextDependentFileSets
) {
1885 this->SourcesAreContextDependent
= Tribool::False
;
1887 this->SourcesAreContextDependent
= Tribool::True
;
1893 void cmGeneratorTarget::GetSourceFiles(std::vector
<cmSourceFile
*>& files
,
1894 const std::string
& config
) const
1896 std::vector
<BT
<cmSourceFile
*>> tmp
= this->GetSourceFiles(config
);
1897 files
.reserve(tmp
.size());
1898 for (BT
<cmSourceFile
*>& v
: tmp
) {
1899 files
.push_back(v
.Value
);
1903 std::vector
<BT
<cmSourceFile
*>> cmGeneratorTarget::GetSourceFiles(
1904 std::string
const& config
) const
1906 std::vector
<BT
<cmSourceFile
*>> files
;
1907 if (!this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
1908 // Since we are still configuring not all sources may exist yet,
1909 // so we need to avoid full source classification because that
1910 // requires the absolute paths to all sources to be determined.
1911 // Since this is only for compatibility with old policies that
1912 // projects should not depend on anymore, just compute the files
1913 // without memoizing them.
1914 std::vector
<BT
<std::string
>> srcs
= this->GetSourceFilePaths(config
);
1915 std::set
<cmSourceFile
*> emitted
;
1916 for (BT
<std::string
> const& s
: srcs
) {
1917 cmSourceFile
* sf
= this->Makefile
->GetOrCreateSource(s
.Value
);
1918 if (emitted
.insert(sf
).second
) {
1919 files
.emplace_back(sf
, s
.Backtrace
);
1925 KindedSources
const& kinded
= this->GetKindedSources(config
);
1926 files
.reserve(kinded
.Sources
.size());
1927 for (SourceAndKind
const& si
: kinded
.Sources
) {
1928 files
.push_back(si
.Source
);
1933 void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1934 std::vector
<cmSourceFile
*>& files
, const std::string
& config
) const
1936 std::vector
<BT
<cmSourceFile
*>> tmp
=
1937 this->GetSourceFilesWithoutObjectLibraries(config
);
1938 files
.reserve(tmp
.size());
1939 for (BT
<cmSourceFile
*>& v
: tmp
) {
1940 files
.push_back(v
.Value
);
1944 std::vector
<BT
<cmSourceFile
*>>
1945 cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
1946 std::string
const& config
) const
1948 std::vector
<BT
<cmSourceFile
*>> files
;
1949 KindedSources
const& kinded
= this->GetKindedSources(config
);
1950 files
.reserve(kinded
.Sources
.size());
1951 for (SourceAndKind
const& si
: kinded
.Sources
) {
1952 if (si
.Source
.Value
->GetObjectLibrary().empty()) {
1953 files
.push_back(si
.Source
);
1959 cmGeneratorTarget::KindedSources
const& cmGeneratorTarget::GetKindedSources(
1960 std::string
const& config
) const
1962 // If we already processed one configuration and found no dependency
1963 // on configuration then always use the one result.
1964 if (this->SourcesAreContextDependent
== Tribool::False
) {
1965 return this->KindedSourcesMap
.begin()->second
;
1968 // Lookup any existing link implementation for this configuration.
1969 std::string
const key
= cmSystemTools::UpperCase(config
);
1970 auto it
= this->KindedSourcesMap
.find(key
);
1971 if (it
!= this->KindedSourcesMap
.end()) {
1972 if (!it
->second
.Initialized
) {
1973 std::ostringstream e
;
1974 e
<< "The SOURCES of \"" << this->GetName()
1975 << "\" use a generator expression that depends on the "
1976 "SOURCES themselves.";
1977 this->GlobalGenerator
->GetCMakeInstance()->IssueMessage(
1978 MessageType::FATAL_ERROR
, e
.str(), this->GetBacktrace());
1979 static KindedSources empty
;
1985 // Add an entry to the map for this configuration.
1986 KindedSources
& files
= this->KindedSourcesMap
[key
];
1987 this->ComputeKindedSources(files
, config
);
1988 files
.Initialized
= true;
1992 void cmGeneratorTarget::ComputeKindedSources(KindedSources
& files
,
1993 std::string
const& config
) const
1995 // Get the source file paths by string.
1996 std::vector
<BT
<std::string
>> srcs
= this->GetSourceFilePaths(config
);
1998 cmsys::RegularExpression
header_regex(CM_HEADER_REGEX
);
1999 std::vector
<cmSourceFile
*> badObjLib
;
2001 std::set
<cmSourceFile
*> emitted
;
2002 for (BT
<std::string
> const& s
: srcs
) {
2003 // Create each source at most once.
2004 cmSourceFile
* sf
= this->Makefile
->GetOrCreateSource(s
.Value
);
2005 if (!emitted
.insert(sf
).second
) {
2009 // Compute the kind (classification) of this source file.
2011 std::string ext
= cmSystemTools::LowerCase(sf
->GetExtension());
2012 cmFileSet
const* fs
= this->GetFileSetForSource(config
, sf
);
2013 if (sf
->GetCustomCommand()) {
2014 kind
= SourceKindCustomCommand
;
2015 } else if (!this->Target
->IsNormal() && !this->Target
->IsImported() &&
2016 fs
&& (fs
->GetType() == "CXX_MODULES"_s
)) {
2017 kind
= SourceKindCxxModuleSource
;
2018 } else if (this->Target
->GetType() == cmStateEnums::UTILITY
||
2019 this->Target
->GetType() == cmStateEnums::INTERFACE_LIBRARY
2020 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2021 // NOLINTNEXTLINE(bugprone-branch-clone)
2023 kind
= SourceKindExtra
;
2024 } else if (this->IsSourceFilePartOfUnityBatch(sf
->ResolveFullPath())) {
2025 kind
= SourceKindUnityBatched
;
2026 // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
2027 // NOLINTNEXTLINE(bugprone-branch-clone)
2028 } else if (sf
->GetPropertyAsBool("HEADER_FILE_ONLY")) {
2029 kind
= SourceKindHeader
;
2030 } else if (sf
->GetPropertyAsBool("EXTERNAL_OBJECT")) {
2031 kind
= SourceKindExternalObject
;
2032 } else if (!sf
->GetOrDetermineLanguage().empty()) {
2033 kind
= SourceKindObjectSource
;
2034 } else if (ext
== "def") {
2035 kind
= SourceKindModuleDefinition
;
2036 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
2037 badObjLib
.push_back(sf
);
2039 } else if (ext
== "idl") {
2040 kind
= SourceKindIDL
;
2041 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
2042 badObjLib
.push_back(sf
);
2044 } else if (ext
== "resx") {
2045 kind
= SourceKindResx
;
2046 } else if (ext
== "appxmanifest") {
2047 kind
= SourceKindAppManifest
;
2048 } else if (ext
== "manifest") {
2049 if (sf
->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) {
2050 kind
= SourceKindExtra
;
2052 kind
= SourceKindManifest
;
2054 } else if (ext
== "pfx") {
2055 kind
= SourceKindCertificate
;
2056 } else if (ext
== "xaml") {
2057 kind
= SourceKindXaml
;
2058 } else if (header_regex
.find(sf
->ResolveFullPath())) {
2059 kind
= SourceKindHeader
;
2061 kind
= SourceKindExtra
;
2064 // Save this classified source file in the result vector.
2065 files
.Sources
.push_back({ BT
<cmSourceFile
*>(sf
, s
.Backtrace
), kind
});
2068 if (!badObjLib
.empty()) {
2069 std::ostringstream e
;
2070 e
<< "OBJECT library \"" << this->GetName() << "\" contains:\n";
2071 for (cmSourceFile
* i
: badObjLib
) {
2072 e
<< " " << i
->GetLocation().GetName() << "\n";
2074 e
<< "but may contain only sources that compile, header files, and "
2075 "other files that would not affect linking of a normal library.";
2076 this->GlobalGenerator
->GetCMakeInstance()->IssueMessage(
2077 MessageType::FATAL_ERROR
, e
.str(), this->GetBacktrace());
2081 std::vector
<cmGeneratorTarget::AllConfigSource
> const&
2082 cmGeneratorTarget::GetAllConfigSources() const
2084 if (this->AllConfigSources
.empty()) {
2085 this->ComputeAllConfigSources();
2087 return this->AllConfigSources
;
2090 void cmGeneratorTarget::ComputeAllConfigSources() const
2092 std::vector
<std::string
> configs
=
2093 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
2095 std::map
<cmSourceFile
const*, size_t> index
;
2097 for (size_t ci
= 0; ci
< configs
.size(); ++ci
) {
2098 KindedSources
const& sources
= this->GetKindedSources(configs
[ci
]);
2099 for (SourceAndKind
const& src
: sources
.Sources
) {
2100 auto mi
= index
.find(src
.Source
.Value
);
2101 if (mi
== index
.end()) {
2102 AllConfigSource acs
;
2103 acs
.Source
= src
.Source
.Value
;
2104 acs
.Kind
= src
.Kind
;
2105 this->AllConfigSources
.push_back(std::move(acs
));
2106 std::map
<cmSourceFile
const*, size_t>::value_type
entry(
2107 src
.Source
.Value
, this->AllConfigSources
.size() - 1);
2108 mi
= index
.insert(entry
).first
;
2110 this->AllConfigSources
[mi
->second
].Configs
.push_back(ci
);
2115 std::vector
<cmGeneratorTarget::AllConfigSource
>
2116 cmGeneratorTarget::GetAllConfigSources(SourceKind kind
) const
2118 std::vector
<AllConfigSource
> result
;
2119 for (AllConfigSource
const& source
: this->GetAllConfigSources()) {
2120 if (source
.Kind
== kind
) {
2121 result
.push_back(source
);
2127 std::set
<std::string
> cmGeneratorTarget::GetAllConfigCompileLanguages() const
2129 std::set
<std::string
> languages
;
2130 std::vector
<AllConfigSource
> const& sources
= this->GetAllConfigSources();
2131 for (AllConfigSource
const& si
: sources
) {
2132 std::string
const& lang
= si
.Source
->GetOrDetermineLanguage();
2133 if (!lang
.empty()) {
2134 languages
.emplace(lang
);
2140 std::string
cmGeneratorTarget::GetCompilePDBName(
2141 const std::string
& config
) const
2143 // Check for a per-configuration output directory target property.
2144 std::string configUpper
= cmSystemTools::UpperCase(config
);
2145 std::string configProp
= cmStrCat("COMPILE_PDB_NAME_", configUpper
);
2146 cmValue config_name
= this->GetProperty(configProp
);
2147 if (cmNonempty(config_name
)) {
2148 NameComponents
const& components
= GetFullNameInternalComponents(
2149 config
, cmStateEnums::RuntimeBinaryArtifact
);
2150 return components
.prefix
+ *config_name
+ ".pdb";
2153 cmValue name
= this->GetProperty("COMPILE_PDB_NAME");
2154 if (cmNonempty(name
)) {
2155 NameComponents
const& components
= GetFullNameInternalComponents(
2156 config
, cmStateEnums::RuntimeBinaryArtifact
);
2157 return components
.prefix
+ *name
+ ".pdb";
2163 std::string
cmGeneratorTarget::GetCompilePDBPath(
2164 const std::string
& config
) const
2166 std::string dir
= this->GetCompilePDBDirectory(config
);
2167 std::string name
= this->GetCompilePDBName(config
);
2168 if (dir
.empty() && !name
.empty() && this->HaveWellDefinedOutputFiles()) {
2169 dir
= this->GetPDBDirectory(config
);
2177 bool cmGeneratorTarget::HasSOName(const std::string
& config
) const
2179 // soname is supported only for shared libraries and modules,
2180 // and then only when the platform supports an soname flag.
2181 return ((this->GetType() == cmStateEnums::SHARED_LIBRARY
) &&
2182 !this->GetPropertyAsBool("NO_SONAME") &&
2183 this->Makefile
->GetSONameFlag(this->GetLinkerLanguage(config
)));
2186 bool cmGeneratorTarget::NeedRelinkBeforeInstall(
2187 const std::string
& config
) const
2189 // Only executables and shared libraries can have an rpath and may
2191 if (this->GetType() != cmStateEnums::EXECUTABLE
&&
2192 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
2193 this->GetType() != cmStateEnums::MODULE_LIBRARY
) {
2197 // If there is no install location this target will not be installed
2198 // and therefore does not need relinking.
2199 if (!this->Target
->GetHaveInstallRule()) {
2203 // If skipping all rpaths completely then no relinking is needed.
2204 if (this->Makefile
->IsOn("CMAKE_SKIP_RPATH")) {
2208 // If building with the install-tree rpath no relinking is needed.
2209 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2213 // If chrpath is going to be used no relinking is needed.
2214 if (this->IsChrpathUsed(config
)) {
2218 // Check for rpath support on this platform.
2219 std::string ll
= this->GetLinkerLanguage(config
);
2221 std::string flagVar
=
2222 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll
, "_FLAG");
2223 if (!this->Makefile
->IsSet(flagVar
)) {
2224 // There is no rpath support on this platform so nothing needs
2229 // No linker language is known. This error will be reported by
2234 // If either a build or install tree rpath is set then the rpath
2235 // will likely change between the build tree and install tree and
2236 // this target must be relinked.
2238 this->HaveBuildTreeRPATH(config
) || this->HaveInstallTreeRPATH(config
);
2239 bool is_ninja
= this->LocalGenerator
->GetGlobalGenerator()->IsNinja();
2241 if (have_rpath
&& is_ninja
) {
2242 std::ostringstream w
;
2243 /* clang-format off */
2245 "The install of the " << this->GetName() << " target requires changing "
2246 "an RPATH from the build tree, but this is not supported with the Ninja "
2247 "generator unless on an ELF-based or XCOFF-based platform. "
2248 "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
2251 /* clang-format on */
2253 cmake
* cm
= this->LocalGenerator
->GetCMakeInstance();
2254 cm
->IssueMessage(MessageType::FATAL_ERROR
, w
.str(), this->GetBacktrace());
2260 bool cmGeneratorTarget::IsChrpathUsed(const std::string
& config
) const
2262 // Only certain target types have an rpath.
2263 if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY
||
2264 this->GetType() == cmStateEnums::MODULE_LIBRARY
||
2265 this->GetType() == cmStateEnums::EXECUTABLE
)) {
2269 // If the target will not be installed we do not need to change its
2271 if (!this->Target
->GetHaveInstallRule()) {
2275 // Skip chrpath if skipping rpath altogether.
2276 if (this->Makefile
->IsOn("CMAKE_SKIP_RPATH")) {
2280 // Skip chrpath if it does not need to be changed at install time.
2281 if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
2285 // Allow the user to disable builtin chrpath explicitly.
2286 if (this->Makefile
->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
2290 if (this->Makefile
->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2294 // Enable if the rpath flag uses a separator and the target uses
2295 // binaries we know how to edit.
2296 std::string ll
= this->GetLinkerLanguage(config
);
2298 std::string sepVar
=
2299 cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll
, "_FLAG_SEP");
2300 cmValue sep
= this->Makefile
->GetDefinition(sepVar
);
2301 if (cmNonempty(sep
)) {
2302 // TODO: Add binary format check to ABI detection and get rid of
2303 // CMAKE_EXECUTABLE_FORMAT.
2305 this->Makefile
->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
2306 if (*fmt
== "ELF") {
2309 #if defined(CMake_USE_XCOFF_PARSER)
2310 if (*fmt
== "XCOFF") {
2320 bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
2321 const std::string
& config
) const
2323 if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY
) {
2324 if (cmGeneratorTarget::ImportInfo
const* info
=
2325 this->GetImportInfo(config
)) {
2326 return info
->NoSOName
;
2332 bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
2333 const std::string
& config
) const
2335 TargetPtrToBoolMap
& cache
= this->MacOSXRpathInstallNameDirCache
[config
];
2336 const auto lookup
= cache
.find(this->Target
);
2338 if (lookup
!= cache
.cend()) {
2339 return lookup
->second
;
2342 const bool result
= this->DetermineHasMacOSXRpathInstallNameDir(config
);
2343 cache
[this->Target
] = result
;
2347 bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir(
2348 const std::string
& config
) const
2350 bool install_name_is_rpath
= false;
2351 bool macosx_rpath
= false;
2353 if (!this->IsImported()) {
2354 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
) {
2357 cmValue install_name
= this->GetProperty("INSTALL_NAME_DIR");
2358 bool use_install_name
= this->MacOSXUseInstallNameDir();
2359 if (install_name
&& use_install_name
&& *install_name
== "@rpath") {
2360 install_name_is_rpath
= true;
2361 } else if (install_name
&& use_install_name
) {
2364 if (!install_name_is_rpath
) {
2365 macosx_rpath
= this->MacOSXRpathInstallNameDirDefault();
2368 // Lookup the imported soname.
2369 if (cmGeneratorTarget::ImportInfo
const* info
=
2370 this->GetImportInfo(config
)) {
2371 if (!info
->NoSOName
&& !info
->SOName
.empty()) {
2372 if (cmHasLiteralPrefix(info
->SOName
, "@rpath/")) {
2373 install_name_is_rpath
= true;
2376 std::string install_name
;
2377 cmSystemTools::GuessLibraryInstallName(info
->Location
, install_name
);
2378 if (install_name
.find("@rpath") != std::string::npos
) {
2379 install_name_is_rpath
= true;
2385 if (!install_name_is_rpath
&& !macosx_rpath
) {
2389 if (!this->Makefile
->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2390 std::ostringstream w
;
2391 w
<< "Attempting to use ";
2393 w
<< "MACOSX_RPATH";
2397 w
<< " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
2398 w
<< " This could be because you are using a Mac OS X version";
2399 w
<< " less than 10.5 or because CMake's platform configuration is";
2401 cmake
* cm
= this->LocalGenerator
->GetCMakeInstance();
2402 cm
->IssueMessage(MessageType::FATAL_ERROR
, w
.str(), this->GetBacktrace());
2408 bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
2410 // we can't do rpaths when unsupported
2411 if (!this->Makefile
->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
2415 cmValue macosx_rpath_str
= this->GetProperty("MACOSX_RPATH");
2416 if (macosx_rpath_str
) {
2417 return this->GetPropertyAsBool("MACOSX_RPATH");
2420 cmPolicies::PolicyStatus cmp0042
= this->GetPolicyStatusCMP0042();
2422 if (cmp0042
== cmPolicies::WARN
) {
2423 this->LocalGenerator
->GetGlobalGenerator()->AddCMP0042WarnTarget(
2427 return cmp0042
== cmPolicies::NEW
;
2430 bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
2432 cmValue build_with_install_name
=
2433 this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
2434 if (build_with_install_name
) {
2435 return cmIsOn(*build_with_install_name
);
2438 cmPolicies::PolicyStatus cmp0068
= this->GetPolicyStatusCMP0068();
2439 if (cmp0068
== cmPolicies::NEW
) {
2443 bool use_install_name
= this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
2445 if (use_install_name
&& cmp0068
== cmPolicies::WARN
) {
2446 this->LocalGenerator
->GetGlobalGenerator()->AddCMP0068WarnTarget(
2450 return use_install_name
;
2453 bool cmGeneratorTarget::CanGenerateInstallNameDir(
2454 InstallNameType name_type
) const
2456 cmPolicies::PolicyStatus cmp0068
= this->GetPolicyStatusCMP0068();
2458 if (cmp0068
== cmPolicies::NEW
) {
2462 bool skip
= this->Makefile
->IsOn("CMAKE_SKIP_RPATH");
2463 if (name_type
== INSTALL_NAME_FOR_INSTALL
) {
2464 skip
|= this->Makefile
->IsOn("CMAKE_SKIP_INSTALL_RPATH");
2466 skip
|= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
2469 if (skip
&& cmp0068
== cmPolicies::WARN
) {
2470 this->LocalGenerator
->GetGlobalGenerator()->AddCMP0068WarnTarget(
2477 std::string
cmGeneratorTarget::GetSOName(
2478 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
2480 if (this->IsImported()) {
2481 // Lookup the imported soname.
2482 if (cmGeneratorTarget::ImportInfo
const* info
=
2483 this->GetImportInfo(config
)) {
2484 if (info
->NoSOName
) {
2485 // The imported library has no builtin soname so the name
2486 // searched at runtime will be just the filename.
2487 return cmSystemTools::GetFilenameName(info
->Location
);
2489 // Use the soname given if any.
2490 if (this->IsFrameworkOnApple()) {
2491 auto fwDescriptor
= this->GetGlobalGenerator()->SplitFrameworkPath(
2492 info
->SOName
, cmGlobalGenerator::FrameworkFormat::Strict
);
2494 return fwDescriptor
->GetVersionedName();
2497 if (cmHasLiteralPrefix(info
->SOName
, "@rpath/")) {
2498 return info
->SOName
.substr(cmStrLen("@rpath/"));
2500 return info
->SOName
;
2504 // Compute the soname that will be built.
2505 return artifact
== cmStateEnums::RuntimeBinaryArtifact
2506 ? this->GetLibraryNames(config
).SharedObject
2507 : this->GetLibraryNames(config
).ImportLibrary
;
2511 bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level
)
2513 return level
== cmGeneratorTarget::FullLevel
;
2516 bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level
)
2518 return level
== cmGeneratorTarget::ContentLevel
|| shouldAddFullLevel(level
);
2522 std::string
cmGeneratorTarget::GetAppBundleDirectory(
2523 const std::string
& config
, BundleDirectoryLevel level
) const
2525 std::string fpath
= cmStrCat(
2526 this->GetFullName(config
, cmStateEnums::RuntimeBinaryArtifact
), '.');
2527 cmValue ext
= this->GetProperty("BUNDLE_EXTENSION");
2528 fpath
+= (ext
? *ext
: "app");
2529 if (shouldAddContentLevel(level
) &&
2530 !this->Makefile
->PlatformIsAppleEmbedded()) {
2531 fpath
+= "/Contents";
2532 if (shouldAddFullLevel(level
)) {
2539 bool cmGeneratorTarget::IsBundleOnApple() const
2541 return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
2542 this->IsCFBundleOnApple();
2545 bool cmGeneratorTarget::IsWin32Executable(const std::string
& config
) const
2547 return cmIsOn(cmGeneratorExpression::Evaluate(
2548 this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator
, config
));
2551 std::string
cmGeneratorTarget::GetCFBundleDirectory(
2552 const std::string
& config
, BundleDirectoryLevel level
) const
2554 std::string fpath
= cmStrCat(
2555 this->GetOutputName(config
, cmStateEnums::RuntimeBinaryArtifact
), '.');
2557 if (cmValue p
= this->GetProperty("BUNDLE_EXTENSION")) {
2560 if (this->IsXCTestOnApple()) {
2567 if (shouldAddContentLevel(level
) &&
2568 !this->Makefile
->PlatformIsAppleEmbedded()) {
2569 fpath
+= "/Contents";
2570 if (shouldAddFullLevel(level
)) {
2577 std::string
cmGeneratorTarget::GetFrameworkDirectory(
2578 const std::string
& config
, BundleDirectoryLevel level
) const
2580 std::string fpath
= cmStrCat(
2581 this->GetOutputName(config
, cmStateEnums::RuntimeBinaryArtifact
), '.');
2582 cmValue ext
= this->GetProperty("BUNDLE_EXTENSION");
2583 fpath
+= (ext
? *ext
: "framework");
2584 if (shouldAddFullLevel(level
) &&
2585 !this->Makefile
->PlatformIsAppleEmbedded()) {
2586 fpath
+= "/Versions/";
2587 fpath
+= this->GetFrameworkVersion();
2592 std::string
cmGeneratorTarget::GetFullName(
2593 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
2595 if (this->IsImported()) {
2596 return this->GetFullNameImported(config
, artifact
);
2598 return this->GetFullNameInternal(config
, artifact
);
2601 std::string
cmGeneratorTarget::GetInstallNameDirForBuildTree(
2602 const std::string
& config
) const
2604 if (this->Makefile
->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2606 // If building directly for installation then the build tree install_name
2607 // is the same as the install tree.
2608 if (this->MacOSXUseInstallNameDir()) {
2609 std::string installPrefix
=
2610 this->Makefile
->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2611 return this->GetInstallNameDirForInstallTree(config
, installPrefix
);
2614 // Use the build tree directory for the target.
2615 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD
)) {
2617 if (this->MacOSXRpathInstallNameDirDefault()) {
2620 dir
= this->GetDirectory(config
);
2629 std::string
cmGeneratorTarget::GetInstallNameDirForInstallTree(
2630 const std::string
& config
, const std::string
& installPrefix
) const
2632 if (this->Makefile
->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2634 cmValue install_name_dir
= this->GetProperty("INSTALL_NAME_DIR");
2636 if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL
)) {
2637 if (cmNonempty(install_name_dir
)) {
2638 dir
= *install_name_dir
;
2639 cmGeneratorExpression::ReplaceInstallPrefix(dir
, installPrefix
);
2641 cmGeneratorExpression::Evaluate(dir
, this->LocalGenerator
, config
);
2643 dir
= cmStrCat(dir
, '/');
2647 if (!install_name_dir
) {
2648 if (this->MacOSXRpathInstallNameDirDefault()) {
2657 cmListFileBacktrace
cmGeneratorTarget::GetBacktrace() const
2659 return this->Target
->GetBacktrace();
2662 const std::set
<BT
<std::pair
<std::string
, bool>>>&
2663 cmGeneratorTarget::GetUtilities() const
2665 return this->Target
->GetUtilities();
2668 bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
2670 return this->GetType() == cmStateEnums::STATIC_LIBRARY
||
2671 this->GetType() == cmStateEnums::SHARED_LIBRARY
||
2672 this->GetType() == cmStateEnums::MODULE_LIBRARY
||
2673 this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
2674 this->GetType() == cmStateEnums::EXECUTABLE
;
2677 const std::string
* cmGeneratorTarget::GetExportMacro() const
2679 // Define the symbol for targets that export symbols.
2680 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
2681 this->GetType() == cmStateEnums::MODULE_LIBRARY
||
2682 this->IsExecutableWithExports()) {
2683 if (cmValue custom_export_name
= this->GetProperty("DEFINE_SYMBOL")) {
2684 this->ExportMacro
= *custom_export_name
;
2686 std::string in
= cmStrCat(this->GetName(), "_EXPORTS");
2687 this->ExportMacro
= cmSystemTools::MakeCidentifier(in
);
2689 return &this->ExportMacro
;
2694 class cmTargetCollectLinkLanguages
2697 cmTargetCollectLinkLanguages(cmGeneratorTarget
const* target
,
2699 std::unordered_set
<std::string
>& languages
,
2700 cmGeneratorTarget
const* head
, bool secondPass
)
2701 : Config(std::move(config
))
2702 , Languages(languages
)
2704 , SecondPass(secondPass
)
2706 this->Visited
.insert(target
);
2709 void Visit(cmLinkItem
const& item
)
2714 if (!this->Visited
.insert(item
.Target
).second
) {
2717 cmLinkInterface
const* iface
= item
.Target
->GetLinkInterface(
2718 this->Config
, this->HeadTarget
, this->SecondPass
);
2722 if (iface
->HadLinkLanguageSensitiveCondition
) {
2723 this->HadLinkLanguageSensitiveCondition
= true;
2726 for (std::string
const& language
: iface
->Languages
) {
2727 this->Languages
.insert(language
);
2730 for (cmLinkItem
const& lib
: iface
->Libraries
) {
2735 bool GetHadLinkLanguageSensitiveCondition() const
2737 return this->HadLinkLanguageSensitiveCondition
;
2742 std::unordered_set
<std::string
>& Languages
;
2743 cmGeneratorTarget
const* HeadTarget
;
2744 std::set
<cmGeneratorTarget
const*> Visited
;
2746 bool HadLinkLanguageSensitiveCondition
= false;
2749 cmGeneratorTarget::LinkClosure
const* cmGeneratorTarget::GetLinkClosure(
2750 const std::string
& config
) const
2752 // There is no link implementation for targets that cannot compile sources.
2753 if (!this->CanCompileSources()) {
2754 static LinkClosure
const empty
= { {}, {} };
2758 std::string
key(cmSystemTools::UpperCase(config
));
2759 auto i
= this->LinkClosureMap
.find(key
);
2760 if (i
== this->LinkClosureMap
.end()) {
2762 this->ComputeLinkClosure(config
, lc
);
2763 LinkClosureMapType::value_type
entry(key
, lc
);
2764 i
= this->LinkClosureMap
.insert(entry
).first
;
2769 class cmTargetSelectLinker
2772 cmGeneratorTarget
const* Target
;
2773 cmGlobalGenerator
* GG
;
2774 std::set
<std::string
> Preferred
;
2777 cmTargetSelectLinker(cmGeneratorTarget
const* target
)
2780 this->GG
= this->Target
->GetLocalGenerator()->GetGlobalGenerator();
2782 void Consider(const std::string
& lang
)
2784 int preference
= this->GG
->GetLinkerPreference(lang
);
2785 if (preference
> this->Preference
) {
2786 this->Preference
= preference
;
2787 this->Preferred
.clear();
2789 if (preference
== this->Preference
) {
2790 this->Preferred
.insert(lang
);
2793 std::string
Choose()
2795 if (this->Preferred
.empty()) {
2798 if (this->Preferred
.size() > 1) {
2799 std::ostringstream e
;
2800 e
<< "Target " << this->Target
->GetName()
2801 << " contains multiple languages with the highest linker preference"
2802 << " (" << this->Preference
<< "):\n";
2803 for (std::string
const& li
: this->Preferred
) {
2804 e
<< " " << li
<< "\n";
2806 e
<< "Set the LINKER_LANGUAGE property for this target.";
2807 cmake
* cm
= this->Target
->GetLocalGenerator()->GetCMakeInstance();
2808 cm
->IssueMessage(MessageType::FATAL_ERROR
, e
.str(),
2809 this->Target
->GetBacktrace());
2811 return *this->Preferred
.begin();
2815 bool cmGeneratorTarget::ComputeLinkClosure(const std::string
& config
,
2817 bool secondPass
) const
2819 // Get languages built in this target.
2820 std::unordered_set
<std::string
> languages
;
2821 cmLinkImplementation
const* impl
=
2822 this->GetLinkImplementation(config
, LinkInterfaceFor::Link
, secondPass
);
2824 languages
.insert(impl
->Languages
.cbegin(), impl
->Languages
.cend());
2826 // Add interface languages from linked targets.
2827 // cmTargetCollectLinkLanguages cll(this, config, languages, this,
2829 cmTargetCollectLinkLanguages
cll(this, config
, languages
, this, secondPass
);
2830 for (cmLinkImplItem
const& lib
: impl
->Libraries
) {
2834 // Store the transitive closure of languages.
2835 cm::append(lc
.Languages
, languages
);
2837 // Choose the language whose linker should be used.
2838 if (secondPass
|| lc
.LinkerLanguage
.empty()) {
2839 // Find the language with the highest preference value.
2840 cmTargetSelectLinker
tsl(this);
2842 // First select from the languages compiled directly in this target.
2843 for (std::string
const& l
: impl
->Languages
) {
2847 // Now consider languages that propagate from linked targets.
2848 for (std::string
const& lang
: languages
) {
2849 std::string propagates
=
2850 "CMAKE_" + lang
+ "_LINKER_PREFERENCE_PROPAGATES";
2851 if (this->Makefile
->IsOn(propagates
)) {
2856 lc
.LinkerLanguage
= tsl
.Choose();
2859 return impl
->HadLinkLanguageSensitiveCondition
||
2860 cll
.GetHadLinkLanguageSensitiveCondition();
2863 void cmGeneratorTarget::ComputeLinkClosure(const std::string
& config
,
2864 LinkClosure
& lc
) const
2866 bool secondPass
= false;
2869 LinkClosure linkClosure
;
2870 linkClosure
.LinkerLanguage
= this->LinkerLanguage
;
2872 bool hasHardCodedLinkerLanguage
= this->Target
->GetProperty("HAS_CXX") ||
2873 !this->Target
->GetSafeProperty("LINKER_LANGUAGE").empty();
2875 // Get languages built in this target.
2876 secondPass
= this->ComputeLinkClosure(config
, linkClosure
, false) &&
2877 !hasHardCodedLinkerLanguage
;
2878 this->LinkerLanguage
= linkClosure
.LinkerLanguage
;
2880 lc
= std::move(linkClosure
);
2885 LinkClosure linkClosure
;
2887 this->ComputeLinkClosure(config
, linkClosure
, secondPass
);
2888 lc
= std::move(linkClosure
);
2890 // linker language must not be changed between the two passes
2891 if (this->LinkerLanguage
!= lc
.LinkerLanguage
) {
2892 std::ostringstream e
;
2893 e
<< "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> "
2894 "changes\nthe linker language for target \""
2895 << this->GetName() << "\" (from '" << this->LinkerLanguage
<< "' to '"
2896 << lc
.LinkerLanguage
<< "') which is invalid.";
2897 cmSystemTools::Error(e
.str());
2902 cmGeneratorTarget::NameComponents
const&
2903 cmGeneratorTarget::GetFullNameComponents(
2904 std::string
const& config
, cmStateEnums::ArtifactType artifact
) const
2906 return this->GetFullNameInternalComponents(config
, artifact
);
2909 std::string
cmGeneratorTarget::BuildBundleDirectory(
2910 const std::string
& base
, const std::string
& config
,
2911 BundleDirectoryLevel level
) const
2913 std::string fpath
= base
;
2914 if (this->IsAppBundleOnApple()) {
2915 fpath
+= this->GetAppBundleDirectory(config
, level
);
2917 if (this->IsFrameworkOnApple()) {
2918 fpath
+= this->GetFrameworkDirectory(config
, level
);
2920 if (this->IsCFBundleOnApple()) {
2921 fpath
+= this->GetCFBundleDirectory(config
, level
);
2926 std::string
cmGeneratorTarget::GetMacContentDirectory(
2927 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
2929 // Start with the output directory for the target.
2930 std::string fpath
= cmStrCat(this->GetDirectory(config
, artifact
), '/');
2931 BundleDirectoryLevel level
= ContentLevel
;
2932 if (this->IsFrameworkOnApple()) {
2933 // additional files with a framework go into the version specific
2937 fpath
= this->BuildBundleDirectory(fpath
, config
, level
);
2941 std::string
cmGeneratorTarget::GetEffectiveFolderName() const
2943 std::string effectiveFolder
;
2945 if (!this->GlobalGenerator
->UseFolderProperty()) {
2946 return effectiveFolder
;
2949 cmValue targetFolder
= this->GetProperty("FOLDER");
2951 effectiveFolder
+= *targetFolder
;
2954 return effectiveFolder
;
2957 cmGeneratorTarget::CompileInfo
const* cmGeneratorTarget::GetCompileInfo(
2958 const std::string
& config
) const
2960 // There is no compile information for imported targets.
2961 if (this->IsImported()) {
2965 if (this->GetType() > cmStateEnums::OBJECT_LIBRARY
) {
2966 std::string msg
= cmStrCat("cmTarget::GetCompileInfo called for ",
2967 this->GetName(), " which has type ",
2968 cmState::GetTargetTypeName(this->GetType()));
2969 this->LocalGenerator
->IssueMessage(MessageType::INTERNAL_ERROR
, msg
);
2973 // Lookup/compute/cache the compile information for this configuration.
2974 std::string config_upper
;
2975 if (!config
.empty()) {
2976 config_upper
= cmSystemTools::UpperCase(config
);
2978 auto i
= this->CompileInfoMap
.find(config_upper
);
2979 if (i
== this->CompileInfoMap
.end()) {
2981 this->ComputePDBOutputDir("COMPILE_PDB", config
, info
.CompilePdbDir
);
2982 CompileInfoMapType::value_type
entry(config_upper
, info
);
2983 i
= this->CompileInfoMap
.insert(entry
).first
;
2988 cmGeneratorTarget::ModuleDefinitionInfo
const*
2989 cmGeneratorTarget::GetModuleDefinitionInfo(std::string
const& config
) const
2991 // A module definition file only makes sense on certain target types.
2992 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
2993 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
2994 !this->IsExecutableWithExports()) {
2998 // Lookup/compute/cache the compile information for this configuration.
2999 std::string config_upper
;
3000 if (!config
.empty()) {
3001 config_upper
= cmSystemTools::UpperCase(config
);
3003 auto i
= this->ModuleDefinitionInfoMap
.find(config_upper
);
3004 if (i
== this->ModuleDefinitionInfoMap
.end()) {
3005 ModuleDefinitionInfo info
;
3006 this->ComputeModuleDefinitionInfo(config
, info
);
3007 ModuleDefinitionInfoMapType::value_type
entry(config_upper
, info
);
3008 i
= this->ModuleDefinitionInfoMap
.insert(entry
).first
;
3013 void cmGeneratorTarget::ComputeModuleDefinitionInfo(
3014 std::string
const& config
, ModuleDefinitionInfo
& info
) const
3016 this->GetModuleDefinitionSources(info
.Sources
, config
);
3017 info
.WindowsExportAllSymbols
=
3018 this->Makefile
->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
3019 this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
3020 #if !defined(CMAKE_BOOTSTRAP)
3021 info
.DefFileGenerated
=
3022 info
.WindowsExportAllSymbols
|| info
.Sources
.size() > 1;
3024 // Our __create_def helper is not available during CMake bootstrap.
3025 info
.DefFileGenerated
= false;
3027 if (info
.DefFileGenerated
) {
3029 this->GetObjectDirectory(config
) /* has slash */ + "exports.def";
3030 } else if (!info
.Sources
.empty()) {
3031 info
.DefFile
= info
.Sources
.front()->GetFullPath();
3035 bool cmGeneratorTarget::IsAIX() const
3037 return this->Target
->IsAIX();
3040 bool cmGeneratorTarget::IsApple() const
3042 return this->Target
->IsApple();
3045 bool cmGeneratorTarget::IsDLLPlatform() const
3047 return this->Target
->IsDLLPlatform();
3050 void cmGeneratorTarget::GetAutoUicOptions(std::vector
<std::string
>& result
,
3051 const std::string
& config
) const
3054 this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config
);
3059 cmGeneratorExpressionDAGChecker
dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
3061 cmExpandList(cmGeneratorExpression::Evaluate(prop
, this->LocalGenerator
,
3062 config
, this, &dagChecker
),
3066 static void processILibs(const std::string
& config
,
3067 cmGeneratorTarget
const* headTarget
,
3068 cmLinkItem
const& item
, cmGlobalGenerator
* gg
,
3069 std::vector
<cmGeneratorTarget
const*>& tgts
,
3070 std::set
<cmGeneratorTarget
const*>& emitted
)
3072 if (item
.Target
&& emitted
.insert(item
.Target
).second
) {
3073 tgts
.push_back(item
.Target
);
3074 if (cmLinkInterfaceLibraries
const* iface
=
3075 item
.Target
->GetLinkInterfaceLibraries(config
, headTarget
,
3076 LinkInterfaceFor::Usage
)) {
3077 for (cmLinkItem
const& lib
: iface
->Libraries
) {
3078 processILibs(config
, headTarget
, lib
, gg
, tgts
, emitted
);
3084 const std::vector
<const cmGeneratorTarget
*>&
3085 cmGeneratorTarget::GetLinkImplementationClosure(
3086 const std::string
& config
) const
3088 // There is no link implementation for targets that cannot compile sources.
3089 if (!this->CanCompileSources()) {
3090 static std::vector
<const cmGeneratorTarget
*> const empty
;
3094 LinkImplClosure
& tgts
= this->LinkImplClosureMap
[config
];
3097 std::set
<cmGeneratorTarget
const*> emitted
;
3099 cmLinkImplementationLibraries
const* impl
=
3100 this->GetLinkImplementationLibraries(config
, LinkInterfaceFor::Usage
);
3103 for (cmLinkImplItem
const& lib
: impl
->Libraries
) {
3104 processILibs(config
, this, lib
,
3105 this->LocalGenerator
->GetGlobalGenerator(), tgts
, emitted
);
3111 class cmTargetTraceDependencies
3114 cmTargetTraceDependencies(cmGeneratorTarget
* target
);
3118 cmGeneratorTarget
* GeneratorTarget
;
3119 cmMakefile
* Makefile
;
3120 cmLocalGenerator
* LocalGenerator
;
3121 cmGlobalGenerator
const* GlobalGenerator
;
3122 using SourceEntry
= cmGeneratorTarget::SourceEntry
;
3123 SourceEntry
* CurrentEntry
;
3124 std::queue
<cmSourceFile
*> SourceQueue
;
3125 std::set
<cmSourceFile
*> SourcesQueued
;
3126 using NameMapType
= std::map
<std::string
, cmSourcesWithOutput
>;
3127 NameMapType NameMap
;
3128 std::vector
<std::string
> NewSources
;
3130 void QueueSource(cmSourceFile
* sf
);
3131 void FollowName(std::string
const& name
);
3132 void FollowNames(std::vector
<std::string
> const& names
);
3133 bool IsUtility(std::string
const& dep
);
3134 void CheckCustomCommand(cmCustomCommand
const& cc
);
3135 void CheckCustomCommands(const std::vector
<cmCustomCommand
>& commands
);
3138 cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget
* target
)
3139 : GeneratorTarget(target
)
3142 this->Makefile
= target
->Target
->GetMakefile();
3143 this->LocalGenerator
= target
->GetLocalGenerator();
3144 this->GlobalGenerator
= this->LocalGenerator
->GetGlobalGenerator();
3145 this->CurrentEntry
= nullptr;
3147 // Queue all the source files already specified for the target.
3148 std::set
<cmSourceFile
*> emitted
;
3149 std::vector
<std::string
> const& configs
=
3150 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
3151 for (std::string
const& c
: configs
) {
3152 std::vector
<cmSourceFile
*> sources
;
3153 this->GeneratorTarget
->GetSourceFiles(sources
, c
);
3154 for (cmSourceFile
* sf
: sources
) {
3155 const std::set
<cmGeneratorTarget
const*> tgts
=
3156 this->GlobalGenerator
->GetFilenameTargetDepends(sf
);
3157 if (cm::contains(tgts
, this->GeneratorTarget
)) {
3158 std::ostringstream e
;
3159 e
<< "Evaluation output file\n \"" << sf
->ResolveFullPath()
3160 << "\"\ndepends on the sources of a target it is used in. This "
3161 "is a dependency loop and is not allowed.";
3162 this->GeneratorTarget
->LocalGenerator
->IssueMessage(
3163 MessageType::FATAL_ERROR
, e
.str());
3166 if (emitted
.insert(sf
).second
&& this->SourcesQueued
.insert(sf
).second
) {
3167 this->SourceQueue
.push(sf
);
3172 // Queue pre-build, pre-link, and post-build rule dependencies.
3173 this->CheckCustomCommands(this->GeneratorTarget
->GetPreBuildCommands());
3174 this->CheckCustomCommands(this->GeneratorTarget
->GetPreLinkCommands());
3175 this->CheckCustomCommands(this->GeneratorTarget
->GetPostBuildCommands());
3178 void cmTargetTraceDependencies::Trace()
3180 // Process one dependency at a time until the queue is empty.
3181 while (!this->SourceQueue
.empty()) {
3182 // Get the next source from the queue.
3183 cmSourceFile
* sf
= this->SourceQueue
.front();
3184 this->SourceQueue
.pop();
3185 this->CurrentEntry
= &this->GeneratorTarget
->SourceDepends
[sf
];
3187 // Queue dependencies added explicitly by the user.
3188 if (cmValue additionalDeps
= sf
->GetProperty("OBJECT_DEPENDS")) {
3189 cmList objDeps
{ *additionalDeps
};
3190 for (auto& objDep
: objDeps
) {
3191 if (cmSystemTools::FileIsFullPath(objDep
)) {
3192 objDep
= cmSystemTools::CollapseFullPath(objDep
);
3195 this->FollowNames(objDeps
);
3198 // Queue the source needed to generate this file, if any.
3199 this->FollowName(sf
->ResolveFullPath());
3201 // Queue dependencies added programmatically by commands.
3202 this->FollowNames(sf
->GetDepends());
3204 // Queue custom command dependencies.
3205 if (cmCustomCommand
const* cc
= sf
->GetCustomCommand()) {
3206 this->CheckCustomCommand(*cc
);
3209 this->CurrentEntry
= nullptr;
3211 this->GeneratorTarget
->AddTracedSources(this->NewSources
);
3214 void cmTargetTraceDependencies::QueueSource(cmSourceFile
* sf
)
3216 if (this->SourcesQueued
.insert(sf
).second
) {
3217 this->SourceQueue
.push(sf
);
3219 // Make sure this file is in the target at the end.
3220 this->NewSources
.push_back(sf
->ResolveFullPath());
3224 void cmTargetTraceDependencies::FollowName(std::string
const& name
)
3226 // Use lower bound with key comparison to not repeat the search for the
3227 // insert position if the name could not be found (which is the common case).
3228 auto i
= this->NameMap
.lower_bound(name
);
3229 if (i
== this->NameMap
.end() || i
->first
!= name
) {
3230 // Check if we know how to generate this file.
3231 cmSourcesWithOutput sources
=
3232 this->LocalGenerator
->GetSourcesWithOutput(name
);
3233 // If we failed to find a target or source and we have a relative path, it
3234 // might be a valid source if made relative to the current binary
3236 if (!sources
.Target
&& !sources
.Source
&&
3237 !cmSystemTools::FileIsFullPath(name
)) {
3239 cmStrCat(this->Makefile
->GetCurrentBinaryDirectory(), '/', name
);
3240 fullname
= cmSystemTools::CollapseFullPath(
3241 fullname
, this->Makefile
->GetHomeOutputDirectory());
3242 sources
= this->LocalGenerator
->GetSourcesWithOutput(fullname
);
3244 i
= this->NameMap
.emplace_hint(i
, name
, sources
);
3246 if (cmTarget
* t
= i
->second
.Target
) {
3247 // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
3248 // POST_BUILD command.
3249 this->GeneratorTarget
->Target
->AddUtility(t
->GetName(), false);
3251 if (cmSourceFile
* sf
= i
->second
.Source
) {
3252 // For now only follow the dependency if the source file is not a
3253 // byproduct. Semantics of byproducts in a non-Ninja context will have to
3254 // be defined first.
3255 if (!i
->second
.SourceIsByproduct
) {
3256 // Record the dependency we just followed.
3257 if (this->CurrentEntry
) {
3258 this->CurrentEntry
->Depends
.push_back(sf
);
3260 this->QueueSource(sf
);
3265 void cmTargetTraceDependencies::FollowNames(
3266 std::vector
<std::string
> const& names
)
3268 for (std::string
const& name
: names
) {
3269 this->FollowName(name
);
3273 bool cmTargetTraceDependencies::IsUtility(std::string
const& dep
)
3275 // Dependencies on targets (utilities) are supposed to be named by
3276 // just the target name. However for compatibility we support
3277 // naming the output file generated by the target (assuming there is
3278 // no output-name property which old code would not have set). In
3279 // that case the target name will be the file basename of the
3281 std::string util
= cmSystemTools::GetFilenameName(dep
);
3282 if (cmSystemTools::GetFilenameLastExtension(util
) == ".exe") {
3283 util
= cmSystemTools::GetFilenameWithoutLastExtension(util
);
3286 // Check for a target with this name.
3287 if (cmGeneratorTarget
* t
=
3288 this->GeneratorTarget
->GetLocalGenerator()->FindGeneratorTargetToUse(
3290 // If we find the target and the dep was given as a full path,
3291 // then make sure it was not a full path to something else, and
3292 // the fact that the name matched a target was just a coincidence.
3293 if (cmSystemTools::FileIsFullPath(dep
)) {
3294 if (t
->GetType() >= cmStateEnums::EXECUTABLE
&&
3295 t
->GetType() <= cmStateEnums::MODULE_LIBRARY
) {
3296 // This is really only for compatibility so we do not need to
3297 // worry about configuration names and output names.
3298 std::string tLocation
= t
->GetLocationForBuild();
3299 tLocation
= cmSystemTools::GetFilenamePath(tLocation
);
3300 std::string depLocation
= cmSystemTools::GetFilenamePath(dep
);
3301 depLocation
= cmSystemTools::CollapseFullPath(depLocation
);
3302 tLocation
= cmSystemTools::CollapseFullPath(tLocation
);
3303 if (depLocation
== tLocation
) {
3304 this->GeneratorTarget
->Target
->AddUtility(util
, false);
3309 // The original name of the dependency was not a full path. It
3310 // must name a target, so add the target-level dependency.
3311 this->GeneratorTarget
->Target
->AddUtility(util
, true);
3316 // The dependency does not name a target built in this project.
3320 void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand
const& cc
)
3322 // Collect dependencies referenced by all configurations.
3323 std::set
<std::string
> depends
;
3324 for (std::string
const& config
:
3325 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
)) {
3326 for (cmCustomCommandGenerator
const& ccg
:
3327 this->LocalGenerator
->MakeCustomCommandGenerators(cc
, config
)) {
3328 // Collect target-level dependencies referenced in command lines.
3329 for (auto const& util
: ccg
.GetUtilities()) {
3330 this->GeneratorTarget
->Target
->AddUtility(util
);
3333 // Collect file-level dependencies referenced in DEPENDS.
3334 depends
.insert(ccg
.GetDepends().begin(), ccg
.GetDepends().end());
3338 // Queue file-level dependencies.
3339 for (std::string
const& dep
: depends
) {
3340 if (!this->IsUtility(dep
)) {
3341 // The dependency does not name a target and may be a file we
3342 // know how to generate. Queue it.
3343 this->FollowName(dep
);
3348 void cmTargetTraceDependencies::CheckCustomCommands(
3349 const std::vector
<cmCustomCommand
>& commands
)
3351 for (cmCustomCommand
const& command
: commands
) {
3352 this->CheckCustomCommand(command
);
3356 void cmGeneratorTarget::TraceDependencies()
3358 // CMake-generated targets have no dependencies to trace. Normally tracing
3359 // would find nothing anyway, but when building CMake itself the "install"
3360 // target command ends up referencing the "cmake" target but we do not
3361 // really want the dependency because "install" depend on "all" anyway.
3362 if (this->GetType() == cmStateEnums::GLOBAL_TARGET
) {
3366 // Use a helper object to trace the dependencies.
3367 cmTargetTraceDependencies
tracer(this);
3371 std::string
cmGeneratorTarget::GetCompilePDBDirectory(
3372 const std::string
& config
) const
3374 if (CompileInfo
const* info
= this->GetCompileInfo(config
)) {
3375 return info
->CompilePdbDir
;
3380 std::vector
<std::string
> cmGeneratorTarget::GetAppleArchs(
3381 std::string
const& config
, cm::optional
<std::string
> lang
) const
3384 if (!this->IsApple()) {
3385 return std::move(archList
.data());
3387 cmValue archs
= nullptr;
3388 if (!config
.empty()) {
3389 std::string defVarName
=
3390 cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config
));
3391 archs
= this->GetProperty(defVarName
);
3394 archs
= this->GetProperty("OSX_ARCHITECTURES");
3397 archList
.assign(*archs
);
3399 if (archList
.empty() &&
3400 // Fall back to a default architecture if no compiler target is set.
3403 ->GetDefinition(cmStrCat("CMAKE_", *lang
, "_COMPILER_TARGET"))
3406 this->Makefile
->GetDefinition("_CMAKE_APPLE_ARCHS_DEFAULT"));
3408 return std::move(archList
.data());
3411 void cmGeneratorTarget::AddExplicitLanguageFlags(std::string
& flags
,
3412 cmSourceFile
const& sf
) const
3414 cmValue lang
= sf
.GetProperty("LANGUAGE");
3419 switch (this->GetPolicyStatusCMP0119()) {
3420 case cmPolicies::WARN
:
3422 case cmPolicies::OLD
:
3423 // The OLD behavior is to not add explicit language flags.
3425 case cmPolicies::REQUIRED_ALWAYS
:
3426 case cmPolicies::REQUIRED_IF_USED
:
3427 case cmPolicies::NEW
:
3428 // The NEW behavior is to add explicit language flags.
3432 this->LocalGenerator
->AppendFeatureOptions(flags
, *lang
,
3433 "EXPLICIT_LANGUAGE");
3436 void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink
,
3437 std::string
const& config
,
3438 std::string
& flags
) const
3440 std::string arch
= this->GetSafeProperty("CUDA_ARCHITECTURES");
3443 switch (this->GetPolicyStatusCMP0104()) {
3444 case cmPolicies::WARN
:
3445 if (!this->LocalGenerator
->GetCMakeInstance()->GetIsInTryCompile()) {
3446 this->Makefile
->IssueMessage(
3447 MessageType::AUTHOR_WARNING
,
3448 cmPolicies::GetPolicyWarning(cmPolicies::CMP0104
) +
3449 "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3453 case cmPolicies::OLD
:
3456 this->Makefile
->IssueMessage(
3457 MessageType::FATAL_ERROR
,
3458 "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
3463 // If CUDA_ARCHITECTURES is false we don't add any architectures.
3464 if (cmIsOff(arch
)) {
3468 return this->AddCUDAArchitectureFlagsImpl(compileOrLink
, config
, "CUDA",
3469 std::move(arch
), flags
);
3472 void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink
,
3473 std::string
const& config
,
3474 std::string
const& lang
,
3476 std::string
& flags
) const
3478 std::string
const& compiler
= this->Makefile
->GetSafeDefinition(
3479 cmStrCat("CMAKE_", lang
, "_COMPILER_ID"));
3480 const bool ipoEnabled
= this->IsIPOEnabled(lang
, config
);
3482 // Check for special modes: `all`, `all-major`.
3483 if (arch
== "all" || arch
== "all-major") {
3484 if (compiler
== "NVIDIA" &&
3485 cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL
,
3486 this->Makefile
->GetDefinition(cmStrCat(
3487 "CMAKE_", lang
, "_COMPILER_VERSION")),
3489 flags
= cmStrCat(flags
, " -arch=", arch
);
3492 if (arch
== "all") {
3493 arch
= *this->Makefile
->GetDefinition(
3494 cmStrCat("CMAKE_", lang
, "_ARCHITECTURES_ALL"));
3495 } else if (arch
== "all-major") {
3496 arch
= *this->Makefile
->GetDefinition(
3497 cmStrCat("CMAKE_", lang
, "_ARCHITECTURES_ALL_MAJOR"));
3499 } else if (arch
== "native") {
3500 cmValue native
= this->Makefile
->GetDefinition(
3501 cmStrCat("CMAKE_", lang
, "_ARCHITECTURES_NATIVE"));
3502 if (native
.IsEmpty()) {
3503 this->Makefile
->IssueMessage(
3504 MessageType::FATAL_ERROR
,
3506 "_ARCHITECTURES is set to \"native\", but no NVIDIA GPU was "
3509 if (compiler
== "NVIDIA" &&
3510 cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL
,
3511 this->Makefile
->GetDefinition(cmStrCat(
3512 "CMAKE_", lang
, "_COMPILER_VERSION")),
3514 flags
= cmStrCat(flags
, " -arch=", arch
);
3520 struct CudaArchitecture
3524 bool virtual_
{ true };
3526 std::vector
<CudaArchitecture
> architectures
;
3529 cmList
options(arch
);
3531 for (auto& option
: options
) {
3532 CudaArchitecture architecture
;
3534 // Architecture name is up to the first specifier.
3535 std::size_t pos
= option
.find_first_of('-');
3536 architecture
.name
= option
.substr(0, pos
);
3538 if (pos
!= std::string::npos
) {
3539 cm::string_view specifier
{ option
.c_str() + pos
+ 1,
3540 option
.length() - pos
- 1 };
3542 if (specifier
== "real") {
3543 architecture
.real
= true;
3544 architecture
.virtual_
= false;
3545 } else if (specifier
== "virtual") {
3546 architecture
.real
= false;
3547 architecture
.virtual_
= true;
3549 this->Makefile
->IssueMessage(
3550 MessageType::FATAL_ERROR
,
3551 "Unknown CUDA architecture specifier \"" + std::string(specifier
) +
3556 architectures
.emplace_back(architecture
);
3560 if (compiler
== "NVIDIA") {
3561 if (ipoEnabled
&& compileOrLink
== cmBuildStep::Link
) {
3562 if (cmValue cudaIPOFlags
= this->Makefile
->GetDefinition(
3563 cmStrCat("CMAKE_", lang
, "_LINK_OPTIONS_IPO"))) {
3564 flags
+= *cudaIPOFlags
;
3568 for (CudaArchitecture
& architecture
: architectures
) {
3570 " \"--generate-code=arch=compute_" + architecture
.name
+ ",code=[";
3572 if (architecture
.virtual_
) {
3573 flags
+= "compute_" + architecture
.name
;
3575 if (ipoEnabled
|| architecture
.real
) {
3581 if (compileOrLink
== cmBuildStep::Compile
) {
3582 flags
+= "lto_" + architecture
.name
;
3583 } else if (compileOrLink
== cmBuildStep::Link
) {
3584 flags
+= "sm_" + architecture
.name
;
3586 } else if (architecture
.real
) {
3587 flags
+= "sm_" + architecture
.name
;
3592 } else if (compiler
== "Clang" && compileOrLink
== cmBuildStep::Compile
) {
3593 for (CudaArchitecture
& architecture
: architectures
) {
3594 flags
+= " --cuda-gpu-arch=sm_" + architecture
.name
;
3596 if (!architecture
.real
) {
3597 this->Makefile
->IssueMessage(
3598 MessageType::WARNING
,
3599 "Clang doesn't support disabling CUDA real code generation.");
3602 if (!architecture
.virtual_
) {
3603 flags
+= " --no-cuda-include-ptx=sm_" + architecture
.name
;
3609 void cmGeneratorTarget::AddISPCTargetFlags(std::string
& flags
) const
3611 const std::string
& arch
= this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
3613 // If ISPC_TARGET is false we don't add any architectures.
3614 if (cmIsOff(arch
)) {
3618 std::string
const& compiler
=
3619 this->Makefile
->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
3621 if (compiler
== "Intel") {
3622 cmList
targets(arch
);
3623 if (!targets
.empty()) {
3624 flags
+= cmStrCat(" --target=", cmWrap("", targets
, "", ","));
3629 void cmGeneratorTarget::AddHIPArchitectureFlags(cmBuildStep compileOrLink
,
3630 std::string
const& config
,
3631 std::string
& flags
) const
3633 std::string arch
= this->GetSafeProperty("HIP_ARCHITECTURES");
3636 this->Makefile
->IssueMessage(MessageType::FATAL_ERROR
,
3637 "HIP_ARCHITECTURES is empty for target \"" +
3638 this->GetName() + "\".");
3641 // If HIP_ARCHITECTURES is false we don't add any architectures.
3642 if (cmIsOff(arch
)) {
3646 if (this->Makefile
->GetSafeDefinition("CMAKE_HIP_PLATFORM") == "nvidia") {
3647 return this->AddCUDAArchitectureFlagsImpl(compileOrLink
, config
, "HIP",
3648 std::move(arch
), flags
);
3651 cmList
options(arch
);
3653 for (std::string
& option
: options
) {
3654 flags
+= " --offload-arch=" + option
;
3658 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string
& flags
) const
3660 std::string
const& compiler
=
3661 this->Makefile
->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
3663 if (compiler
== "Clang") {
3664 // Pass CUDA toolkit explicitly to Clang.
3665 // Clang's searching for the system CUDA toolkit isn't very good and it's
3666 // expected the user will explicitly pass the toolkit path.
3667 // This also avoids Clang having to search for the toolkit on every
3669 std::string toolkitRoot
=
3670 this->Makefile
->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
3672 if (!toolkitRoot
.empty()) {
3673 flags
+= " --cuda-path=" +
3674 this->LocalGenerator
->ConvertToOutputFormat(toolkitRoot
,
3675 cmOutputConverter::SHELL
);
3680 //----------------------------------------------------------------------------
3681 std::string
cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
3682 std::string
const& var
, std::string
const& lang
,
3683 std::string
const& config
) const
3685 if (this->IsIPOEnabled(lang
, config
)) {
3686 std::string varIPO
= var
+ "_IPO";
3687 if (this->Makefile
->IsDefinitionSet(varIPO
)) {
3695 //----------------------------------------------------------------------------
3696 std::string
cmGeneratorTarget::GetCreateRuleVariable(
3697 std::string
const& lang
, std::string
const& config
) const
3699 switch (this->GetType()) {
3700 case cmStateEnums::STATIC_LIBRARY
: {
3701 std::string var
= "CMAKE_" + lang
+ "_CREATE_STATIC_LIBRARY";
3702 return this->GetFeatureSpecificLinkRuleVariable(var
, lang
, config
);
3704 case cmStateEnums::SHARED_LIBRARY
:
3705 return "CMAKE_" + lang
+ "_CREATE_SHARED_LIBRARY";
3706 case cmStateEnums::MODULE_LIBRARY
:
3707 return "CMAKE_" + lang
+ "_CREATE_SHARED_MODULE";
3708 case cmStateEnums::EXECUTABLE
:
3709 if (this->IsExecutableWithExports()) {
3710 std::string linkExeWithExports
=
3711 "CMAKE_" + lang
+ "_LINK_EXECUTABLE_WITH_EXPORTS";
3712 if (this->Makefile
->IsDefinitionSet(linkExeWithExports
)) {
3713 return linkExeWithExports
;
3716 return "CMAKE_" + lang
+ "_LINK_EXECUTABLE";
3723 //----------------------------------------------------------------------------
3724 std::string
cmGeneratorTarget::GetClangTidyExportFixesDirectory(
3725 const std::string
& lang
) const
3728 this->GetProperty(cmStrCat(lang
, "_CLANG_TIDY_EXPORT_FIXES_DIR"));
3729 if (!cmNonempty(val
)) {
3733 std::string path
= *val
;
3734 if (!cmSystemTools::FileIsFullPath(path
)) {
3736 cmStrCat(this->LocalGenerator
->GetCurrentBinaryDirectory(), '/', path
);
3738 return cmSystemTools::CollapseFullPath(path
);
3742 void processIncludeDirectories(cmGeneratorTarget
const* tgt
,
3743 EvaluatedTargetPropertyEntries
& entries
,
3744 std::vector
<BT
<std::string
>>& includes
,
3745 std::unordered_set
<std::string
>& uniqueIncludes
,
3748 for (EvaluatedTargetPropertyEntry
& entry
: entries
.Entries
) {
3749 cmLinkImplItem
const& item
= entry
.LinkImplItem
;
3750 std::string
const& targetName
= item
.AsStr();
3751 bool const fromImported
= item
.Target
&& item
.Target
->IsImported();
3752 bool const checkCMP0027
= item
.CheckCMP0027
;
3754 std::string usedIncludes
;
3755 for (std::string
& entryInclude
: entry
.Values
) {
3756 if (fromImported
&& !cmSystemTools::FileExists(entryInclude
)) {
3757 std::ostringstream e
;
3758 MessageType messageType
= MessageType::FATAL_ERROR
;
3760 switch (tgt
->GetPolicyStatusCMP0027()) {
3761 case cmPolicies::WARN
:
3762 e
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0027
) << "\n";
3764 case cmPolicies::OLD
:
3765 messageType
= MessageType::AUTHOR_WARNING
;
3767 case cmPolicies::REQUIRED_ALWAYS
:
3768 case cmPolicies::REQUIRED_IF_USED
:
3769 case cmPolicies::NEW
:
3773 /* clang-format off */
3774 e
<< "Imported target \"" << targetName
<< "\" includes "
3775 "non-existent path\n \"" << entryInclude
<< "\"\nin its "
3776 "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
3777 "* The path was deleted, renamed, or moved to another "
3779 "* An install or uninstall procedure did not complete "
3781 "* The installation package was faulty and references files it "
3782 "does not provide.\n";
3783 /* clang-format on */
3784 tgt
->GetLocalGenerator()->IssueMessage(messageType
, e
.str());
3788 if (!cmSystemTools::FileIsFullPath(entryInclude
)) {
3789 std::ostringstream e
;
3790 bool noMessage
= false;
3791 MessageType messageType
= MessageType::FATAL_ERROR
;
3792 if (!targetName
.empty()) {
3793 /* clang-format off */
3794 e
<< "Target \"" << targetName
<< "\" contains relative "
3795 "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
3796 " \"" << entryInclude
<< "\"";
3797 /* clang-format on */
3799 switch (tgt
->GetPolicyStatusCMP0021()) {
3800 case cmPolicies::WARN
: {
3801 e
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0021
) << "\n";
3802 messageType
= MessageType::AUTHOR_WARNING
;
3804 case cmPolicies::OLD
:
3807 case cmPolicies::REQUIRED_IF_USED
:
3808 case cmPolicies::REQUIRED_ALWAYS
:
3809 case cmPolicies::NEW
:
3810 // Issue the fatal message.
3813 e
<< "Found relative path while evaluating include directories of "
3815 << tgt
->GetName() << "\":\n \"" << entryInclude
<< "\"\n";
3818 tgt
->GetLocalGenerator()->IssueMessage(messageType
, e
.str());
3819 if (messageType
== MessageType::FATAL_ERROR
) {
3825 if (!cmIsOff(entryInclude
)) {
3826 cmSystemTools::ConvertToUnixSlashes(entryInclude
);
3829 if (uniqueIncludes
.insert(entryInclude
).second
) {
3830 includes
.emplace_back(entryInclude
, entry
.Backtrace
);
3831 if (debugIncludes
) {
3832 usedIncludes
+= " * " + entryInclude
+ "\n";
3836 if (!usedIncludes
.empty()) {
3837 tgt
->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3839 std::string("Used includes for target ") + tgt
->GetName() + ":\n" +
3847 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetIncludeDirectories(
3848 const std::string
& config
, const std::string
& lang
) const
3850 ConfigAndLanguage
cacheKey(config
, lang
);
3852 auto it
= this->IncludeDirectoriesCache
.find(cacheKey
);
3853 if (it
!= this->IncludeDirectoriesCache
.end()) {
3857 std::vector
<BT
<std::string
>> includes
;
3858 std::unordered_set
<std::string
> uniqueIncludes
;
3860 cmGeneratorExpressionDAGChecker
dagChecker(this, "INCLUDE_DIRECTORIES",
3863 cmList debugProperties
{ this->Makefile
->GetDefinition(
3864 "CMAKE_DEBUG_TARGET_PROPERTIES") };
3865 bool debugIncludes
= !this->DebugIncludesDone
&&
3866 cm::contains(debugProperties
, "INCLUDE_DIRECTORIES");
3868 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
3869 this->DebugIncludesDone
= true;
3872 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
3873 this, config
, lang
, &dagChecker
, this->IncludeDirectoriesEntries
);
3875 if (lang
== "Swift") {
3876 AddLangSpecificImplicitIncludeDirectories(
3877 this, lang
, config
, "Swift_MODULE_DIRECTORY",
3878 IncludeDirectoryFallBack::BINARY
, entries
);
3881 if (this->CanCompileSources() && (lang
!= "Swift" && lang
!= "Fortran")) {
3883 const std::string propertyName
= "ISPC_HEADER_DIRECTORY";
3885 // If this target has ISPC sources make sure to add the header
3886 // directory to other compilation units
3887 if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
3888 if (cmValue val
= this->GetProperty(propertyName
)) {
3889 includes
.emplace_back(*val
);
3891 includes
.emplace_back(this->GetObjectDirectory(config
));
3895 AddLangSpecificImplicitIncludeDirectories(
3896 this, "ISPC", config
, propertyName
, IncludeDirectoryFallBack::OBJECT
,
3900 AddInterfaceEntries(this, config
, "INTERFACE_INCLUDE_DIRECTORIES", lang
,
3901 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
);
3903 processIncludeDirectories(this, entries
, includes
, uniqueIncludes
,
3906 if (this->IsApple()) {
3907 if (cmLinkImplementationLibraries
const* impl
=
3908 this->GetLinkImplementationLibraries(config
,
3909 LinkInterfaceFor::Usage
)) {
3910 for (cmLinkImplItem
const& lib
: impl
->Libraries
) {
3912 if (lib
.Target
== nullptr) {
3913 libDir
= cmSystemTools::CollapseFullPath(
3914 lib
.AsStr(), this->Makefile
->GetHomeOutputDirectory());
3915 } else if (lib
.Target
->Target
->IsFrameworkOnApple() ||
3916 this->IsImportedFrameworkFolderOnApple(config
)) {
3917 libDir
= lib
.Target
->GetLocation(config
);
3923 this->GetGlobalGenerator()->SplitFrameworkPath(libDir
);
3924 if (!fwDescriptor
) {
3928 auto fwInclude
= fwDescriptor
->GetFrameworkPath();
3929 if (uniqueIncludes
.insert(fwInclude
).second
) {
3930 includes
.emplace_back(fwInclude
, cmListFileBacktrace());
3936 this->IncludeDirectoriesCache
.emplace(cacheKey
, includes
);
3940 enum class OptionsParse
3947 const auto DL_BEGIN
= "<DEVICE_LINK>"_s
;
3948 const auto DL_END
= "</DEVICE_LINK>"_s
;
3950 void processOptions(cmGeneratorTarget
const* tgt
,
3951 EvaluatedTargetPropertyEntries
const& entries
,
3952 std::vector
<BT
<std::string
>>& options
,
3953 std::unordered_set
<std::string
>& uniqueOptions
,
3954 bool debugOptions
, const char* logName
, OptionsParse parse
,
3955 bool processDeviceOptions
= false)
3957 bool splitOption
= !processDeviceOptions
;
3958 for (EvaluatedTargetPropertyEntry
const& entry
: entries
.Entries
) {
3959 std::string usedOptions
;
3960 for (std::string
const& opt
: entry
.Values
) {
3961 if (processDeviceOptions
&& (opt
== DL_BEGIN
|| opt
== DL_END
)) {
3962 options
.emplace_back(opt
, entry
.Backtrace
);
3963 splitOption
= opt
== DL_BEGIN
;
3967 if (uniqueOptions
.insert(opt
).second
) {
3968 if (parse
== OptionsParse::Shell
&&
3969 cmHasLiteralPrefix(opt
, "SHELL:")) {
3971 std::vector
<std::string
> tmp
;
3972 cmSystemTools::ParseUnixCommandLine(opt
.c_str() + 6, tmp
);
3973 for (std::string
& o
: tmp
) {
3974 options
.emplace_back(std::move(o
), entry
.Backtrace
);
3977 options
.emplace_back(std::string(opt
.c_str() + 6),
3981 options
.emplace_back(opt
, entry
.Backtrace
);
3984 usedOptions
+= " * " + opt
+ "\n";
3988 if (!usedOptions
.empty()) {
3989 tgt
->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
3991 std::string("Used ") + logName
+ std::string(" for target ") +
3992 tgt
->GetName() + ":\n" + usedOptions
,
3998 std::vector
<BT
<std::string
>> wrapOptions(
3999 std::vector
<std::string
>& options
, const cmListFileBacktrace
& bt
,
4000 const std::vector
<std::string
>& wrapperFlag
, const std::string
& wrapperSep
,
4001 bool concatFlagAndArgs
)
4003 std::vector
<BT
<std::string
>> result
;
4005 if (options
.empty()) {
4009 if (wrapperFlag
.empty()) {
4010 // nothing specified, insert elements as is
4011 result
.reserve(options
.size());
4012 for (std::string
& o
: options
) {
4013 result
.emplace_back(std::move(o
), bt
);
4018 for (std::vector
<std::string
>::size_type index
= 0; index
< options
.size();
4020 if (cmHasLiteralPrefix(options
[index
], "LINKER:")) {
4021 // LINKER wrapper specified, insert elements as is
4022 result
.emplace_back(std::move(options
[index
]), bt
);
4025 if (cmHasLiteralPrefix(options
[index
], "-Wl,")) {
4026 // replace option by LINKER wrapper
4027 result
.emplace_back(options
[index
].replace(0, 4, "LINKER:"), bt
);
4030 if (cmHasLiteralPrefix(options
[index
], "-Xlinker=")) {
4031 // replace option by LINKER wrapper
4032 result
.emplace_back(options
[index
].replace(0, 9, "LINKER:"), bt
);
4035 if (options
[index
] == "-Xlinker") {
4036 // replace option by LINKER wrapper
4037 if (index
+ 1 < options
.size()) {
4038 result
.emplace_back("LINKER:" + options
[++index
], bt
);
4040 result
.emplace_back(std::move(options
[index
]), bt
);
4045 // collect all options which must be transformed
4046 std::vector
<std::string
> opts
;
4047 while (index
< options
.size()) {
4048 if (!cmHasLiteralPrefix(options
[index
], "LINKER:") &&
4049 !cmHasLiteralPrefix(options
[index
], "-Wl,") &&
4050 !cmHasLiteralPrefix(options
[index
], "-Xlinker")) {
4051 opts
.emplace_back(std::move(options
[index
++]));
4061 if (!wrapperSep
.empty()) {
4062 if (concatFlagAndArgs
) {
4063 // insert flag elements except last one
4064 for (auto i
= wrapperFlag
.begin(); i
!= wrapperFlag
.end() - 1; ++i
) {
4065 result
.emplace_back(*i
, bt
);
4067 // concatenate last flag element and all list values
4069 result
.emplace_back(wrapperFlag
.back() + cmJoin(opts
, wrapperSep
), bt
);
4071 for (std::string
const& i
: wrapperFlag
) {
4072 result
.emplace_back(i
, bt
);
4074 // concatenate all list values in one option
4075 result
.emplace_back(cmJoin(opts
, wrapperSep
), bt
);
4078 // prefix each element of list with wrapper
4079 if (concatFlagAndArgs
) {
4080 std::transform(opts
.begin(), opts
.end(), opts
.begin(),
4081 [&wrapperFlag
](std::string
const& o
) -> std::string
{
4082 return wrapperFlag
.back() + o
;
4085 for (std::string
& o
: opts
) {
4086 for (auto i
= wrapperFlag
.begin(),
4087 e
= concatFlagAndArgs
? wrapperFlag
.end() - 1
4088 : wrapperFlag
.end();
4090 result
.emplace_back(*i
, bt
);
4092 result
.emplace_back(std::move(o
), bt
);
4100 void cmGeneratorTarget::GetCompileOptions(std::vector
<std::string
>& result
,
4101 const std::string
& config
,
4102 const std::string
& language
) const
4104 std::vector
<BT
<std::string
>> tmp
= this->GetCompileOptions(config
, language
);
4105 result
.reserve(tmp
.size());
4106 for (BT
<std::string
>& v
: tmp
) {
4107 result
.emplace_back(std::move(v
.Value
));
4111 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetCompileOptions(
4112 std::string
const& config
, std::string
const& language
) const
4114 ConfigAndLanguage
cacheKey(config
, language
);
4116 auto it
= this->CompileOptionsCache
.find(cacheKey
);
4117 if (it
!= this->CompileOptionsCache
.end()) {
4121 std::vector
<BT
<std::string
>> result
;
4122 std::unordered_set
<std::string
> uniqueOptions
;
4124 cmGeneratorExpressionDAGChecker
dagChecker(this, "COMPILE_OPTIONS", nullptr,
4127 cmList debugProperties
{ this->Makefile
->GetDefinition(
4128 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4129 bool debugOptions
= !this->DebugCompileOptionsDone
&&
4130 cm::contains(debugProperties
, "COMPILE_OPTIONS");
4132 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4133 this->DebugCompileOptionsDone
= true;
4136 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4137 this, config
, language
, &dagChecker
, this->CompileOptionsEntries
);
4139 AddInterfaceEntries(this, config
, "INTERFACE_COMPILE_OPTIONS", language
,
4140 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
);
4142 processOptions(this, entries
, result
, uniqueOptions
, debugOptions
,
4143 "compile options", OptionsParse::Shell
);
4145 CompileOptionsCache
.emplace(cacheKey
, result
);
4149 void cmGeneratorTarget::GetCompileFeatures(std::vector
<std::string
>& result
,
4150 const std::string
& config
) const
4152 std::vector
<BT
<std::string
>> tmp
= this->GetCompileFeatures(config
);
4153 result
.reserve(tmp
.size());
4154 for (BT
<std::string
>& v
: tmp
) {
4155 result
.emplace_back(std::move(v
.Value
));
4159 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetCompileFeatures(
4160 std::string
const& config
) const
4162 std::vector
<BT
<std::string
>> result
;
4163 std::unordered_set
<std::string
> uniqueFeatures
;
4165 cmGeneratorExpressionDAGChecker
dagChecker(this, "COMPILE_FEATURES", nullptr,
4168 cmList debugProperties
{ this->Makefile
->GetDefinition(
4169 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4170 bool debugFeatures
= !this->DebugCompileFeaturesDone
&&
4171 cm::contains(debugProperties
, "COMPILE_FEATURES");
4173 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4174 this->DebugCompileFeaturesDone
= true;
4177 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4178 this, config
, std::string(), &dagChecker
, this->CompileFeaturesEntries
);
4180 AddInterfaceEntries(this, config
, "INTERFACE_COMPILE_FEATURES",
4181 std::string(), &dagChecker
, entries
,
4182 IncludeRuntimeInterface::Yes
);
4184 processOptions(this, entries
, result
, uniqueFeatures
, debugFeatures
,
4185 "compile features", OptionsParse::None
);
4190 void cmGeneratorTarget::GetCompileDefinitions(
4191 std::vector
<std::string
>& result
, const std::string
& config
,
4192 const std::string
& language
) const
4194 std::vector
<BT
<std::string
>> tmp
=
4195 this->GetCompileDefinitions(config
, language
);
4196 result
.reserve(tmp
.size());
4197 for (BT
<std::string
>& v
: tmp
) {
4198 result
.emplace_back(std::move(v
.Value
));
4202 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetCompileDefinitions(
4203 std::string
const& config
, std::string
const& language
) const
4205 ConfigAndLanguage
cacheKey(config
, language
);
4207 auto it
= this->CompileDefinitionsCache
.find(cacheKey
);
4208 if (it
!= this->CompileDefinitionsCache
.end()) {
4212 std::vector
<BT
<std::string
>> list
;
4213 std::unordered_set
<std::string
> uniqueOptions
;
4215 cmGeneratorExpressionDAGChecker
dagChecker(this, "COMPILE_DEFINITIONS",
4218 cmList debugProperties
{ this->Makefile
->GetDefinition(
4219 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4220 bool debugDefines
= !this->DebugCompileDefinitionsDone
&&
4221 cm::contains(debugProperties
, "COMPILE_DEFINITIONS");
4223 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4224 this->DebugCompileDefinitionsDone
= true;
4227 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4228 this, config
, language
, &dagChecker
, this->CompileDefinitionsEntries
);
4230 AddInterfaceEntries(this, config
, "INTERFACE_COMPILE_DEFINITIONS", language
,
4231 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
);
4233 if (!config
.empty()) {
4234 std::string configPropName
=
4235 "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config
);
4236 cmValue configProp
= this->GetProperty(configPropName
);
4238 switch (this->Makefile
->GetPolicyStatus(cmPolicies::CMP0043
)) {
4239 case cmPolicies::WARN
: {
4240 this->LocalGenerator
->IssueMessage(
4241 MessageType::AUTHOR_WARNING
,
4242 cmPolicies::GetPolicyWarning(cmPolicies::CMP0043
));
4245 case cmPolicies::OLD
: {
4246 std::unique_ptr
<TargetPropertyEntry
> entry
=
4247 CreateTargetPropertyEntry(
4248 *this->LocalGenerator
->GetCMakeInstance(), *configProp
);
4249 entries
.Entries
.emplace_back(EvaluateTargetPropertyEntry(
4250 this, config
, language
, &dagChecker
, *entry
));
4252 case cmPolicies::NEW
:
4253 case cmPolicies::REQUIRED_ALWAYS
:
4254 case cmPolicies::REQUIRED_IF_USED
:
4260 processOptions(this, entries
, list
, uniqueOptions
, debugDefines
,
4261 "compile definitions", OptionsParse::None
);
4263 this->CompileDefinitionsCache
.emplace(cacheKey
, list
);
4267 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetPrecompileHeaders(
4268 const std::string
& config
, const std::string
& language
) const
4270 ConfigAndLanguage
cacheKey(config
, language
);
4272 auto it
= this->PrecompileHeadersCache
.find(cacheKey
);
4273 if (it
!= this->PrecompileHeadersCache
.end()) {
4277 std::unordered_set
<std::string
> uniqueOptions
;
4279 cmGeneratorExpressionDAGChecker
dagChecker(this, "PRECOMPILE_HEADERS",
4282 cmList debugProperties
{ this->Makefile
->GetDefinition(
4283 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4284 bool debugDefines
= !this->DebugPrecompileHeadersDone
&&
4285 std::find(debugProperties
.begin(), debugProperties
.end(),
4286 "PRECOMPILE_HEADERS") != debugProperties
.end();
4288 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4289 this->DebugPrecompileHeadersDone
= true;
4292 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4293 this, config
, language
, &dagChecker
, this->PrecompileHeadersEntries
);
4295 AddInterfaceEntries(this, config
, "INTERFACE_PRECOMPILE_HEADERS", language
,
4296 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
);
4298 std::vector
<BT
<std::string
>> list
;
4299 processOptions(this, entries
, list
, uniqueOptions
, debugDefines
,
4300 "precompile headers", OptionsParse::None
);
4302 this->PrecompileHeadersCache
.emplace(cacheKey
, list
);
4306 std::string
cmGeneratorTarget::GetPchHeader(const std::string
& config
,
4307 const std::string
& language
,
4308 const std::string
& arch
) const
4310 if (language
!= "C" && language
!= "CXX" && language
!= "OBJC" &&
4311 language
!= "OBJCXX") {
4312 return std::string();
4315 if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
4316 return std::string();
4318 const cmGeneratorTarget
* generatorTarget
= this;
4319 cmValue pchReuseFrom
=
4320 generatorTarget
->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4322 const auto inserted
=
4323 this->PchHeaders
.insert(std::make_pair(language
+ config
+ arch
, ""));
4324 if (inserted
.second
) {
4325 const std::vector
<BT
<std::string
>> headers
=
4326 this->GetPrecompileHeaders(config
, language
);
4327 if (headers
.empty() && !pchReuseFrom
) {
4328 return std::string();
4330 std::string
& filename
= inserted
.first
->second
;
4334 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom
);
4337 const std::map
<std::string
, std::string
> languageToExtension
= {
4340 { "OBJC", ".objc.h" },
4341 { "OBJCXX", ".objcxx.hxx" }
4344 filename
= generatorTarget
->GetSupportDirectory();
4346 if (this->GetGlobalGenerator()->IsMultiConfig()) {
4347 filename
= cmStrCat(filename
, "/", config
);
4351 cmStrCat(filename
, "/cmake_pch", arch
.empty() ? "" : cmStrCat("_", arch
),
4352 languageToExtension
.at(language
));
4354 const std::string filename_tmp
= cmStrCat(filename
, ".tmp");
4355 if (!pchReuseFrom
) {
4356 cmValue pchPrologue
=
4357 this->Makefile
->GetDefinition("CMAKE_PCH_PROLOGUE");
4358 cmValue pchEpilogue
=
4359 this->Makefile
->GetDefinition("CMAKE_PCH_EPILOGUE");
4361 std::string firstHeaderOnDisk
;
4363 cmGeneratedFileStream
file(
4364 filename_tmp
, false,
4365 this->GetGlobalGenerator()->GetMakefileEncoding());
4366 file
<< "/* generated by CMake */\n\n";
4368 file
<< *pchPrologue
<< "\n";
4370 if (this->GetGlobalGenerator()->IsXcode()) {
4371 file
<< "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4373 if (language
== "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4374 file
<< "#ifdef __cplusplus\n";
4376 for (auto const& header_bt
: headers
) {
4377 if (header_bt
.Value
.empty()) {
4380 if (header_bt
.Value
[0] == '<' || header_bt
.Value
[0] == '\"') {
4381 file
<< "#include " << header_bt
.Value
<< "\n";
4383 file
<< "#include \"" << header_bt
.Value
<< "\"\n";
4386 if (cmSystemTools::FileExists(header_bt
.Value
) &&
4387 firstHeaderOnDisk
.empty()) {
4388 firstHeaderOnDisk
= header_bt
.Value
;
4391 if (language
== "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
4392 file
<< "#endif // __cplusplus\n";
4394 if (this->GetGlobalGenerator()->IsXcode()) {
4395 file
<< "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
4398 file
<< *pchEpilogue
<< "\n";
4402 if (!firstHeaderOnDisk
.empty()) {
4403 cmFileTimes::Copy(firstHeaderOnDisk
, filename_tmp
);
4406 cmSystemTools::MoveFileIfDifferent(filename_tmp
, filename
);
4409 return inserted
.first
->second
;
4412 std::string
cmGeneratorTarget::GetPchSource(const std::string
& config
,
4413 const std::string
& language
,
4414 const std::string
& arch
) const
4416 if (language
!= "C" && language
!= "CXX" && language
!= "OBJC" &&
4417 language
!= "OBJCXX") {
4418 return std::string();
4420 const auto inserted
=
4421 this->PchSources
.insert(std::make_pair(language
+ config
+ arch
, ""));
4422 if (inserted
.second
) {
4423 const std::string pchHeader
= this->GetPchHeader(config
, language
, arch
);
4424 if (pchHeader
.empty()) {
4425 return std::string();
4427 std::string
& filename
= inserted
.first
->second
;
4429 const cmGeneratorTarget
* generatorTarget
= this;
4430 cmValue pchReuseFrom
=
4431 generatorTarget
->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4434 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom
);
4437 filename
= cmStrCat(generatorTarget
->GetSupportDirectory(), "/cmake_pch");
4439 // For GCC the source extension will be transformed into .h[xx].gch
4440 if (!this->Makefile
->IsOn("CMAKE_LINK_PCH")) {
4441 const std::map
<std::string
, std::string
> languageToExtension
= {
4443 { "CXX", ".hxx.cxx" },
4444 { "OBJC", ".objc.h.m" },
4445 { "OBJCXX", ".objcxx.hxx.mm" }
4448 filename
= cmStrCat(filename
, arch
.empty() ? "" : cmStrCat("_", arch
),
4449 languageToExtension
.at(language
));
4451 const std::map
<std::string
, std::string
> languageToExtension
= {
4452 { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
4455 filename
= cmStrCat(filename
, arch
.empty() ? "" : cmStrCat("_", arch
),
4456 languageToExtension
.at(language
));
4459 const std::string filename_tmp
= cmStrCat(filename
, ".tmp");
4460 if (!pchReuseFrom
) {
4462 cmGeneratedFileStream
file(filename_tmp
);
4463 file
<< "/* generated by CMake */\n";
4465 cmFileTimes::Copy(pchHeader
, filename_tmp
);
4466 cmSystemTools::MoveFileIfDifferent(filename_tmp
, filename
);
4469 return inserted
.first
->second
;
4472 std::string
cmGeneratorTarget::GetPchFileObject(const std::string
& config
,
4473 const std::string
& language
,
4474 const std::string
& arch
)
4476 if (language
!= "C" && language
!= "CXX" && language
!= "OBJC" &&
4477 language
!= "OBJCXX") {
4478 return std::string();
4480 const auto inserted
=
4481 this->PchObjectFiles
.insert(std::make_pair(language
+ config
+ arch
, ""));
4482 if (inserted
.second
) {
4483 const std::string pchSource
= this->GetPchSource(config
, language
, arch
);
4484 if (pchSource
.empty()) {
4485 return std::string();
4487 std::string
& filename
= inserted
.first
->second
;
4489 auto* pchSf
= this->Makefile
->GetOrCreateSource(
4490 pchSource
, false, cmSourceFileLocationKind::Known
);
4492 filename
= cmStrCat(this->ObjectDirectory
, this->GetObjectName(pchSf
));
4493 if (this->GetGlobalGenerator()->IsMultiConfig()) {
4494 cmSystemTools::ReplaceString(
4495 filename
, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config
);
4498 return inserted
.first
->second
;
4501 std::string
cmGeneratorTarget::GetPchFile(const std::string
& config
,
4502 const std::string
& language
,
4503 const std::string
& arch
)
4505 const auto inserted
=
4506 this->PchFiles
.insert(std::make_pair(language
+ config
+ arch
, ""));
4507 if (inserted
.second
) {
4508 std::string
& pchFile
= inserted
.first
->second
;
4510 const std::string pchExtension
=
4511 this->Makefile
->GetSafeDefinition("CMAKE_PCH_EXTENSION");
4513 if (this->Makefile
->IsOn("CMAKE_LINK_PCH")) {
4514 auto replaceExtension
= [](const std::string
& str
,
4515 const std::string
& ext
) -> std::string
{
4516 auto dot_pos
= str
.rfind('.');
4518 if (dot_pos
!= std::string::npos
) {
4519 result
= str
.substr(0, dot_pos
);
4525 cmGeneratorTarget
* generatorTarget
= this;
4526 cmValue pchReuseFrom
=
4527 generatorTarget
->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
4530 this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom
);
4533 const std::string pchFileObject
=
4534 generatorTarget
->GetPchFileObject(config
, language
, arch
);
4535 if (!pchExtension
.empty()) {
4536 pchFile
= replaceExtension(pchFileObject
, pchExtension
);
4539 pchFile
= this->GetPchHeader(config
, language
, arch
);
4540 pchFile
+= pchExtension
;
4543 return inserted
.first
->second
;
4546 std::string
cmGeneratorTarget::GetPchCreateCompileOptions(
4547 const std::string
& config
, const std::string
& language
,
4548 const std::string
& arch
)
4550 const auto inserted
= this->PchCreateCompileOptions
.insert(
4551 std::make_pair(language
+ config
+ arch
, ""));
4552 if (inserted
.second
) {
4553 std::string
& createOptionList
= inserted
.first
->second
;
4555 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4556 createOptionList
= this->Makefile
->GetSafeDefinition(
4557 cmStrCat("CMAKE_", language
, "_COMPILE_OPTIONS_INVALID_PCH"));
4560 if (this->GetPropertyAsBool("PCH_INSTANTIATE_TEMPLATES")) {
4561 std::string varName
= cmStrCat(
4562 "CMAKE_", language
, "_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH");
4563 std::string instantiateOption
=
4564 this->Makefile
->GetSafeDefinition(varName
);
4565 if (!instantiateOption
.empty()) {
4566 createOptionList
= cmStrCat(createOptionList
, ";", instantiateOption
);
4570 const std::string createOptVar
=
4571 cmStrCat("CMAKE_", language
, "_COMPILE_OPTIONS_CREATE_PCH");
4573 createOptionList
= cmStrCat(
4574 createOptionList
, ";", this->Makefile
->GetSafeDefinition(createOptVar
));
4576 const std::string pchHeader
= this->GetPchHeader(config
, language
, arch
);
4577 const std::string pchFile
= this->GetPchFile(config
, language
, arch
);
4579 cmSystemTools::ReplaceString(createOptionList
, "<PCH_HEADER>", pchHeader
);
4580 cmSystemTools::ReplaceString(createOptionList
, "<PCH_FILE>", pchFile
);
4582 return inserted
.first
->second
;
4585 std::string
cmGeneratorTarget::GetPchUseCompileOptions(
4586 const std::string
& config
, const std::string
& language
,
4587 const std::string
& arch
)
4589 const auto inserted
= this->PchUseCompileOptions
.insert(
4590 std::make_pair(language
+ config
+ arch
, ""));
4591 if (inserted
.second
) {
4592 std::string
& useOptionList
= inserted
.first
->second
;
4594 if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
4595 useOptionList
= this->Makefile
->GetSafeDefinition(
4596 cmStrCat("CMAKE_", language
, "_COMPILE_OPTIONS_INVALID_PCH"));
4599 const std::string useOptVar
=
4600 cmStrCat(language
, "_COMPILE_OPTIONS_USE_PCH");
4602 std::string
const& useOptionListProperty
=
4603 this->GetSafeProperty(useOptVar
);
4605 useOptionList
= cmStrCat(
4607 useOptionListProperty
.empty()
4608 ? this->Makefile
->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar
))
4609 : useOptionListProperty
);
4611 const std::string pchHeader
= this->GetPchHeader(config
, language
, arch
);
4612 const std::string pchFile
= this->GetPchFile(config
, language
, arch
);
4614 cmSystemTools::ReplaceString(useOptionList
, "<PCH_HEADER>", pchHeader
);
4615 cmSystemTools::ReplaceString(useOptionList
, "<PCH_FILE>", pchFile
);
4617 return inserted
.first
->second
;
4620 void cmGeneratorTarget::AddSourceFileToUnityBatch(
4621 const std::string
& sourceFilename
)
4623 this->UnityBatchedSourceFiles
.insert(sourceFilename
);
4626 bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
4627 const std::string
& sourceFilename
) const
4629 if (!this->GetPropertyAsBool("UNITY_BUILD")) {
4633 return this->UnityBatchedSourceFiles
.find(sourceFilename
) !=
4634 this->UnityBatchedSourceFiles
.end();
4637 void cmGeneratorTarget::GetLinkOptions(std::vector
<std::string
>& result
,
4638 const std::string
& config
,
4639 const std::string
& language
) const
4641 if (this->IsDeviceLink() &&
4642 this->GetPolicyStatusCMP0105() != cmPolicies::NEW
) {
4643 // link options are not propagated to the device link step
4647 std::vector
<BT
<std::string
>> tmp
= this->GetLinkOptions(config
, language
);
4648 result
.reserve(tmp
.size());
4649 for (BT
<std::string
>& v
: tmp
) {
4650 result
.emplace_back(std::move(v
.Value
));
4654 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetLinkOptions(
4655 std::string
const& config
, std::string
const& language
) const
4657 ConfigAndLanguage
cacheKey(
4658 config
, cmStrCat(language
, this->IsDeviceLink() ? "-device" : ""));
4660 auto it
= this->LinkOptionsCache
.find(cacheKey
);
4661 if (it
!= this->LinkOptionsCache
.end()) {
4665 std::vector
<BT
<std::string
>> result
;
4666 std::unordered_set
<std::string
> uniqueOptions
;
4668 cmGeneratorExpressionDAGChecker
dagChecker(this, "LINK_OPTIONS", nullptr,
4671 cmList debugProperties
{ this->Makefile
->GetDefinition(
4672 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4673 bool debugOptions
= !this->DebugLinkOptionsDone
&&
4674 cm::contains(debugProperties
, "LINK_OPTIONS");
4676 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4677 this->DebugLinkOptionsDone
= true;
4680 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4681 this, config
, language
, &dagChecker
, this->LinkOptionsEntries
);
4683 AddInterfaceEntries(this, config
, "INTERFACE_LINK_OPTIONS", language
,
4684 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
,
4685 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4686 ? LinkInterfaceFor::Link
4687 : LinkInterfaceFor::Usage
);
4689 processOptions(this, entries
, result
, uniqueOptions
, debugOptions
,
4690 "link options", OptionsParse::Shell
, this->IsDeviceLink());
4692 if (this->IsDeviceLink()) {
4693 // wrap host link options
4694 const std::string
wrapper(this->Makefile
->GetSafeDefinition(
4695 "CMAKE_" + language
+ "_DEVICE_COMPILER_WRAPPER_FLAG"));
4696 cmList wrapperFlag
{ wrapper
};
4697 const std::string
wrapperSep(this->Makefile
->GetSafeDefinition(
4698 "CMAKE_" + language
+ "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
4699 bool concatFlagAndArgs
= true;
4700 if (!wrapperFlag
.empty() && wrapperFlag
.back() == " ") {
4701 concatFlagAndArgs
= false;
4702 wrapperFlag
.pop_back();
4705 auto it
= result
.begin();
4706 while (it
!= result
.end()) {
4707 if (it
->Value
== DL_BEGIN
) {
4708 // device link options, no treatment
4709 it
= result
.erase(it
);
4710 it
= std::find_if(it
, result
.end(), [](const BT
<std::string
>& item
) {
4711 return item
.Value
== DL_END
;
4713 if (it
!= result
.end()) {
4714 it
= result
.erase(it
);
4717 // host link options must be wrapped
4718 std::vector
<std::string
> options
;
4719 cmSystemTools::ParseUnixCommandLine(it
->Value
.c_str(), options
);
4720 auto hostOptions
= wrapOptions(options
, it
->Backtrace
, wrapperFlag
,
4721 wrapperSep
, concatFlagAndArgs
);
4722 it
= result
.erase(it
);
4723 // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
4724 // C++11 standard: 'std::vector::insert()' do not returns an iterator,
4725 // so need to recompute the iterator after insertion.
4726 if (it
== result
.end()) {
4727 cm::append(result
, hostOptions
);
4730 auto index
= it
- result
.begin();
4731 result
.insert(it
, hostOptions
.begin(), hostOptions
.end());
4732 it
= result
.begin() + index
+ hostOptions
.size();
4738 // Last step: replace "LINKER:" prefixed elements by
4739 // actual linker wrapper
4740 result
= this->ResolveLinkerWrapper(result
, language
);
4742 this->LinkOptionsCache
.emplace(cacheKey
, result
);
4746 std::vector
<BT
<std::string
>>& cmGeneratorTarget::ResolveLinkerWrapper(
4747 std::vector
<BT
<std::string
>>& result
, const std::string
& language
,
4748 bool joinItems
) const
4750 // replace "LINKER:" prefixed elements by actual linker wrapper
4751 const std::string
wrapper(this->Makefile
->GetSafeDefinition(
4752 "CMAKE_" + language
+
4753 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
4754 : "_LINKER_WRAPPER_FLAG")));
4755 cmList wrapperFlag
{ wrapper
};
4756 const std::string
wrapperSep(this->Makefile
->GetSafeDefinition(
4757 "CMAKE_" + language
+
4758 (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
4759 : "_LINKER_WRAPPER_FLAG_SEP")));
4760 bool concatFlagAndArgs
= true;
4761 if (!wrapperFlag
.empty() && wrapperFlag
.back() == " ") {
4762 concatFlagAndArgs
= false;
4763 wrapperFlag
.pop_back();
4766 const std::string LINKER
{ "LINKER:" };
4767 const std::string SHELL
{ "SHELL:" };
4768 const std::string LINKER_SHELL
= LINKER
+ SHELL
;
4770 std::vector
<BT
<std::string
>>::iterator entry
;
4771 while ((entry
= std::find_if(result
.begin(), result
.end(),
4772 [&LINKER
](BT
<std::string
> const& item
) -> bool {
4773 return item
.Value
.compare(0, LINKER
.length(),
4775 })) != result
.end()) {
4776 std::string value
= std::move(entry
->Value
);
4777 cmListFileBacktrace bt
= std::move(entry
->Backtrace
);
4778 entry
= result
.erase(entry
);
4780 std::vector
<std::string
> linkerOptions
;
4781 if (value
.compare(0, LINKER_SHELL
.length(), LINKER_SHELL
) == 0) {
4782 cmSystemTools::ParseUnixCommandLine(
4783 value
.c_str() + LINKER_SHELL
.length(), linkerOptions
);
4785 linkerOptions
= cmTokenize(value
.substr(LINKER
.length()), ",");
4788 if (linkerOptions
.empty() ||
4789 (linkerOptions
.size() == 1 && linkerOptions
.front().empty())) {
4793 // for now, raise an error if prefix SHELL: is part of arguments
4794 if (std::find_if(linkerOptions
.begin(), linkerOptions
.end(),
4795 [&SHELL
](const std::string
& item
) -> bool {
4796 return item
.find(SHELL
) != std::string::npos
;
4797 }) != linkerOptions
.end()) {
4798 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
4799 MessageType::FATAL_ERROR
,
4800 "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
4801 this->GetBacktrace());
4805 std::vector
<BT
<std::string
>> options
= wrapOptions(
4806 linkerOptions
, bt
, wrapperFlag
, wrapperSep
, concatFlagAndArgs
);
4808 result
.insert(entry
,
4809 cmJoin(cmRange
<decltype(options
.cbegin())>(
4810 options
.cbegin(), options
.cend()),
4813 result
.insert(entry
, options
.begin(), options
.end());
4819 void cmGeneratorTarget::GetStaticLibraryLinkOptions(
4820 std::vector
<std::string
>& result
, const std::string
& config
,
4821 const std::string
& language
) const
4823 std::vector
<BT
<std::string
>> tmp
=
4824 this->GetStaticLibraryLinkOptions(config
, language
);
4825 result
.reserve(tmp
.size());
4826 for (BT
<std::string
>& v
: tmp
) {
4827 result
.emplace_back(std::move(v
.Value
));
4831 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
4832 std::string
const& config
, std::string
const& language
) const
4834 std::vector
<BT
<std::string
>> result
;
4835 std::unordered_set
<std::string
> uniqueOptions
;
4837 cmGeneratorExpressionDAGChecker
dagChecker(this, "STATIC_LIBRARY_OPTIONS",
4840 EvaluatedTargetPropertyEntries entries
;
4841 if (cmValue linkOptions
= this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
4842 std::unique_ptr
<TargetPropertyEntry
> entry
= CreateTargetPropertyEntry(
4843 *this->LocalGenerator
->GetCMakeInstance(), *linkOptions
);
4844 entries
.Entries
.emplace_back(EvaluateTargetPropertyEntry(
4845 this, config
, language
, &dagChecker
, *entry
));
4847 processOptions(this, entries
, result
, uniqueOptions
, false,
4848 "static library link options", OptionsParse::Shell
);
4854 void processLinkDirectories(cmGeneratorTarget
const* tgt
,
4855 EvaluatedTargetPropertyEntries
& entries
,
4856 std::vector
<BT
<std::string
>>& directories
,
4857 std::unordered_set
<std::string
>& uniqueDirectories
,
4858 bool debugDirectories
)
4860 for (EvaluatedTargetPropertyEntry
& entry
: entries
.Entries
) {
4861 cmLinkImplItem
const& item
= entry
.LinkImplItem
;
4862 std::string
const& targetName
= item
.AsStr();
4864 std::string usedDirectories
;
4865 for (std::string
& entryDirectory
: entry
.Values
) {
4866 if (!cmSystemTools::FileIsFullPath(entryDirectory
)) {
4867 std::ostringstream e
;
4868 bool noMessage
= false;
4869 MessageType messageType
= MessageType::FATAL_ERROR
;
4870 if (!targetName
.empty()) {
4871 /* clang-format off */
4872 e
<< "Target \"" << targetName
<< "\" contains relative "
4873 "path in its INTERFACE_LINK_DIRECTORIES:\n"
4874 " \"" << entryDirectory
<< "\"";
4875 /* clang-format on */
4877 switch (tgt
->GetPolicyStatusCMP0081()) {
4878 case cmPolicies::WARN
: {
4879 e
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0081
) << "\n";
4880 messageType
= MessageType::AUTHOR_WARNING
;
4882 case cmPolicies::OLD
:
4885 case cmPolicies::REQUIRED_IF_USED
:
4886 case cmPolicies::REQUIRED_ALWAYS
:
4887 case cmPolicies::NEW
:
4888 // Issue the fatal message.
4891 e
<< "Found relative path while evaluating link directories of "
4893 << tgt
->GetName() << "\":\n \"" << entryDirectory
<< "\"\n";
4896 tgt
->GetLocalGenerator()->IssueMessage(messageType
, e
.str());
4897 if (messageType
== MessageType::FATAL_ERROR
) {
4903 // Sanitize the path the same way the link_directories command does
4904 // in case projects set the LINK_DIRECTORIES property directly.
4905 cmSystemTools::ConvertToUnixSlashes(entryDirectory
);
4906 if (uniqueDirectories
.insert(entryDirectory
).second
) {
4907 directories
.emplace_back(entryDirectory
, entry
.Backtrace
);
4908 if (debugDirectories
) {
4909 usedDirectories
+= " * " + entryDirectory
+ "\n";
4913 if (!usedDirectories
.empty()) {
4914 tgt
->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
4916 std::string("Used link directories for target ") + tgt
->GetName() +
4917 ":\n" + usedDirectories
,
4924 void cmGeneratorTarget::GetLinkDirectories(std::vector
<std::string
>& result
,
4925 const std::string
& config
,
4926 const std::string
& language
) const
4928 std::vector
<BT
<std::string
>> tmp
=
4929 this->GetLinkDirectories(config
, language
);
4930 result
.reserve(tmp
.size());
4931 for (BT
<std::string
>& v
: tmp
) {
4932 result
.emplace_back(std::move(v
.Value
));
4936 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetLinkDirectories(
4937 std::string
const& config
, std::string
const& language
) const
4939 ConfigAndLanguage
cacheKey(
4940 config
, cmStrCat(language
, this->IsDeviceLink() ? "-device" : ""));
4942 auto it
= this->LinkDirectoriesCache
.find(cacheKey
);
4943 if (it
!= this->LinkDirectoriesCache
.end()) {
4947 std::vector
<BT
<std::string
>> result
;
4948 std::unordered_set
<std::string
> uniqueDirectories
;
4950 cmGeneratorExpressionDAGChecker
dagChecker(this, "LINK_DIRECTORIES", nullptr,
4953 cmList debugProperties
{ this->Makefile
->GetDefinition(
4954 "CMAKE_DEBUG_TARGET_PROPERTIES") };
4955 bool debugDirectories
= !this->DebugLinkDirectoriesDone
&&
4956 cm::contains(debugProperties
, "LINK_DIRECTORIES");
4958 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
4959 this->DebugLinkDirectoriesDone
= true;
4962 EvaluatedTargetPropertyEntries entries
= EvaluateTargetPropertyEntries(
4963 this, config
, language
, &dagChecker
, this->LinkDirectoriesEntries
);
4965 AddInterfaceEntries(this, config
, "INTERFACE_LINK_DIRECTORIES", language
,
4966 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
,
4967 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
4968 ? LinkInterfaceFor::Link
4969 : LinkInterfaceFor::Usage
);
4971 processLinkDirectories(this, entries
, result
, uniqueDirectories
,
4974 this->LinkDirectoriesCache
.emplace(cacheKey
, result
);
4978 void cmGeneratorTarget::GetLinkDepends(std::vector
<std::string
>& result
,
4979 const std::string
& config
,
4980 const std::string
& language
) const
4982 std::vector
<BT
<std::string
>> tmp
= this->GetLinkDepends(config
, language
);
4983 result
.reserve(tmp
.size());
4984 for (BT
<std::string
>& v
: tmp
) {
4985 result
.emplace_back(std::move(v
.Value
));
4989 std::vector
<BT
<std::string
>> cmGeneratorTarget::GetLinkDepends(
4990 std::string
const& config
, std::string
const& language
) const
4992 std::vector
<BT
<std::string
>> result
;
4993 std::unordered_set
<std::string
> uniqueOptions
;
4994 cmGeneratorExpressionDAGChecker
dagChecker(this, "LINK_DEPENDS", nullptr,
4997 EvaluatedTargetPropertyEntries entries
;
4998 if (cmValue linkDepends
= this->GetProperty("LINK_DEPENDS")) {
4999 cmList depends
{ *linkDepends
};
5000 for (const auto& depend
: depends
) {
5001 std::unique_ptr
<TargetPropertyEntry
> entry
= CreateTargetPropertyEntry(
5002 *this->LocalGenerator
->GetCMakeInstance(), depend
);
5003 entries
.Entries
.emplace_back(EvaluateTargetPropertyEntry(
5004 this, config
, language
, &dagChecker
, *entry
));
5007 AddInterfaceEntries(this, config
, "INTERFACE_LINK_DEPENDS", language
,
5008 &dagChecker
, entries
, IncludeRuntimeInterface::Yes
,
5009 this->GetPolicyStatusCMP0099() == cmPolicies::NEW
5010 ? LinkInterfaceFor::Link
5011 : LinkInterfaceFor::Usage
);
5013 processOptions(this, entries
, result
, uniqueOptions
, false, "link depends",
5014 OptionsParse::None
);
5019 void cmGeneratorTarget::ComputeTargetManifest(const std::string
& config
) const
5021 if (this->IsImported()) {
5024 cmGlobalGenerator
* gg
= this->LocalGenerator
->GetGlobalGenerator();
5027 cmGeneratorTarget::Names targetNames
;
5028 if (this->GetType() == cmStateEnums::EXECUTABLE
) {
5029 targetNames
= this->GetExecutableNames(config
);
5030 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY
||
5031 this->GetType() == cmStateEnums::SHARED_LIBRARY
||
5032 this->GetType() == cmStateEnums::MODULE_LIBRARY
) {
5033 targetNames
= this->GetLibraryNames(config
);
5038 // Get the directory.
5040 this->GetDirectory(config
, cmStateEnums::RuntimeBinaryArtifact
);
5044 if (!targetNames
.Output
.empty()) {
5045 f
= cmStrCat(dir
, '/', targetNames
.Output
);
5046 gg
->AddToManifest(f
);
5048 if (!targetNames
.SharedObject
.empty()) {
5049 f
= cmStrCat(dir
, '/', targetNames
.SharedObject
);
5050 gg
->AddToManifest(f
);
5052 if (!targetNames
.Real
.empty()) {
5053 f
= cmStrCat(dir
, '/', targetNames
.Real
);
5054 gg
->AddToManifest(f
);
5056 if (!targetNames
.PDB
.empty()) {
5057 f
= cmStrCat(dir
, '/', targetNames
.PDB
);
5058 gg
->AddToManifest(f
);
5061 dir
= this->GetDirectory(config
, cmStateEnums::ImportLibraryArtifact
);
5062 if (!targetNames
.ImportOutput
.empty()) {
5063 f
= cmStrCat(dir
, '/', targetNames
.ImportOutput
);
5064 gg
->AddToManifest(f
);
5066 if (!targetNames
.ImportLibrary
.empty()) {
5067 f
= cmStrCat(dir
, '/', targetNames
.ImportLibrary
);
5068 gg
->AddToManifest(f
);
5070 if (!targetNames
.ImportReal
.empty()) {
5071 f
= cmStrCat(dir
, '/', targetNames
.ImportReal
);
5072 gg
->AddToManifest(f
);
5076 cm::optional
<cmStandardLevel
> cmGeneratorTarget::GetExplicitStandardLevel(
5077 std::string
const& lang
, std::string
const& config
) const
5079 cm::optional
<cmStandardLevel
> level
;
5080 std::string key
= cmStrCat(cmSystemTools::UpperCase(config
), '-', lang
);
5081 auto i
= this->ExplicitStandardLevel
.find(key
);
5082 if (i
!= this->ExplicitStandardLevel
.end()) {
5088 void cmGeneratorTarget::UpdateExplicitStandardLevel(std::string
const& lang
,
5089 std::string
const& config
,
5090 cmStandardLevel level
)
5092 auto e
= this->ExplicitStandardLevel
.emplace(
5093 cmStrCat(cmSystemTools::UpperCase(config
), '-', lang
), level
);
5094 if (!e
.second
&& e
.first
->second
< level
) {
5095 e
.first
->second
= level
;
5099 bool cmGeneratorTarget::ComputeCompileFeatures(std::string
const& config
)
5101 cmStandardLevelResolver
standardResolver(this->Makefile
);
5103 for (std::string
const& lang
:
5104 this->Makefile
->GetState()->GetEnabledLanguages()) {
5105 if (cmValue languageStd
= this->GetLanguageStandard(lang
, config
)) {
5106 if (cm::optional
<cmStandardLevel
> langLevel
=
5107 standardResolver
.LanguageStandardLevel(lang
, *languageStd
)) {
5108 this->UpdateExplicitStandardLevel(lang
, config
, *langLevel
);
5113 // Compute the language standard based on the compile features.
5114 std::vector
<BT
<std::string
>> features
= this->GetCompileFeatures(config
);
5115 for (BT
<std::string
> const& f
: features
) {
5117 if (!standardResolver
.CompileFeatureKnown(this->Target
->GetName(), f
.Value
,
5122 std::string key
= cmStrCat(cmSystemTools::UpperCase(config
), '-', lang
);
5123 cmValue currentLanguageStandard
= this->GetLanguageStandard(lang
, config
);
5125 cm::optional
<cmStandardLevel
> featureLevel
;
5126 std::string newRequiredStandard
;
5127 if (!standardResolver
.GetNewRequiredStandard(
5128 this->Target
->GetName(), f
.Value
, currentLanguageStandard
,
5129 featureLevel
, newRequiredStandard
)) {
5134 this->UpdateExplicitStandardLevel(lang
, config
, *featureLevel
);
5137 if (!newRequiredStandard
.empty()) {
5138 BTs
<std::string
>& languageStandardProperty
=
5139 this->LanguageStandardMap
[key
];
5140 if (languageStandardProperty
.Value
!= newRequiredStandard
) {
5141 languageStandardProperty
.Value
= newRequiredStandard
;
5142 languageStandardProperty
.Backtraces
.clear();
5144 languageStandardProperty
.Backtraces
.emplace_back(f
.Backtrace
);
5151 bool cmGeneratorTarget::ComputeCompileFeatures(
5152 std::string
const& config
, std::set
<LanguagePair
> const& languagePairs
)
5154 for (const auto& language
: languagePairs
) {
5155 BTs
<std::string
> const* generatorTargetLanguageStandard
=
5156 this->GetLanguageStandardProperty(language
.first
, config
);
5157 if (!generatorTargetLanguageStandard
) {
5158 // If the standard isn't explicitly set we copy it over from the
5159 // specified paired language.
5161 cmStrCat(cmSystemTools::UpperCase(config
), '-', language
.first
);
5162 BTs
<std::string
> const* standardToCopy
=
5163 this->GetLanguageStandardProperty(language
.second
, config
);
5164 if (standardToCopy
) {
5165 this->LanguageStandardMap
[key
] = *standardToCopy
;
5166 generatorTargetLanguageStandard
= &this->LanguageStandardMap
[key
];
5168 cmValue defaultStandard
= this->Makefile
->GetDefinition(
5169 cmStrCat("CMAKE_", language
.second
, "_STANDARD_DEFAULT"));
5170 if (defaultStandard
) {
5171 this->LanguageStandardMap
[key
] = BTs
<std::string
>(*defaultStandard
);
5172 generatorTargetLanguageStandard
= &this->LanguageStandardMap
[key
];
5176 // Custom updates for the CUDA standard.
5177 if (generatorTargetLanguageStandard
!= nullptr &&
5178 (language
.first
== "CUDA")) {
5179 if (generatorTargetLanguageStandard
->Value
== "98") {
5180 this->LanguageStandardMap
[key
].Value
= "03";
5189 std::string
cmGeneratorTarget::GetImportedLibName(
5190 std::string
const& config
) const
5192 if (cmGeneratorTarget::ImportInfo
const* info
=
5193 this->GetImportInfo(config
)) {
5194 return info
->LibName
;
5196 return std::string();
5199 std::string
cmGeneratorTarget::GetFullPath(const std::string
& config
,
5200 cmStateEnums::ArtifactType artifact
,
5201 bool realname
) const
5203 if (this->IsImported()) {
5204 return this->Target
->ImportedGetFullPath(config
, artifact
);
5206 return this->NormalGetFullPath(config
, artifact
, realname
);
5209 std::string
cmGeneratorTarget::NormalGetFullPath(
5210 const std::string
& config
, cmStateEnums::ArtifactType artifact
,
5211 bool realname
) const
5213 std::string fpath
= cmStrCat(this->GetDirectory(config
, artifact
), '/');
5214 if (this->IsAppBundleOnApple()) {
5216 cmStrCat(this->BuildBundleDirectory(fpath
, config
, FullLevel
), '/');
5219 // Add the full name of the target.
5221 case cmStateEnums::RuntimeBinaryArtifact
:
5223 fpath
+= this->NormalGetRealName(config
);
5226 this->GetFullName(config
, cmStateEnums::RuntimeBinaryArtifact
);
5229 case cmStateEnums::ImportLibraryArtifact
:
5232 this->NormalGetRealName(config
, cmStateEnums::ImportLibraryArtifact
);
5235 this->GetFullName(config
, cmStateEnums::ImportLibraryArtifact
);
5242 std::string
cmGeneratorTarget::NormalGetRealName(
5243 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
5245 // This should not be called for imported targets.
5246 // TODO: Split cmTarget into a class hierarchy to get compile-time
5247 // enforcement of the limited imported target API.
5248 if (this->IsImported()) {
5249 std::string msg
= cmStrCat("NormalGetRealName called on imported target: ",
5251 this->LocalGenerator
->IssueMessage(MessageType::INTERNAL_ERROR
, msg
);
5254 Names names
= this->GetType() == cmStateEnums::EXECUTABLE
5255 ? this->GetExecutableNames(config
)
5256 : this->GetLibraryNames(config
);
5258 // Compute the real name that will be built.
5259 return artifact
== cmStateEnums::RuntimeBinaryArtifact
? names
.Real
5263 cmGeneratorTarget::Names
cmGeneratorTarget::GetLibraryNames(
5264 const std::string
& config
) const
5266 cmGeneratorTarget::Names targetNames
;
5268 // This should not be called for imported targets.
5269 // TODO: Split cmTarget into a class hierarchy to get compile-time
5270 // enforcement of the limited imported target API.
5271 if (this->IsImported()) {
5273 cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
5274 this->LocalGenerator
->IssueMessage(MessageType::INTERNAL_ERROR
, msg
);
5277 // Check for library version properties.
5278 cmValue version
= this->GetProperty("VERSION");
5279 cmValue soversion
= this->GetProperty("SOVERSION");
5280 if (!this->HasSOName(config
) ||
5281 this->Makefile
->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
5282 this->IsFrameworkOnApple()) {
5283 // Versioning is supported only for shared libraries and modules,
5284 // and then only when the platform supports an soname flag.
5286 soversion
= nullptr;
5288 if (version
&& !soversion
) {
5289 // The soversion must be set if the library version is set. Use
5290 // the library version as the soversion.
5291 soversion
= version
;
5293 if (!version
&& soversion
) {
5294 // Use the soversion as the library version.
5295 version
= soversion
;
5298 // Get the components of the library name.
5299 NameComponents
const& components
= this->GetFullNameInternalComponents(
5300 config
, cmStateEnums::RuntimeBinaryArtifact
);
5302 // The library name.
5303 targetNames
.Base
= components
.base
;
5304 targetNames
.Output
=
5305 cmStrCat(components
.prefix
, targetNames
.Base
, components
.suffix
);
5307 if (this->IsFrameworkOnApple()) {
5308 targetNames
.Real
= components
.prefix
;
5309 if (!this->Makefile
->PlatformIsAppleEmbedded()) {
5311 cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
5313 targetNames
.Real
+= cmStrCat(targetNames
.Base
, components
.suffix
);
5314 targetNames
.SharedObject
= targetNames
.Real
;
5316 // The library's soname.
5317 this->ComputeVersionedName(targetNames
.SharedObject
, components
.prefix
,
5318 targetNames
.Base
, components
.suffix
,
5319 targetNames
.Output
, soversion
);
5321 // The library's real name on disk.
5322 this->ComputeVersionedName(targetNames
.Real
, components
.prefix
,
5323 targetNames
.Base
, components
.suffix
,
5324 targetNames
.Output
, version
);
5327 // The import library names.
5328 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
5329 this->GetType() == cmStateEnums::MODULE_LIBRARY
) {
5330 NameComponents
const& importComponents
=
5331 this->GetFullNameInternalComponents(config
,
5332 cmStateEnums::ImportLibraryArtifact
);
5333 targetNames
.ImportOutput
= cmStrCat(
5334 importComponents
.prefix
, importComponents
.base
, importComponents
.suffix
);
5336 if (this->IsFrameworkOnApple() && this->IsSharedLibraryWithExports()) {
5337 targetNames
.ImportReal
= components
.prefix
;
5338 if (!this->Makefile
->PlatformIsAppleEmbedded()) {
5339 targetNames
.ImportReal
+=
5340 cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
5342 targetNames
.ImportReal
+=
5343 cmStrCat(importComponents
.base
, importComponents
.suffix
);
5344 targetNames
.ImportLibrary
= targetNames
.ImportOutput
;
5346 // The import library's soname.
5347 this->ComputeVersionedName(
5348 targetNames
.ImportLibrary
, importComponents
.prefix
,
5349 importComponents
.base
, importComponents
.suffix
,
5350 targetNames
.ImportOutput
, soversion
);
5352 // The import library's real name on disk.
5353 this->ComputeVersionedName(
5354 targetNames
.ImportReal
, importComponents
.prefix
, importComponents
.base
,
5355 importComponents
.suffix
, targetNames
.ImportOutput
, version
);
5359 // The program database file name.
5360 targetNames
.PDB
= this->GetPDBName(config
);
5365 cmGeneratorTarget::Names
cmGeneratorTarget::GetExecutableNames(
5366 const std::string
& config
) const
5368 cmGeneratorTarget::Names targetNames
;
5370 // This should not be called for imported targets.
5371 // TODO: Split cmTarget into a class hierarchy to get compile-time
5372 // enforcement of the limited imported target API.
5373 if (this->IsImported()) {
5374 std::string msg
= cmStrCat(
5375 "GetExecutableNames called on imported target: ", this->GetName());
5376 this->LocalGenerator
->IssueMessage(MessageType::INTERNAL_ERROR
, msg
);
5379 // This versioning is supported only for executables and then only
5380 // when the platform supports symbolic links.
5381 #if defined(_WIN32) && !defined(__CYGWIN__)
5384 // Check for executable version properties.
5385 cmValue version
= this->GetProperty("VERSION");
5386 if (this->GetType() != cmStateEnums::EXECUTABLE
||
5387 this->Makefile
->IsOn("XCODE")) {
5392 // Get the components of the executable name.
5393 NameComponents
const& components
= this->GetFullNameInternalComponents(
5394 config
, cmStateEnums::RuntimeBinaryArtifact
);
5396 // The executable name.
5397 targetNames
.Base
= components
.base
;
5398 targetNames
.Output
=
5399 components
.prefix
+ targetNames
.Base
+ components
.suffix
;
5401 // The executable's real name on disk.
5402 #if defined(__CYGWIN__)
5403 targetNames
.Real
= components
.prefix
+ targetNames
.Base
;
5405 targetNames
.Real
= targetNames
.Output
;
5408 targetNames
.Real
+= "-";
5409 targetNames
.Real
+= *version
;
5411 #if defined(__CYGWIN__)
5412 targetNames
.Real
+= components
.suffix
;
5415 // The import library name.
5416 targetNames
.ImportLibrary
=
5417 this->GetFullNameInternal(config
, cmStateEnums::ImportLibraryArtifact
);
5418 targetNames
.ImportReal
= targetNames
.ImportLibrary
;
5419 targetNames
.ImportOutput
= targetNames
.ImportLibrary
;
5421 // The program database file name.
5422 targetNames
.PDB
= this->GetPDBName(config
);
5427 std::string
cmGeneratorTarget::GetFullNameInternal(
5428 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
5430 NameComponents
const& components
=
5431 this->GetFullNameInternalComponents(config
, artifact
);
5432 return components
.prefix
+ components
.base
+ components
.suffix
;
5435 std::string
cmGeneratorTarget::ImportedGetLocation(
5436 const std::string
& config
) const
5438 assert(this->IsImported());
5439 return this->Target
->ImportedGetFullPath(
5440 config
, cmStateEnums::RuntimeBinaryArtifact
);
5443 std::string
cmGeneratorTarget::GetFullNameImported(
5444 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
5446 return cmSystemTools::GetFilenameName(
5447 this->Target
->ImportedGetFullPath(config
, artifact
));
5450 cmGeneratorTarget::NameComponents
const&
5451 cmGeneratorTarget::GetFullNameInternalComponents(
5452 std::string
const& config
, cmStateEnums::ArtifactType artifact
) const
5454 assert(artifact
== cmStateEnums::RuntimeBinaryArtifact
||
5455 artifact
== cmStateEnums::ImportLibraryArtifact
);
5456 FullNameCache
& cache
= artifact
== cmStateEnums::RuntimeBinaryArtifact
5457 ? RuntimeBinaryFullNameCache
5458 : ImportLibraryFullNameCache
;
5459 auto search
= cache
.find(config
);
5460 if (search
!= cache
.end()) {
5461 return search
->second
;
5463 // Use just the target name for non-main target types.
5464 if (this->GetType() != cmStateEnums::STATIC_LIBRARY
&&
5465 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
5466 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
5467 this->GetType() != cmStateEnums::EXECUTABLE
) {
5468 NameComponents components
;
5469 components
.base
= this->GetName();
5470 return cache
.emplace(config
, std::move(components
)).first
->second
;
5473 const bool isImportedLibraryArtifact
=
5474 (artifact
== cmStateEnums::ImportLibraryArtifact
);
5476 // Return an empty name for the import library if this platform
5477 // does not support import libraries.
5478 if (isImportedLibraryArtifact
&& !this->NeedImportLibraryName(config
)) {
5479 return cache
.emplace(config
, NameComponents()).first
->second
;
5482 NameComponents parts
;
5483 std::string
& outPrefix
= parts
.prefix
;
5484 std::string
& outBase
= parts
.base
;
5485 std::string
& outSuffix
= parts
.suffix
;
5487 // retrieve prefix and suffix
5488 std::string ll
= this->GetLinkerLanguage(config
);
5489 cmValue targetPrefix
= this->GetFilePrefixInternal(config
, artifact
, ll
);
5490 cmValue targetSuffix
= this->GetFileSuffixInternal(config
, artifact
, ll
);
5492 // The implib option is only allowed for shared libraries, module
5493 // libraries, and executables.
5494 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
5495 this->GetType() != cmStateEnums::MODULE_LIBRARY
&&
5496 this->GetType() != cmStateEnums::EXECUTABLE
) {
5497 artifact
= cmStateEnums::RuntimeBinaryArtifact
;
5500 // Compute the full name for main target types.
5501 std::string configPostfix
= this->GetFilePostfix(config
);
5503 // frameworks have directory prefix
5504 std::string fw_prefix
;
5505 if (this->IsFrameworkOnApple()) {
5507 cmStrCat(this->GetFrameworkDirectory(config
, ContentLevel
), '/');
5508 targetPrefix
= cmValue(fw_prefix
);
5509 if (!isImportedLibraryArtifact
) {
5511 targetSuffix
= nullptr;
5515 if (this->IsCFBundleOnApple()) {
5516 fw_prefix
= cmStrCat(this->GetCFBundleDirectory(config
, FullLevel
), '/');
5517 targetPrefix
= cmValue(fw_prefix
);
5518 targetSuffix
= nullptr;
5521 // Begin the final name with the prefix.
5522 outPrefix
= targetPrefix
? *targetPrefix
: "";
5524 // Append the target name or property-specified name.
5525 outBase
+= this->GetOutputName(config
, artifact
);
5527 // Append the per-configuration postfix.
5528 // When using Xcode, the postfix should be part of the suffix rather than
5529 // the base, because the suffix ends up being used in Xcode's
5530 // EXECUTABLE_SUFFIX attribute.
5531 if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->IsXcode()) {
5532 configPostfix
+= *targetSuffix
;
5533 targetSuffix
= cmValue(configPostfix
);
5535 outBase
+= configPostfix
;
5538 // Name shared libraries with their version number on some platforms.
5539 if (cmValue soversion
= this->GetProperty("SOVERSION")) {
5541 if (this->IsDLLPlatform()) {
5542 dllProp
= this->GetProperty("DLL_NAME_WITH_SOVERSION");
5544 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
&&
5545 !isImportedLibraryArtifact
&&
5547 (!dllProp
.IsSet() &&
5548 this->Makefile
->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")))) {
5550 outBase
+= *soversion
;
5554 // Append the suffix.
5555 outSuffix
= targetSuffix
? *targetSuffix
: "";
5557 return cache
.emplace(config
, std::move(parts
)).first
->second
;
5560 std::string
cmGeneratorTarget::GetLinkerLanguage(
5561 const std::string
& config
) const
5563 return this->GetLinkClosure(config
)->LinkerLanguage
;
5566 std::string
cmGeneratorTarget::GetLinkerTool(const std::string
& config
) const
5568 return this->GetLinkerTool(this->GetLinkerLanguage(config
), config
);
5571 std::string
cmGeneratorTarget::GetLinkerTool(const std::string
& lang
,
5572 const std::string
& config
) const
5575 cmStrCat("CMAKE_", lang
, "_USING_", this->IsDeviceLink() ? "DEVICE_" : "",
5577 auto format
= this->Makefile
->GetDefinition(cmStrCat(usingLinker
, "MODE"));
5578 if (!format
|| format
!= "TOOL"_s
) {
5579 return this->Makefile
->GetDefinition("CMAKE_LINKER");
5582 auto linkerType
= this->GetLinkerTypeProperty(lang
, config
);
5583 if (linkerType
.empty()) {
5584 linkerType
= "DEFAULT";
5586 usingLinker
= cmStrCat(usingLinker
, linkerType
);
5587 auto linkerTool
= this->Makefile
->GetDefinition(usingLinker
);
5590 if (this->GetGlobalGenerator()->IsVisualStudio() &&
5591 linkerType
== "DEFAULT"_s
) {
5592 return std::string
{};
5595 // fall-back to generic definition
5596 linkerTool
= this->Makefile
->GetDefinition("CMAKE_LINKER");
5598 if (linkerType
!= "DEFAULT"_s
) {
5599 auto isCMakeLinkerType
= [](const std::string
& type
) -> bool {
5600 return std::all_of(type
.cbegin(), type
.cend(),
5601 [](char c
) { return std::isupper(c
); });
5603 if (isCMakeLinkerType(linkerType
)) {
5604 this->LocalGenerator
->IssueMessage(
5605 MessageType::FATAL_ERROR
,
5606 cmStrCat("LINKER_TYPE '", linkerType
,
5607 "' is unknown or not supported by this toolchain."));
5609 this->LocalGenerator
->IssueMessage(
5610 MessageType::FATAL_ERROR
,
5611 cmStrCat("LINKER_TYPE '", linkerType
,
5612 "' is unknown. Did you forget to define the '", usingLinker
,
5621 bool cmGeneratorTarget::LinkerEnforcesNoAllowShLibUndefined(
5622 std::string
const& config
) const
5624 // FIXME(#25486): Account for the LINKER_TYPE target property.
5625 // Also factor out the hard-coded list below into a platform
5626 // information table based on the linker id.
5627 std::string ll
= this->GetLinkerLanguage(config
);
5628 std::string linkerIdVar
= cmStrCat("CMAKE_", ll
, "_COMPILER_LINKER_ID");
5629 cmValue linkerId
= this->Makefile
->GetDefinition(linkerIdVar
);
5630 // The GNU bfd-based linker may enforce '--no-allow-shlib-undefined'
5631 // recursively by default. The Solaris linker has similar behavior.
5632 return linkerId
&& (*linkerId
== "GNU" || *linkerId
== "Solaris");
5635 std::string
cmGeneratorTarget::GetPDBOutputName(
5636 const std::string
& config
) const
5639 this->GetOutputName(config
, cmStateEnums::RuntimeBinaryArtifact
);
5641 std::vector
<std::string
> props
;
5642 std::string configUpper
= cmSystemTools::UpperCase(config
);
5643 if (!configUpper
.empty()) {
5644 // PDB_NAME_<CONFIG>
5645 props
.push_back("PDB_NAME_" + configUpper
);
5649 props
.emplace_back("PDB_NAME");
5651 for (std::string
const& p
: props
) {
5652 if (cmValue outName
= this->GetProperty(p
)) {
5660 std::string
cmGeneratorTarget::GetPDBName(const std::string
& config
) const
5662 NameComponents
const& parts
= this->GetFullNameInternalComponents(
5663 config
, cmStateEnums::RuntimeBinaryArtifact
);
5665 std::vector
<std::string
> props
;
5666 std::string configUpper
= cmSystemTools::UpperCase(config
);
5667 if (!configUpper
.empty()) {
5668 // PDB_NAME_<CONFIG>
5669 props
.push_back("PDB_NAME_" + configUpper
);
5673 props
.emplace_back("PDB_NAME");
5675 for (std::string
const& p
: props
) {
5676 if (cmValue outName
= this->GetProperty(p
)) {
5677 return parts
.prefix
+ *outName
+ ".pdb";
5680 return parts
.prefix
+ parts
.base
+ ".pdb";
5683 std::string
cmGeneratorTarget::GetObjectDirectory(
5684 std::string
const& config
) const
5686 std::string obj_dir
=
5687 this->GlobalGenerator
->ExpandCFGIntDir(this->ObjectDirectory
, config
);
5688 #if defined(__APPLE__)
5689 // Replace Xcode's placeholder for the object file directory since
5690 // installation and export scripts need to know the real directory.
5691 // Xcode has build-time settings (e.g. for sanitizers) that affect this,
5692 // but we use the default here. Users that want to enable sanitizers
5693 // will do so at the cost of object library installation and export.
5694 cmSystemTools::ReplaceString(obj_dir
, "$(OBJECT_FILE_DIR_normal:base)",
5700 void cmGeneratorTarget::GetTargetObjectNames(
5701 std::string
const& config
, std::vector
<std::string
>& objects
) const
5703 std::vector
<cmSourceFile
const*> objectSources
;
5704 this->GetObjectSources(objectSources
, config
);
5705 std::map
<cmSourceFile
const*, std::string
> mapping
;
5707 for (cmSourceFile
const* sf
: objectSources
) {
5711 this->LocalGenerator
->ComputeObjectFilenames(mapping
, this);
5713 for (cmSourceFile
const* src
: objectSources
) {
5714 // Find the object file name corresponding to this source file.
5715 auto map_it
= mapping
.find(src
);
5716 // It must exist because we populated the mapping just above.
5717 assert(!map_it
->second
.empty());
5718 objects
.push_back(map_it
->second
);
5721 // We need to compute the relative path from the root of
5722 // of the object directory to handle subdirectory paths
5723 std::string rootObjectDir
= this->GetObjectDirectory(config
);
5724 rootObjectDir
= cmSystemTools::CollapseFullPath(rootObjectDir
);
5725 auto ispcObjects
= this->GetGeneratedISPCObjects(config
);
5726 for (std::string
const& output
: ispcObjects
) {
5727 auto relativePathFromObjectDir
= output
.substr(rootObjectDir
.size());
5728 objects
.push_back(relativePathFromObjectDir
);
5732 bool cmGeneratorTarget::StrictTargetComparison::operator()(
5733 cmGeneratorTarget
const* t1
, cmGeneratorTarget
const* t2
) const
5735 int nameResult
= strcmp(t1
->GetName().c_str(), t2
->GetName().c_str());
5736 if (nameResult
== 0) {
5738 t1
->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
5739 t2
->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
5741 return nameResult
< 0;
5744 struct cmGeneratorTarget::SourceFileFlags
5745 cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile
* sf
) const
5747 struct SourceFileFlags flags
;
5748 this->ConstructSourceFileFlags();
5749 auto si
= this->SourceFlagsMap
.find(sf
);
5750 if (si
!= this->SourceFlagsMap
.end()) {
5753 // Handle the MACOSX_PACKAGE_LOCATION property on source files that
5754 // were not listed in one of the other lists.
5755 if (cmValue location
= sf
->GetProperty("MACOSX_PACKAGE_LOCATION")) {
5756 flags
.MacFolder
= location
->c_str();
5757 const bool stripResources
=
5758 this->GlobalGenerator
->ShouldStripResourcePath(this->Makefile
);
5759 if (*location
== "Resources") {
5760 flags
.Type
= cmGeneratorTarget::SourceFileTypeResource
;
5761 if (stripResources
) {
5762 flags
.MacFolder
= "";
5764 } else if (cmHasLiteralPrefix(*location
, "Resources/")) {
5765 flags
.Type
= cmGeneratorTarget::SourceFileTypeDeepResource
;
5766 if (stripResources
) {
5767 flags
.MacFolder
+= cmStrLen("Resources/");
5770 flags
.Type
= cmGeneratorTarget::SourceFileTypeMacContent
;
5777 void cmGeneratorTarget::ConstructSourceFileFlags() const
5779 if (this->SourceFileFlagsConstructed
) {
5782 this->SourceFileFlagsConstructed
= true;
5784 // Process public headers to mark the source files.
5785 if (cmValue files
= this->GetProperty("PUBLIC_HEADER")) {
5786 cmList relFiles
{ *files
};
5787 for (auto const& relFile
: relFiles
) {
5788 if (cmSourceFile
* sf
= this->Makefile
->GetSource(relFile
)) {
5789 SourceFileFlags
& flags
= this->SourceFlagsMap
[sf
];
5790 flags
.MacFolder
= "Headers";
5791 flags
.Type
= cmGeneratorTarget::SourceFileTypePublicHeader
;
5796 // Process private headers after public headers so that they take
5797 // precedence if a file is listed in both.
5798 if (cmValue files
= this->GetProperty("PRIVATE_HEADER")) {
5799 cmList relFiles
{ *files
};
5800 for (auto const& relFile
: relFiles
) {
5801 if (cmSourceFile
* sf
= this->Makefile
->GetSource(relFile
)) {
5802 SourceFileFlags
& flags
= this->SourceFlagsMap
[sf
];
5803 flags
.MacFolder
= "PrivateHeaders";
5804 flags
.Type
= cmGeneratorTarget::SourceFileTypePrivateHeader
;
5809 // Mark sources listed as resources.
5810 if (cmValue files
= this->GetProperty("RESOURCE")) {
5811 cmList relFiles
{ *files
};
5812 for (auto const& relFile
: relFiles
) {
5813 if (cmSourceFile
* sf
= this->Makefile
->GetSource(relFile
)) {
5814 SourceFileFlags
& flags
= this->SourceFlagsMap
[sf
];
5815 flags
.MacFolder
= "";
5816 if (!this->GlobalGenerator
->ShouldStripResourcePath(this->Makefile
)) {
5817 flags
.MacFolder
= "Resources";
5819 flags
.Type
= cmGeneratorTarget::SourceFileTypeResource
;
5825 const cmGeneratorTarget::CompatibleInterfacesBase
&
5826 cmGeneratorTarget::GetCompatibleInterfaces(std::string
const& config
) const
5828 cmGeneratorTarget::CompatibleInterfaces
& compat
=
5829 this->CompatibleInterfacesMap
[config
];
5832 compat
.PropsBool
.insert("POSITION_INDEPENDENT_CODE");
5833 compat
.PropsString
.insert("AUTOUIC_OPTIONS");
5834 std::vector
<cmGeneratorTarget
const*> const& deps
=
5835 this->GetLinkImplementationClosure(config
);
5836 for (cmGeneratorTarget
const* li
: deps
) {
5837 #define CM_READ_COMPATIBLE_INTERFACE(X, x) \
5838 if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
5839 cmList props(*prop); \
5840 compat.Props##x.insert(props.begin(), props.end()); \
5842 CM_READ_COMPATIBLE_INTERFACE(BOOL
, Bool
)
5843 CM_READ_COMPATIBLE_INTERFACE(STRING
, String
)
5844 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN
, NumberMin
)
5845 CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX
, NumberMax
)
5846 #undef CM_READ_COMPATIBLE_INTERFACE
5852 bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
5853 const std::string
& p
, const std::string
& config
) const
5855 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
5856 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
5859 return this->GetCompatibleInterfaces(config
).PropsBool
.count(p
) > 0;
5862 bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
5863 const std::string
& p
, const std::string
& config
) const
5865 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
5866 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
5869 return this->GetCompatibleInterfaces(config
).PropsString
.count(p
) > 0;
5872 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
5873 const std::string
& p
, const std::string
& config
) const
5875 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
5876 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
5879 return this->GetCompatibleInterfaces(config
).PropsNumberMin
.count(p
) > 0;
5882 bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
5883 const std::string
& p
, const std::string
& config
) const
5885 if (this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
5886 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
5889 return this->GetCompatibleInterfaces(config
).PropsNumberMax
.count(p
) > 0;
5900 template <typename PropertyType
>
5901 PropertyType
getLinkInterfaceDependentProperty(cmGeneratorTarget
const* tgt
,
5902 const std::string
& prop
,
5903 const std::string
& config
,
5904 CompatibleType
, PropertyType
*);
5907 bool getLinkInterfaceDependentProperty(cmGeneratorTarget
const* tgt
,
5908 const std::string
& prop
,
5909 const std::string
& config
,
5910 CompatibleType
/*unused*/,
5913 return tgt
->GetLinkInterfaceDependentBoolProperty(prop
, config
);
5917 const char* getLinkInterfaceDependentProperty(cmGeneratorTarget
const* tgt
,
5918 const std::string
& prop
,
5919 const std::string
& config
,
5921 const char** /*unused*/)
5926 "String compatibility check function called for boolean");
5929 return tgt
->GetLinkInterfaceDependentStringProperty(prop
, config
);
5931 return tgt
->GetLinkInterfaceDependentNumberMinProperty(prop
, config
);
5933 return tgt
->GetLinkInterfaceDependentNumberMaxProperty(prop
, config
);
5935 assert(false && "Unreachable!");
5939 template <typename PropertyType
>
5940 void checkPropertyConsistency(cmGeneratorTarget
const* depender
,
5941 cmGeneratorTarget
const* dependee
,
5942 const std::string
& propName
,
5943 std::set
<std::string
>& emitted
,
5944 const std::string
& config
, CompatibleType t
,
5945 PropertyType
* /*unused*/)
5947 cmValue prop
= dependee
->GetProperty(propName
);
5952 cmList props
{ *prop
};
5954 cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
5956 for (std::string
const& p
: props
) {
5957 std::string pname
= cmSystemTools::HelpFileName(p
);
5958 std::string pfile
= pdir
+ pname
+ ".rst";
5959 if (cmSystemTools::FileExists(pfile
, true)) {
5960 std::ostringstream e
;
5961 e
<< "Target \"" << dependee
->GetName() << "\" has property \"" << p
5962 << "\" listed in its " << propName
5964 "This is not allowed. Only user-defined properties may appear "
5966 << propName
<< " property.";
5967 depender
->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR
,
5971 if (emitted
.insert(p
).second
) {
5972 getLinkInterfaceDependentProperty
<PropertyType
>(depender
, p
, config
, t
,
5974 if (cmSystemTools::GetErrorOccurredFlag()) {
5982 std::string
intersect(const std::set
<std::string
>& s1
,
5983 const std::set
<std::string
>& s2
)
5985 std::set
<std::string
> intersect
;
5986 std::set_intersection(s1
.begin(), s1
.end(), s2
.begin(), s2
.end(),
5987 std::inserter(intersect
, intersect
.begin()));
5988 if (!intersect
.empty()) {
5989 return *intersect
.begin();
5994 std::string
intersect(const std::set
<std::string
>& s1
,
5995 const std::set
<std::string
>& s2
,
5996 const std::set
<std::string
>& s3
)
5999 result
= intersect(s1
, s2
);
6000 if (!result
.empty()) {
6003 result
= intersect(s1
, s3
);
6004 if (!result
.empty()) {
6007 return intersect(s2
, s3
);
6010 std::string
intersect(const std::set
<std::string
>& s1
,
6011 const std::set
<std::string
>& s2
,
6012 const std::set
<std::string
>& s3
,
6013 const std::set
<std::string
>& s4
)
6016 result
= intersect(s1
, s2
);
6017 if (!result
.empty()) {
6020 result
= intersect(s1
, s3
);
6021 if (!result
.empty()) {
6024 result
= intersect(s1
, s4
);
6025 if (!result
.empty()) {
6028 return intersect(s2
, s3
, s4
);
6032 void cmGeneratorTarget::CheckPropertyCompatibility(
6033 cmComputeLinkInformation
& info
, const std::string
& config
) const
6035 const cmComputeLinkInformation::ItemVector
& deps
= info
.GetItems();
6037 std::set
<std::string
> emittedBools
;
6038 static const std::string strBool
= "COMPATIBLE_INTERFACE_BOOL";
6039 std::set
<std::string
> emittedStrings
;
6040 static const std::string strString
= "COMPATIBLE_INTERFACE_STRING";
6041 std::set
<std::string
> emittedMinNumbers
;
6042 static const std::string strNumMin
= "COMPATIBLE_INTERFACE_NUMBER_MIN";
6043 std::set
<std::string
> emittedMaxNumbers
;
6044 static const std::string strNumMax
= "COMPATIBLE_INTERFACE_NUMBER_MAX";
6046 for (auto const& dep
: deps
) {
6047 if (!dep
.Target
|| dep
.Target
->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
6051 checkPropertyConsistency
<bool>(this, dep
.Target
, strBool
, emittedBools
,
6052 config
, BoolType
, nullptr);
6053 if (cmSystemTools::GetErrorOccurredFlag()) {
6056 checkPropertyConsistency
<const char*>(this, dep
.Target
, strString
,
6057 emittedStrings
, config
, StringType
,
6059 if (cmSystemTools::GetErrorOccurredFlag()) {
6062 checkPropertyConsistency
<const char*>(this, dep
.Target
, strNumMin
,
6063 emittedMinNumbers
, config
,
6064 NumberMinType
, nullptr);
6065 if (cmSystemTools::GetErrorOccurredFlag()) {
6068 checkPropertyConsistency
<const char*>(this, dep
.Target
, strNumMax
,
6069 emittedMaxNumbers
, config
,
6070 NumberMaxType
, nullptr);
6071 if (cmSystemTools::GetErrorOccurredFlag()) {
6076 std::string prop
= intersect(emittedBools
, emittedStrings
, emittedMinNumbers
,
6079 if (!prop
.empty()) {
6080 // Use a sorted std::vector to keep the error message sorted.
6081 std::vector
<std::string
> props
;
6082 auto i
= emittedBools
.find(prop
);
6083 if (i
!= emittedBools
.end()) {
6084 props
.push_back(strBool
);
6086 i
= emittedStrings
.find(prop
);
6087 if (i
!= emittedStrings
.end()) {
6088 props
.push_back(strString
);
6090 i
= emittedMinNumbers
.find(prop
);
6091 if (i
!= emittedMinNumbers
.end()) {
6092 props
.push_back(strNumMin
);
6094 i
= emittedMaxNumbers
.find(prop
);
6095 if (i
!= emittedMaxNumbers
.end()) {
6096 props
.push_back(strNumMax
);
6098 std::sort(props
.begin(), props
.end());
6100 std::string propsString
= cmStrCat(
6101 cmJoin(cmMakeRange(props
).retreat(1), ", "), " and the ", props
.back());
6103 std::ostringstream e
;
6104 e
<< "Property \"" << prop
<< "\" appears in both the " << propsString
6105 << " property in the dependencies of target \"" << this->GetName()
6106 << "\". This is not allowed. A property may only require "
6108 "in a boolean interpretation, a numeric minimum, a numeric maximum "
6110 "string interpretation, but not a mixture.";
6111 this->LocalGenerator
->IssueMessage(MessageType::FATAL_ERROR
, e
.str());
6115 template <typename PropertyType
>
6116 std::string
valueAsString(PropertyType
);
6118 std::string valueAsString
<bool>(bool value
)
6120 return value
? "TRUE" : "FALSE";
6123 std::string valueAsString
<const char*>(const char* value
)
6125 return value
? value
: "(unset)";
6128 std::string valueAsString
<std::string
>(std::string value
)
6133 std::string valueAsString
<cmValue
>(cmValue value
)
6135 return value
? *value
: std::string("(unset)");
6138 std::string valueAsString
<std::nullptr_t
>(std::nullptr_t
/*unused*/)
6143 static std::string
compatibilityType(CompatibleType t
)
6147 return "Boolean compatibility";
6149 return "String compatibility";
6151 return "Numeric maximum compatibility";
6153 return "Numeric minimum compatibility";
6155 assert(false && "Unreachable!");
6159 static std::string
compatibilityAgree(CompatibleType t
, bool dominant
)
6164 return dominant
? "(Disagree)\n" : "(Agree)\n";
6167 return dominant
? "(Dominant)\n" : "(Ignored)\n";
6169 assert(false && "Unreachable!");
6173 template <typename PropertyType
>
6174 PropertyType
getTypedProperty(
6175 cmGeneratorTarget
const* tgt
, const std::string
& prop
,
6176 cmGeneratorExpressionInterpreter
* genexInterpreter
= nullptr);
6179 bool getTypedProperty
<bool>(cmGeneratorTarget
const* tgt
,
6180 const std::string
& prop
,
6181 cmGeneratorExpressionInterpreter
* genexInterpreter
)
6183 if (genexInterpreter
== nullptr) {
6184 return tgt
->GetPropertyAsBool(prop
);
6187 cmValue value
= tgt
->GetProperty(prop
);
6188 return cmIsOn(genexInterpreter
->Evaluate(value
? *value
: "", prop
));
6192 const char* getTypedProperty
<const char*>(
6193 cmGeneratorTarget
const* tgt
, const std::string
& prop
,
6194 cmGeneratorExpressionInterpreter
* genexInterpreter
)
6196 cmValue value
= tgt
->GetProperty(prop
);
6198 if (genexInterpreter
== nullptr) {
6199 return value
.GetCStr();
6202 return genexInterpreter
->Evaluate(value
? *value
: "", prop
).c_str();
6206 std::string getTypedProperty
<std::string
>(
6207 cmGeneratorTarget
const* tgt
, const std::string
& prop
,
6208 cmGeneratorExpressionInterpreter
* genexInterpreter
)
6210 cmValue value
= tgt
->GetProperty(prop
);
6212 if (genexInterpreter
== nullptr) {
6213 return valueAsString(value
);
6216 return genexInterpreter
->Evaluate(value
? *value
: "", prop
);
6219 template <typename PropertyType
>
6220 PropertyType
impliedValue(PropertyType
);
6222 bool impliedValue
<bool>(bool /*unused*/)
6227 const char* impliedValue
<const char*>(const char* /*unused*/)
6232 std::string impliedValue
<std::string
>(std::string
/*unused*/) // NOLINT(*)
6234 return std::string();
6237 template <typename PropertyType
>
6238 std::pair
<bool, PropertyType
> consistentProperty(PropertyType lhs
,
6243 std::pair
<bool, bool> consistentProperty(bool lhs
, bool rhs
,
6244 CompatibleType
/*unused*/)
6246 return { lhs
== rhs
, lhs
};
6249 static std::pair
<bool, const char*> consistentStringProperty(const char* lhs
,
6252 const bool b
= strcmp(lhs
, rhs
) == 0;
6253 return { b
, b
? lhs
: nullptr };
6256 static std::pair
<bool, std::string
> consistentStringProperty(
6257 const std::string
& lhs
, const std::string
& rhs
)
6259 const bool b
= lhs
== rhs
;
6260 return { b
, b
? lhs
: valueAsString(nullptr) };
6263 static std::pair
<bool, const char*> consistentNumberProperty(const char* lhs
,
6269 long lnum
= strtol(lhs
, &pEnd
, 0);
6270 if (pEnd
== lhs
|| *pEnd
!= '\0' || errno
== ERANGE
) {
6271 return { false, nullptr };
6274 long rnum
= strtol(rhs
, &pEnd
, 0);
6275 if (pEnd
== rhs
|| *pEnd
!= '\0' || errno
== ERANGE
) {
6276 return { false, nullptr };
6279 if (t
== NumberMaxType
) {
6280 return { true, std::max(lnum
, rnum
) == lnum
? lhs
: rhs
};
6283 return { true, std::min(lnum
, rnum
) == lnum
? lhs
: rhs
};
6287 std::pair
<bool, const char*> consistentProperty(const char* lhs
,
6292 return { true, lhs
};
6295 return { true, rhs
};
6298 return { true, lhs
};
6303 bool same
= cmIsOn(lhs
) == cmIsOn(rhs
);
6304 return { same
, same
? lhs
: nullptr };
6307 return consistentStringProperty(lhs
, rhs
);
6310 return consistentNumberProperty(lhs
, rhs
, t
);
6312 assert(false && "Unreachable!");
6313 return { false, nullptr };
6316 static std::pair
<bool, std::string
> consistentProperty(const std::string
& lhs
,
6317 const std::string
& rhs
,
6320 const std::string null_ptr
= valueAsString(nullptr);
6322 if (lhs
== null_ptr
&& rhs
== null_ptr
) {
6323 return { true, lhs
};
6325 if (lhs
== null_ptr
) {
6326 return { true, rhs
};
6328 if (rhs
== null_ptr
) {
6329 return { true, lhs
};
6334 bool same
= cmIsOn(lhs
) == cmIsOn(rhs
);
6335 return { same
, same
? lhs
: null_ptr
};
6338 return consistentStringProperty(lhs
, rhs
);
6340 case NumberMaxType
: {
6341 auto value
= consistentNumberProperty(lhs
.c_str(), rhs
.c_str(), t
);
6342 return { value
.first
,
6343 value
.first
? std::string(value
.second
) : null_ptr
};
6346 assert(false && "Unreachable!");
6347 return { false, null_ptr
};
6350 template <typename PropertyType
>
6351 PropertyType
checkInterfacePropertyCompatibility(cmGeneratorTarget
const* tgt
,
6352 const std::string
& p
,
6353 const std::string
& config
,
6354 const char* defaultValue
,
6356 PropertyType
* /*unused*/)
6358 PropertyType propContent
= getTypedProperty
<PropertyType
>(tgt
, p
);
6360 std::vector
<std::string
> headPropKeys
= tgt
->GetPropertyKeys();
6361 const bool explicitlySet
= cm::contains(headPropKeys
, p
);
6363 const bool impliedByUse
= tgt
->IsNullImpliedByLinkLibraries(p
);
6364 assert((impliedByUse
^ explicitlySet
) || (!impliedByUse
&& !explicitlySet
));
6366 std::vector
<cmGeneratorTarget
const*> const& deps
=
6367 tgt
->GetLinkImplementationClosure(config
);
6372 bool propInitialized
= explicitlySet
;
6374 std::string report
= cmStrCat(" * Target \"", tgt
->GetName());
6375 if (explicitlySet
) {
6376 report
+= "\" has property content \"";
6377 report
+= valueAsString
<PropertyType
>(propContent
);
6379 } else if (impliedByUse
) {
6380 report
+= "\" property is implied by use.\n";
6382 report
+= "\" property not set.\n";
6385 std::string interfaceProperty
= "INTERFACE_" + p
;
6386 std::unique_ptr
<cmGeneratorExpressionInterpreter
> genexInterpreter
;
6387 if (p
== "POSITION_INDEPENDENT_CODE") {
6388 genexInterpreter
= cm::make_unique
<cmGeneratorExpressionInterpreter
>(
6389 tgt
->GetLocalGenerator(), config
, tgt
);
6392 for (cmGeneratorTarget
const* theTarget
: deps
) {
6393 // An error should be reported if one dependency
6394 // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
6395 // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
6396 // target itself has a POSITION_INDEPENDENT_CODE which disagrees
6397 // with a dependency.
6399 std::vector
<std::string
> propKeys
= theTarget
->GetPropertyKeys();
6401 const bool ifaceIsSet
= cm::contains(propKeys
, interfaceProperty
);
6402 PropertyType ifacePropContent
= getTypedProperty
<PropertyType
>(
6403 theTarget
, interfaceProperty
, genexInterpreter
.get());
6405 std::string reportEntry
;
6407 reportEntry
+= " * Target \"";
6408 reportEntry
+= theTarget
->GetName();
6409 reportEntry
+= "\" property value \"";
6410 reportEntry
+= valueAsString
<PropertyType
>(ifacePropContent
);
6411 reportEntry
+= "\" ";
6414 if (explicitlySet
) {
6416 std::pair
<bool, PropertyType
> consistent
=
6417 consistentProperty(propContent
, ifacePropContent
, t
);
6418 report
+= reportEntry
;
6419 report
+= compatibilityAgree(t
, propContent
!= consistent
.second
);
6420 if (!consistent
.first
) {
6421 std::ostringstream e
;
6422 e
<< "Property " << p
<< " on target \"" << tgt
->GetName()
6423 << "\" does\nnot match the "
6426 << " property requirement\nof "
6428 << theTarget
->GetName() << "\".\n";
6429 cmSystemTools::Error(e
.str());
6432 propContent
= consistent
.second
;
6435 // Explicitly set on target and not set in iface. Can't disagree.
6439 propContent
= impliedValue
<PropertyType
>(propContent
);
6442 std::pair
<bool, PropertyType
> consistent
=
6443 consistentProperty(propContent
, ifacePropContent
, t
);
6444 report
+= reportEntry
;
6445 report
+= compatibilityAgree(t
, propContent
!= consistent
.second
);
6446 if (!consistent
.first
) {
6447 std::ostringstream e
;
6448 e
<< "Property " << p
<< " on target \"" << tgt
->GetName()
6449 << "\" is\nimplied to be " << defaultValue
6450 << " because it was used to determine the link libraries\n"
6451 "already. The INTERFACE_"
6452 << p
<< " property on\ndependency \"" << theTarget
->GetName()
6453 << "\" is in conflict.\n";
6454 cmSystemTools::Error(e
.str());
6457 propContent
= consistent
.second
;
6460 // Implicitly set on target and not set in iface. Can't disagree.
6464 if (propInitialized
) {
6465 std::pair
<bool, PropertyType
> consistent
=
6466 consistentProperty(propContent
, ifacePropContent
, t
);
6467 report
+= reportEntry
;
6468 report
+= compatibilityAgree(t
, propContent
!= consistent
.second
);
6469 if (!consistent
.first
) {
6470 std::ostringstream e
;
6471 e
<< "The INTERFACE_" << p
<< " property of \""
6472 << theTarget
->GetName() << "\" does\nnot agree with the value of "
6473 << p
<< " already determined\nfor \"" << tgt
->GetName() << "\".\n";
6474 cmSystemTools::Error(e
.str());
6477 propContent
= consistent
.second
;
6480 report
+= reportEntry
+ "(Interface set)\n";
6481 propContent
= ifacePropContent
;
6482 propInitialized
= true;
6484 // Not set. Nothing to agree on.
6489 tgt
->ReportPropertyOrigin(p
, valueAsString
<PropertyType
>(propContent
),
6490 report
, compatibilityType(t
));
6494 bool cmGeneratorTarget::SetDeviceLink(bool deviceLink
)
6496 bool previous
= this->DeviceLink
;
6497 this->DeviceLink
= deviceLink
;
6501 bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
6502 const std::string
& p
, const std::string
& config
) const
6504 return checkInterfacePropertyCompatibility
<bool>(this, p
, config
, "FALSE",
6508 std::string
cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
6509 const std::string
& p
, const std::string
& config
) const
6511 return checkInterfacePropertyCompatibility
<std::string
>(
6512 this, p
, config
, "FALSE", BoolType
, nullptr);
6515 const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
6516 const std::string
& p
, const std::string
& config
) const
6518 return checkInterfacePropertyCompatibility
<const char*>(
6519 this, p
, config
, "empty", StringType
, nullptr);
6522 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
6523 const std::string
& p
, const std::string
& config
) const
6525 return checkInterfacePropertyCompatibility
<const char*>(
6526 this, p
, config
, "empty", NumberMinType
, nullptr);
6529 const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
6530 const std::string
& p
, const std::string
& config
) const
6532 return checkInterfacePropertyCompatibility
<const char*>(
6533 this, p
, config
, "empty", NumberMaxType
, nullptr);
6536 cmComputeLinkInformation
* cmGeneratorTarget::GetLinkInformation(
6537 const std::string
& config
) const
6539 // Lookup any existing information for this configuration.
6540 std::string
key(cmSystemTools::UpperCase(config
));
6541 auto i
= this->LinkInformation
.find(key
);
6542 if (i
== this->LinkInformation
.end()) {
6543 // Compute information for this configuration.
6544 auto info
= cm::make_unique
<cmComputeLinkInformation
>(this, config
);
6545 if (info
&& !info
->Compute()) {
6549 // Store the information for this configuration.
6550 i
= this->LinkInformation
.emplace(key
, std::move(info
)).first
;
6553 this->CheckPropertyCompatibility(*i
->second
, config
);
6556 return i
->second
.get();
6559 void cmGeneratorTarget::CheckLinkLibraries() const
6561 bool linkLibrariesOnlyTargets
=
6562 this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS");
6564 // Evaluate the link interface of this target if needed for extra checks.
6565 if (linkLibrariesOnlyTargets
) {
6566 std::vector
<std::string
> const& configs
=
6567 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
6568 for (std::string
const& config
: configs
) {
6569 this->GetLinkInterfaceLibraries(config
, this, LinkInterfaceFor::Link
);
6573 // Check link the implementation for each generated configuration.
6574 for (auto const& hmp
: this->LinkImplMap
) {
6575 HeadToLinkImplementationMap
const& hm
= hmp
.second
;
6576 // There could be several entries used when computing the pre-CMP0022
6577 // default link interface. Check only the entry for our own link impl.
6578 auto const hmi
= hm
.find(this);
6579 if (hmi
== hm
.end() || !hmi
->second
.LibrariesDone
) {
6582 for (cmLinkImplItem
const& item
: hmi
->second
.Libraries
) {
6583 if (!this->VerifyLinkItemColons(LinkItemRole::Implementation
, item
)) {
6586 if (linkLibrariesOnlyTargets
&&
6587 !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation
, item
)) {
6593 // Check link the interface for each generated combination of
6594 // configuration and consuming head target. We should not need to
6595 // consider LinkInterfaceUsageRequirementsOnlyMap because its entries
6596 // should be a subset of LinkInterfaceMap (with LINK_ONLY left out).
6597 for (auto const& hmp
: this->LinkInterfaceMap
) {
6598 for (auto const& hmi
: hmp
.second
) {
6599 if (!hmi
.second
.LibrariesDone
) {
6602 for (cmLinkItem
const& item
: hmi
.second
.Libraries
) {
6603 if (!this->VerifyLinkItemColons(LinkItemRole::Interface
, item
)) {
6606 if (linkLibrariesOnlyTargets
&&
6607 !this->VerifyLinkItemIsTarget(LinkItemRole::Interface
, item
)) {
6616 cm::string_view missingTargetPossibleReasons
=
6617 "Possible reasons include:\n"
6618 " * There is a typo in the target name.\n"
6619 " * A find_package call is missing for an IMPORTED target.\n"
6620 " * An ALIAS target is missing.\n"_s
;
6623 bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role
,
6624 cmLinkItem
const& item
) const
6626 if (item
.Target
|| cmHasPrefix(item
.AsStr(), "<LINK_GROUP:"_s
) ||
6627 item
.AsStr().find("::") == std::string::npos
) {
6630 MessageType messageType
= MessageType::FATAL_ERROR
;
6632 switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028
)) {
6633 case cmPolicies::WARN
: {
6634 e
= cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028
), "\n");
6635 messageType
= MessageType::AUTHOR_WARNING
;
6637 case cmPolicies::OLD
:
6639 case cmPolicies::REQUIRED_IF_USED
:
6640 case cmPolicies::REQUIRED_ALWAYS
:
6641 case cmPolicies::NEW
:
6642 // Issue the fatal message.
6646 if (role
== LinkItemRole::Implementation
) {
6647 e
= cmStrCat(e
, "Target \"", this->GetName(), "\" links to");
6649 e
= cmStrCat(e
, "The link interface of target \"", this->GetName(),
6653 cmStrCat(e
, ":\n ", item
.AsStr(), "\n", "but the target was not found. ",
6654 missingTargetPossibleReasons
);
6655 cmListFileBacktrace backtrace
= item
.Backtrace
;
6656 if (backtrace
.Empty()) {
6657 backtrace
= this->GetBacktrace();
6659 this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType
, e
,
6664 bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role
,
6665 cmLinkItem
const& item
) const
6670 std::string
const& str
= item
.AsStr();
6672 (str
[0] == '-' || str
[0] == '$' || str
[0] == '`' ||
6673 str
.find_first_of("/\\") != std::string::npos
||
6674 cmHasPrefix(str
, "<LINK_LIBRARY:"_s
) ||
6675 cmHasPrefix(str
, "<LINK_GROUP:"_s
))) {
6679 std::string e
= cmStrCat("Target \"", this->GetName(),
6680 "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ",
6681 role
== LinkItemRole::Implementation
6683 : "its link interface contains",
6684 ":\n ", item
.AsStr(), "\nwhich is not a target. ",
6685 missingTargetPossibleReasons
);
6686 cmListFileBacktrace backtrace
= item
.Backtrace
;
6687 if (backtrace
.Empty()) {
6688 backtrace
= this->GetBacktrace();
6690 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
6691 MessageType::FATAL_ERROR
, e
, backtrace
);
6695 void cmGeneratorTarget::GetTargetVersion(int& major
, int& minor
) const
6698 this->GetTargetVersion("VERSION", major
, minor
, patch
);
6701 void cmGeneratorTarget::GetTargetVersionFallback(
6702 const std::string
& property
, const std::string
& fallback_property
,
6703 int& major
, int& minor
, int& patch
) const
6705 if (this->GetProperty(property
)) {
6706 this->GetTargetVersion(property
, major
, minor
, patch
);
6708 this->GetTargetVersion(fallback_property
, major
, minor
, patch
);
6712 void cmGeneratorTarget::GetTargetVersion(const std::string
& property
,
6713 int& major
, int& minor
,
6716 // Set the default values.
6721 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY
);
6723 if (cmValue version
= this->GetProperty(property
)) {
6724 // Try to parse the version number and store the results that were
6725 // successfully parsed.
6729 switch (sscanf(version
->c_str(), "%d.%d.%d", &parsed_major
, &parsed_minor
,
6732 patch
= parsed_patch
;
6735 minor
= parsed_minor
;
6738 major
= parsed_major
;
6746 std::string
cmGeneratorTarget::GetRuntimeLinkLibrary(
6747 std::string
const& lang
, std::string
const& config
) const
6749 // This is activated by the presence of a default selection whether or
6750 // not it is overridden by a property.
6751 cmValue runtimeLibraryDefault
= this->Makefile
->GetDefinition(
6752 cmStrCat("CMAKE_", lang
, "_RUNTIME_LIBRARY_DEFAULT"));
6753 if (!cmNonempty(runtimeLibraryDefault
)) {
6754 return std::string();
6756 cmValue runtimeLibraryValue
=
6757 this->Target
->GetProperty(cmStrCat(lang
, "_RUNTIME_LIBRARY"));
6758 if (!runtimeLibraryValue
) {
6759 runtimeLibraryValue
= runtimeLibraryDefault
;
6761 return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
6762 *runtimeLibraryValue
, this->LocalGenerator
, config
, this));
6765 std::string
cmGeneratorTarget::GetFortranModuleDirectory(
6766 std::string
const& working_dir
) const
6768 if (!this->FortranModuleDirectoryCreated
) {
6769 this->FortranModuleDirectory
=
6770 this->CreateFortranModuleDirectory(working_dir
);
6771 this->FortranModuleDirectoryCreated
= true;
6774 return this->FortranModuleDirectory
;
6777 bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const
6780 this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) {
6781 return cmIsOn(*prop
);
6786 std::string
cmGeneratorTarget::CreateFortranModuleDirectory(
6787 std::string
const& working_dir
) const
6789 std::string mod_dir
;
6790 std::string target_mod_dir
;
6791 if (cmValue prop
= this->GetProperty("Fortran_MODULE_DIRECTORY")) {
6792 target_mod_dir
= *prop
;
6794 std::string
const& default_mod_dir
=
6795 this->LocalGenerator
->GetCurrentBinaryDirectory();
6796 if (default_mod_dir
!= working_dir
) {
6797 target_mod_dir
= default_mod_dir
;
6800 cmValue moddir_flag
=
6801 this->Makefile
->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
6802 if (!target_mod_dir
.empty() && moddir_flag
) {
6803 // Compute the full path to the module directory.
6804 if (cmSystemTools::FileIsFullPath(target_mod_dir
)) {
6805 // Already a full path.
6806 mod_dir
= target_mod_dir
;
6808 // Interpret relative to the current output directory.
6809 mod_dir
= cmStrCat(this->LocalGenerator
->GetCurrentBinaryDirectory(),
6810 '/', target_mod_dir
);
6813 // Make sure the module output directory exists.
6814 cmSystemTools::MakeDirectory(mod_dir
);
6819 void cmGeneratorTarget::AddISPCGeneratedHeader(std::string
const& header
,
6820 std::string
const& config
)
6822 std::string config_upper
;
6823 if (!config
.empty()) {
6824 config_upper
= cmSystemTools::UpperCase(config
);
6826 auto iter
= this->ISPCGeneratedHeaders
.find(config_upper
);
6827 if (iter
== this->ISPCGeneratedHeaders
.end()) {
6828 std::vector
<std::string
> headers
;
6829 headers
.emplace_back(header
);
6830 this->ISPCGeneratedHeaders
.insert({ config_upper
, headers
});
6832 iter
->second
.emplace_back(header
);
6836 std::vector
<std::string
> cmGeneratorTarget::GetGeneratedISPCHeaders(
6837 std::string
const& config
) const
6839 std::string config_upper
;
6840 if (!config
.empty()) {
6841 config_upper
= cmSystemTools::UpperCase(config
);
6843 auto iter
= this->ISPCGeneratedHeaders
.find(config_upper
);
6844 if (iter
== this->ISPCGeneratedHeaders
.end()) {
6845 return std::vector
<std::string
>{};
6847 return iter
->second
;
6850 void cmGeneratorTarget::AddISPCGeneratedObject(std::vector
<std::string
>&& objs
,
6851 std::string
const& config
)
6853 std::string config_upper
;
6854 if (!config
.empty()) {
6855 config_upper
= cmSystemTools::UpperCase(config
);
6857 auto iter
= this->ISPCGeneratedObjects
.find(config_upper
);
6858 if (iter
== this->ISPCGeneratedObjects
.end()) {
6859 this->ISPCGeneratedObjects
.insert({ config_upper
, objs
});
6861 iter
->second
.insert(iter
->second
.end(), objs
.begin(), objs
.end());
6865 std::vector
<std::string
> cmGeneratorTarget::GetGeneratedISPCObjects(
6866 std::string
const& config
) const
6868 std::string config_upper
;
6869 if (!config
.empty()) {
6870 config_upper
= cmSystemTools::UpperCase(config
);
6872 auto iter
= this->ISPCGeneratedObjects
.find(config_upper
);
6873 if (iter
== this->ISPCGeneratedObjects
.end()) {
6874 return std::vector
<std::string
>{};
6876 return iter
->second
;
6879 std::string
cmGeneratorTarget::GetFrameworkVersion() const
6881 assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY
);
6883 if (cmValue fversion
= this->GetProperty("FRAMEWORK_VERSION")) {
6886 if (cmValue tversion
= this->GetProperty("VERSION")) {
6892 void cmGeneratorTarget::ComputeVersionedName(
6893 std::string
& vName
, std::string
const& prefix
, std::string
const& base
,
6894 std::string
const& suffix
, std::string
const& name
, cmValue version
) const
6896 vName
= this->IsApple() ? (prefix
+ base
) : name
;
6901 vName
+= this->IsApple() ? suffix
: std::string();
6904 std::vector
<std::string
> cmGeneratorTarget::GetPropertyKeys() const
6906 return this->Target
->GetProperties().GetKeys();
6909 void cmGeneratorTarget::ReportPropertyOrigin(
6910 const std::string
& p
, const std::string
& result
, const std::string
& report
,
6911 const std::string
& compatibilityType
) const
6913 cmList debugProperties
{ this->Target
->GetMakefile()->GetDefinition(
6914 "CMAKE_DEBUG_TARGET_PROPERTIES") };
6915 bool debugOrigin
= !this->DebugCompatiblePropertiesDone
[p
] &&
6916 cm::contains(debugProperties
, p
);
6918 if (this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
6919 this->DebugCompatiblePropertiesDone
[p
] = true;
6925 std::string areport
=
6926 cmStrCat(compatibilityType
, " of property \"", p
, "\" for target \"",
6927 this->GetName(), "\" (result: \"", result
, "\"):\n", report
);
6929 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(MessageType::LOG
,
6933 bool cmGeneratorTarget::IsLinkLookupScope(std::string
const& n
,
6934 cmLocalGenerator
const*& lg
) const
6936 if (cmHasLiteralPrefix(n
, CMAKE_DIRECTORY_ID_SEP
)) {
6937 cmDirectoryId
const dirId
= n
.substr(cmStrLen(CMAKE_DIRECTORY_ID_SEP
));
6938 if (dirId
.String
.empty()) {
6939 lg
= this->LocalGenerator
;
6942 if (cmLocalGenerator
const* otherLG
=
6943 this->GlobalGenerator
->FindLocalGenerator(dirId
)) {
6951 cm::optional
<cmLinkItem
> cmGeneratorTarget::LookupLinkItem(
6952 std::string
const& n
, cmListFileBacktrace
const& bt
,
6953 std::string
const& linkFeature
, LookupLinkItemScope
* scope
,
6954 LookupSelf lookupSelf
) const
6956 cm::optional
<cmLinkItem
> maybeItem
;
6957 if (this->IsLinkLookupScope(n
, scope
->LG
)) {
6961 std::string name
= this->CheckCMP0004(n
);
6963 (lookupSelf
== LookupSelf::No
&& name
== this->GetName())) {
6967 this->ResolveLinkItem(BT
<std::string
>(name
, bt
), scope
->LG
, linkFeature
);
6971 void cmGeneratorTarget::ExpandLinkItems(
6972 std::string
const& prop
, cmBTStringRange entries
, std::string
const& config
,
6973 cmGeneratorTarget
const* headTarget
, LinkInterfaceFor interfaceFor
,
6974 LinkInterfaceField field
, cmLinkInterface
& iface
) const
6976 if (entries
.empty()) {
6979 // Keep this logic in sync with ComputeLinkImplementationLibraries.
6980 cmGeneratorExpressionDAGChecker
dagChecker(this, prop
, nullptr, nullptr);
6981 // The $<LINK_ONLY> expression may be in a link interface to specify
6982 // private link dependencies that are otherwise excluded from usage
6984 if (interfaceFor
== LinkInterfaceFor::Usage
) {
6985 dagChecker
.SetTransitivePropertiesOnly();
6986 dagChecker
.SetTransitivePropertiesOnlyCMP0131();
6988 cmMakefile
const* mf
= this->LocalGenerator
->GetMakefile();
6989 LookupLinkItemScope scope
{ this->LocalGenerator
};
6990 for (BT
<std::string
> const& entry
: entries
) {
6991 cmGeneratorExpression
ge(*this->LocalGenerator
->GetCMakeInstance(),
6993 std::unique_ptr
<cmCompiledGeneratorExpression
> cge
= ge
.Parse(entry
.Value
);
6994 cge
->SetEvaluateForBuildsystem(true);
6995 cmList libs
{ cge
->Evaluate(this->LocalGenerator
, config
, headTarget
,
6997 headTarget
->LinkerLanguage
) };
6999 auto linkFeature
= cmLinkItem::DEFAULT
;
7000 for (auto const& lib
: libs
) {
7001 if (auto maybeLinkFeature
= ParseLinkFeature(lib
)) {
7002 linkFeature
= std::move(*maybeLinkFeature
);
7006 if (cm::optional
<cmLinkItem
> maybeItem
= this->LookupLinkItem(
7007 lib
, cge
->GetBacktrace(), linkFeature
, &scope
,
7008 field
== LinkInterfaceField::Libraries
? LookupSelf::No
7009 : LookupSelf::Yes
)) {
7010 cmLinkItem item
= std::move(*maybeItem
);
7012 if (field
== LinkInterfaceField::HeadInclude
) {
7013 iface
.HeadInclude
.emplace_back(std::move(item
));
7016 if (field
== LinkInterfaceField::HeadExclude
) {
7017 iface
.HeadExclude
.emplace_back(std::move(item
));
7021 // Report explicitly linked object files separately.
7022 std::string
const& maybeObj
= item
.AsStr();
7023 if (cmSystemTools::FileIsFullPath(maybeObj
)) {
7024 cmSourceFile
const* sf
=
7025 mf
->GetSource(maybeObj
, cmSourceFileLocationKind::Known
);
7026 if (sf
&& sf
->GetPropertyAsBool("EXTERNAL_OBJECT")) {
7027 item
.ObjectSource
= sf
;
7028 iface
.Objects
.emplace_back(std::move(item
));
7034 iface
.Libraries
.emplace_back(std::move(item
));
7037 if (cge
->GetHadHeadSensitiveCondition()) {
7038 iface
.HadHeadSensitiveCondition
= true;
7040 if (cge
->GetHadContextSensitiveCondition()) {
7041 iface
.HadContextSensitiveCondition
= true;
7043 if (cge
->GetHadLinkLanguageSensitiveCondition()) {
7044 iface
.HadLinkLanguageSensitiveCondition
= true;
7049 cmLinkInterface
const* cmGeneratorTarget::GetLinkInterface(
7050 const std::string
& config
, cmGeneratorTarget
const* head
) const
7052 return this->GetLinkInterface(config
, head
, false);
7055 cmLinkInterface
const* cmGeneratorTarget::GetLinkInterface(
7056 const std::string
& config
, cmGeneratorTarget
const* head
,
7057 bool secondPass
) const
7059 // Imported targets have their own link interface.
7060 if (this->IsImported()) {
7061 return this->GetImportLinkInterface(config
, head
, LinkInterfaceFor::Link
,
7065 // Link interfaces are not supported for executables that do not
7067 if (this->GetType() == cmStateEnums::EXECUTABLE
&&
7068 !this->IsExecutableWithExports()) {
7072 // Lookup any existing link interface for this configuration.
7073 cmHeadToLinkInterfaceMap
& hm
= this->GetHeadToLinkInterfaceMap(config
);
7075 // If the link interface does not depend on the head target
7076 // then reuse the one from the head we computed first.
7077 if (!hm
.empty() && !hm
.begin()->second
.HadHeadSensitiveCondition
) {
7078 head
= hm
.begin()->first
;
7081 cmOptionalLinkInterface
& iface
= hm
[head
];
7083 iface
= cmOptionalLinkInterface();
7085 if (!iface
.LibrariesDone
) {
7086 iface
.LibrariesDone
= true;
7087 this->ComputeLinkInterfaceLibraries(config
, iface
, head
,
7088 LinkInterfaceFor::Link
);
7090 if (!iface
.AllDone
) {
7091 iface
.AllDone
= true;
7093 this->ComputeLinkInterface(config
, iface
, head
, secondPass
);
7094 this->ComputeLinkInterfaceRuntimeLibraries(config
, iface
);
7098 return iface
.Exists
? &iface
: nullptr;
7101 void cmGeneratorTarget::ComputeLinkInterface(
7102 const std::string
& config
, cmOptionalLinkInterface
& iface
,
7103 cmGeneratorTarget
const* headTarget
) const
7105 this->ComputeLinkInterface(config
, iface
, headTarget
, false);
7108 void cmGeneratorTarget::ComputeLinkInterface(
7109 const std::string
& config
, cmOptionalLinkInterface
& iface
,
7110 cmGeneratorTarget
const* headTarget
, bool secondPass
) const
7112 if (iface
.Explicit
) {
7113 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
7114 this->GetType() == cmStateEnums::STATIC_LIBRARY
||
7115 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
7116 // Shared libraries may have runtime implementation dependencies
7117 // on other shared libraries that are not in the interface.
7118 std::set
<cmLinkItem
> emitted
;
7119 for (cmLinkItem
const& lib
: iface
.Libraries
) {
7120 emitted
.insert(lib
);
7122 if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY
) {
7123 cmLinkImplementation
const* impl
= this->GetLinkImplementation(
7124 config
, LinkInterfaceFor::Link
, secondPass
);
7125 for (cmLinkImplItem
const& lib
: impl
->Libraries
) {
7126 if (emitted
.insert(lib
).second
) {
7128 // This is a runtime dependency on another shared library.
7129 if (lib
.Target
->GetType() == cmStateEnums::SHARED_LIBRARY
) {
7130 iface
.SharedDeps
.push_back(lib
);
7133 // TODO: Recognize shared library file names. Perhaps this
7134 // should be moved to cmComputeLinkInformation, but that
7135 // creates a chicken-and-egg problem since this list is needed
7136 // for its construction.
7142 } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN
||
7143 this->GetPolicyStatusCMP0022() == cmPolicies::OLD
) {
7144 // The link implementation is the default link interface.
7145 cmLinkImplementationLibraries
const* impl
=
7146 this->GetLinkImplementationLibrariesInternal(config
, headTarget
,
7147 LinkInterfaceFor::Link
);
7148 iface
.ImplementationIsInterface
= true;
7149 iface
.WrongConfigLibraries
= impl
->WrongConfigLibraries
;
7152 if (this->LinkLanguagePropagatesToDependents()) {
7153 // Targets using this archive need its language runtime libraries.
7154 if (cmLinkImplementation
const* impl
= this->GetLinkImplementation(
7155 config
, LinkInterfaceFor::Link
, secondPass
)) {
7156 iface
.Languages
= impl
->Languages
;
7160 if (this->GetType() == cmStateEnums::STATIC_LIBRARY
) {
7161 // Construct the property name suffix for this configuration.
7162 std::string suffix
= "_";
7163 if (!config
.empty()) {
7164 suffix
+= cmSystemTools::UpperCase(config
);
7166 suffix
+= "NOCONFIG";
7169 // How many repetitions are needed if this library has cyclic
7171 std::string propName
= cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix
);
7172 if (cmValue config_reps
= this->GetProperty(propName
)) {
7173 sscanf(config_reps
->c_str(), "%u", &iface
.Multiplicity
);
7174 } else if (cmValue reps
=
7175 this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
7176 sscanf(reps
->c_str(), "%u", &iface
.Multiplicity
);
7181 const cmLinkInterfaceLibraries
* cmGeneratorTarget::GetLinkInterfaceLibraries(
7182 const std::string
& config
, cmGeneratorTarget
const* head
,
7183 LinkInterfaceFor interfaceFor
) const
7185 // Imported targets have their own link interface.
7186 if (this->IsImported()) {
7187 return this->GetImportLinkInterface(config
, head
, interfaceFor
);
7190 // Link interfaces are not supported for executables that do not
7192 if (this->GetType() == cmStateEnums::EXECUTABLE
&&
7193 !this->IsExecutableWithExports()) {
7197 // Lookup any existing link interface for this configuration.
7198 cmHeadToLinkInterfaceMap
& hm
=
7199 (interfaceFor
== LinkInterfaceFor::Usage
7200 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config
)
7201 : this->GetHeadToLinkInterfaceMap(config
));
7203 // If the link interface does not depend on the head target
7204 // then reuse the one from the head we computed first.
7205 if (!hm
.empty() && !hm
.begin()->second
.HadHeadSensitiveCondition
) {
7206 head
= hm
.begin()->first
;
7209 cmOptionalLinkInterface
& iface
= hm
[head
];
7210 if (!iface
.LibrariesDone
) {
7211 iface
.LibrariesDone
= true;
7212 this->ComputeLinkInterfaceLibraries(config
, iface
, head
, interfaceFor
);
7215 return iface
.Exists
? &iface
: nullptr;
7218 std::string
cmGeneratorTarget::GetDirectory(
7219 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
7221 if (this->IsImported()) {
7222 auto fullPath
= this->Target
->ImportedGetFullPath(config
, artifact
);
7223 if (this->IsFrameworkOnApple()) {
7224 auto fwDescriptor
= this->GetGlobalGenerator()->SplitFrameworkPath(
7225 fullPath
, cmGlobalGenerator::FrameworkFormat::Strict
);
7227 return fwDescriptor
->Directory
;
7230 // Return the directory from which the target is imported.
7231 return cmSystemTools::GetFilenamePath(fullPath
);
7233 if (OutputInfo
const* info
= this->GetOutputInfo(config
)) {
7234 // Return the directory in which the target will be built.
7236 case cmStateEnums::RuntimeBinaryArtifact
:
7237 return info
->OutDir
;
7238 case cmStateEnums::ImportLibraryArtifact
:
7239 return info
->ImpDir
;
7245 bool cmGeneratorTarget::UsesDefaultOutputDir(
7246 const std::string
& config
, cmStateEnums::ArtifactType artifact
) const
7249 return this->ComputeOutputDir(config
, artifact
, dir
);
7252 cmGeneratorTarget::OutputInfo
const* cmGeneratorTarget::GetOutputInfo(
7253 const std::string
& config
) const
7255 // There is no output information for imported targets.
7256 if (this->IsImported()) {
7260 // Synthetic targets don't have output.
7261 if (this->IsSynthetic()) {
7265 // Only libraries and executables have well-defined output files.
7266 if (!this->HaveWellDefinedOutputFiles()) {
7267 std::string msg
= cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
7268 this->GetName(), " which has type ",
7269 cmState::GetTargetTypeName(this->GetType()));
7270 this->LocalGenerator
->IssueMessage(MessageType::INTERNAL_ERROR
, msg
);
7274 // Lookup/compute/cache the output information for this configuration.
7275 std::string config_upper
;
7276 if (!config
.empty()) {
7277 config_upper
= cmSystemTools::UpperCase(config
);
7279 auto i
= this->OutputInfoMap
.find(config_upper
);
7280 if (i
== this->OutputInfoMap
.end()) {
7281 // Add empty info in map to detect potential recursion.
7283 OutputInfoMapType::value_type
entry(config_upper
, info
);
7284 i
= this->OutputInfoMap
.insert(entry
).first
;
7286 // Compute output directories.
7287 this->ComputeOutputDir(config
, cmStateEnums::RuntimeBinaryArtifact
,
7289 this->ComputeOutputDir(config
, cmStateEnums::ImportLibraryArtifact
,
7291 if (!this->ComputePDBOutputDir("PDB", config
, info
.PdbDir
)) {
7292 info
.PdbDir
= info
.OutDir
;
7295 // Now update the previously-prepared map entry.
7297 } else if (i
->second
.empty()) {
7298 // An empty map entry indicates we have been called recursively
7299 // from the above block.
7300 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
7301 MessageType::FATAL_ERROR
,
7302 "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
7303 this->GetBacktrace());
7309 bool cmGeneratorTarget::ComputeOutputDir(const std::string
& config
,
7310 cmStateEnums::ArtifactType artifact
,
7311 std::string
& out
) const
7313 bool usesDefaultOutputDir
= false;
7314 std::string conf
= config
;
7316 // Look for a target property defining the target output directory
7317 // based on the target type.
7318 std::string targetTypeName
= this->GetOutputTargetType(artifact
);
7319 std::string propertyName
;
7320 if (!targetTypeName
.empty()) {
7321 propertyName
= cmStrCat(targetTypeName
, "_OUTPUT_DIRECTORY");
7324 // Check for a per-configuration output directory target property.
7325 std::string configUpper
= cmSystemTools::UpperCase(conf
);
7326 std::string configProp
;
7327 if (!targetTypeName
.empty()) {
7328 configProp
= cmStrCat(targetTypeName
, "_OUTPUT_DIRECTORY_", configUpper
);
7331 // Select an output directory.
7332 if (cmValue config_outdir
= this->GetProperty(configProp
)) {
7333 // Use the user-specified per-configuration output directory.
7334 out
= cmGeneratorExpression::Evaluate(*config_outdir
, this->LocalGenerator
,
7337 // Skip per-configuration subdirectory.
7339 } else if (cmValue outdir
= this->GetProperty(propertyName
)) {
7340 // Use the user-specified output directory.
7341 out
= cmGeneratorExpression::Evaluate(*outdir
, this->LocalGenerator
,
7343 // Skip per-configuration subdirectory if the value contained a
7344 // generator expression.
7345 if (out
!= *outdir
) {
7348 } else if (this->GetType() == cmStateEnums::EXECUTABLE
) {
7349 // Lookup the output path for executables.
7350 out
= this->Makefile
->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
7351 } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY
||
7352 this->GetType() == cmStateEnums::SHARED_LIBRARY
||
7353 this->GetType() == cmStateEnums::MODULE_LIBRARY
) {
7354 // Lookup the output path for libraries.
7355 out
= this->Makefile
->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
7358 // Default to the current output directory.
7359 usesDefaultOutputDir
= true;
7363 // Convert the output path to a full path in case it is
7364 // specified as a relative path. Treat a relative path as
7365 // relative to the current output directory for this makefile.
7366 out
= (cmSystemTools::CollapseFullPath(
7367 out
, this->LocalGenerator
->GetCurrentBinaryDirectory()));
7369 // The generator may add the configuration's subdirectory.
7370 if (!conf
.empty()) {
7372 this->GlobalGenerator
->UseEffectivePlatformName(this->Makefile
);
7373 std::string suffix
=
7374 usesDefaultOutputDir
&& useEPN
? "${EFFECTIVE_PLATFORM_NAME}" : "";
7375 this->LocalGenerator
->GetGlobalGenerator()->AppendDirectoryForConfig(
7376 "/", conf
, suffix
, out
);
7379 return usesDefaultOutputDir
;
7382 bool cmGeneratorTarget::ComputePDBOutputDir(const std::string
& kind
,
7383 const std::string
& config
,
7384 std::string
& out
) const
7386 // Look for a target property defining the target output directory
7387 // based on the target type.
7388 std::string propertyName
;
7389 if (!kind
.empty()) {
7390 propertyName
= cmStrCat(kind
, "_OUTPUT_DIRECTORY");
7392 std::string conf
= config
;
7394 // Check for a per-configuration output directory target property.
7395 std::string configUpper
= cmSystemTools::UpperCase(conf
);
7396 std::string configProp
;
7397 if (!kind
.empty()) {
7398 configProp
= cmStrCat(kind
, "_OUTPUT_DIRECTORY_", configUpper
);
7401 // Select an output directory.
7402 if (cmValue config_outdir
= this->GetProperty(configProp
)) {
7403 // Use the user-specified per-configuration output directory.
7404 out
= cmGeneratorExpression::Evaluate(*config_outdir
, this->LocalGenerator
,
7407 // Skip per-configuration subdirectory.
7409 } else if (cmValue outdir
= this->GetProperty(propertyName
)) {
7410 // Use the user-specified output directory.
7412 cmGeneratorExpression::Evaluate(*outdir
, this->LocalGenerator
, config
);
7414 // Skip per-configuration subdirectory if the value contained a
7415 // generator expression.
7416 if (out
!= *outdir
) {
7424 // Convert the output path to a full path in case it is
7425 // specified as a relative path. Treat a relative path as
7426 // relative to the current output directory for this makefile.
7427 out
= (cmSystemTools::CollapseFullPath(
7428 out
, this->LocalGenerator
->GetCurrentBinaryDirectory()));
7430 // The generator may add the configuration's subdirectory.
7431 if (!conf
.empty()) {
7432 this->LocalGenerator
->GetGlobalGenerator()->AppendDirectoryForConfig(
7433 "/", conf
, "", out
);
7438 bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string
& config
) const
7440 std::string install_rpath
;
7441 this->GetInstallRPATH(config
, install_rpath
);
7442 return !install_rpath
.empty() &&
7443 !this->Makefile
->IsOn("CMAKE_SKIP_INSTALL_RPATH");
7446 bool cmGeneratorTarget::GetBuildRPATH(const std::string
& config
,
7447 std::string
& rpath
) const
7449 return this->GetRPATH(config
, "BUILD_RPATH", rpath
);
7452 bool cmGeneratorTarget::GetInstallRPATH(const std::string
& config
,
7453 std::string
& rpath
) const
7455 return this->GetRPATH(config
, "INSTALL_RPATH", rpath
);
7458 bool cmGeneratorTarget::GetRPATH(const std::string
& config
,
7459 const std::string
& prop
,
7460 std::string
& rpath
) const
7462 cmValue value
= this->GetProperty(prop
);
7468 cmGeneratorExpression::Evaluate(*value
, this->LocalGenerator
, config
);
7473 void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
7474 const std::string
& config
, cmOptionalLinkInterface
& iface
,
7475 cmGeneratorTarget
const* headTarget
, LinkInterfaceFor interfaceFor
) const
7477 // Construct the property name suffix for this configuration.
7478 std::string suffix
= "_";
7479 if (!config
.empty()) {
7480 suffix
+= cmSystemTools::UpperCase(config
);
7482 suffix
+= "NOCONFIG";
7485 // An explicit list of interface libraries may be set for shared
7486 // libraries and executables that export symbols.
7487 bool haveExplicitLibraries
= false;
7488 cmValue explicitLibrariesCMP0022OLD
;
7489 std::string linkIfacePropCMP0022OLD
;
7490 bool const cmp0022NEW
= (this->GetPolicyStatusCMP0022() != cmPolicies::OLD
&&
7491 this->GetPolicyStatusCMP0022() != cmPolicies::WARN
);
7493 // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
7494 haveExplicitLibraries
= !this->Target
->GetLinkInterfaceEntries().empty() ||
7495 !this->Target
->GetLinkInterfaceDirectEntries().empty() ||
7496 !this->Target
->GetLinkInterfaceDirectExcludeEntries().empty();
7498 // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
7499 // shared lib or executable.
7500 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
7501 this->IsExecutableWithExports()) {
7502 // Lookup the per-configuration property.
7503 linkIfacePropCMP0022OLD
= cmStrCat("LINK_INTERFACE_LIBRARIES", suffix
);
7504 explicitLibrariesCMP0022OLD
= this->GetProperty(linkIfacePropCMP0022OLD
);
7506 // If not set, try the generic property.
7507 if (!explicitLibrariesCMP0022OLD
) {
7508 linkIfacePropCMP0022OLD
= "LINK_INTERFACE_LIBRARIES";
7509 explicitLibrariesCMP0022OLD
=
7510 this->GetProperty(linkIfacePropCMP0022OLD
);
7514 if (explicitLibrariesCMP0022OLD
&&
7515 this->GetPolicyStatusCMP0022() == cmPolicies::WARN
&&
7516 !this->PolicyWarnedCMP0022
) {
7517 // Compare the explicitly set old link interface properties to the
7518 // preferred new link interface property one and warn if different.
7519 cmValue newExplicitLibraries
=
7520 this->GetProperty("INTERFACE_LINK_LIBRARIES");
7521 if (newExplicitLibraries
&&
7522 (*newExplicitLibraries
!= *explicitLibrariesCMP0022OLD
)) {
7523 std::ostringstream w
;
7524 /* clang-format off */
7525 w
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0022
) << "\n"
7526 "Target \"" << this->GetName() << "\" has an "
7527 "INTERFACE_LINK_LIBRARIES property which differs from its " <<
7528 linkIfacePropCMP0022OLD
<< " properties."
7530 "INTERFACE_LINK_LIBRARIES:\n"
7531 " " << *newExplicitLibraries
<< "\n" <<
7532 linkIfacePropCMP0022OLD
<< ":\n"
7533 " " << *explicitLibrariesCMP0022OLD
<< "\n";
7534 /* clang-format on */
7535 this->LocalGenerator
->IssueMessage(MessageType::AUTHOR_WARNING
,
7537 this->PolicyWarnedCMP0022
= true;
7541 haveExplicitLibraries
= static_cast<bool>(explicitLibrariesCMP0022OLD
);
7544 // There is no implicit link interface for executables or modules
7545 // so if none was explicitly set then there is no link interface.
7546 if (!haveExplicitLibraries
&&
7547 (this->GetType() == cmStateEnums::EXECUTABLE
||
7548 (this->GetType() == cmStateEnums::MODULE_LIBRARY
))) {
7551 iface
.Exists
= true;
7553 // If CMP0022 is NEW then the plain tll signature sets the
7554 // INTERFACE_LINK_LIBRARIES property. Even if the project
7555 // clears it, the link interface is still explicit.
7556 iface
.Explicit
= cmp0022NEW
|| explicitLibrariesCMP0022OLD
;
7559 // The interface libraries are specified by INTERFACE_LINK_LIBRARIES.
7560 // Use its special representation directly to get backtraces.
7561 this->ExpandLinkItems(
7562 kINTERFACE_LINK_LIBRARIES
, this->Target
->GetLinkInterfaceEntries(),
7563 config
, headTarget
, interfaceFor
, LinkInterfaceField::Libraries
, iface
);
7564 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT
,
7565 this->Target
->GetLinkInterfaceDirectEntries(),
7566 config
, headTarget
, interfaceFor
,
7567 LinkInterfaceField::HeadInclude
, iface
);
7568 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE
,
7569 this->Target
->GetLinkInterfaceDirectExcludeEntries(),
7570 config
, headTarget
, interfaceFor
,
7571 LinkInterfaceField::HeadExclude
, iface
);
7572 } else if (explicitLibrariesCMP0022OLD
) {
7573 // The interface libraries have been explicitly set in pre-CMP0022 style.
7574 std::vector
<BT
<std::string
>> entries
;
7575 entries
.emplace_back(*explicitLibrariesCMP0022OLD
);
7576 this->ExpandLinkItems(linkIfacePropCMP0022OLD
, cmMakeRange(entries
),
7577 config
, headTarget
, interfaceFor
,
7578 LinkInterfaceField::Libraries
, iface
);
7581 // If the link interface is explicit, do not fall back to the link impl.
7582 if (iface
.Explicit
) {
7586 // The link implementation is the default link interface.
7587 if (cmLinkImplementationLibraries
const* impl
=
7588 this->GetLinkImplementationLibrariesInternal(config
, headTarget
,
7590 iface
.Libraries
.insert(iface
.Libraries
.end(), impl
->Libraries
.begin(),
7591 impl
->Libraries
.end());
7592 if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN
&&
7593 !this->PolicyWarnedCMP0022
&& interfaceFor
== LinkInterfaceFor::Link
) {
7594 // Compare the link implementation fallback link interface to the
7595 // preferred new link interface property and warn if different.
7596 cmLinkInterface ifaceNew
;
7597 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES
,
7598 this->Target
->GetLinkInterfaceEntries(), config
,
7599 headTarget
, interfaceFor
,
7600 LinkInterfaceField::Libraries
, ifaceNew
);
7601 if (ifaceNew
.Libraries
!= iface
.Libraries
) {
7602 std::string oldLibraries
= cmJoin(impl
->Libraries
, ";");
7603 std::string newLibraries
= cmJoin(ifaceNew
.Libraries
, ";");
7604 if (oldLibraries
.empty()) {
7605 oldLibraries
= "(empty)";
7607 if (newLibraries
.empty()) {
7608 newLibraries
= "(empty)";
7611 std::ostringstream w
;
7612 /* clang-format off */
7613 w
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0022
) << "\n"
7614 "Target \"" << this->GetName() << "\" has an "
7615 "INTERFACE_LINK_LIBRARIES property. "
7616 "This should be preferred as the source of the link interface "
7617 "for this library but because CMP0022 is not set CMake is "
7618 "ignoring the property and using the link implementation "
7619 "as the link interface instead."
7621 "INTERFACE_LINK_LIBRARIES:\n"
7622 " " << newLibraries
<< "\n"
7623 "Link implementation:\n"
7624 " " << oldLibraries
<< "\n";
7625 /* clang-format on */
7626 this->LocalGenerator
->IssueMessage(MessageType::AUTHOR_WARNING
,
7628 this->PolicyWarnedCMP0022
= true;
7636 template <typename ReturnType
>
7637 ReturnType
constructItem(cmGeneratorTarget
* target
,
7638 cmListFileBacktrace
const& bt
);
7641 inline cmLinkImplItem
constructItem(cmGeneratorTarget
* target
,
7642 cmListFileBacktrace
const& bt
)
7644 return cmLinkImplItem(cmLinkItem(target
, false, bt
), false);
7648 inline cmLinkItem
constructItem(cmGeneratorTarget
* target
,
7649 cmListFileBacktrace
const& bt
)
7651 return cmLinkItem(target
, false, bt
);
7654 template <typename ValueType
>
7655 std::vector
<ValueType
> computeImplicitLanguageTargets(
7656 std::string
const& lang
, std::string
const& config
,
7657 cmGeneratorTarget
const* currentTarget
)
7659 cmListFileBacktrace bt
;
7660 std::vector
<ValueType
> result
;
7661 cmLocalGenerator
* lg
= currentTarget
->GetLocalGenerator();
7663 std::string
const& runtimeLibrary
=
7664 currentTarget
->GetRuntimeLinkLibrary(lang
, config
);
7665 if (cmValue runtimeLinkOptions
= currentTarget
->Makefile
->GetDefinition(
7666 "CMAKE_" + lang
+ "_RUNTIME_LIBRARIES_" + runtimeLibrary
)) {
7667 cmList libsList
{ *runtimeLinkOptions
};
7668 result
.reserve(libsList
.size());
7670 for (auto const& i
: libsList
) {
7671 cmGeneratorTarget::TargetOrString resolved
=
7672 currentTarget
->ResolveTargetReference(i
, lg
);
7673 if (resolved
.Target
) {
7674 result
.emplace_back(constructItem
<ValueType
>(resolved
.Target
, bt
));
7683 void cmGeneratorTarget::ComputeLinkInterfaceRuntimeLibraries(
7684 const std::string
& config
, cmOptionalLinkInterface
& iface
) const
7686 for (std::string
const& lang
: iface
.Languages
) {
7687 if ((lang
== "CUDA" || lang
== "HIP") &&
7688 iface
.LanguageRuntimeLibraries
.find(lang
) ==
7689 iface
.LanguageRuntimeLibraries
.end()) {
7690 auto implicitTargets
=
7691 computeImplicitLanguageTargets
<cmLinkItem
>(lang
, config
, this);
7692 iface
.LanguageRuntimeLibraries
[lang
] = std::move(implicitTargets
);
7697 void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries(
7698 const std::string
& config
, cmOptionalLinkImplementation
& impl
) const
7700 for (std::string
const& lang
: impl
.Languages
) {
7701 if ((lang
== "CUDA" || lang
== "HIP") &&
7702 impl
.LanguageRuntimeLibraries
.find(lang
) ==
7703 impl
.LanguageRuntimeLibraries
.end()) {
7704 auto implicitTargets
=
7705 computeImplicitLanguageTargets
<cmLinkImplItem
>(lang
, config
, this);
7706 impl
.LanguageRuntimeLibraries
[lang
] = std::move(implicitTargets
);
7711 const cmLinkInterface
* cmGeneratorTarget::GetImportLinkInterface(
7712 const std::string
& config
, cmGeneratorTarget
const* headTarget
,
7713 LinkInterfaceFor interfaceFor
, bool secondPass
) const
7715 cmGeneratorTarget::ImportInfo
const* info
= this->GetImportInfo(config
);
7720 cmHeadToLinkInterfaceMap
& hm
=
7721 (interfaceFor
== LinkInterfaceFor::Usage
7722 ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config
)
7723 : this->GetHeadToLinkInterfaceMap(config
));
7725 // If the link interface does not depend on the head target
7726 // then reuse the one from the head we computed first.
7727 if (!hm
.empty() && !hm
.begin()->second
.HadHeadSensitiveCondition
) {
7728 headTarget
= hm
.begin()->first
;
7731 cmOptionalLinkInterface
& iface
= hm
[headTarget
];
7733 iface
= cmOptionalLinkInterface();
7735 if (!iface
.AllDone
) {
7736 iface
.AllDone
= true;
7737 iface
.LibrariesDone
= true;
7738 iface
.Multiplicity
= info
->Multiplicity
;
7739 cmExpandList(info
->Languages
, iface
.Languages
);
7740 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT
,
7741 cmMakeRange(info
->LibrariesHeadInclude
), config
,
7742 headTarget
, interfaceFor
,
7743 LinkInterfaceField::HeadInclude
, iface
);
7744 this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE
,
7745 cmMakeRange(info
->LibrariesHeadExclude
), config
,
7746 headTarget
, interfaceFor
,
7747 LinkInterfaceField::HeadExclude
, iface
);
7748 this->ExpandLinkItems(info
->LibrariesProp
, cmMakeRange(info
->Libraries
),
7749 config
, headTarget
, interfaceFor
,
7750 LinkInterfaceField::Libraries
, iface
);
7751 cmList deps
{ info
->SharedDeps
};
7752 LookupLinkItemScope scope
{ this->LocalGenerator
};
7754 auto linkFeature
= cmLinkItem::DEFAULT
;
7755 for (auto const& dep
: deps
) {
7756 if (auto maybeLinkFeature
= ParseLinkFeature(dep
)) {
7757 linkFeature
= std::move(*maybeLinkFeature
);
7761 if (cm::optional
<cmLinkItem
> maybeItem
= this->LookupLinkItem(
7762 dep
, cmListFileBacktrace(), linkFeature
, &scope
, LookupSelf::No
)) {
7763 iface
.SharedDeps
.emplace_back(std::move(*maybeItem
));
7771 cmGeneratorTarget::ImportInfo
const* cmGeneratorTarget::GetImportInfo(
7772 const std::string
& config
) const
7774 // There is no imported information for non-imported targets.
7775 if (!this->IsImported()) {
7779 // Lookup/compute/cache the import information for this
7781 std::string config_upper
;
7782 if (!config
.empty()) {
7783 config_upper
= cmSystemTools::UpperCase(config
);
7785 config_upper
= "NOCONFIG";
7788 auto i
= this->ImportInfoMap
.find(config_upper
);
7789 if (i
== this->ImportInfoMap
.end()) {
7791 this->ComputeImportInfo(config_upper
, info
);
7792 ImportInfoMapType::value_type
entry(config_upper
, info
);
7793 i
= this->ImportInfoMap
.insert(entry
).first
;
7796 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
7799 // If the location is empty then the target is not available for
7800 // this configuration.
7801 if (i
->second
.Location
.empty() && i
->second
.ImportLibrary
.empty()) {
7805 // Return the import information.
7809 void cmGeneratorTarget::ComputeImportInfo(std::string
const& desired_config
,
7810 ImportInfo
& info
) const
7812 // This method finds information about an imported target from its
7813 // properties. The "IMPORTED_" namespace is reserved for properties
7814 // defined by the project exporting the target.
7816 // Initialize members.
7817 info
.NoSOName
= false;
7819 cmValue loc
= nullptr;
7820 cmValue imp
= nullptr;
7822 if (!this->Target
->GetMappedConfig(desired_config
, loc
, imp
, suffix
)) {
7826 // Get the link interface.
7828 // Use the INTERFACE_LINK_LIBRARIES special representation directly
7829 // to get backtraces.
7830 cmBTStringRange entries
= this->Target
->GetLinkInterfaceEntries();
7831 if (!entries
.empty()) {
7832 info
.LibrariesProp
= "INTERFACE_LINK_LIBRARIES";
7833 for (BT
<std::string
> const& entry
: entries
) {
7834 info
.Libraries
.emplace_back(entry
);
7836 } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY
) {
7837 std::string linkProp
=
7838 cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix
);
7839 cmValue propertyLibs
= this->GetProperty(linkProp
);
7840 if (!propertyLibs
) {
7841 linkProp
= "IMPORTED_LINK_INTERFACE_LIBRARIES";
7842 propertyLibs
= this->GetProperty(linkProp
);
7845 info
.LibrariesProp
= linkProp
;
7846 info
.Libraries
.emplace_back(*propertyLibs
);
7850 for (BT
<std::string
> const& entry
:
7851 this->Target
->GetLinkInterfaceDirectEntries()) {
7852 info
.LibrariesHeadInclude
.emplace_back(entry
);
7854 for (BT
<std::string
> const& entry
:
7855 this->Target
->GetLinkInterfaceDirectExcludeEntries()) {
7856 info
.LibrariesHeadExclude
.emplace_back(entry
);
7858 if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY
) {
7860 info
.LibName
= *loc
;
7865 // A provided configuration has been chosen. Load the
7866 // configuration's properties.
7868 // Get the location.
7870 info
.Location
= *loc
;
7872 std::string impProp
= cmStrCat("IMPORTED_LOCATION", suffix
);
7873 if (cmValue config_location
= this->GetProperty(impProp
)) {
7874 info
.Location
= *config_location
;
7875 } else if (cmValue location
= this->GetProperty("IMPORTED_LOCATION")) {
7876 info
.Location
= *location
;
7881 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
) {
7882 std::string soProp
= cmStrCat("IMPORTED_SONAME", suffix
);
7883 if (cmValue config_soname
= this->GetProperty(soProp
)) {
7884 info
.SOName
= *config_soname
;
7885 } else if (cmValue soname
= this->GetProperty("IMPORTED_SONAME")) {
7886 info
.SOName
= *soname
;
7890 // Get the "no-soname" mark.
7891 if (this->GetType() == cmStateEnums::SHARED_LIBRARY
) {
7892 std::string soProp
= cmStrCat("IMPORTED_NO_SONAME", suffix
);
7893 if (cmValue config_no_soname
= this->GetProperty(soProp
)) {
7894 info
.NoSOName
= cmIsOn(*config_no_soname
);
7895 } else if (cmValue no_soname
= this->GetProperty("IMPORTED_NO_SONAME")) {
7896 info
.NoSOName
= cmIsOn(*no_soname
);
7900 // Get the import library.
7902 info
.ImportLibrary
= *imp
;
7903 } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
7904 this->IsExecutableWithExports()) {
7905 std::string impProp
= cmStrCat("IMPORTED_IMPLIB", suffix
);
7906 if (cmValue config_implib
= this->GetProperty(impProp
)) {
7907 info
.ImportLibrary
= *config_implib
;
7908 } else if (cmValue implib
= this->GetProperty("IMPORTED_IMPLIB")) {
7909 info
.ImportLibrary
= *implib
;
7913 // Get the link dependencies.
7915 std::string linkProp
=
7916 cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix
);
7917 if (cmValue config_libs
= this->GetProperty(linkProp
)) {
7918 info
.SharedDeps
= *config_libs
;
7919 } else if (cmValue libs
=
7920 this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
7921 info
.SharedDeps
= *libs
;
7925 // Get the link languages.
7926 if (this->LinkLanguagePropagatesToDependents()) {
7927 std::string linkProp
=
7928 cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix
);
7929 if (cmValue config_libs
= this->GetProperty(linkProp
)) {
7930 info
.Languages
= *config_libs
;
7931 } else if (cmValue libs
=
7932 this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
7933 info
.Languages
= *libs
;
7937 // Get information if target is managed assembly.
7939 std::string linkProp
= "IMPORTED_COMMON_LANGUAGE_RUNTIME";
7940 if (cmValue pc
= this->GetProperty(linkProp
+ suffix
)) {
7941 info
.Managed
= this->CheckManagedType(*pc
);
7942 } else if (cmValue p
= this->GetProperty(linkProp
)) {
7943 info
.Managed
= this->CheckManagedType(*p
);
7947 // Get the cyclic repetition count.
7948 if (this->GetType() == cmStateEnums::STATIC_LIBRARY
) {
7949 std::string linkProp
=
7950 cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix
);
7951 if (cmValue config_reps
= this->GetProperty(linkProp
)) {
7952 sscanf(config_reps
->c_str(), "%u", &info
.Multiplicity
);
7953 } else if (cmValue reps
=
7954 this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
7955 sscanf(reps
->c_str(), "%u", &info
.Multiplicity
);
7960 cmHeadToLinkInterfaceMap
& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
7961 const std::string
& config
) const
7963 return this->LinkInterfaceMap
[cmSystemTools::UpperCase(config
)];
7966 cmHeadToLinkInterfaceMap
&
7967 cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
7968 const std::string
& config
) const
7971 ->LinkInterfaceUsageRequirementsOnlyMap
[cmSystemTools::UpperCase(config
)];
7974 const cmLinkImplementation
* cmGeneratorTarget::GetLinkImplementation(
7975 const std::string
& config
, LinkInterfaceFor implFor
) const
7977 return this->GetLinkImplementation(config
, implFor
, false);
7980 const cmLinkImplementation
* cmGeneratorTarget::GetLinkImplementation(
7981 const std::string
& config
, LinkInterfaceFor implFor
, bool secondPass
) const
7983 // There is no link implementation for targets that cannot compile sources.
7984 if (!this->CanCompileSources()) {
7988 HeadToLinkImplementationMap
& hm
=
7989 (implFor
== LinkInterfaceFor::Usage
7990 ? this->GetHeadToLinkImplementationUsageRequirementsMap(config
)
7991 : this->GetHeadToLinkImplementationMap(config
));
7992 cmOptionalLinkImplementation
& impl
= hm
[this];
7994 impl
= cmOptionalLinkImplementation();
7996 if (!impl
.LibrariesDone
) {
7997 impl
.LibrariesDone
= true;
7998 this->ComputeLinkImplementationLibraries(config
, impl
, this, implFor
);
8000 if (!impl
.LanguagesDone
) {
8001 impl
.LanguagesDone
= true;
8002 this->ComputeLinkImplementationLanguages(config
, impl
);
8003 this->ComputeLinkImplementationRuntimeLibraries(config
, impl
);
8008 cmGeneratorTarget::HeadToLinkImplementationMap
&
8009 cmGeneratorTarget::GetHeadToLinkImplementationMap(
8010 std::string
const& config
) const
8012 return this->LinkImplMap
[cmSystemTools::UpperCase(config
)];
8015 cmGeneratorTarget::HeadToLinkImplementationMap
&
8016 cmGeneratorTarget::GetHeadToLinkImplementationUsageRequirementsMap(
8017 std::string
const& config
) const
8020 ->LinkImplUsageRequirementsOnlyMap
[cmSystemTools::UpperCase(config
)];
8023 bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
8024 std::vector
<cmSourceFile
*>& files
) const
8026 std::vector
<std::string
> const& configs
=
8027 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
8029 auto it
= configs
.begin();
8030 const std::string
& firstConfig
= *it
;
8031 this->GetSourceFilesWithoutObjectLibraries(files
, firstConfig
);
8033 for (; it
!= configs
.end(); ++it
) {
8034 std::vector
<cmSourceFile
*> configFiles
;
8035 this->GetSourceFilesWithoutObjectLibraries(configFiles
, *it
);
8036 if (configFiles
!= files
) {
8037 std::string firstConfigFiles
;
8038 const char* sep
= "";
8039 for (cmSourceFile
* f
: files
) {
8040 firstConfigFiles
+= sep
;
8041 firstConfigFiles
+= f
->ResolveFullPath();
8045 std::string thisConfigFiles
;
8047 for (cmSourceFile
* f
: configFiles
) {
8048 thisConfigFiles
+= sep
;
8049 thisConfigFiles
+= f
->ResolveFullPath();
8052 std::ostringstream e
;
8053 /* clang-format off */
8054 e
<< "Target \"" << this->GetName()
8055 << "\" has source files which vary by "
8056 "configuration. This is not supported by the \""
8057 << this->GlobalGenerator
->GetName()
8058 << "\" generator.\n"
8059 "Config \"" << firstConfig
<< "\":\n"
8060 " " << firstConfigFiles
<< "\n"
8061 "Config \"" << *it
<< "\":\n"
8062 " " << thisConfigFiles
<< "\n";
8063 /* clang-format on */
8064 this->LocalGenerator
->IssueMessage(MessageType::FATAL_ERROR
, e
.str());
8071 void cmGeneratorTarget::GetObjectLibrariesCMP0026(
8072 std::vector
<cmGeneratorTarget
*>& objlibs
) const
8074 // At configure-time, this method can be called as part of getting the
8075 // LOCATION property or to export() a file to be include()d. However
8076 // there is no cmGeneratorTarget at configure-time, so search the SOURCES
8077 // for TARGET_OBJECTS instead for backwards compatibility with OLD
8078 // behavior of CMP0024 and CMP0026 only.
8079 cmBTStringRange rng
= this->Target
->GetSourceEntries();
8080 for (auto const& entry
: rng
) {
8081 cmList files
{ entry
.Value
};
8082 for (auto const& li
: files
) {
8083 if (cmHasLiteralPrefix(li
, "$<TARGET_OBJECTS:") && li
.back() == '>') {
8084 std::string objLibName
= li
.substr(17, li
.size() - 18);
8086 if (cmGeneratorExpression::Find(objLibName
) != std::string::npos
) {
8089 cmGeneratorTarget
* objLib
=
8090 this->LocalGenerator
->FindGeneratorTargetToUse(objLibName
);
8092 objlibs
.push_back(objLib
);
8099 std::string
cmGeneratorTarget::CheckCMP0004(std::string
const& item
) const
8101 // Strip whitespace off the library names because we used to do this
8102 // in case variables were expanded at generate time. We no longer
8103 // do the expansion but users link to libraries like " ${VAR} ".
8104 std::string lib
= item
;
8105 std::string::size_type pos
= lib
.find_first_not_of(" \t\r\n");
8106 if (pos
!= std::string::npos
) {
8107 lib
= lib
.substr(pos
);
8109 pos
= lib
.find_last_not_of(" \t\r\n");
8110 if (pos
!= std::string::npos
) {
8111 lib
= lib
.substr(0, pos
+ 1);
8114 cmake
* cm
= this->LocalGenerator
->GetCMakeInstance();
8115 switch (this->GetPolicyStatusCMP0004()) {
8116 case cmPolicies::WARN
: {
8117 std::ostringstream w
;
8118 w
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0004
) << "\n"
8119 << "Target \"" << this->GetName() << "\" links to item \"" << item
8120 << "\" which has leading or trailing whitespace.";
8121 cm
->IssueMessage(MessageType::AUTHOR_WARNING
, w
.str(),
8122 this->GetBacktrace());
8125 case cmPolicies::OLD
:
8127 case cmPolicies::NEW
: {
8128 std::ostringstream e
;
8129 e
<< "Target \"" << this->GetName() << "\" links to item \"" << item
8130 << "\" which has leading or trailing whitespace. "
8131 << "This is now an error according to policy CMP0004.";
8132 cm
->IssueMessage(MessageType::FATAL_ERROR
, e
.str(),
8133 this->GetBacktrace());
8135 case cmPolicies::REQUIRED_IF_USED
:
8136 case cmPolicies::REQUIRED_ALWAYS
: {
8137 std::ostringstream e
;
8138 e
<< cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004
) << "\n"
8139 << "Target \"" << this->GetName() << "\" links to item \"" << item
8140 << "\" which has leading or trailing whitespace.";
8141 cm
->IssueMessage(MessageType::FATAL_ERROR
, e
.str(),
8142 this->GetBacktrace());
8149 bool cmGeneratorTarget::IsDeprecated() const
8151 cmValue deprecation
= this->GetProperty("DEPRECATION");
8152 return cmNonempty(deprecation
);
8155 std::string
cmGeneratorTarget::GetDeprecation() const
8157 // find DEPRECATION property
8158 if (cmValue deprecation
= this->GetProperty("DEPRECATION")) {
8159 return *deprecation
;
8161 return std::string();
8164 void cmGeneratorTarget::GetLanguages(std::set
<std::string
>& languages
,
8165 const std::string
& config
) const
8167 // Targets that do not compile anything have no languages.
8168 if (!this->CanCompileSources()) {
8172 std::vector
<cmSourceFile
*> sourceFiles
;
8173 this->GetSourceFiles(sourceFiles
, config
);
8174 for (cmSourceFile
* src
: sourceFiles
) {
8175 const std::string
& lang
= src
->GetOrDetermineLanguage();
8176 if (!lang
.empty()) {
8177 languages
.insert(lang
);
8181 std::set
<cmGeneratorTarget
const*> objectLibraries
;
8182 if (!this->GlobalGenerator
->GetConfigureDoneCMP0026()) {
8183 std::vector
<cmGeneratorTarget
*> objectTargets
;
8184 this->GetObjectLibrariesCMP0026(objectTargets
);
8185 for (cmGeneratorTarget
* gt
: objectTargets
) {
8186 objectLibraries
.insert(gt
);
8189 objectLibraries
= this->GetSourceObjectLibraries(config
);
8191 for (cmGeneratorTarget
const* objLib
: objectLibraries
) {
8192 objLib
->GetLanguages(languages
, config
);
8196 std::set
<cmGeneratorTarget
const*> cmGeneratorTarget::GetSourceObjectLibraries(
8197 std::string
const& config
) const
8199 std::set
<cmGeneratorTarget
const*> objectLibraries
;
8200 std::vector
<cmSourceFile
const*> externalObjects
;
8201 this->GetExternalObjects(externalObjects
, config
);
8202 for (cmSourceFile
const* extObj
: externalObjects
) {
8203 std::string objLib
= extObj
->GetObjectLibrary();
8204 if (cmGeneratorTarget
* tgt
=
8205 this->LocalGenerator
->FindGeneratorTargetToUse(objLib
)) {
8206 objectLibraries
.insert(tgt
);
8210 return objectLibraries
;
8213 bool cmGeneratorTarget::IsLanguageUsed(std::string
const& language
,
8214 std::string
const& config
) const
8216 std::set
<std::string
> languages
;
8217 this->GetLanguages(languages
, config
);
8218 return languages
.count(language
);
8221 bool cmGeneratorTarget::IsCSharpOnly() const
8223 // Only certain target types may compile CSharp.
8224 if (this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
8225 this->GetType() != cmStateEnums::STATIC_LIBRARY
&&
8226 this->GetType() != cmStateEnums::EXECUTABLE
) {
8229 std::set
<std::string
> languages
= this->GetAllConfigCompileLanguages();
8230 // Consider an explicit linker language property, but *not* the
8231 // computed linker language that may depend on linked targets.
8232 cmValue linkLang
= this->GetProperty("LINKER_LANGUAGE");
8233 if (cmNonempty(linkLang
)) {
8234 languages
.insert(*linkLang
);
8236 return languages
.size() == 1 && languages
.count("CSharp") > 0;
8239 bool cmGeneratorTarget::IsDotNetSdkTarget() const
8241 return !this->GetProperty("DOTNET_SDK").IsEmpty();
8244 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
8245 const std::string
& config
, cmOptionalLinkImplementation
& impl
) const
8247 // This target needs runtime libraries for its source languages.
8248 std::set
<std::string
> languages
;
8249 // Get languages used in our source files.
8250 this->GetLanguages(languages
, config
);
8251 // Copy the set of languages to the link implementation.
8252 impl
.Languages
.insert(impl
.Languages
.begin(), languages
.begin(),
8256 bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string
& config
) const
8258 if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
8261 std::string build_rpath
;
8262 if (this->GetBuildRPATH(config
, build_rpath
)) {
8265 if (cmLinkImplementationLibraries
const* impl
=
8266 this->GetLinkImplementationLibraries(config
, LinkInterfaceFor::Link
)) {
8267 return !impl
->Libraries
.empty();
8272 cmLinkImplementationLibraries
const*
8273 cmGeneratorTarget::GetLinkImplementationLibraries(
8274 const std::string
& config
, LinkInterfaceFor implFor
) const
8276 return this->GetLinkImplementationLibrariesInternal(config
, this, implFor
);
8279 cmLinkImplementationLibraries
const*
8280 cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
8281 const std::string
& config
, cmGeneratorTarget
const* head
,
8282 LinkInterfaceFor implFor
) const
8284 // There is no link implementation for targets that cannot compile sources.
8285 if (!this->CanCompileSources()) {
8289 // Populate the link implementation libraries for this configuration.
8290 HeadToLinkImplementationMap
& hm
=
8291 (implFor
== LinkInterfaceFor::Usage
8292 ? this->GetHeadToLinkImplementationUsageRequirementsMap(config
)
8293 : this->GetHeadToLinkImplementationMap(config
));
8295 // If the link implementation does not depend on the head target
8296 // then reuse the one from the head we computed first.
8297 if (!hm
.empty() && !hm
.begin()->second
.HadHeadSensitiveCondition
) {
8298 head
= hm
.begin()->first
;
8301 cmOptionalLinkImplementation
& impl
= hm
[head
];
8302 if (!impl
.LibrariesDone
) {
8303 impl
.LibrariesDone
= true;
8304 this->ComputeLinkImplementationLibraries(config
, impl
, head
, implFor
);
8309 bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
8310 const std::string
& p
) const
8312 return cm::contains(this->LinkImplicitNullProperties
, p
);
8316 class TransitiveLinkImpl
8318 cmGeneratorTarget
const* Self
;
8319 std::string
const& Config
;
8320 LinkInterfaceFor ImplFor
;
8321 cmLinkImplementation
& Impl
;
8323 std::set
<cmLinkItem
> Emitted
;
8324 std::set
<cmLinkItem
> Excluded
;
8325 std::unordered_set
<cmGeneratorTarget
const*> Followed
;
8327 void Follow(cmGeneratorTarget
const* target
);
8330 TransitiveLinkImpl(cmGeneratorTarget
const* self
, std::string
const& config
,
8331 LinkInterfaceFor implFor
, cmLinkImplementation
& impl
)
8342 void TransitiveLinkImpl::Follow(cmGeneratorTarget
const* target
)
8344 if (!target
|| !this->Followed
.insert(target
).second
||
8345 target
->GetPolicyStatusCMP0022() == cmPolicies::OLD
||
8346 target
->GetPolicyStatusCMP0022() == cmPolicies::WARN
) {
8350 // Get this target's usage requirements.
8351 cmLinkInterfaceLibraries
const* iface
=
8352 target
->GetLinkInterfaceLibraries(this->Config
, this->Self
, this->ImplFor
);
8356 if (iface
->HadContextSensitiveCondition
) {
8357 this->Impl
.HadContextSensitiveCondition
= true;
8360 // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements.
8361 for (cmLinkItem
const& item
: iface
->HeadInclude
) {
8362 // Inject direct dependencies from the item's usage requirements
8363 // before the item itself.
8364 this->Follow(item
.Target
);
8366 // Add the item itself, but at most once.
8367 if (this->Emitted
.insert(item
).second
) {
8368 this->Impl
.Libraries
.emplace_back(item
, /* checkCMP0027= */ false);
8372 // Follow transitive dependencies.
8373 for (cmLinkItem
const& item
: iface
->Libraries
) {
8374 this->Follow(item
.Target
);
8377 // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8378 // usage requirements.
8379 for (cmLinkItem
const& item
: iface
->HeadExclude
) {
8380 this->Excluded
.insert(item
);
8384 void TransitiveLinkImpl::Compute()
8386 // Save the original items and start with an empty list.
8387 std::vector
<cmLinkImplItem
> original
= std::move(this->Impl
.Libraries
);
8389 // Avoid injecting any original items as usage requirements.
8390 // This gives LINK_LIBRARIES final control over the order
8391 // if it explicitly lists everything.
8392 this->Emitted
.insert(original
.cbegin(), original
.cend());
8394 // Process each original item.
8395 for (cmLinkImplItem
& item
: original
) {
8396 // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT'
8397 // usage requirements before the item itself.
8398 this->Follow(item
.Target
);
8400 // Add the item itself.
8401 this->Impl
.Libraries
.emplace_back(std::move(item
));
8404 // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
8405 // usage requirements found through any dependency above.
8406 this->Impl
.Libraries
.erase(
8407 std::remove_if(this->Impl
.Libraries
.begin(), this->Impl
.Libraries
.end(),
8408 [this](cmLinkImplItem
const& item
) {
8409 return this->Excluded
.find(item
) != this->Excluded
.end();
8411 this->Impl
.Libraries
.end());
8414 void ComputeLinkImplTransitive(cmGeneratorTarget
const* self
,
8415 std::string
const& config
,
8416 LinkInterfaceFor implFor
,
8417 cmLinkImplementation
& impl
)
8419 TransitiveLinkImpl
transitiveLinkImpl(self
, config
, implFor
, impl
);
8420 transitiveLinkImpl
.Compute();
8424 bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache
& cache
,
8425 std::string
const& config
)
8427 cmOptionalLinkImplementation impl
;
8428 this->ComputeLinkImplementationLibraries(config
, impl
, this,
8429 LinkInterfaceFor::Link
);
8431 cmCxxModuleUsageEffects
usage(this);
8433 auto& SyntheticDeps
= this->Configs
[config
].SyntheticDeps
;
8435 for (auto const& entry
: impl
.Libraries
) {
8436 auto const* gt
= entry
.Target
;
8437 if (!gt
|| !gt
->IsImported()) {
8441 if (gt
->HaveCxx20ModuleSources()) {
8442 cmCryptoHash
hasher(cmCryptoHash::AlgoSHA3_512
);
8443 constexpr size_t HASH_TRUNCATION
= 12;
8444 auto dirhash
= hasher
.HashString(
8445 gt
->GetLocalGenerator()->GetCurrentBinaryDirectory());
8446 std::string safeName
= gt
->GetName();
8447 cmSystemTools::ReplaceString(safeName
, ":", "_");
8449 hasher
.HashString(cmStrCat("@d_", dirhash
, "@u_", usage
.GetHash()));
8450 std::string targetName
=
8451 cmStrCat(safeName
, "@synth_", targetIdent
.substr(0, HASH_TRUNCATION
));
8453 // Check the cache to see if this instance of the imported target has
8454 // already been created.
8455 auto cached
= cache
.CxxModuleTargets
.find(targetName
);
8456 cmGeneratorTarget
const* synthDep
= nullptr;
8457 if (cached
== cache
.CxxModuleTargets
.end()) {
8458 auto const* model
= gt
->Target
;
8459 auto* mf
= gt
->Makefile
;
8460 auto* lg
= gt
->GetLocalGenerator();
8461 auto* tgt
= mf
->AddSynthesizedTarget(cmStateEnums::INTERFACE_LIBRARY
,
8464 // Copy relevant information from the existing IMPORTED target.
8466 // Copy policies to the target.
8467 tgt
->CopyPolicyStatuses(model
);
8471 auto fsNames
= model
->GetAllFileSetNames();
8472 for (auto const& fsName
: fsNames
) {
8473 auto const* fs
= model
->GetFileSet(fsName
);
8475 mf
->IssueMessage(MessageType::INTERNAL_ERROR
,
8476 cmStrCat("Failed to find file set named '",
8477 fsName
, "' on target '",
8478 tgt
->GetName(), '\''));
8482 ->GetOrCreateFileSet(fs
->GetName(), fs
->GetType(),
8483 fs
->GetVisibility())
8485 newFs
->CopyEntries(fs
);
8489 // Copy imported C++ module properties.
8490 tgt
->CopyImportedCxxModulesEntries(model
);
8492 // Copy other properties which may affect the C++ module BMI
8494 tgt
->CopyImportedCxxModulesProperties(model
);
8496 tgt
->AddLinkLibrary(*mf
,
8497 cmStrCat("$<COMPILE_ONLY:", model
->GetName(), '>'),
8498 GENERAL_LibraryType
);
8500 // Apply usage requirements to the target.
8501 usage
.ApplyToTarget(tgt
);
8503 // Create the generator target and attach it to the local generator.
8504 auto gtp
= cm::make_unique
<cmGeneratorTarget
>(tgt
, lg
);
8505 synthDep
= gtp
.get();
8506 cache
.CxxModuleTargets
[targetName
] = synthDep
;
8507 gtp
->DiscoverSyntheticTargets(cache
, config
);
8508 lg
->AddGeneratorTarget(std::move(gtp
));
8510 synthDep
= cached
->second
;
8513 SyntheticDeps
[gt
].push_back(synthDep
);
8520 void cmGeneratorTarget::ComputeLinkImplementationLibraries(
8521 const std::string
& config
, cmOptionalLinkImplementation
& impl
,
8522 cmGeneratorTarget
const* head
, LinkInterfaceFor implFor
) const
8524 cmLocalGenerator
const* lg
= this->LocalGenerator
;
8525 cmMakefile
const* mf
= lg
->GetMakefile();
8526 cmBTStringRange entryRange
= this->Target
->GetLinkImplementationEntries();
8527 auto const& synthTargetsForConfig
= this->Configs
[config
].SyntheticDeps
;
8528 // Collect libraries directly linked in this configuration.
8529 for (auto const& entry
: entryRange
) {
8530 // Keep this logic in sync with ExpandLinkItems.
8531 cmGeneratorExpressionDAGChecker
dagChecker(this, "LINK_LIBRARIES", nullptr,
8533 // The $<LINK_ONLY> expression may be used to specify link dependencies
8534 // that are otherwise excluded from usage requirements.
8535 if (implFor
== LinkInterfaceFor::Usage
) {
8536 dagChecker
.SetTransitivePropertiesOnly();
8537 switch (this->GetPolicyStatusCMP0131()) {
8538 case cmPolicies::WARN
:
8539 case cmPolicies::OLD
:
8541 case cmPolicies::REQUIRED_IF_USED
:
8542 case cmPolicies::REQUIRED_ALWAYS
:
8543 case cmPolicies::NEW
:
8544 dagChecker
.SetTransitivePropertiesOnlyCMP0131();
8548 cmGeneratorExpression
ge(*this->LocalGenerator
->GetCMakeInstance(),
8550 std::unique_ptr
<cmCompiledGeneratorExpression
> const cge
=
8551 ge
.Parse(entry
.Value
);
8552 cge
->SetEvaluateForBuildsystem(true);
8553 std::string
const& evaluated
=
8554 cge
->Evaluate(this->LocalGenerator
, config
, head
, &dagChecker
, nullptr,
8555 this->LinkerLanguage
);
8556 bool const checkCMP0027
= evaluated
!= entry
.Value
;
8557 cmList
llibs(evaluated
);
8558 if (cge
->GetHadHeadSensitiveCondition()) {
8559 impl
.HadHeadSensitiveCondition
= true;
8561 if (cge
->GetHadContextSensitiveCondition()) {
8562 impl
.HadContextSensitiveCondition
= true;
8564 if (cge
->GetHadLinkLanguageSensitiveCondition()) {
8565 impl
.HadLinkLanguageSensitiveCondition
= true;
8568 auto linkFeature
= cmLinkItem::DEFAULT
;
8569 for (auto const& lib
: llibs
) {
8570 if (auto maybeLinkFeature
= ParseLinkFeature(lib
)) {
8571 linkFeature
= std::move(*maybeLinkFeature
);
8575 if (this->IsLinkLookupScope(lib
, lg
)) {
8579 // Skip entries that resolve to the target itself or are empty.
8580 std::string name
= this->CheckCMP0004(lib
);
8581 if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW
) {
8582 // resolve alias name
8583 auto* target
= this->Makefile
->FindTargetToUse(name
);
8585 name
= target
->GetName();
8588 if (name
== this->GetName() || name
.empty()) {
8589 if (name
== this->GetName()) {
8590 bool noMessage
= false;
8591 MessageType messageType
= MessageType::FATAL_ERROR
;
8592 std::ostringstream e
;
8593 switch (this->GetPolicyStatusCMP0038()) {
8594 case cmPolicies::WARN
: {
8595 e
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0038
) << "\n";
8596 messageType
= MessageType::AUTHOR_WARNING
;
8598 case cmPolicies::OLD
:
8601 case cmPolicies::REQUIRED_IF_USED
:
8602 case cmPolicies::REQUIRED_ALWAYS
:
8603 case cmPolicies::NEW
:
8604 // Issue the fatal message.
8609 e
<< "Target \"" << this->GetName() << "\" links to itself.";
8610 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
8611 messageType
, e
.str(), this->GetBacktrace());
8612 if (messageType
== MessageType::FATAL_ERROR
) {
8620 // The entry is meant for this configuration.
8621 cmLinkItem item
= this->ResolveLinkItem(
8622 BT
<std::string
>(name
, entry
.Backtrace
), lg
, linkFeature
);
8624 auto depsForTarget
= synthTargetsForConfig
.find(item
.Target
);
8625 if (depsForTarget
!= synthTargetsForConfig
.end()) {
8626 for (auto const* depForTarget
: depsForTarget
->second
) {
8627 cmLinkItem
synthItem(depForTarget
, item
.Cross
, item
.Backtrace
);
8628 impl
.Libraries
.emplace_back(std::move(synthItem
), false);
8632 // Report explicitly linked object files separately.
8633 std::string
const& maybeObj
= item
.AsStr();
8634 if (cmSystemTools::FileIsFullPath(maybeObj
)) {
8635 cmSourceFile
const* sf
=
8636 mf
->GetSource(maybeObj
, cmSourceFileLocationKind::Known
);
8637 if (sf
&& sf
->GetPropertyAsBool("EXTERNAL_OBJECT")) {
8638 item
.ObjectSource
= sf
;
8639 impl
.Objects
.emplace_back(std::move(item
));
8645 impl
.Libraries
.emplace_back(std::move(item
), checkCMP0027
);
8648 std::set
<std::string
> const& seenProps
= cge
->GetSeenTargetProperties();
8649 for (std::string
const& sp
: seenProps
) {
8650 if (!this->GetProperty(sp
)) {
8651 this->LinkImplicitNullProperties
.insert(sp
);
8654 cge
->GetMaxLanguageStandard(this, this->MaxLanguageStandards
);
8657 // Update the list of direct link dependencies from usage requirements.
8659 ComputeLinkImplTransitive(this, config
, implFor
, impl
);
8662 // Get the list of configurations considered to be DEBUG.
8663 std::vector
<std::string
> debugConfigs
=
8664 this->Makefile
->GetCMakeInstance()->GetDebugConfigs();
8666 cmTargetLinkLibraryType linkType
=
8667 CMP0003_ComputeLinkType(config
, debugConfigs
);
8668 cmTarget::LinkLibraryVectorType
const& oldllibs
=
8669 this->Target
->GetOriginalLinkLibraries();
8671 auto linkFeature
= cmLinkItem::DEFAULT
;
8672 for (cmTarget::LibraryID
const& oldllib
: oldllibs
) {
8673 if (auto maybeLinkFeature
= ParseLinkFeature(oldllib
.first
)) {
8674 linkFeature
= std::move(*maybeLinkFeature
);
8678 if (oldllib
.second
!= GENERAL_LibraryType
&& oldllib
.second
!= linkType
) {
8679 std::string name
= this->CheckCMP0004(oldllib
.first
);
8680 if (name
== this->GetName() || name
.empty()) {
8683 // Support OLD behavior for CMP0003.
8684 impl
.WrongConfigLibraries
.push_back(
8685 this->ResolveLinkItem(BT
<std::string
>(name
), linkFeature
));
8690 cmGeneratorTarget::TargetOrString
cmGeneratorTarget::ResolveTargetReference(
8691 std::string
const& name
) const
8693 return this->ResolveTargetReference(name
, this->LocalGenerator
);
8696 cmGeneratorTarget::TargetOrString
cmGeneratorTarget::ResolveTargetReference(
8697 std::string
const& name
, cmLocalGenerator
const* lg
) const
8699 TargetOrString resolved
;
8701 if (cmGeneratorTarget
* tgt
= lg
->FindGeneratorTargetToUse(name
)) {
8702 resolved
.Target
= tgt
;
8704 resolved
.String
= name
;
8710 cmLinkItem
cmGeneratorTarget::ResolveLinkItem(
8711 BT
<std::string
> const& name
, std::string
const& linkFeature
) const
8713 return this->ResolveLinkItem(name
, this->LocalGenerator
, linkFeature
);
8716 cmLinkItem
cmGeneratorTarget::ResolveLinkItem(
8717 BT
<std::string
> const& name
, cmLocalGenerator
const* lg
,
8718 std::string
const& linkFeature
) const
8720 auto bt
= name
.Backtrace
;
8721 TargetOrString resolved
= this->ResolveTargetReference(name
.Value
, lg
);
8723 if (!resolved
.Target
) {
8724 return cmLinkItem(resolved
.String
, false, bt
, linkFeature
);
8727 // Check deprecation, issue message with `bt` backtrace.
8728 if (resolved
.Target
->IsDeprecated()) {
8729 std::ostringstream w
;
8730 /* clang-format off */
8732 "The library that is being linked to, " << resolved
.Target
->GetName() <<
8733 ", is marked as being deprecated by the owner. The message provided by "
8734 "the developer is: \n" << resolved
.Target
->GetDeprecation() << "\n";
8735 /* clang-format on */
8736 this->LocalGenerator
->GetCMakeInstance()->IssueMessage(
8737 MessageType::AUTHOR_WARNING
, w
.str(), bt
);
8740 // Skip targets that will not really be linked. This is probably a
8741 // name conflict between an external library and an executable
8742 // within the project.
8743 if (resolved
.Target
->GetType() == cmStateEnums::EXECUTABLE
&&
8744 !resolved
.Target
->IsExecutableWithExports()) {
8745 return cmLinkItem(resolved
.Target
->GetName(), false, bt
, linkFeature
);
8748 return cmLinkItem(resolved
.Target
, false, bt
, linkFeature
);
8751 bool cmGeneratorTarget::HasPackageReferences() const
8753 return this->IsInBuildSystem() &&
8754 !this->GetProperty("VS_PACKAGE_REFERENCES")->empty();
8757 std::vector
<std::string
> cmGeneratorTarget::GetPackageReferences() const
8759 cmList packageReferences
;
8761 if (this->IsInBuildSystem()) {
8762 if (cmValue vsPackageReferences
=
8763 this->GetProperty("VS_PACKAGE_REFERENCES")) {
8764 packageReferences
.assign(*vsPackageReferences
);
8768 return std::move(packageReferences
.data());
8771 std::string
cmGeneratorTarget::GetPDBDirectory(const std::string
& config
) const
8773 if (OutputInfo
const* info
= this->GetOutputInfo(config
)) {
8774 // Return the directory in which the target will be built.
8775 return info
->PdbDir
;
8780 bool cmGeneratorTarget::HasImplibGNUtoMS(std::string
const& config
) const
8782 return this->HasImportLibrary(config
) && this->GetPropertyAsBool("GNUtoMS");
8785 bool cmGeneratorTarget::GetImplibGNUtoMS(std::string
const& config
,
8786 std::string
const& gnuName
,
8788 const char* newExt
) const
8790 if (this->HasImplibGNUtoMS(config
) && gnuName
.size() > 6 &&
8791 gnuName
.substr(gnuName
.size() - 6) == ".dll.a") {
8792 out
= cmStrCat(cm::string_view(gnuName
).substr(0, gnuName
.size() - 6),
8793 newExt
? newExt
: ".lib");
8799 bool cmGeneratorTarget::HasContextDependentSources() const
8801 return this->SourcesAreContextDependent
== Tribool::True
;
8804 bool cmGeneratorTarget::IsExecutableWithExports() const
8806 return this->Target
->IsExecutableWithExports();
8809 bool cmGeneratorTarget::IsSharedLibraryWithExports() const
8811 return this->Target
->IsSharedLibraryWithExports();
8814 bool cmGeneratorTarget::HasImportLibrary(std::string
const& config
) const
8816 bool generate_Stubs
= true;
8817 if (this->GetGlobalGenerator()->IsXcode()) {
8818 // take care of CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS variable
8819 // as well as XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS property
8820 if (cmValue propGenStubs
=
8821 this->GetProperty("XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
8822 generate_Stubs
= propGenStubs
== "YES";
8823 } else if (cmValue varGenStubs
= this->Makefile
->GetDefinition(
8824 "CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
8825 generate_Stubs
= varGenStubs
== "YES";
8829 return (this->IsDLLPlatform() &&
8830 (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
8831 this->IsExecutableWithExports()) &&
8832 // Assemblies which have only managed code do not have
8833 // import libraries.
8834 this->GetManagedType(config
) != ManagedType::Managed
) ||
8835 (this->IsAIX() && this->IsExecutableWithExports()) ||
8836 (this->Makefile
->PlatformSupportsAppleTextStubs() &&
8837 this->IsSharedLibraryWithExports() && generate_Stubs
);
8840 bool cmGeneratorTarget::NeedImportLibraryName(std::string
const& config
) const
8842 return this->HasImportLibrary(config
) ||
8843 // On DLL platforms we always generate the import library name
8844 // just in case the sources have export markup.
8845 (this->IsDLLPlatform() &&
8846 (this->GetType() == cmStateEnums::EXECUTABLE
||
8847 this->GetType() == cmStateEnums::MODULE_LIBRARY
));
8850 std::string
cmGeneratorTarget::GetSupportDirectory() const
8852 std::string dir
= cmStrCat(this->LocalGenerator
->GetCurrentBinaryDirectory(),
8853 "/CMakeFiles/", this->GetName());
8862 bool cmGeneratorTarget::IsLinkable() const
8864 return (this->GetType() == cmStateEnums::STATIC_LIBRARY
||
8865 this->GetType() == cmStateEnums::SHARED_LIBRARY
||
8866 this->GetType() == cmStateEnums::MODULE_LIBRARY
||
8867 this->GetType() == cmStateEnums::UNKNOWN_LIBRARY
||
8868 this->GetType() == cmStateEnums::OBJECT_LIBRARY
||
8869 this->GetType() == cmStateEnums::INTERFACE_LIBRARY
||
8870 this->IsExecutableWithExports());
8873 bool cmGeneratorTarget::HasLinkDependencyFile(std::string
const& config
) const
8875 if (this->GetType() != cmStateEnums::EXECUTABLE
&&
8876 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
8877 this->GetType() != cmStateEnums::MODULE_LIBRARY
) {
8881 if (this->Target
->GetProperty("LINK_DEPENDS_NO_SHARED").IsOn()) {
8882 // Do not use the linker dependency file because it includes shared
8883 // libraries as well
8887 const std::string depsUseLinker
{ "CMAKE_LINK_DEPENDS_USE_LINKER" };
8888 auto linkLanguage
= this->GetLinkerLanguage(config
);
8889 const std::string langDepsUseLinker
{ cmStrCat("CMAKE_", linkLanguage
,
8890 "_LINK_DEPENDS_USE_LINKER") };
8892 return (!this->Makefile
->IsDefinitionSet(depsUseLinker
) ||
8893 this->Makefile
->IsOn(depsUseLinker
)) &&
8894 this->Makefile
->IsOn(langDepsUseLinker
);
8897 bool cmGeneratorTarget::IsFrameworkOnApple() const
8899 return this->Target
->IsFrameworkOnApple();
8902 bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple(
8903 const std::string
& config
) const
8905 if (this->IsApple() && this->IsImported() &&
8906 (this->GetType() == cmStateEnums::STATIC_LIBRARY
||
8907 this->GetType() == cmStateEnums::SHARED_LIBRARY
||
8908 this->GetType() == cmStateEnums::UNKNOWN_LIBRARY
)) {
8909 std::string cfg
= config
;
8910 if (cfg
.empty() && this->GetGlobalGenerator()->IsXcode()) {
8911 // FIXME(#25515): Remove the need for this workaround.
8912 // The Xcode generator queries include directories without any
8913 // specific configuration. Pick one in case this target does
8914 // not set either IMPORTED_LOCATION or IMPORTED_CONFIGURATIONS.
8916 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
)[0];
8918 return cmSystemTools::IsPathToFramework(this->GetLocation(cfg
));
8924 bool cmGeneratorTarget::IsAppBundleOnApple() const
8926 return this->Target
->IsAppBundleOnApple();
8929 bool cmGeneratorTarget::IsXCTestOnApple() const
8931 return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
8934 bool cmGeneratorTarget::IsCFBundleOnApple() const
8936 return (this->GetType() == cmStateEnums::MODULE_LIBRARY
&& this->IsApple() &&
8937 this->GetPropertyAsBool("BUNDLE"));
8940 cmGeneratorTarget::ManagedType
cmGeneratorTarget::CheckManagedType(
8941 std::string
const& propval
) const
8943 // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
8944 // or only C++/CLI) does only depend on whether the property is an empty
8945 // string or contains any value at all. In Visual Studio generators
8946 // this propval is prepended with /clr[:] which results in:
8948 // 1. propval does not exist: no /clr flag, unmanaged target, has import
8950 // 2. empty propval: add /clr as flag, mixed unmanaged/managed
8951 // target, has import lib
8952 // 3. netcore propval: add /clr:netcore as flag, mixed
8953 // unmanaged/managed target, has import lib.
8954 // 4. any value (safe,pure): add /clr:[propval] as flag, target with
8955 // managed code only, no import lib
8956 if (propval
.empty() || propval
== "netcore") {
8957 return ManagedType::Mixed
;
8959 return ManagedType::Managed
;
8962 cmGeneratorTarget::ManagedType
cmGeneratorTarget::GetManagedType(
8963 const std::string
& config
) const
8965 // Only libraries and executables can be managed targets.
8966 if (this->GetType() > cmStateEnums::SHARED_LIBRARY
) {
8967 return ManagedType::Undefined
;
8970 if (this->GetType() == cmStateEnums::STATIC_LIBRARY
) {
8971 return ManagedType::Native
;
8974 // Check imported target.
8975 if (this->IsImported()) {
8976 if (cmGeneratorTarget::ImportInfo
const* info
=
8977 this->GetImportInfo(config
)) {
8978 return info
->Managed
;
8980 return ManagedType::Undefined
;
8983 // Check for explicitly set clr target property.
8984 if (cmValue clr
= this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
8985 return this->CheckManagedType(*clr
);
8988 // C# targets are always managed. This language specific check
8989 // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
8990 // has to be set manually for C# targets.
8991 return this->IsCSharpOnly() ? ManagedType::Managed
: ManagedType::Native
;
8994 bool cmGeneratorTarget::AddHeaderSetVerification()
8996 if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) {
9000 if (this->GetType() != cmStateEnums::STATIC_LIBRARY
&&
9001 this->GetType() != cmStateEnums::SHARED_LIBRARY
&&
9002 this->GetType() != cmStateEnums::UNKNOWN_LIBRARY
&&
9003 this->GetType() != cmStateEnums::OBJECT_LIBRARY
&&
9004 this->GetType() != cmStateEnums::INTERFACE_LIBRARY
&&
9005 !this->IsExecutableWithExports()) {
9009 auto verifyValue
= this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY");
9010 const bool all
= verifyValue
.IsEmpty();
9011 std::set
<std::string
> verifySet
;
9013 cmList verifyList
{ verifyValue
};
9014 verifySet
.insert(verifyList
.begin(), verifyList
.end());
9017 cmTarget
* verifyTarget
= nullptr;
9018 cmTarget
* allVerifyTarget
=
9019 this->GlobalGenerator
->GetMakefiles().front()->FindTargetToUse(
9020 "all_verify_interface_header_sets", true);
9022 auto interfaceFileSetEntries
= this->Target
->GetInterfaceHeaderSetsEntries();
9024 std::set
<cmFileSet
*> fileSets
;
9025 for (auto const& entry
: interfaceFileSetEntries
) {
9026 for (auto const& name
: cmList
{ entry
.Value
}) {
9027 if (all
|| verifySet
.count(name
)) {
9028 fileSets
.insert(this->Target
->GetFileSet(name
));
9029 verifySet
.erase(name
);
9033 if (!verifySet
.empty()) {
9034 this->Makefile
->IssueMessage(
9035 MessageType::FATAL_ERROR
,
9036 cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"",
9038 "\" contained the following header sets that are nonexistent "
9039 "or not INTERFACE:\n ",
9040 cmJoin(verifySet
, "\n ")));
9044 cm::optional
<std::set
<std::string
>> languages
;
9045 for (auto* fileSet
: fileSets
) {
9046 auto dirCges
= fileSet
->CompileDirectoryEntries();
9047 auto fileCges
= fileSet
->CompileFileEntries();
9049 static auto const contextSensitive
=
9050 [](const std::unique_ptr
<cmCompiledGeneratorExpression
>& cge
) {
9051 return cge
->GetHadContextSensitiveCondition();
9053 bool dirCgesContextSensitive
= false;
9054 bool fileCgesContextSensitive
= false;
9056 std::vector
<std::string
> dirs
;
9057 std::map
<std::string
, std::vector
<std::string
>> filesPerDir
;
9059 for (auto const& config
: this->Makefile
->GetGeneratorConfigs(
9060 cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig
)) {
9061 if (first
|| dirCgesContextSensitive
) {
9062 dirs
= fileSet
->EvaluateDirectoryEntries(dirCges
, this->LocalGenerator
,
9064 dirCgesContextSensitive
=
9065 std::any_of(dirCges
.begin(), dirCges
.end(), contextSensitive
);
9067 if (first
|| fileCgesContextSensitive
) {
9068 filesPerDir
.clear();
9069 for (auto const& fileCge
: fileCges
) {
9070 fileSet
->EvaluateFileEntry(dirs
, filesPerDir
, fileCge
,
9071 this->LocalGenerator
, config
, this);
9072 if (fileCge
->GetHadContextSensitiveCondition()) {
9073 fileCgesContextSensitive
= true;
9078 for (auto const& files
: filesPerDir
) {
9079 for (auto const& file
: files
.second
) {
9080 std::string filename
= this->GenerateHeaderSetVerificationFile(
9081 *this->Makefile
->GetOrCreateSource(file
), files
.first
, languages
);
9082 if (filename
.empty()) {
9086 if (!verifyTarget
) {
9088 cmMakefile::PolicyPushPop
polScope(this->Makefile
);
9089 this->Makefile
->SetPolicy(cmPolicies::CMP0119
, cmPolicies::NEW
);
9090 verifyTarget
= this->Makefile
->AddLibrary(
9091 cmStrCat(this->GetName(), "_verify_interface_header_sets"),
9092 cmStateEnums::OBJECT_LIBRARY
, {}, true);
9095 verifyTarget
->AddLinkLibrary(
9096 *this->Makefile
, this->GetName(),
9097 cmTargetLinkLibraryType::GENERAL_LibraryType
);
9098 verifyTarget
->SetProperty("AUTOMOC", "OFF");
9099 verifyTarget
->SetProperty("AUTORCC", "OFF");
9100 verifyTarget
->SetProperty("AUTOUIC", "OFF");
9101 verifyTarget
->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
9102 verifyTarget
->SetProperty("UNITY_BUILD", "OFF");
9103 verifyTarget
->SetProperty("CXX_SCAN_FOR_MODULES", "OFF");
9104 cm::optional
<std::map
<std::string
, cmValue
>>
9105 perConfigCompileDefinitions
;
9106 verifyTarget
->FinalizeTargetConfiguration(
9107 this->Makefile
->GetCompileDefinitionsEntries(),
9108 perConfigCompileDefinitions
);
9110 if (!allVerifyTarget
) {
9111 allVerifyTarget
= this->GlobalGenerator
->GetMakefiles()
9113 ->AddNewUtilityTarget(
9114 "all_verify_interface_header_sets", true);
9117 allVerifyTarget
->AddUtility(verifyTarget
->GetName(), false);
9120 if (fileCgesContextSensitive
) {
9121 filename
= cmStrCat("$<$<CONFIG:", config
, ">:", filename
, ">");
9123 verifyTarget
->AddSource(filename
);
9127 if (!dirCgesContextSensitive
&& !fileCgesContextSensitive
) {
9135 this->LocalGenerator
->AddGeneratorTarget(
9136 cm::make_unique
<cmGeneratorTarget
>(verifyTarget
, this->LocalGenerator
));
9142 std::string
cmGeneratorTarget::GenerateHeaderSetVerificationFile(
9143 cmSourceFile
& source
, const std::string
& dir
,
9144 cm::optional
<std::set
<std::string
>>& languages
) const
9146 std::string extension
;
9147 std::string language
= source
.GetOrDetermineLanguage();
9149 if (source
.GetPropertyAsBool("SKIP_LINTING")) {
9150 return std::string
{};
9153 if (language
.empty()) {
9155 languages
.emplace();
9156 for (auto const& tgtSource
: this->GetAllConfigSources()) {
9157 auto const& tgtSourceLanguage
=
9158 tgtSource
.Source
->GetOrDetermineLanguage();
9159 if (tgtSourceLanguage
== "CXX") {
9160 languages
->insert("CXX");
9161 break; // C++ overrides everything else, so we don't need to keep
9164 if (tgtSourceLanguage
== "C") {
9165 languages
->insert("C");
9169 if (languages
->empty()) {
9170 std::vector
<std::string
> languagesVector
;
9171 this->GlobalGenerator
->GetEnabledLanguages(languagesVector
);
9172 languages
->insert(languagesVector
.begin(), languagesVector
.end());
9176 if (languages
->count("CXX")) {
9178 } else if (languages
->count("C")) {
9183 if (language
== "C") {
9185 } else if (language
== "CXX") {
9191 std::string headerFilename
= dir
;
9192 if (!headerFilename
.empty()) {
9193 headerFilename
+= '/';
9195 headerFilename
+= source
.GetLocation().GetName();
9197 auto filename
= cmStrCat(
9198 this->LocalGenerator
->GetCurrentBinaryDirectory(), '/', this->GetName(),
9199 "_verify_interface_header_sets/", headerFilename
, extension
);
9200 auto* verificationSource
= this->Makefile
->GetOrCreateSource(filename
);
9201 verificationSource
->SetProperty("LANGUAGE", language
);
9203 cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename
));
9205 cmGeneratedFileStream
fout(filename
);
9206 fout
.SetCopyIfDifferent(true);
9207 // The IWYU "associated" pragma tells include-what-you-use to
9208 // consider the headerFile as part of the entire language
9209 // unit within include-what-you-use and as a result allows
9210 // one to get IWYU advice for headers.
9211 fout
<< "#include <" << headerFilename
<< "> // IWYU pragma: associated\n";
9217 std::string
cmGeneratorTarget::GetImportedXcFrameworkPath(
9218 const std::string
& config
) const
9220 if (!(this->IsApple() && this->IsImported() &&
9221 (this->GetType() == cmStateEnums::SHARED_LIBRARY
||
9222 this->GetType() == cmStateEnums::STATIC_LIBRARY
||
9223 this->GetType() == cmStateEnums::UNKNOWN_LIBRARY
))) {
9227 std::string desiredConfig
= config
;
9228 if (config
.empty()) {
9229 desiredConfig
= "NOCONFIG";
9234 cmValue loc
= nullptr;
9235 cmValue imp
= nullptr;
9238 if (this->Target
->GetMappedConfig(desiredConfig
, loc
, imp
, suffix
)) {
9242 std::string impProp
= cmStrCat("IMPORTED_LOCATION", suffix
);
9243 if (cmValue configLocation
= this->GetProperty(impProp
)) {
9244 result
= *configLocation
;
9245 } else if (cmValue location
= this->GetProperty("IMPORTED_LOCATION")) {
9250 if (cmSystemTools::IsPathToXcFramework(result
)) {
9258 bool cmGeneratorTarget::HaveFortranSources(std::string
const& config
) const
9260 auto sources
= this->GetSourceFiles(config
);
9261 bool const have_direct
= std::any_of(
9262 sources
.begin(), sources
.end(), [](BT
<cmSourceFile
*> const& sf
) -> bool {
9263 return sf
.Value
->GetLanguage() == "Fortran"_s
;
9265 bool have_via_target_objects
= false;
9267 auto const sourceObjectLibraries
= this->GetSourceObjectLibraries(config
);
9268 have_via_target_objects
=
9269 std::any_of(sourceObjectLibraries
.begin(), sourceObjectLibraries
.end(),
9270 [&config
](cmGeneratorTarget
const* tgt
) -> bool {
9271 return tgt
->HaveFortranSources(config
);
9274 return have_direct
|| have_via_target_objects
;
9277 bool cmGeneratorTarget::HaveFortranSources() const
9279 auto sources
= this->GetAllConfigSources();
9280 bool const have_direct
= std::any_of(
9281 sources
.begin(), sources
.end(), [](AllConfigSource
const& sf
) -> bool {
9282 return sf
.Source
->GetLanguage() == "Fortran"_s
;
9284 bool have_via_target_objects
= false;
9286 std::vector
<std::string
> configs
=
9287 this->Makefile
->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig
);
9288 for (auto const& config
: configs
) {
9289 auto const sourceObjectLibraries
=
9290 this->GetSourceObjectLibraries(config
);
9291 have_via_target_objects
=
9292 std::any_of(sourceObjectLibraries
.begin(), sourceObjectLibraries
.end(),
9293 [&config
](cmGeneratorTarget
const* tgt
) -> bool {
9294 return tgt
->HaveFortranSources(config
);
9296 if (have_via_target_objects
) {
9301 return have_direct
|| have_via_target_objects
;
9304 bool cmGeneratorTarget::HaveCxx20ModuleSources(std::string
* errorMessage
) const
9306 auto const& fs_names
= this->Target
->GetAllFileSetNames();
9308 fs_names
.begin(), fs_names
.end(),
9309 [this, errorMessage
](std::string
const& name
) -> bool {
9310 auto const* file_set
= this->Target
->GetFileSet(name
);
9312 auto message
= cmStrCat("Target \"", this->Target
->GetName(),
9313 "\" is tracked to have file set \"", name
,
9314 "\", but it was not found.");
9316 *errorMessage
= std::move(message
);
9318 this->Makefile
->IssueMessage(MessageType::INTERNAL_ERROR
, message
);
9323 auto const& fs_type
= file_set
->GetType();
9324 return fs_type
== "CXX_MODULES"_s
;
9328 cmGeneratorTarget::Cxx20SupportLevel
cmGeneratorTarget::HaveCxxModuleSupport(
9329 std::string
const& config
) const
9331 auto const* state
= this->Makefile
->GetState();
9332 if (!state
->GetLanguageEnabled("CXX")) {
9333 return Cxx20SupportLevel::MissingCxx
;
9336 cmValue standardDefault
=
9337 this->Makefile
->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
9338 if (!standardDefault
|| standardDefault
->empty()) {
9339 // We do not know any meaningful C++ standard levels for this compiler.
9340 return Cxx20SupportLevel::NoCxx20
;
9343 cmStandardLevelResolver
standardResolver(this->Makefile
);
9344 cmStandardLevel
const cxxStd20
=
9345 *standardResolver
.LanguageStandardLevel("CXX", "20");
9346 cm::optional
<cmStandardLevel
> explicitLevel
=
9347 this->GetExplicitStandardLevel("CXX", config
);
9348 if (!explicitLevel
|| *explicitLevel
< cxxStd20
) {
9349 return Cxx20SupportLevel::NoCxx20
;
9352 cmValue scandepRule
=
9353 this->Makefile
->GetDefinition("CMAKE_CXX_SCANDEP_SOURCE");
9355 return Cxx20SupportLevel::MissingRule
;
9357 return Cxx20SupportLevel::Supported
;
9360 void cmGeneratorTarget::CheckCxxModuleStatus(std::string
const& config
) const
9362 bool haveScannableSources
= false;
9364 // Check for `CXX_MODULE*` file sets and a lack of support.
9365 if (this->HaveCxx20ModuleSources()) {
9366 haveScannableSources
= true;
9369 if (!haveScannableSources
) {
9370 // Check to see if there are regular sources that have requested scanning.
9371 auto sources
= this->GetSourceFiles(config
);
9372 for (auto const& source
: sources
) {
9373 auto const* sf
= source
.Value
;
9374 auto const& lang
= sf
->GetLanguage();
9375 if (lang
!= "CXX"_s
) {
9378 // Ignore sources which do not need dyndep.
9379 if (this->NeedDyndepForSource(lang
, config
, sf
)) {
9380 haveScannableSources
= true;
9385 // If there isn't anything scannable, ignore it.
9386 if (!haveScannableSources
) {
9390 // If the generator doesn't support modules at all, error that we have
9391 // sources that require the support.
9392 if (!this->GetGlobalGenerator()->CheckCxxModuleSupport(
9393 cmGlobalGenerator::CxxModuleSupportQuery::Expected
)) {
9394 this->Makefile
->IssueMessage(
9395 MessageType::FATAL_ERROR
,
9396 cmStrCat("The target named \"", this->GetName(),
9397 "\" has C++ sources that may use modules, but modules are not "
9398 "supported by this generator:\n ",
9399 this->GetGlobalGenerator()->GetName(), '\n',
9400 "Modules are supported only by Ninja, Ninja Multi-Config, "
9401 "and Visual Studio generators for VS 17.4 and newer. "
9402 "See the cmake-cxxmodules(7) manual for details. "
9403 "Use the CMAKE_CXX_SCAN_FOR_MODULES variable to enable or "
9404 "disable scanning."));
9408 switch (this->HaveCxxModuleSupport(config
)) {
9409 case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx
:
9410 this->Makefile
->IssueMessage(
9411 MessageType::FATAL_ERROR
,
9412 cmStrCat("The target named \"", this->GetName(),
9413 "\" has C++ sources that use modules, but the \"CXX\" "
9414 "language has not been enabled."));
9416 case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20
: {
9417 cmStandardLevelResolver
standardResolver(this->Makefile
);
9419 standardResolver
.GetEffectiveStandard(this, "CXX", config
);
9420 if (effStandard
.empty()) {
9421 effStandard
= "; no C++ standard found";
9423 effStandard
= cmStrCat("; found \"cxx_std_", effStandard
, '"');
9425 this->Makefile
->IssueMessage(
9426 MessageType::FATAL_ERROR
,
9428 "The target named \"", this->GetName(),
9429 "\" has C++ sources that use modules, but does not include "
9430 "\"cxx_std_20\" (or newer) among its `target_compile_features`",
9433 case cmGeneratorTarget::Cxx20SupportLevel::MissingRule
: {
9434 this->Makefile
->IssueMessage(
9435 MessageType::FATAL_ERROR
,
9436 cmStrCat("The target named \"", this->GetName(),
9437 "\" has C++ sources that may use modules, but the compiler "
9438 "does not provide a way to discover the import graph "
9439 "dependencies. See the cmake-cxxmodules(7) manual for "
9440 "details. Use the CMAKE_CXX_SCAN_FOR_MODULES variable to "
9441 "enable or disable scanning."));
9443 case cmGeneratorTarget::Cxx20SupportLevel::Supported
:
9449 bool cmGeneratorTarget::NeedCxxModuleSupport(std::string
const& lang
,
9450 std::string
const& config
) const
9452 if (lang
!= "CXX"_s
) {
9455 return this->HaveCxxModuleSupport(config
) == Cxx20SupportLevel::Supported
&&
9456 this->GetGlobalGenerator()->CheckCxxModuleSupport(
9457 cmGlobalGenerator::CxxModuleSupportQuery::Inspect
);
9460 bool cmGeneratorTarget::NeedDyndep(std::string
const& lang
,
9461 std::string
const& config
) const
9463 return lang
== "Fortran"_s
|| this->NeedCxxModuleSupport(lang
, config
);
9466 cmFileSet
const* cmGeneratorTarget::GetFileSetForSource(
9467 std::string
const& config
, cmSourceFile
const* sf
) const
9469 this->BuildFileSetInfoCache(config
);
9471 auto const& path
= sf
->GetFullPath();
9472 auto const& per_config
= this->Configs
[config
];
9474 auto const fsit
= per_config
.FileSetCache
.find(path
);
9475 if (fsit
== per_config
.FileSetCache
.end()) {
9478 return fsit
->second
;
9481 bool cmGeneratorTarget::NeedDyndepForSource(std::string
const& lang
,
9482 std::string
const& config
,
9483 cmSourceFile
const* sf
) const
9485 // Fortran always needs to be scanned.
9486 if (lang
== "Fortran"_s
) {
9489 // Only C++ code needs scanned otherwise.
9490 if (lang
!= "CXX"_s
) {
9494 // Any file in `CXX_MODULES` file sets need scanned (it being `CXX` is
9495 // enforced elsewhere).
9496 auto const* fs
= this->GetFileSetForSource(config
, sf
);
9497 if (fs
&& fs
->GetType() == "CXX_MODULES"_s
) {
9501 auto targetDyndep
= this->NeedCxxDyndep(config
);
9502 if (targetDyndep
== CxxModuleSupport::Unavailable
) {
9505 auto const sfProp
= sf
->GetProperty("CXX_SCAN_FOR_MODULES");
9506 if (sfProp
.IsSet()) {
9507 return sfProp
.IsOn();
9509 return targetDyndep
== CxxModuleSupport::Enabled
;
9512 cmGeneratorTarget::CxxModuleSupport
cmGeneratorTarget::NeedCxxDyndep(
9513 std::string
const& config
) const
9515 bool haveRule
= false;
9516 switch (this->HaveCxxModuleSupport(config
)) {
9517 case Cxx20SupportLevel::MissingCxx
:
9518 case Cxx20SupportLevel::NoCxx20
:
9519 return CxxModuleSupport::Unavailable
;
9520 case Cxx20SupportLevel::MissingRule
:
9522 case Cxx20SupportLevel::Supported
:
9526 bool haveGeneratorSupport
=
9527 this->GetGlobalGenerator()->CheckCxxModuleSupport(
9528 cmGlobalGenerator::CxxModuleSupportQuery::Inspect
);
9529 auto const tgtProp
= this->GetProperty("CXX_SCAN_FOR_MODULES");
9530 if (tgtProp
.IsSet()) {
9531 return tgtProp
.IsOn() ? CxxModuleSupport::Enabled
9532 : CxxModuleSupport::Disabled
;
9535 CxxModuleSupport policyAnswer
= CxxModuleSupport::Unavailable
;
9536 switch (this->GetPolicyStatusCMP0155()) {
9537 case cmPolicies::WARN
:
9538 case cmPolicies::OLD
:
9539 // The OLD behavior is to not scan the source.
9540 policyAnswer
= CxxModuleSupport::Disabled
;
9542 case cmPolicies::REQUIRED_ALWAYS
:
9543 case cmPolicies::REQUIRED_IF_USED
:
9544 case cmPolicies::NEW
:
9545 // The NEW behavior is to scan the source if the compiler supports
9546 // scanning and the generator supports it.
9547 if (haveRule
&& haveGeneratorSupport
) {
9548 policyAnswer
= CxxModuleSupport::Enabled
;
9550 policyAnswer
= CxxModuleSupport::Disabled
;
9554 return policyAnswer
;
9557 void cmGeneratorTarget::BuildFileSetInfoCache(std::string
const& config
) const
9559 auto& per_config
= this->Configs
[config
];
9561 if (per_config
.BuiltFileSetCache
) {
9565 auto const* tgt
= this->Target
;
9567 for (auto const& name
: tgt
->GetAllFileSetNames()) {
9568 auto const* file_set
= tgt
->GetFileSet(name
);
9570 tgt
->GetMakefile()->IssueMessage(
9571 MessageType::INTERNAL_ERROR
,
9572 cmStrCat("Target \"", tgt
->GetName(),
9573 "\" is tracked to have file set \"", name
,
9574 "\", but it was not found."));
9578 auto fileEntries
= file_set
->CompileFileEntries();
9579 auto directoryEntries
= file_set
->CompileDirectoryEntries();
9580 auto directories
= file_set
->EvaluateDirectoryEntries(
9581 directoryEntries
, this->LocalGenerator
, config
, this);
9583 std::map
<std::string
, std::vector
<std::string
>> files
;
9584 for (auto const& entry
: fileEntries
) {
9585 file_set
->EvaluateFileEntry(directories
, files
, entry
,
9586 this->LocalGenerator
, config
, this);
9589 for (auto const& it
: files
) {
9590 for (auto const& filename
: it
.second
) {
9591 auto collapsedFile
= cmSystemTools::CollapseFullPath(filename
);
9592 per_config
.FileSetCache
[collapsedFile
] = file_set
;
9597 per_config
.BuiltFileSetCache
= true;