diff options
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
| -rw-r--r-- | Source/cmGeneratorTarget.cxx | 1374 |
1 files changed, 936 insertions, 438 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f1ef130..9f1029e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -25,6 +25,7 @@ #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" +#include "cmFileSet.h" #include "cmFileTimes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" @@ -41,6 +42,7 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" +#include "cmSourceGroup.h" #include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -50,19 +52,23 @@ #include "cmTargetPropertyComputer.h" #include "cmake.h" -class cmMessenger; - namespace { +using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor; + const cmsys::RegularExpression FrameworkRegularExpression( "^(.*/)?([^/]*)\\.framework/(.*)$"); +const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES"; +const std::string kINTERFACE_LINK_LIBRARIES_DIRECT = + "INTERFACE_LINK_LIBRARIES_DIRECT"; +const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE = + "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"; } template <> -cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( - cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, - cmListFileBacktrace const& /* context */) +cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( + cmGeneratorTarget const* tgt, cmMakefile const& /* mf */) { - return &tgt->GetSourcesProperty(); + return tgt->GetSourcesProperty(); } template <> @@ -145,12 +151,10 @@ private: class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry { public: - TargetPropertyEntryString(std::string propertyValue, - cmListFileBacktrace backtrace, + TargetPropertyEntryString(BT<std::string> propertyValue, cmLinkImplItem const& item = NoLinkImplItem) : cmGeneratorTarget::TargetPropertyEntry(item) , PropertyValue(std::move(propertyValue)) - , Backtrace(std::move(backtrace)) { } @@ -159,46 +163,110 @@ public: cmGeneratorExpressionDAGChecker*, std::string const&) const override { - return this->PropertyValue; + return this->PropertyValue.Value; } - cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; } - std::string const& GetInput() const override { return this->PropertyValue; } + cmListFileBacktrace GetBacktrace() const override + { + return this->PropertyValue.Backtrace; + } + std::string const& GetInput() const override + { + return this->PropertyValue.Value; + } private: - std::string PropertyValue; - cmListFileBacktrace Backtrace; + BT<std::string> PropertyValue; }; -std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry> -CreateTargetPropertyEntry( - const std::string& propertyValue, - cmListFileBacktrace backtrace = cmListFileBacktrace(), - bool evaluateForBuildsystem = false) +class TargetPropertyEntryFileSet + : public cmGeneratorTarget::TargetPropertyEntry { - if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) { - cmGeneratorExpression ge(std::move(backtrace)); +public: + TargetPropertyEntryFileSet( + std::vector<std::string> dirs, bool contextSensitiveDirs, + std::unique_ptr<cmCompiledGeneratorExpression> entryCge, + const cmFileSet* fileSet, cmLinkImplItem const& item = NoLinkImplItem) + : cmGeneratorTarget::TargetPropertyEntry(item) + , BaseDirs(std::move(dirs)) + , ContextSensitiveDirs(contextSensitiveDirs) + , EntryCge(std::move(entryCge)) + , FileSet(fileSet) + { + } + + const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config, + cmGeneratorTarget const* headTarget, + cmGeneratorExpressionDAGChecker* dagChecker, + std::string const& /*lang*/) const override + { + std::map<std::string, std::vector<std::string>> filesPerDir; + this->FileSet->EvaluateFileEntry(this->BaseDirs, filesPerDir, + this->EntryCge, lg, config, headTarget, + dagChecker); + + std::vector<std::string> files; + for (auto const& it : filesPerDir) { + files.insert(files.end(), it.second.begin(), it.second.end()); + } + + static std::string filesStr; + filesStr = cmJoin(files, ";"); + return filesStr; + } + + cmListFileBacktrace GetBacktrace() const override + { + return this->EntryCge->GetBacktrace(); + } + + std::string const& GetInput() const override + { + return this->EntryCge->GetInput(); + } + + bool GetHadContextSensitiveCondition() const override + { + return this->ContextSensitiveDirs || + this->EntryCge->GetHadContextSensitiveCondition(); + } + +private: + const std::vector<std::string> BaseDirs; + const bool ContextSensitiveDirs; + const std::unique_ptr<cmCompiledGeneratorExpression> EntryCge; + const cmFileSet* FileSet; +}; + +std::unique_ptr< + cmGeneratorTarget:: + TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std:: + string>& + propertyValue, + bool + evaluateForBuildsystem = + false) +{ + if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) { + cmGeneratorExpression ge(propertyValue.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(propertyValue); + ge.Parse(propertyValue.Value); cge->SetEvaluateForBuildsystem(evaluateForBuildsystem); return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>( cm::make_unique<TargetPropertyEntryGenex>(std::move(cge))); } return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>( - cm::make_unique<TargetPropertyEntryString>(propertyValue, - std::move(backtrace))); + cm::make_unique<TargetPropertyEntryString>(propertyValue)); } -void CreatePropertyGeneratorExpressions( - cmStringRange entries, cmBacktraceRange backtraces, +static void CreatePropertyGeneratorExpressions( + cmBTStringRange entries, std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items, bool evaluateForBuildsystem = false) { - auto btIt = backtraces.begin(); - for (auto it = entries.begin(); it != entries.end(); ++it, ++btIt) { - items.push_back( - CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem)); + for (auto const& entry : entries) { + items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem)); } } @@ -289,35 +357,27 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->GlobalGenerator->ComputeTargetObjectDirectory(this); CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(), - t->GetIncludeDirectoriesBacktraces(), this->IncludeDirectoriesEntries); CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(), - t->GetCompileOptionsBacktraces(), this->CompileOptionsEntries); CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(), - t->GetCompileFeaturesBacktraces(), this->CompileFeaturesEntries); CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(), - t->GetCompileDefinitionsBacktraces(), this->CompileDefinitionsEntries); CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(), - t->GetLinkOptionsBacktraces(), this->LinkOptionsEntries); CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(), - t->GetLinkDirectoriesBacktraces(), this->LinkDirectoriesEntries); CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(), - t->GetPrecompileHeadersBacktraces(), this->PrecompileHeadersEntries); CreatePropertyGeneratorExpressions(t->GetSourceEntries(), - t->GetSourceBacktraces(), this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); @@ -332,7 +392,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) cmGeneratorTarget::~cmGeneratorTarget() = default; -const std::string& cmGeneratorTarget::GetSourcesProperty() const +cmValue cmGeneratorTarget::GetSourcesProperty() const { std::vector<std::string> values; for (auto const& se : this->SourceEntries) { @@ -341,7 +401,7 @@ const std::string& cmGeneratorTarget::GetSourcesProperty() const static std::string value; value.clear(); value = cmJoin(values, ";"); - return value; + return cmValue(value); } cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const @@ -366,7 +426,7 @@ const std::string& cmGeneratorTarget::GetName() const std::string cmGeneratorTarget::GetExportName() const { - cmProp exportName = this->GetProperty("EXPORT_NAME"); + cmValue exportName = this->GetProperty("EXPORT_NAME"); if (cmNonempty(exportName)) { if (!cmGeneratorExpression::IsValidTargetName(*exportName)) { @@ -381,10 +441,10 @@ std::string cmGeneratorTarget::GetExportName() const return this->GetName(); } -cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const +cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const { - if (cmProp result = cmTargetPropertyComputer::GetProperty( - this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { + if (cmValue result = + cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) { return result; } if (cmSystemTools::GetFatalErrorOccured()) { @@ -396,13 +456,7 @@ cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const std::string const& cmGeneratorTarget::GetSafeProperty( std::string const& prop) const { - cmProp ret = this->GetProperty(prop); - if (ret) { - return *ret; - } - - static std::string const s_empty; - return s_empty; + return this->GetProperty(prop); } const char* cmGeneratorTarget::GetOutputTargetType( @@ -491,7 +545,7 @@ std::string cmGeneratorTarget::GetOutputName( std::string outName; for (std::string const& p : props) { - if (cmProp outNameProp = this->GetProperty(p)) { + if (cmValue outNameProp = this->GetProperty(p)) { outName = *outNameProp; break; } @@ -519,7 +573,7 @@ std::string cmGeneratorTarget::GetFilePrefix( const std::string& config, cmStateEnums::ArtifactType artifact) const { if (this->IsImported()) { - cmProp prefix = this->GetFilePrefixInternal(config, artifact); + cmValue prefix = this->GetFilePrefixInternal(config, artifact); return prefix ? *prefix : std::string(); } @@ -533,7 +587,7 @@ std::string cmGeneratorTarget::GetFileSuffix( const std::string& config, cmStateEnums::ArtifactType artifact) const { if (this->IsImported()) { - cmProp suffix = this->GetFileSuffixInternal(config, artifact); + cmValue suffix = this->GetFileSuffixInternal(config, artifact); return suffix ? *suffix : std::string(); } @@ -546,7 +600,7 @@ std::string cmGeneratorTarget::GetFileSuffix( std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const { - cmProp postfix = nullptr; + cmValue postfix = nullptr; std::string frameworkPostfix; if (!config.empty()) { std::string configProp = @@ -564,7 +618,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const // framework postfix. frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config); if (!frameworkPostfix.empty()) { - postfix = &frameworkPostfix; + postfix = cmValue(frameworkPostfix); } } return postfix ? *postfix : std::string(); @@ -573,7 +627,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( const std::string& config) const { - cmProp postfix = nullptr; + cmValue postfix = nullptr; if (!config.empty()) { std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_", cmSystemTools::UpperCase(config)); @@ -588,7 +642,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( return postfix ? *postfix : std::string(); } -cmProp cmGeneratorTarget::GetFilePrefixInternal( +cmValue cmGeneratorTarget::GetFilePrefixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, const std::string& language) const { @@ -618,7 +672,7 @@ cmProp cmGeneratorTarget::GetFilePrefixInternal( } // Compute prefix value. - cmProp targetPrefix = + cmValue targetPrefix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX") : this->GetProperty("PREFIX")); @@ -639,7 +693,7 @@ cmProp cmGeneratorTarget::GetFilePrefixInternal( return targetPrefix; } -cmProp cmGeneratorTarget::GetFileSuffixInternal( +cmValue cmGeneratorTarget::GetFileSuffixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, const std::string& language) const { @@ -669,7 +723,7 @@ cmProp cmGeneratorTarget::GetFileSuffixInternal( } // Compute suffix value. - cmProp targetSuffix = + cmValue targetSuffix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX") : this->GetProperty("SUFFIX")); @@ -700,11 +754,18 @@ void cmGeneratorTarget::ClearSourcesCache() this->LinkImplMap.clear(); } +void cmGeneratorTarget::ClearLinkInterfaceCache() +{ + this->LinkInterfaceMap.clear(); + this->LinkInterfaceUsageRequirementsOnlyMap.clear(); +} + void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before) { this->SourceEntries.insert( before ? this->SourceEntries.begin() : this->SourceEntries.end(), - CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true)); + CreateTargetPropertyEntry( + BT<std::string>(src, this->Makefile->GetBacktrace()), true)); this->ClearSourcesCache(); } @@ -725,11 +786,13 @@ void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs) void cmGeneratorTarget::AddIncludeDirectory(const std::string& src, bool before) { - this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before); + this->Target->InsertInclude( + BT<std::string>(src, this->Makefile->GetBacktrace()), before); this->IncludeDirectoriesEntries.insert( before ? this->IncludeDirectoriesEntries.begin() : this->IncludeDirectoriesEntries.end(), - CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true)); + CreateTargetPropertyEntry( + BT<std::string>(src, this->Makefile->GetBacktrace()), true)); } std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends( @@ -751,7 +814,7 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, std::vector<std::string>& result, bool excludeImported, std::string const& language) { - if (cmProp dirs = + if (cmValue dirs = depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) { cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), @@ -760,8 +823,11 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, if (!depTgt->IsImported() || excludeImported) { return; } + if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) { + return; + } - if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { + if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), result); @@ -813,17 +879,17 @@ void cmGeneratorTarget::ComputeObjectMapping() } } -cmProp cmGeneratorTarget::GetFeature(const std::string& feature, - const std::string& config) const +cmValue cmGeneratorTarget::GetFeature(const std::string& feature, + const std::string& config) const { if (!config.empty()) { std::string featureConfig = cmStrCat(feature, '_', cmSystemTools::UpperCase(config)); - if (cmProp value = this->GetProperty(featureConfig)) { + if (cmValue value = this->GetProperty(featureConfig)) { return value; } } - if (cmProp value = this->GetProperty(feature)) { + if (cmValue value = this->GetProperty(feature)) { return value; } return this->LocalGenerator->GetFeature(feature, config); @@ -851,7 +917,7 @@ const char* cmGeneratorTarget::GetLinkPIEProperty( bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang, std::string const& config) const { - cmProp feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config); + cmValue feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config); if (!cmIsOn(feature)) { // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies @@ -959,23 +1025,23 @@ BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty( cmStrCat(lang, "_STANDARD")); } -cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, - std::string const& config) const +cmValue cmGeneratorTarget::GetLanguageStandard(std::string const& lang, + std::string const& config) const { BTs<std::string> const* languageStandard = this->GetLanguageStandardProperty(lang, config); if (languageStandard) { - return &(languageStandard->Value); + return cmValue(languageStandard->Value); } return nullptr; } -cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport( +cmValue cmGeneratorTarget::GetPropertyWithPairedLanguageSupport( std::string const& lang, const char* suffix) const { - cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix)); + cmValue propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix)); if (!propertyValue) { // Check if we should use the value set by another language. if (lang == "OBJC") { @@ -988,7 +1054,7 @@ cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport( return propertyValue; } -cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const +cmValue cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const { return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS"); } @@ -1150,6 +1216,7 @@ bool cmGeneratorTarget::IsInBuildSystem() const if (!this->SourceEntries.empty()) { return true; } + break; case cmStateEnums::UNKNOWN_LIBRARY: break; } @@ -1183,7 +1250,7 @@ const std::string& cmGeneratorTarget::GetLocationForBuild() const // Now handle the deprecated build-time configuration location. std::string const noConfig; location = this->GetDirectory(noConfig); - cmProp cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR"); + cmValue cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR"); if (cfgid && (*cfgid != ".")) { location += "/"; location += *cfgid; @@ -1267,7 +1334,7 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const bool cmGeneratorTarget::MaybeHaveInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { std::string const key = prop + '@' + context->Config; auto i = this->MaybeInterfacePropertyExists.find(key); @@ -1285,7 +1352,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( context->HeadTarget ? context->HeadTarget : this; if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(context->Config, headTarget, - usage_requirements_only)) { + interfaceFor)) { if (iface->HadHeadSensitiveCondition) { // With a different head target we may get to a library with // this interface property. @@ -1295,8 +1362,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( // head target, so we can follow them. for (cmLinkItem const& lib : iface->Libraries) { if (lib.Target && - lib.Target->MaybeHaveInterfaceProperty( - prop, context, usage_requirements_only)) { + lib.Target->MaybeHaveInterfaceProperty(prop, context, + interfaceFor)) { maybeInterfaceProp = true; break; } @@ -1311,13 +1378,12 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( std::string cmGeneratorTarget::EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagCheckerParent, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { std::string result; // If the property does not appear transitively at all, we are done. - if (!this->MaybeHaveInterfaceProperty(prop, context, - usage_requirements_only)) { + if (!this->MaybeHaveInterfaceProperty(prop, context, interfaceFor)) { return result; } @@ -1343,13 +1409,13 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( cmGeneratorTarget const* headTarget = context->HeadTarget ? context->HeadTarget : this; - if (cmProp p = this->GetProperty(prop)) { + if (cmValue p = this->GetProperty(prop)) { result = cmGeneratorExpressionNode::EvaluateDependentExpression( *p, context->LG, context, headTarget, &dagChecker, this); } if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( - context->Config, headTarget, usage_requirements_only)) { + context->Config, headTarget, interfaceFor)) { context->HadContextSensitiveCondition = context->HadContextSensitiveCondition || iface->HadContextSensitiveCondition; @@ -1367,7 +1433,7 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( context->Language); std::string libResult = cmGeneratorExpression::StripEmptyListElements( lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker, - usage_requirements_only)); + interfaceFor)); if (!libResult.empty()) { if (result.empty()) { result = std::move(libResult); @@ -1421,8 +1487,8 @@ std::string AddLangSpecificInterfaceIncludeDirectories( } std::string directories; - if (const auto* interface = - target->GetLinkInterfaceLibraries(config, root, true)) { + if (const auto* interface = target->GetLinkInterfaceLibraries( + config, root, LinkInterfaceFor::Usage)) { for (const cmLinkItem& library : interface->Libraries) { if (const cmGeneratorTarget* dependency = library.Target) { if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) { @@ -1466,7 +1532,7 @@ void AddLangSpecificImplicitIncludeDirectories( auto* lg = dependency->GetLocalGenerator(); EvaluatedTargetPropertyEntry entry{ library, library.Backtrace }; - if (cmProp val = dependency->GetProperty(propertyName)) { + if (cmValue val = dependency->GetProperty(propertyName)) { entry.Values.emplace_back(*val); } else { if (mode == IncludeDirectoryFallBack::BINARY) { @@ -1493,7 +1559,7 @@ void addInterfaceEntry(cmGeneratorTarget const* headTarget, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, EvaluatedTargetPropertyEntries& entries, - bool usage_requirements_only, + LinkInterfaceFor interfaceFor, std::vector<cmLinkImplItem> const& libraries) { for (cmLinkImplItem const& lib : libraries) { @@ -1506,7 +1572,7 @@ void addInterfaceEntry(cmGeneratorTarget const* headTarget, headTarget->GetLocalGenerator(), config, false, headTarget, headTarget, true, lib.Backtrace, lang); cmExpandList(lib.Target->EvaluateInterfaceProperty( - prop, &context, dagChecker, usage_requirements_only), + prop, &context, dagChecker, interfaceFor), ee.Values); ee.ContextDependent = context.HadContextSensitiveCondition; entries.Entries.emplace_back(std::move(ee)); @@ -1533,13 +1599,13 @@ enum class IncludeRuntimeInterface Yes, No }; -void AddInterfaceEntries(cmGeneratorTarget const* headTarget, - std::string const& config, std::string const& prop, - std::string const& lang, - cmGeneratorExpressionDAGChecker* dagChecker, - EvaluatedTargetPropertyEntries& entries, - IncludeRuntimeInterface searchRuntime, - bool usage_requirements_only = true) +void AddInterfaceEntries( + cmGeneratorTarget const* headTarget, std::string const& config, + std::string const& prop, std::string const& lang, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries, + IncludeRuntimeInterface searchRuntime, + LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage) { if (searchRuntime == IncludeRuntimeInterface::Yes) { if (cmLinkImplementation const* impl = @@ -1550,10 +1616,10 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang); if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) { addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, runtimeLibIt->second); + interfaceFor, runtimeLibIt->second); } addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, impl->Libraries); + interfaceFor, impl->Libraries); } } else { if (cmLinkImplementationLibraries const* impl = @@ -1561,7 +1627,7 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, impl->Libraries); + interfaceFor, impl->Libraries); } } } @@ -1598,6 +1664,80 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, } } +void addFileSetEntry(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + cmFileSet const* fileSet, + EvaluatedTargetPropertyEntries& entries) +{ + auto dirCges = fileSet->CompileDirectoryEntries(); + auto dirs = fileSet->EvaluateDirectoryEntries( + dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker); + bool contextSensitiveDirs = false; + for (auto const& dirCge : dirCges) { + if (dirCge->GetHadContextSensitiveCondition()) { + contextSensitiveDirs = true; + break; + } + } + cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance(); + for (auto& entryCge : fileSet->CompileFileEntries()) { + TargetPropertyEntryFileSet tpe(dirs, contextSensitiveDirs, + std::move(entryCge), fileSet); + entries.Entries.emplace_back( + EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, tpe)); + for (auto const& file : entries.Entries.back().Values) { + auto* sf = headTarget->Makefile->GetOrCreateSource(file); + if (fileSet->GetType() == "HEADERS"_s) { + sf->SetProperty("HEADER_FILE_ONLY", "TRUE"); + } + +#ifndef CMAKE_BOOTSTRAP + std::string e; + std::string w; + auto path = sf->ResolveFullPath(&e, &w); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, + headTarget->GetBacktrace()); + } + if (path.empty()) { + if (!e.empty()) { + cm->IssueMessage(MessageType::FATAL_ERROR, e, + headTarget->GetBacktrace()); + } + return; + } + bool found = false; + for (auto const& sg : headTarget->Makefile->GetSourceGroups()) { + if (sg.MatchesFiles(path)) { + found = true; + break; + } + } + if (!found) { + if (fileSet->GetType() == "HEADERS"_s) { + headTarget->Makefile->GetOrCreateSourceGroup("Header Files") + ->AddGroupFile(path); + } + } +#endif + } + } +} + +void AddFileSetEntries(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries) +{ + for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) { + for (auto const& name : cmExpandedList(entry.Value)) { + auto const* headerSet = headTarget->Target->GetFileSet(name); + addFileSetEntry(headTarget, config, dagChecker, headerSet, entries); + } + } +} + bool processSources(cmGeneratorTarget const* tgt, EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& srcs, @@ -1681,9 +1821,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( // for TARGET_OBJECTS instead for backwards compatibility with OLD // behavior of CMP0024 and CMP0026 only. - cmStringRange sourceEntries = this->Target->GetSourceEntries(); - for (std::string const& entry : sourceEntries) { - std::vector<std::string> items = cmExpandedList(entry); + cmBTStringRange sourceEntries = this->Target->GetSourceEntries(); + for (auto const& entry : sourceEntries) { + std::vector<std::string> items = cmExpandedList(entry.Value); for (std::string const& item : items) { if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") && item.back() == '>') { @@ -1720,7 +1860,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), &dagChecker, linkInterfaceSourcesEntries, - IncludeRuntimeInterface::No, true); + IncludeRuntimeInterface::No, LinkInterfaceFor::Usage); std::vector<std::string>::size_type numFilesBefore = files.size(); bool contextDependentInterfaceSources = processSources( this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); @@ -1735,10 +1875,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( uniqueSrcs, debugSources); } + // Collect this target's file sets. + std::vector<std::string>::size_type numFilesBefore3 = files.size(); + EvaluatedTargetPropertyEntries fileSetEntries; + AddFileSetEntries(this, config, &dagChecker, fileSetEntries); + bool contextDependentFileSets = + processSources(this, fileSetEntries, files, uniqueSrcs, debugSources); + // Determine if sources are context-dependent or not. if (!contextDependentDirectSources && !(contextDependentInterfaceSources && numFilesBefore < files.size()) && - !(contextDependentObjects && numFilesBefore2 < files.size())) { + !(contextDependentObjects && numFilesBefore2 < files.size()) && + !(contextDependentFileSets && numFilesBefore3 < files.size())) { this->SourcesAreContextDependent = Tribool::False; } else { this->SourcesAreContextDependent = Tribool::True; @@ -1998,12 +2146,12 @@ std::string cmGeneratorTarget::GetCompilePDBName( // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(config); std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper); - cmProp config_name = this->GetProperty(configProp); + cmValue config_name = this->GetProperty(configProp); if (cmNonempty(config_name)) { return prefix + *config_name + ".pdb"; } - cmProp name = this->GetProperty("COMPILE_PDB_NAME"); + cmValue name = this->GetProperty("COMPILE_PDB_NAME"); if (cmNonempty(name)) { return prefix + *name + ".pdb"; } @@ -2142,34 +2290,29 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const return true; } -#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER) // Enable if the rpath flag uses a separator and the target uses // binaries we know how to edit. std::string ll = this->GetLinkerLanguage(config); if (!ll.empty()) { std::string sepVar = cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP"); - cmProp sep = this->Makefile->GetDefinition(sepVar); + cmValue sep = this->Makefile->GetDefinition(sepVar); if (cmNonempty(sep)) { // TODO: Add binary format check to ABI detection and get rid of // CMAKE_EXECUTABLE_FORMAT. - if (cmProp fmt = + if (cmValue fmt = this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) { -# if defined(CMake_USE_ELF_PARSER) if (*fmt == "ELF") { return true; } -# endif -# if defined(CMake_USE_XCOFF_PARSER) +#if defined(CMake_USE_XCOFF_PARSER) if (*fmt == "XCOFF") { return true; } -# endif +#endif } } } -#endif - static_cast<void>(config); return false; } @@ -2188,6 +2331,21 @@ bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName( bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( const std::string& config) const { + TargetPtrToBoolMap& cache = this->MacOSXRpathInstallNameDirCache[config]; + const auto lookup = cache.find(this->Target); + + if (lookup != cache.cend()) { + return lookup->second; + } + + const bool result = this->DetermineHasMacOSXRpathInstallNameDir(config); + cache[this->Target] = result; + return result; +} + +bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir( + const std::string& config) const +{ bool install_name_is_rpath = false; bool macosx_rpath = false; @@ -2195,7 +2353,7 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (this->GetType() != cmStateEnums::SHARED_LIBRARY) { return false; } - cmProp install_name = this->GetProperty("INSTALL_NAME_DIR"); + cmValue install_name = this->GetProperty("INSTALL_NAME_DIR"); bool use_install_name = this->MacOSXUseInstallNameDir(); if (install_name && use_install_name && *install_name == "@rpath") { install_name_is_rpath = true; @@ -2253,7 +2411,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const return false; } - cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); + cmValue macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); if (macosx_rpath_str) { return this->GetPropertyAsBool("MACOSX_RPATH"); } @@ -2270,7 +2428,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const bool cmGeneratorTarget::MacOSXUseInstallNameDir() const { - cmProp build_with_install_name = + cmValue build_with_install_name = this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR"); if (build_with_install_name) { return cmIsOn(*build_with_install_name); @@ -2363,7 +2521,7 @@ std::string cmGeneratorTarget::GetAppBundleDirectory( { std::string fpath = cmStrCat( this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + cmValue ext = this->GetProperty("BUNDLE_EXTENSION"); fpath += (ext ? *ext : "app"); if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { @@ -2393,7 +2551,7 @@ std::string cmGeneratorTarget::GetCFBundleDirectory( std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); std::string ext; - if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) { + if (cmValue p = this->GetProperty("BUNDLE_EXTENSION")) { ext = *p; } else { if (this->IsXCTestOnApple()) { @@ -2418,7 +2576,7 @@ std::string cmGeneratorTarget::GetFrameworkDirectory( { std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + cmValue ext = this->GetProperty("BUNDLE_EXTENSION"); fpath += (ext ? *ext : "framework"); if (shouldAddFullLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { @@ -2470,7 +2628,7 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree( { if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { std::string dir; - cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); + cmValue install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) { if (cmNonempty(install_name_dir)) { @@ -2519,7 +2677,7 @@ const std::string* cmGeneratorTarget::GetExportMacro() const if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || this->IsExecutableWithExports()) { - if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { + if (cmValue custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { this->ExportMacro = *custom_export_name; } else { std::string in = cmStrCat(this->GetName(), "_EXPORTS"); @@ -2540,7 +2698,6 @@ public: : Config(std::move(config)) , Languages(languages) , HeadTarget(head) - , Target(target) , SecondPass(secondPass) { this->Visited.insert(target); @@ -2549,35 +2706,6 @@ public: void Visit(cmLinkItem const& item) { if (!item.Target) { - if (item.AsStr().find("::") != std::string::npos) { - bool noMessage = false; - MessageType messageType = MessageType::FATAL_ERROR; - std::ostringstream e; - switch (this->Target->GetLocalGenerator()->GetPolicyStatus( - cmPolicies::CMP0028)) { - case cmPolicies::WARN: { - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n"; - messageType = MessageType::AUTHOR_WARNING; - } break; - case cmPolicies::OLD: - noMessage = true; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Issue the fatal message. - break; - } - - if (!noMessage) { - e << "Target \"" << this->Target->GetName() - << "\" links to target \"" << item.AsStr() - << "\" but the target was not found. Perhaps a find_package() " - "call is missing for an IMPORTED target, or an ALIAS target is " - "missing?"; - this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( - messageType, e.str(), this->Target->GetBacktrace()); - } - } return; } if (!this->Visited.insert(item.Target).second) { @@ -2610,7 +2738,6 @@ private: std::string Config; std::unordered_set<std::string>& Languages; cmGeneratorTarget const* HeadTarget; - const cmGeneratorTarget* Target; std::set<cmGeneratorTarget const*> Visited; bool SecondPass; bool HadLinkLanguageSensitiveCondition = false; @@ -2817,7 +2944,7 @@ std::string cmGeneratorTarget::GetEffectiveFolderName() const return effectiveFolder; } - cmProp targetFolder = this->GetProperty("FOLDER"); + cmValue targetFolder = this->GetProperty("FOLDER"); if (targetFolder) { effectiveFolder += *targetFolder; } @@ -2924,16 +3051,17 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result, result); } -void processILibs(const std::string& config, - cmGeneratorTarget const* headTarget, cmLinkItem const& item, - cmGlobalGenerator* gg, - std::vector<cmGeneratorTarget const*>& tgts, - std::set<cmGeneratorTarget const*>& emitted) +static void processILibs(const std::string& config, + cmGeneratorTarget const* headTarget, + cmLinkItem const& item, cmGlobalGenerator* gg, + std::vector<cmGeneratorTarget const*>& tgts, + std::set<cmGeneratorTarget const*>& emitted) { if (item.Target && emitted.insert(item.Target).second) { tgts.push_back(item.Target); if (cmLinkInterfaceLibraries const* iface = - item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) { + item.Target->GetLinkInterfaceLibraries(config, headTarget, + LinkInterfaceFor::Usage)) { for (cmLinkItem const& lib : iface->Libraries) { processILibs(config, headTarget, lib, gg, tgts, emitted); } @@ -3045,7 +3173,7 @@ void cmTargetTraceDependencies::Trace() this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf]; // Queue dependencies added explicitly by the user. - if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { + if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { std::vector<std::string> objDeps = cmExpandedList(*additionalDeps); for (std::string& objDep : objDeps) { if (cmSystemTools::FileIsFullPath(objDep)) { @@ -3243,7 +3371,7 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, if (!this->Makefile->IsOn("APPLE")) { return; } - cmProp archs = nullptr; + cmValue archs = nullptr; if (!config.empty()) { std::string defVarName = cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config)); @@ -3263,13 +3391,14 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, cmSourceFile const& sf) const { - cmProp lang = sf.GetProperty("LANGUAGE"); + cmValue lang = sf.GetProperty("LANGUAGE"); if (!lang) { return; } switch (this->GetPolicyStatusCMP0119()) { case cmPolicies::WARN: + CM_FALLTHROUGH; case cmPolicies::OLD: // The OLD behavior is to not add explicit language flags. return; @@ -3286,7 +3415,7 @@ void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const { - const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES"); + std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES"); if (property.empty()) { switch (this->GetPolicyStatusCMP0104()) { @@ -3314,6 +3443,30 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const return; } + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + // Check for special modes: `all`, `all-major`. + if (compiler == "NVIDIA" && + cmSystemTools::VersionCompare( + cmSystemTools::OP_GREATER_EQUAL, + this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"), + "11.5")) { + if (property == "all") { + flags += " -arch=all"; + } else if (property == "all-major") { + flags += " -arch=all-major"; + } + return; + } + + if (property == "all") { + property = *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL"); + } else if (property == "all-major") { + property = + *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR"); + } + struct CudaArchitecture { std::string name; @@ -3355,9 +3508,6 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const } } - std::string const& compiler = - this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); - if (compiler == "NVIDIA") { for (CudaArchitecture& architecture : architectures) { flags += @@ -3514,7 +3664,7 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt, cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); bool const fromImported = item.Target && item.Target->IsImported(); - bool const checkCMP0027 = item.FromGenex; + bool const checkCMP0027 = item.CheckCMP0027; std::string usedIncludes; for (std::string& entryInclude : entry.Values) { @@ -3568,6 +3718,7 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt, } break; case cmPolicies::OLD: noMessage = true; + break; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::NEW: @@ -3644,7 +3795,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( // If this target has ISPC sources make sure to add the header // directory to other compilation units if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) { - if (cmProp val = this->GetProperty(propertyName)) { + if (cmValue val = this->GetProperty(propertyName)) { includes.emplace_back(*val); } else { includes.emplace_back(this->GetObjectDirectory(config)); @@ -3974,7 +4125,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( if (!config.empty()) { std::string configPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - cmProp configProp = this->GetProperty(configPropName); + cmValue configProp = this->GetProperty(configPropName); if (configProp) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) { case cmPolicies::WARN: { @@ -4049,7 +4200,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, return std::string(); } const cmGeneratorTarget* generatorTarget = this; - cmProp pchReuseFrom = + cmValue pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); const auto inserted = @@ -4090,8 +4241,10 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, const std::string filename_tmp = cmStrCat(filename, ".tmp"); if (!pchReuseFrom) { - cmProp pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE"); - cmProp pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE"); + cmValue pchPrologue = + this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE"); + cmValue pchEpilogue = + this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE"); std::string firstHeaderOnDisk; { @@ -4105,7 +4258,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, if (this->GetGlobalGenerator()->IsXcode()) { file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n"; } - if (language == "CXX") { + if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) { file << "#ifdef __cplusplus\n"; } for (auto const& header_bt : headers) { @@ -4123,7 +4276,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, firstHeaderOnDisk = header_bt.Value; } } - if (language == "CXX") { + if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) { file << "#endif // __cplusplus\n"; } if (this->GetGlobalGenerator()->IsXcode()) { @@ -4162,7 +4315,7 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, std::string& filename = inserted.first->second; const cmGeneratorTarget* generatorTarget = this; - cmProp pchReuseFrom = + cmValue pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = @@ -4260,7 +4413,7 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config, }; cmGeneratorTarget* generatorTarget = this; - cmProp pchReuseFrom = + cmValue pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = @@ -4413,7 +4566,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processOptions(this, entries, result, uniqueOptions, debugOptions, "link options", OptionsParse::Shell, this->IsDeviceLink()); @@ -4466,6 +4621,13 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper + return this->ResolveLinkerWrapper(result, language); +} + +std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( + std::vector<BT<std::string>>& result, const std::string& language) const +{ + // replace "LINKER:" prefixed elements by actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( "CMAKE_" + language + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG" @@ -4549,7 +4711,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( nullptr, nullptr); EvaluatedTargetPropertyEntries entries; - if (cmProp linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { + if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { std::vector<std::string> options = cmExpandedList(*linkOptions); for (const auto& option : options) { std::unique_ptr<TargetPropertyEntry> entry = @@ -4672,7 +4834,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processLinkDirectories(this, entries, result, uniqueDirectories, debugDirectories); @@ -4700,7 +4864,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( nullptr); EvaluatedTargetPropertyEntries entries; - if (cmProp linkDepends = this->GetProperty("LINK_DEPENDS")) { + if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) { std::vector<std::string> depends = cmExpandedList(*linkDepends); for (const auto& depend : depends) { std::unique_ptr<TargetPropertyEntry> entry = @@ -4711,7 +4875,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processOptions(this, entries, result, uniqueOptions, false, "link depends", OptionsParse::None); @@ -4781,7 +4947,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const } std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); - cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config); + cmValue currentLanguageStandard = this->GetLanguageStandard(lang, config); std::string newRequiredStandard; if (!standardResolver.GetNewRequiredStandard( @@ -4821,7 +4987,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures( this->LanguageStandardMap[key] = *standardToCopy; generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; } else { - cmProp defaultStandard = this->Makefile->GetDefinition( + cmValue defaultStandard = this->Makefile->GetDefinition( cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT")); if (defaultStandard) { this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard); @@ -4924,8 +5090,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( } // Check for library version properties. - cmProp version = this->GetProperty("VERSION"); - cmProp soversion = this->GetProperty("SOVERSION"); + cmValue version = this->GetProperty("VERSION"); + cmValue soversion = this->GetProperty("SOVERSION"); if (!this->HasSOName(config) || this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") || this->IsFrameworkOnApple()) { @@ -4966,11 +5132,11 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( // The library's soname. this->ComputeVersionedName(targetNames.SharedObject, prefix, targetNames.Base, suffix, targetNames.Output, - cmToCStr(soversion)); + soversion); // The library's real name on disk. this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base, - suffix, targetNames.Output, cmToCStr(version)); + suffix, targetNames.Output, version); } // The import library name. @@ -5003,10 +5169,10 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames( // This versioning is supported only for executables and then only // when the platform supports symbolic links. #if defined(_WIN32) && !defined(__CYGWIN__) - const char* version = nullptr; + cmValue version; #else // Check for executable version properties. - const char* version = cmToCStr(this->GetProperty("VERSION")); + cmValue version = this->GetProperty("VERSION"); if (this->GetType() != cmStateEnums::EXECUTABLE || this->Makefile->IsOn("XCODE")) { version = nullptr; @@ -5030,7 +5196,7 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames( #endif if (version) { targetNames.Real += "-"; - targetNames.Real += version; + targetNames.Real += *version; } #if defined(__CYGWIN__) targetNames.Real += suffix; @@ -5100,8 +5266,8 @@ void cmGeneratorTarget::GetFullNameInternal( // retrieve prefix and suffix std::string ll = this->GetLinkerLanguage(config); - cmProp targetPrefix = this->GetFilePrefixInternal(config, artifact, ll); - cmProp targetSuffix = this->GetFileSuffixInternal(config, artifact, ll); + cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll); + cmValue targetSuffix = this->GetFileSuffixInternal(config, artifact, ll); // The implib option is only allowed for shared libraries, module // libraries, and executables. @@ -5119,13 +5285,13 @@ void cmGeneratorTarget::GetFullNameInternal( if (this->IsFrameworkOnApple()) { fw_prefix = cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/'); - targetPrefix = &fw_prefix; + targetPrefix = cmValue(fw_prefix); targetSuffix = nullptr; } if (this->IsCFBundleOnApple()) { fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/'); - targetPrefix = &fw_prefix; + targetPrefix = cmValue(fw_prefix); targetSuffix = nullptr; } @@ -5141,13 +5307,13 @@ void cmGeneratorTarget::GetFullNameInternal( // EXECUTABLE_SUFFIX attribute. if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->GetName() == "Xcode") { - targetSuffix = &configPostfix; + targetSuffix = cmValue(configPostfix); } else { outBase += configPostfix; } // Name shared libraries with their version number on some platforms. - if (cmProp soversion = this->GetProperty("SOVERSION")) { + if (cmValue soversion = this->GetProperty("SOVERSION")) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY && !isImportedLibraryArtifact && this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) { @@ -5183,7 +5349,7 @@ std::string cmGeneratorTarget::GetPDBOutputName( props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (cmProp outName = this->GetProperty(p)) { + if (cmValue outName = this->GetProperty(p)) { base = *outName; break; } @@ -5210,7 +5376,7 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (cmProp outName = this->GetProperty(p)) { + if (cmValue outName = this->GetProperty(p)) { base = *outName; break; } @@ -5293,7 +5459,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const } else { // Handle the MACOSX_PACKAGE_LOCATION property on source files that // were not listed in one of the other lists. - if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { + if (cmValue location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { flags.MacFolder = location->c_str(); const bool stripResources = this->GlobalGenerator->ShouldStripResourcePath(this->Makefile); @@ -5323,7 +5489,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const this->SourceFileFlagsConstructed = true; // Process public headers to mark the source files. - if (cmProp files = this->GetProperty("PUBLIC_HEADER")) { + if (cmValue files = this->GetProperty("PUBLIC_HEADER")) { std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { @@ -5336,7 +5502,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Process private headers after public headers so that they take // precedence if a file is listed in both. - if (cmProp files = this->GetProperty("PRIVATE_HEADER")) { + if (cmValue files = this->GetProperty("PRIVATE_HEADER")) { std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { @@ -5348,7 +5514,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const } // Mark sources listed as resources. - if (cmProp files = this->GetProperty("RESOURCE")) { + if (cmValue files = this->GetProperty("RESOURCE")) { std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { @@ -5376,7 +5542,7 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const this->GetLinkImplementationClosure(config); for (cmGeneratorTarget const* li : deps) { #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ - if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ + if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ std::vector<std::string> props; \ cmExpandList(*prop, props); \ compat.Props##x.insert(props.begin(), props.end()); \ @@ -5486,7 +5652,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, const std::string& config, CompatibleType t, PropertyType* /*unused*/) { - cmProp prop = dependee->GetProperty(propName); + cmValue prop = dependee->GetProperty(propName); if (!prop) { return; } @@ -5672,12 +5838,17 @@ std::string valueAsString<std::string>(std::string value) return value; } template <> +std::string valueAsString<cmValue>(cmValue value) +{ + return value ? value : std::string("(unset)"); +} +template <> std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/) { return "(unset)"; } -std::string compatibilityType(CompatibleType t) +static std::string compatibilityType(CompatibleType t) { switch (t) { case BoolType: @@ -5693,7 +5864,7 @@ std::string compatibilityType(CompatibleType t) return ""; } -std::string compatibilityAgree(CompatibleType t, bool dominant) +static std::string compatibilityAgree(CompatibleType t, bool dominant) { switch (t) { case BoolType: @@ -5721,7 +5892,7 @@ bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, return tgt->GetPropertyAsBool(prop); } - cmProp value = tgt->GetProperty(prop); + cmValue value = tgt->GetProperty(prop); return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop)); } @@ -5730,10 +5901,10 @@ const char* getTypedProperty<const char*>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - cmProp value = tgt->GetProperty(prop); + cmValue value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return cmToCStr(value); + return value.GetCStr(); } return genexInterpreter->Evaluate(value ? *value : "", prop).c_str(); @@ -5744,10 +5915,10 @@ std::string getTypedProperty<std::string>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - cmProp value = tgt->GetProperty(prop); + cmValue value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return valueAsString(cmToCStr(value)); + return valueAsString(value); } return genexInterpreter->Evaluate(value ? *value : "", prop); @@ -5783,23 +5954,23 @@ std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, return { lhs == rhs, lhs }; } -std::pair<bool, const char*> consistentStringProperty(const char* lhs, - const char* rhs) +static std::pair<bool, const char*> consistentStringProperty(const char* lhs, + const char* rhs) { const bool b = strcmp(lhs, rhs) == 0; return { b, b ? lhs : nullptr }; } -std::pair<bool, std::string> consistentStringProperty(const std::string& lhs, - const std::string& rhs) +static std::pair<bool, std::string> consistentStringProperty( + const std::string& lhs, const std::string& rhs) { const bool b = lhs == rhs; return { b, b ? lhs : valueAsString(nullptr) }; } -std::pair<bool, const char*> consistentNumberProperty(const char* lhs, - const char* rhs, - CompatibleType t) +static std::pair<bool, const char*> consistentNumberProperty(const char* lhs, + const char* rhs, + CompatibleType t) { char* pEnd; @@ -5850,9 +6021,9 @@ std::pair<bool, const char*> consistentProperty(const char* lhs, return { false, nullptr }; } -std::pair<bool, std::string> consistentProperty(const std::string& lhs, - const std::string& rhs, - CompatibleType t) +static std::pair<bool, std::string> consistentProperty(const std::string& lhs, + const std::string& rhs, + CompatibleType t) { const std::string null_ptr = valueAsString(nullptr); @@ -6093,6 +6264,139 @@ cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation( return i->second.get(); } +void cmGeneratorTarget::CheckLinkLibraries() const +{ + bool linkLibrariesOnlyTargets = + this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS"); + + // Evaluate the link interface of this target if needed for extra checks. + if (linkLibrariesOnlyTargets) { + std::vector<std::string> const& configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (std::string const& config : configs) { + this->GetLinkInterfaceLibraries(config, this, LinkInterfaceFor::Link); + } + } + + // Check link the implementation for each generated configuration. + for (auto const& hmp : this->LinkImplMap) { + HeadToLinkImplementationMap const& hm = hmp.second; + // There could be several entries used when computing the pre-CMP0022 + // default link interface. Check only the entry for our own link impl. + auto const hmi = hm.find(this); + if (hmi == hm.end() || !hmi->second.LibrariesDone) { + continue; + } + for (cmLinkImplItem const& item : hmi->second.Libraries) { + if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) { + return; + } + if (linkLibrariesOnlyTargets && + !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) { + return; + } + } + } + + // Check link the interface for each generated combination of + // configuration and consuming head target. We should not need to + // consider LinkInterfaceUsageRequirementsOnlyMap because its entries + // should be a subset of LinkInterfaceMap (with LINK_ONLY left out). + for (auto const& hmp : this->LinkInterfaceMap) { + for (auto const& hmi : hmp.second) { + if (!hmi.second.LibrariesDone) { + continue; + } + for (cmLinkItem const& item : hmi.second.Libraries) { + if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) { + return; + } + if (linkLibrariesOnlyTargets && + !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) { + return; + } + } + } + } +} + +namespace { +cm::string_view missingTargetPossibleReasons = + "Possible reasons include:\n" + " * There is a typo in the target name.\n" + " * A find_package call is missing for an IMPORTED target.\n" + " * An ALIAS target is missing.\n"_s; +} + +bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role, + cmLinkItem const& item) const +{ + if (item.Target || item.AsStr().find("::") == std::string::npos) { + return true; + } + MessageType messageType = MessageType::FATAL_ERROR; + std::string e; + switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028)) { + case cmPolicies::WARN: { + e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028), "\n"); + messageType = MessageType::AUTHOR_WARNING; + } break; + case cmPolicies::OLD: + return true; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Issue the fatal message. + break; + } + + if (role == LinkItemRole::Implementation) { + e = cmStrCat(e, "Target \"", this->GetName(), "\" links to"); + } else { + e = cmStrCat(e, "The link interface of target \"", this->GetName(), + "\" contains"); + } + e = + cmStrCat(e, ":\n ", item.AsStr(), "\n", "but the target was not found. ", + missingTargetPossibleReasons); + cmListFileBacktrace backtrace = item.Backtrace; + if (backtrace.Empty()) { + backtrace = this->GetBacktrace(); + } + this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType, e, + backtrace); + return false; +} + +bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, + cmLinkItem const& item) const +{ + if (item.Target) { + return true; + } + std::string const& str = item.AsStr(); + if (!str.empty() && + (str[0] == '-' || str[0] == '$' || str[0] == '`' || + str.find_first_of("/\\") != std::string::npos)) { + return true; + } + + std::string e = cmStrCat("Target \"", this->GetName(), + "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ", + role == LinkItemRole::Implementation + ? "it links to" + : "its link interface contains", + ":\n ", item.AsStr(), "\nwhich is not a target. ", + missingTargetPossibleReasons); + cmListFileBacktrace backtrace = item.Backtrace; + if (backtrace.Empty()) { + backtrace = this->GetBacktrace(); + } + this->LocalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, e, backtrace); + return false; +} + void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const { int patch; @@ -6121,7 +6425,7 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property, assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (cmProp version = this->GetProperty(property)) { + if (cmValue version = this->GetProperty(property)) { // Try to parse the version number and store the results that were // successfully parsed. int parsed_major; @@ -6149,12 +6453,12 @@ std::string cmGeneratorTarget::GetRuntimeLinkLibrary( { // This is activated by the presence of a default selection whether or // not it is overridden by a property. - cmProp runtimeLibraryDefault = this->Makefile->GetDefinition( + cmValue runtimeLibraryDefault = this->Makefile->GetDefinition( cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT")); if (!cmNonempty(runtimeLibraryDefault)) { return std::string(); } - cmProp runtimeLibraryValue = + cmValue runtimeLibraryValue = this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY")); if (!runtimeLibraryValue) { runtimeLibraryValue = runtimeLibraryDefault; @@ -6175,12 +6479,21 @@ std::string cmGeneratorTarget::GetFortranModuleDirectory( return this->FortranModuleDirectory; } +bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const +{ + if (cmValue prop = + this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) { + return cmIsOn(*prop); + } + return false; +} + std::string cmGeneratorTarget::CreateFortranModuleDirectory( std::string const& working_dir) const { std::string mod_dir; std::string target_mod_dir; - if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { + if (cmValue prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { target_mod_dir = *prop; } else { std::string const& default_mod_dir = @@ -6189,7 +6502,7 @@ std::string cmGeneratorTarget::CreateFortranModuleDirectory( target_mod_dir = default_mod_dir; } } - cmProp moddir_flag = + cmValue moddir_flag = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); if (!target_mod_dir.empty() && moddir_flag) { // Compute the full path to the module directory. @@ -6272,26 +6585,23 @@ std::string cmGeneratorTarget::GetFrameworkVersion() const { assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) { + if (cmValue fversion = this->GetProperty("FRAMEWORK_VERSION")) { return *fversion; } - if (cmProp tversion = this->GetProperty("VERSION")) { + if (cmValue tversion = this->GetProperty("VERSION")) { return *tversion; } return "A"; } -void cmGeneratorTarget::ComputeVersionedName(std::string& vName, - std::string const& prefix, - std::string const& base, - std::string const& suffix, - std::string const& name, - const char* version) const +void cmGeneratorTarget::ComputeVersionedName( + std::string& vName, std::string const& prefix, std::string const& base, + std::string const& suffix, std::string const& name, cmValue version) const { vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name; if (version) { vName += "."; - vName += version; + vName += *version; } vName += this->Makefile->IsOn("APPLE") ? suffix : std::string(); } @@ -6347,7 +6657,7 @@ bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n, cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( std::string const& n, cmListFileBacktrace const& bt, - LookupLinkItemScope* scope) const + LookupLinkItemScope* scope, LookupSelf lookupSelf) const { cm::optional<cmLinkItem> maybeItem; if (this->IsLinkLookupScope(n, scope->LG)) { @@ -6355,59 +6665,80 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( } std::string name = this->CheckCMP0004(n); - if (name == this->GetName() || name.empty()) { + if (name.empty() || + (lookupSelf == LookupSelf::No && name == this->GetName())) { return maybeItem; } - maybeItem = this->ResolveLinkItem(name, bt, scope->LG); + maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG); return maybeItem; } void cmGeneratorTarget::ExpandLinkItems( - std::string const& prop, std::string const& value, std::string const& config, - cmGeneratorTarget const* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, std::vector<cmLinkItem>& objects, - bool& hadHeadSensitiveCondition, bool& hadContextSensitiveCondition, - bool& hadLinkLanguageSensitiveCondition) const + std::string const& prop, cmBTStringRange entries, std::string const& config, + cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor, + LinkInterfaceField field, cmLinkInterface& iface) const { + if (entries.empty()) { + return; + } // Keep this logic in sync with ComputeLinkImplementationLibraries. - cmGeneratorExpression ge; cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr); // The $<LINK_ONLY> expression may be in a link interface to specify // private link dependencies that are otherwise excluded from usage // requirements. - if (usage_requirements_only) { + if (interfaceFor == LinkInterfaceFor::Usage) { dagChecker.SetTransitivePropertiesOnly(); } - std::vector<std::string> libs; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - cge->SetEvaluateForBuildsystem(true); - cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget, - &dagChecker, this, headTarget->LinkerLanguage), - libs); cmMakefile const* mf = this->LocalGenerator->GetMakefile(); LookupLinkItemScope scope{ this->LocalGenerator }; - for (std::string const& lib : libs) { - if (cm::optional<cmLinkItem> maybeItem = - this->LookupLinkItem(lib, cge->GetBacktrace(), &scope)) { - if (!maybeItem->Target) { - // Report explicitly linked object files separately. - std::string const& maybeObj = maybeItem->AsStr(); - if (cmSystemTools::FileIsFullPath(maybeObj)) { - cmSourceFile const* sf = - mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); - if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { - objects.emplace_back(std::move(*maybeItem)); - continue; + for (BT<std::string> const& entry : entries) { + cmGeneratorExpression ge(entry.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value); + cge->SetEvaluateForBuildsystem(true); + std::vector<std::string> libs = cmExpandedList( + cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker, + this, headTarget->LinkerLanguage)); + for (std::string const& lib : libs) { + if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( + lib, cge->GetBacktrace(), &scope, + field == LinkInterfaceField::Libraries ? LookupSelf::No + : LookupSelf::Yes)) { + cmLinkItem item = std::move(*maybeItem); + + if (field == LinkInterfaceField::HeadInclude) { + iface.HeadInclude.emplace_back(std::move(item)); + continue; + } + if (field == LinkInterfaceField::HeadExclude) { + iface.HeadExclude.emplace_back(std::move(item)); + continue; + } + if (!item.Target) { + // Report explicitly linked object files separately. + std::string const& maybeObj = item.AsStr(); + if (cmSystemTools::FileIsFullPath(maybeObj)) { + cmSourceFile const* sf = + mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); + if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { + iface.Objects.emplace_back(std::move(item)); + continue; + } } } + + iface.Libraries.emplace_back(std::move(item)); } - items.emplace_back(std::move(*maybeItem)); + } + if (cge->GetHadHeadSensitiveCondition()) { + iface.HadHeadSensitiveCondition = true; + } + if (cge->GetHadContextSensitiveCondition()) { + iface.HadContextSensitiveCondition = true; + } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + iface.HadLinkLanguageSensitiveCondition = true; } } - hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); - hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); - hadLinkLanguageSensitiveCondition = - cge->GetHadLinkLanguageSensitiveCondition(); } cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( @@ -6422,7 +6753,8 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( { // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, false, secondPass); + return this->GetImportLinkInterface(config, head, LinkInterfaceFor::Link, + secondPass); } // Link interfaces are not supported for executables that do not @@ -6435,20 +6767,20 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); - if (secondPass) { - hm.erase(head); - } - // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[head]; + if (secondPass) { + iface = cmOptionalLinkInterface(); + } if (!iface.LibrariesDone) { iface.LibrariesDone = true; - this->ComputeLinkInterfaceLibraries(config, iface, head, false); + this->ComputeLinkInterfaceLibraries(config, iface, head, + LinkInterfaceFor::Link); } if (!iface.AllDone) { iface.AllDone = true; @@ -6531,9 +6863,9 @@ void cmGeneratorTarget::ComputeLinkInterface( // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix); - if (cmProp config_reps = this->GetProperty(propName)) { + if (cmValue config_reps = this->GetProperty(propName)) { sscanf(config_reps->c_str(), "%u", &iface.Multiplicity); - } else if (cmProp reps = + } else if (cmValue reps = this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { sscanf(reps->c_str(), "%u", &iface.Multiplicity); } @@ -6542,11 +6874,11 @@ void cmGeneratorTarget::ComputeLinkInterface( const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( const std::string& config, cmGeneratorTarget const* head, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, usage_requirements_only); + return this->GetImportLinkInterface(config, head, interfaceFor); } // Link interfaces are not supported for executables that do not @@ -6558,21 +6890,20 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = - (usage_requirements_only + (interfaceFor == LinkInterfaceFor::Usage ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[head]; if (!iface.LibrariesDone) { iface.LibrariesDone = true; - this->ComputeLinkInterfaceLibraries(config, iface, head, - usage_requirements_only); + this->ComputeLinkInterfaceLibraries(config, iface, head, interfaceFor); } return iface.Exists ? &iface : nullptr; @@ -6690,14 +7021,14 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config, } // Select an output directory. - if (cmProp config_outdir = this->GetProperty(configProp)) { + if (cmValue config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config, this); // Skip per-configuration subdirectory. conf.clear(); - } else if (cmProp outdir = this->GetProperty(propertyName)) { + } else if (cmValue outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config, this); @@ -6760,14 +7091,14 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind, } // Select an output directory. - if (cmProp config_outdir = this->GetProperty(configProp)) { + if (cmValue config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory. conf.clear(); - } else if (cmProp outdir = this->GetProperty(propertyName)) { + } else if (cmValue outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config); @@ -6820,7 +7151,7 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const { - cmProp value = this->GetProperty(prop); + cmValue value = this->GetProperty(prop); if (!value) { return false; } @@ -6833,7 +7164,7 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config, void cmGeneratorTarget::ComputeLinkInterfaceLibraries( const std::string& config, cmOptionalLinkInterface& iface, - cmGeneratorTarget const* headTarget, bool usage_requirements_only) const + cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor) const { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -6845,81 +7176,102 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. - cmProp explicitLibraries = nullptr; - std::string linkIfaceProp; + bool haveExplicitLibraries = false; + cmValue explicitLibrariesCMP0022OLD; + std::string linkIfacePropCMP0022OLD; bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && this->GetPolicyStatusCMP0022() != cmPolicies::WARN); if (cmp0022NEW) { // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. - linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; - explicitLibraries = this->GetProperty(linkIfaceProp); - } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || - this->IsExecutableWithExports()) { + haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty() || + !this->Target->GetLinkInterfaceDirectEntries().empty() || + !this->Target->GetLinkInterfaceDirectExcludeEntries().empty(); + } else { // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a // shared lib or executable. - - // Lookup the per-configuration property. - linkIfaceProp = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix); - explicitLibraries = this->GetProperty(linkIfaceProp); - - // If not set, try the generic property. - if (!explicitLibraries) { - linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; - explicitLibraries = this->GetProperty(linkIfaceProp); + if (this->GetType() == cmStateEnums::SHARED_LIBRARY || + this->IsExecutableWithExports()) { + // Lookup the per-configuration property. + linkIfacePropCMP0022OLD = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix); + explicitLibrariesCMP0022OLD = this->GetProperty(linkIfacePropCMP0022OLD); + + // If not set, try the generic property. + if (!explicitLibrariesCMP0022OLD) { + linkIfacePropCMP0022OLD = "LINK_INTERFACE_LIBRARIES"; + explicitLibrariesCMP0022OLD = + this->GetProperty(linkIfacePropCMP0022OLD); + } } - } - if (explicitLibraries && - this->GetPolicyStatusCMP0022() == cmPolicies::WARN && - !this->PolicyWarnedCMP0022) { - // Compare the explicitly set old link interface properties to the - // preferred new link interface property one and warn if different. - cmProp newExplicitLibraries = - this->GetProperty("INTERFACE_LINK_LIBRARIES"); - if (newExplicitLibraries && - (*newExplicitLibraries != *explicitLibraries)) { - std::ostringstream w; - /* clang-format off */ - w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" - "Target \"" << this->GetName() << "\" has an " - "INTERFACE_LINK_LIBRARIES property which differs from its " << - linkIfaceProp << " properties." - "\n" - "INTERFACE_LINK_LIBRARIES:\n" - " " << *newExplicitLibraries << "\n" << - linkIfaceProp << ":\n" - " " << *explicitLibraries << "\n"; - /* clang-format on */ - this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); - this->PolicyWarnedCMP0022 = true; + if (explicitLibrariesCMP0022OLD && + this->GetPolicyStatusCMP0022() == cmPolicies::WARN && + !this->PolicyWarnedCMP0022) { + // Compare the explicitly set old link interface properties to the + // preferred new link interface property one and warn if different. + cmValue newExplicitLibraries = + this->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (newExplicitLibraries && + (*newExplicitLibraries != *explicitLibrariesCMP0022OLD)) { + std::ostringstream w; + /* clang-format off */ + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property which differs from its " << + linkIfacePropCMP0022OLD << " properties." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << *newExplicitLibraries << "\n" << + linkIfacePropCMP0022OLD << ":\n" + " " << *explicitLibrariesCMP0022OLD << "\n"; + /* clang-format on */ + this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, + w.str()); + this->PolicyWarnedCMP0022 = true; + } } + + haveExplicitLibraries = static_cast<bool>(explicitLibrariesCMP0022OLD); } // There is no implicit link interface for executables or modules // so if none was explicitly set then there is no link interface. - if (!explicitLibraries && + if (!haveExplicitLibraries && (this->GetType() == cmStateEnums::EXECUTABLE || (this->GetType() == cmStateEnums::MODULE_LIBRARY))) { return; } iface.Exists = true; - iface.Explicit = cmp0022NEW || explicitLibraries; - - if (explicitLibraries) { - // The interface libraries have been explicitly set. - this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config, - headTarget, usage_requirements_only, iface.Libraries, - iface.Objects, iface.HadHeadSensitiveCondition, - iface.HadContextSensitiveCondition, - iface.HadLinkLanguageSensitiveCondition); - return; - } // If CMP0022 is NEW then the plain tll signature sets the - // INTERFACE_LINK_LIBRARIES, so if we get here then the project - // cleared the property explicitly and we should not fall back - // to the link implementation. + // INTERFACE_LINK_LIBRARIES property. Even if the project + // clears it, the link interface is still explicit. + iface.Explicit = cmp0022NEW || explicitLibrariesCMP0022OLD; + if (cmp0022NEW) { + // The interface libraries are specified by INTERFACE_LINK_LIBRARIES. + // Use its special representation directly to get backtraces. + this->ExpandLinkItems( + kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(), + config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, + this->Target->GetLinkInterfaceDirectEntries(), + config, headTarget, interfaceFor, + LinkInterfaceField::HeadInclude, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, + this->Target->GetLinkInterfaceDirectExcludeEntries(), + config, headTarget, interfaceFor, + LinkInterfaceField::HeadExclude, iface); + } else if (explicitLibrariesCMP0022OLD) { + // The interface libraries have been explicitly set in pre-CMP0022 style. + std::vector<BT<std::string>> entries; + entries.emplace_back(*explicitLibrariesCMP0022OLD); + this->ExpandLinkItems(linkIfacePropCMP0022OLD, cmMakeRange(entries), + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); + } + + // If the link interface is explicit, do not fall back to the link impl. + if (iface.Explicit) { return; } @@ -6929,25 +7281,17 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(), impl->Libraries.end()); if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN && - !this->PolicyWarnedCMP0022 && !usage_requirements_only) { + !this->PolicyWarnedCMP0022 && interfaceFor == LinkInterfaceFor::Link) { // Compare the link implementation fallback link interface to the // preferred new link interface property and warn if different. - std::vector<cmLinkItem> ifaceLibs; - std::vector<cmLinkItem> ifaceObjects; - static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; - if (cmProp newExplicitLibraries = this->GetProperty(newProp)) { - bool hadHeadSensitiveConditionDummy = false; - bool hadContextSensitiveConditionDummy = false; - bool hadLinkLanguageSensitiveConditionDummy = false; - this->ExpandLinkItems(newProp, *newExplicitLibraries, config, - headTarget, usage_requirements_only, ifaceLibs, - ifaceObjects, hadHeadSensitiveConditionDummy, - hadContextSensitiveConditionDummy, - hadLinkLanguageSensitiveConditionDummy); - } - if (ifaceLibs != iface.Libraries) { + cmLinkInterface ifaceNew; + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES, + this->Target->GetLinkInterfaceEntries(), config, + headTarget, interfaceFor, + LinkInterfaceField::Libraries, ifaceNew); + if (ifaceNew.Libraries != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); - std::string newLibraries = cmJoin(ifaceLibs, ";"); + std::string newLibraries = cmJoin(ifaceNew.Libraries, ";"); if (oldLibraries.empty()) { oldLibraries = "(empty)"; } @@ -7009,7 +7353,7 @@ std::vector<ValueType> computeImplicitLanguageTargets( std::string const& runtimeLibrary = currentTarget->GetRuntimeLinkLibrary(lang, config); - if (cmProp runtimeLinkOptions = currentTarget->Makefile->GetDefinition( + if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition( "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) { std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions); result.reserve(libsVec.size()); @@ -7057,7 +7401,7 @@ void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries( const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, - bool usage_requirements_only, bool secondPass) const + LinkInterfaceFor interfaceFor, bool secondPass) const { cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); if (!info) { @@ -7065,35 +7409,41 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( } cmHeadToLinkInterfaceMap& hm = - (usage_requirements_only + (interfaceFor == LinkInterfaceFor::Usage ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); - if (secondPass) { - hm.erase(headTarget); - } - // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + headTarget = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[headTarget]; + if (secondPass) { + iface = cmOptionalLinkInterface(); + } if (!iface.AllDone) { iface.AllDone = true; + iface.LibrariesDone = true; iface.Multiplicity = info->Multiplicity; cmExpandList(info->Languages, iface.Languages); - this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, - headTarget, usage_requirements_only, iface.Libraries, - iface.Objects, iface.HadHeadSensitiveCondition, - iface.HadContextSensitiveCondition, - iface.HadLinkLanguageSensitiveCondition); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, + cmMakeRange(info->LibrariesHeadInclude), config, + headTarget, interfaceFor, + LinkInterfaceField::HeadInclude, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, + cmMakeRange(info->LibrariesHeadExclude), config, + headTarget, interfaceFor, + LinkInterfaceField::HeadExclude, iface); + this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries), + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); LookupLinkItemScope scope{ this->LocalGenerator }; for (std::string const& dep : deps) { - if (cm::optional<cmLinkItem> maybeItem = - this->LookupLinkItem(dep, cmListFileBacktrace(), &scope)) { + if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( + dep, cmListFileBacktrace(), &scope, LookupSelf::No)) { iface.SharedDeps.emplace_back(std::move(*maybeItem)); } } @@ -7150,8 +7500,8 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Initialize members. info.NoSOName = false; - cmProp loc = nullptr; - cmProp imp = nullptr; + cmValue loc = nullptr; + cmValue imp = nullptr; std::string suffix; if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) { return; @@ -7159,24 +7509,35 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the link interface. { - std::string linkProp = "INTERFACE_LINK_LIBRARIES"; - cmProp propertyLibs = this->GetProperty(linkProp); - - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - if (!propertyLibs) { - linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix); - propertyLibs = this->GetProperty(linkProp); + // Use the INTERFACE_LINK_LIBRARIES special representation directly + // to get backtraces. + cmBTStringRange entries = this->Target->GetLinkInterfaceEntries(); + if (!entries.empty()) { + info.LibrariesProp = "INTERFACE_LINK_LIBRARIES"; + for (BT<std::string> const& entry : entries) { + info.Libraries.emplace_back(entry); } - + } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + std::string linkProp = + cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix); + cmValue propertyLibs = this->GetProperty(linkProp); if (!propertyLibs) { linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; propertyLibs = this->GetProperty(linkProp); } + if (propertyLibs) { + info.LibrariesProp = linkProp; + info.Libraries.emplace_back(*propertyLibs); + } } - if (propertyLibs) { - info.LibrariesProp = linkProp; - info.Libraries = *propertyLibs; - } + } + for (BT<std::string> const& entry : + this->Target->GetLinkInterfaceDirectEntries()) { + info.LibrariesHeadInclude.emplace_back(entry); + } + for (BT<std::string> const& entry : + this->Target->GetLinkInterfaceDirectExcludeEntries()) { + info.LibrariesHeadExclude.emplace_back(entry); } if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { if (loc) { @@ -7193,9 +7554,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, info.Location = *loc; } else { std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix); - if (cmProp config_location = this->GetProperty(impProp)) { + if (cmValue config_location = this->GetProperty(impProp)) { info.Location = *config_location; - } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) { + } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) { info.Location = *location; } } @@ -7203,9 +7564,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the soname. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_SONAME", suffix); - if (cmProp config_soname = this->GetProperty(soProp)) { + if (cmValue config_soname = this->GetProperty(soProp)) { info.SOName = *config_soname; - } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) { + } else if (cmValue soname = this->GetProperty("IMPORTED_SONAME")) { info.SOName = *soname; } } @@ -7213,9 +7574,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the "no-soname" mark. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix); - if (cmProp config_no_soname = this->GetProperty(soProp)) { + if (cmValue config_no_soname = this->GetProperty(soProp)) { info.NoSOName = cmIsOn(*config_no_soname); - } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) { + } else if (cmValue no_soname = this->GetProperty("IMPORTED_NO_SONAME")) { info.NoSOName = cmIsOn(*no_soname); } } @@ -7226,9 +7587,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports()) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - if (cmProp config_implib = this->GetProperty(impProp)) { + if (cmValue config_implib = this->GetProperty(impProp)) { info.ImportLibrary = *config_implib; - } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) { + } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) { info.ImportLibrary = *implib; } } @@ -7237,9 +7598,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, { std::string linkProp = cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix); - if (cmProp config_libs = this->GetProperty(linkProp)) { + if (cmValue config_libs = this->GetProperty(linkProp)) { info.SharedDeps = *config_libs; - } else if (cmProp libs = + } else if (cmValue libs = this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) { info.SharedDeps = *libs; } @@ -7249,9 +7610,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->LinkLanguagePropagatesToDependents()) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix); - if (cmProp config_libs = this->GetProperty(linkProp)) { + if (cmValue config_libs = this->GetProperty(linkProp)) { info.Languages = *config_libs; - } else if (cmProp libs = + } else if (cmValue libs = this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) { info.Languages = *libs; } @@ -7260,9 +7621,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get information if target is managed assembly. { std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME"; - if (cmProp pc = this->GetProperty(linkProp + suffix)) { + if (cmValue pc = this->GetProperty(linkProp + suffix)) { info.Managed = this->CheckManagedType(*pc); - } else if (cmProp p = this->GetProperty(linkProp)) { + } else if (cmValue p = this->GetProperty(linkProp)) { info.Managed = this->CheckManagedType(*p); } } @@ -7271,9 +7632,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->GetType() == cmStateEnums::STATIC_LIBRARY) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); - if (cmProp config_reps = this->GetProperty(linkProp)) { + if (cmValue config_reps = this->GetProperty(linkProp)) { sscanf(config_reps->c_str(), "%u", &info.Multiplicity); - } else if (cmProp reps = + } else if (cmValue reps = this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) { sscanf(reps->c_str(), "%u", &info.Multiplicity); } @@ -7381,9 +7742,9 @@ void cmGeneratorTarget::GetObjectLibrariesCMP0026( // there is no cmGeneratorTarget at configure-time, so search the SOURCES // for TARGET_OBJECTS instead for backwards compatibility with OLD // behavior of CMP0024 and CMP0026 only. - cmStringRange rng = this->Target->GetSourceEntries(); - for (std::string const& entry : rng) { - std::vector<std::string> files = cmExpandedList(entry); + cmBTStringRange rng = this->Target->GetSourceEntries(); + for (auto const& entry : rng) { + std::vector<std::string> files = cmExpandedList(entry.Value); for (std::string const& li : files) { if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') { std::string objLibName = li.substr(17, li.size() - 18); @@ -7426,6 +7787,7 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace()); } + CM_FALLTHROUGH; case cmPolicies::OLD: break; case cmPolicies::NEW: { @@ -7452,14 +7814,14 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const bool cmGeneratorTarget::IsDeprecated() const { - cmProp deprecation = this->GetProperty("DEPRECATION"); + cmValue deprecation = this->GetProperty("DEPRECATION"); return cmNonempty(deprecation); } std::string cmGeneratorTarget::GetDeprecation() const { // find DEPRECATION property - if (cmProp deprecation = this->GetProperty("DEPRECATION")) { + if (cmValue deprecation = this->GetProperty("DEPRECATION")) { return *deprecation; } return std::string(); @@ -7530,13 +7892,18 @@ bool cmGeneratorTarget::IsCSharpOnly() const std::set<std::string> languages = this->GetAllConfigCompileLanguages(); // Consider an explicit linker language property, but *not* the // computed linker language that may depend on linked targets. - cmProp linkLang = this->GetProperty("LINKER_LANGUAGE"); + cmValue linkLang = this->GetProperty("LINKER_LANGUAGE"); if (cmNonempty(linkLang)) { languages.insert(*linkLang); } return languages.size() == 1 && languages.count("CSharp") > 0; } +bool cmGeneratorTarget::IsDotNetSdkTarget() const +{ + return !this->GetProperty("DOTNET_SDK").IsEmpty(); +} + void cmGeneratorTarget::ComputeLinkImplementationLanguages( const std::string& config, cmOptionalLinkImplementation& impl) const { @@ -7586,9 +7953,9 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( this->LinkImplMap[cmSystemTools::UpperCase(config)]; // If the link implementation does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkImplementation& impl = hm[head]; @@ -7605,29 +7972,133 @@ bool cmGeneratorTarget::IsNullImpliedByLinkLibraries( return cm::contains(this->LinkImplicitNullProperties, p); } +namespace { +class TransitiveLinkImpl +{ + cmGeneratorTarget const* Self; + std::string const& Config; + cmLinkImplementation& Impl; + + std::set<cmLinkItem> Emitted; + std::set<cmLinkItem> Excluded; + std::unordered_set<cmGeneratorTarget const*> Followed; + + void Follow(cmGeneratorTarget const* target); + +public: + TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config, + cmLinkImplementation& impl) + : Self(self) + , Config(config) + , Impl(impl) + { + } + + void Compute(); +}; + +void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target) +{ + if (!target || !this->Followed.insert(target).second || + target->GetPolicyStatusCMP0022() == cmPolicies::OLD || + target->GetPolicyStatusCMP0022() == cmPolicies::WARN) { + return; + } + + // Get this target's usage requirements. + cmLinkInterfaceLibraries const* iface = target->GetLinkInterfaceLibraries( + this->Config, this->Self, LinkInterfaceFor::Usage); + if (!iface) { + return; + } + if (iface->HadContextSensitiveCondition) { + this->Impl.HadContextSensitiveCondition = true; + } + + // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements. + for (cmLinkItem const& item : iface->HeadInclude) { + // Inject direct dependencies from the item's usage requirements + // before the item itself. + this->Follow(item.Target); + + // Add the item itself, but at most once. + if (this->Emitted.insert(item).second) { + this->Impl.Libraries.emplace_back(item, /* checkCMP0027= */ false); + } + } + + // Follow transitive dependencies. + for (cmLinkItem const& item : iface->Libraries) { + this->Follow(item.Target); + } + + // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' + // usage requirements. + for (cmLinkItem const& item : iface->HeadExclude) { + this->Excluded.insert(item); + } +} + +void TransitiveLinkImpl::Compute() +{ + // Save the original items and start with an empty list. + std::vector<cmLinkImplItem> original = std::move(this->Impl.Libraries); + + // Avoid injecting any original items as usage requirements. + // This gives LINK_LIBRARIES final control over the order + // if it explicitly lists everything. + this->Emitted.insert(original.cbegin(), original.cend()); + + // Process each original item. + for (cmLinkImplItem& item : original) { + // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT' + // usage requirements before the item itself. + this->Follow(item.Target); + + // Add the item itself. + this->Impl.Libraries.emplace_back(std::move(item)); + } + + // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' + // usage requirements found through any dependency above. + this->Impl.Libraries.erase( + std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(), + [this](cmLinkImplItem const& item) { + return this->Excluded.find(item) != this->Excluded.end(); + }), + this->Impl.Libraries.end()); +} + +void ComputeLinkImplTransitive(cmGeneratorTarget const* self, + std::string const& config, + cmLinkImplementation& impl) +{ + TransitiveLinkImpl transitiveLinkImpl(self, config, impl); + transitiveLinkImpl.Compute(); +} +} + void cmGeneratorTarget::ComputeLinkImplementationLibraries( const std::string& config, cmOptionalLinkImplementation& impl, cmGeneratorTarget const* head) const { cmLocalGenerator const* lg = this->LocalGenerator; cmMakefile const* mf = lg->GetMakefile(); - cmStringRange entryRange = this->Target->GetLinkImplementationEntries(); - cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces(); - cmBacktraceRange::const_iterator btIt = btRange.begin(); + cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries(); // Collect libraries directly linked in this configuration. - for (cmStringRange::const_iterator le = entryRange.begin(), - end = entryRange.end(); - le != end; ++le, ++btIt) { + for (auto const& entry : entryRange) { std::vector<std::string> llibs; // Keep this logic in sync with ExpandLinkItems. cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, nullptr); - cmGeneratorExpression ge(*btIt); - std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le); + cmGeneratorExpression ge(entry.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> const cge = + ge.Parse(entry.Value); cge->SetEvaluateForBuildsystem(true); std::string const& evaluated = cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, this->LinkerLanguage); + bool const checkCMP0027 = evaluated != entry.Value; cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; @@ -7665,6 +8136,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } break; case cmPolicies::OLD: noMessage = true; + break; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::NEW: @@ -7685,7 +8157,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } // The entry is meant for this configuration. - cmLinkItem item = this->ResolveLinkItem(name, *btIt, lg); + cmLinkItem item = + this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg); if (!item.Target) { // Report explicitly linked object files separately. std::string const& maybeObj = item.AsStr(); @@ -7699,7 +8172,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } } - impl.Libraries.emplace_back(std::move(item), evaluated != *le); + impl.Libraries.emplace_back(std::move(item), checkCMP0027); } std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); @@ -7711,6 +8184,11 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); } + // Update the list of direct link dependencies from usage requirements. + if (head == this) { + ComputeLinkImplTransitive(this, config, impl); + } + // Get the list of configurations considered to be DEBUG. std::vector<std::string> debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); @@ -7727,7 +8205,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } // Support OLD behavior for CMP0003. impl.WrongConfigLibraries.push_back( - this->ResolveLinkItem(name, cmListFileBacktrace())); + this->ResolveLinkItem(BT<std::string>(name))); } } } @@ -7753,16 +8231,16 @@ cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( } cmLinkItem cmGeneratorTarget::ResolveLinkItem( - std::string const& name, cmListFileBacktrace const& bt) const + BT<std::string> const& name) const { - return this->ResolveLinkItem(name, bt, this->LocalGenerator); + return this->ResolveLinkItem(name, this->LocalGenerator); } -cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name, - cmListFileBacktrace const& bt, +cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name, cmLocalGenerator const* lg) const { - TargetOrString resolved = this->ResolveTargetReference(name, lg); + auto bt = name.Backtrace; + TargetOrString resolved = this->ResolveTargetReference(name.Value, lg); if (!resolved.Target) { return cmLinkItem(resolved.String, false, bt); @@ -7792,6 +8270,26 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name, return cmLinkItem(resolved.Target, false, bt); } +bool cmGeneratorTarget::HasPackageReferences() const +{ + return this->IsInBuildSystem() && + !this->GetProperty("VS_PACKAGE_REFERENCES")->empty(); +} + +std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const +{ + std::vector<std::string> packageReferences; + + if (this->IsInBuildSystem()) { + if (cmValue vsPackageReferences = + this->GetProperty("VS_PACKAGE_REFERENCES")) { + cmExpandList(*vsPackageReferences, packageReferences); + } + } + + return packageReferences; +} + std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const { if (OutputInfo const* info = this->GetOutputInfo(config)) { @@ -7940,7 +8438,7 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( } // Check for explicitly set clr target property. - if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { + if (cmValue clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { return this->CheckManagedType(*clr); } |
