diff options
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
| -rw-r--r-- | Source/cmGeneratorTarget.cxx | 569 |
1 files changed, 499 insertions, 70 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index fec4679..6235a2a 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -16,6 +16,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -58,6 +59,10 @@ 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 <> @@ -331,20 +336,6 @@ EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries( cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) : Target(t) - , FortranModuleDirectoryCreated(false) - , SourceFileFlagsConstructed(false) - , PolicyWarnedCMP0022(false) - , PolicyReportedCMP0069(false) - , DebugIncludesDone(false) - , DebugCompileOptionsDone(false) - , DebugCompileFeaturesDone(false) - , DebugCompileDefinitionsDone(false) - , DebugLinkOptionsDone(false) - , DebugLinkDirectoriesDone(false) - , DebugPrecompileHeadersDone(false) - , DebugSourcesDone(false) - , UtilityItemsDone(false) - , SourcesAreContextDependent(Tribool::Indeterminate) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = lg; @@ -443,7 +434,7 @@ cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) { return result; } - if (cmSystemTools::GetFatalErrorOccured()) { + if (cmSystemTools::GetFatalErrorOccurred()) { return nullptr; } return this->Target->GetProperty(prop); @@ -748,6 +739,7 @@ void cmGeneratorTarget::ClearSourcesCache() this->Objects.clear(); this->VisitedConfigsForObjects.clear(); this->LinkImplMap.clear(); + this->LinkImplUsageRequirementsOnlyMap.clear(); } void cmGeneratorTarget::ClearLinkInterfaceCache() @@ -1300,7 +1292,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( &dagChecker, result, excludeImported, language); } - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, LinkInterfaceFor::Usage); if (impl != nullptr) { auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language); if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) { @@ -1517,7 +1510,8 @@ void AddLangSpecificImplicitIncludeDirectories( const std::string& config, const std::string& propertyName, IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries) { - if (const auto* libraries = target->GetLinkImplementationLibraries(config)) { + if (const auto* libraries = target->GetLinkImplementationLibraries( + config, LinkInterfaceFor::Usage)) { cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, propertyName, nullptr, nullptr }; @@ -1607,7 +1601,7 @@ void AddInterfaceEntries( { if (searchRuntime == IncludeRuntimeInterface::Yes) { if (cmLinkImplementation const* impl = - headTarget->GetLinkImplementation(config)) { + headTarget->GetLinkImplementation(config, interfaceFor)) { entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; @@ -1621,7 +1615,7 @@ void AddInterfaceEntries( } } else { if (cmLinkImplementationLibraries const* impl = - headTarget->GetLinkImplementationLibraries(config)) { + headTarget->GetLinkImplementationLibraries(config, interfaceFor)) { entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, @@ -1636,7 +1630,8 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, EvaluatedTargetPropertyEntries& entries) { if (cmLinkImplementationLibraries const* impl = - headTarget->GetLinkImplementationLibraries(config)) { + headTarget->GetLinkImplementationLibraries(config, + LinkInterfaceFor::Usage)) { entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target && @@ -1707,7 +1702,7 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget, } bool found = false; for (auto const& sg : headTarget->Makefile->GetSourceGroups()) { - if (sg.MatchesFiles(path)) { + if (sg.MatchChildrenFiles(path)) { found = true; break; } @@ -2045,7 +2040,11 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } else if (ext == "appxmanifest") { kind = SourceKindAppManifest; } else if (ext == "manifest") { - kind = SourceKindManifest; + if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) { + kind = SourceKindExtra; + } else { + kind = SourceKindManifest; + } } else if (ext == "pfx") { kind = SourceKindCertificate; } else if (ext == "xaml") { @@ -2763,15 +2762,14 @@ cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( class cmTargetSelectLinker { - int Preference; + int Preference = 0; cmGeneratorTarget const* Target; cmGlobalGenerator* GG; std::set<std::string> Preferred; public: cmTargetSelectLinker(cmGeneratorTarget const* target) - : Preference(0) - , Target(target) + : Target(target) { this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator(); } @@ -2815,7 +2813,7 @@ bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config, // Get languages built in this target. std::unordered_set<std::string> languages; cmLinkImplementation const* impl = - this->GetLinkImplementation(config, secondPass); + this->GetLinkImplementation(config, LinkInterfaceFor::Link, secondPass); assert(impl); languages.insert(impl->Languages.cbegin(), impl->Languages.cend()); @@ -3083,7 +3081,7 @@ cmGeneratorTarget::GetLinkImplementationClosure( std::set<cmGeneratorTarget const*> emitted; cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibraries(config); + this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Usage); assert(impl); for (cmLinkImplItem const& lib : impl->Libraries) { @@ -3461,6 +3459,23 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const property = *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR"); } + } else if (property == "native") { + cmValue native = + this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_NATIVE"); + if (native.IsEmpty()) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "CUDA_ARCHITECTURES is set to \"native\", but no GPU was detected."); + } + if (compiler == "NVIDIA" && + cmSystemTools::VersionCompare( + cmSystemTools::OP_GREATER_EQUAL, + this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"), + "11.6")) { + flags = cmStrCat(flags, " -arch=", property); + return; + } + property = *native; } struct CudaArchitecture @@ -3808,7 +3823,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( if (this->Makefile->IsOn("APPLE")) { if (cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibraries(config)) { + this->GetLinkImplementationLibraries(config, + LinkInterfaceFor::Usage)) { for (cmLinkImplItem const& lib : impl->Libraries) { std::string libDir = cmSystemTools::CollapseFullPath( lib.AsStr(), this->Makefile->GetHomeOutputDirectory()); @@ -4621,7 +4637,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( } std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( - std::vector<BT<std::string>>& result, const std::string& language) const + std::vector<BT<std::string>>& result, const std::string& language, + bool joinItems) const { // replace "LINKER:" prefixed elements by actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( @@ -4680,7 +4697,14 @@ std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( std::vector<BT<std::string>> options = wrapOptions( linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs); - result.insert(entry, options.begin(), options.end()); + if (joinItems) { + result.insert(entry, + cmJoin(cmRange<decltype(options.cbegin())>( + options.cbegin(), options.cend()), + " "_s)); + } else { + result.insert(entry, options.begin(), options.end()); + } } return result; } @@ -5675,7 +5699,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, if (emitted.insert(p).second) { getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t, nullptr); - if (cmSystemTools::GetErrorOccuredFlag()) { + if (cmSystemTools::GetErrorOccurredFlag()) { return; } } @@ -5754,25 +5778,25 @@ void cmGeneratorTarget::CheckPropertyCompatibility( checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools, config, BoolType, nullptr); - if (cmSystemTools::GetErrorOccuredFlag()) { + if (cmSystemTools::GetErrorOccurredFlag()) { return; } checkPropertyConsistency<const char*>(this, dep.Target, strString, emittedStrings, config, StringType, nullptr); - if (cmSystemTools::GetErrorOccuredFlag()) { + if (cmSystemTools::GetErrorOccurredFlag()) { return; } checkPropertyConsistency<const char*>(this, dep.Target, strNumMin, emittedMinNumbers, config, NumberMinType, nullptr); - if (cmSystemTools::GetErrorOccuredFlag()) { + if (cmSystemTools::GetErrorOccurredFlag()) { return; } checkPropertyConsistency<const char*>(this, dep.Target, strNumMax, emittedMaxNumbers, config, NumberMaxType, nullptr); - if (cmSystemTools::GetErrorOccuredFlag()) { + if (cmSystemTools::GetErrorOccurredFlag()) { return; } } @@ -6327,7 +6351,8 @@ cm::string_view missingTargetPossibleReasons = bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role, cmLinkItem const& item) const { - if (item.Target || item.AsStr().find("::") == std::string::npos) { + if (item.Target || cmHasPrefix(item.AsStr(), "<LINK_GROUP:"_s) || + item.AsStr().find("::") == std::string::npos) { return true; } MessageType messageType = MessageType::FATAL_ERROR; @@ -6373,7 +6398,9 @@ bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, std::string const& str = item.AsStr(); if (!str.empty() && (str[0] == '-' || str[0] == '$' || str[0] == '`' || - str.find_first_of("/\\") != std::string::npos)) { + str.find_first_of("/\\") != std::string::npos || + cmHasPrefix(str, "<LINK_LIBRARY:"_s) || + cmHasPrefix(str, "<LINK_GROUP:"_s))) { return true; } @@ -6669,12 +6696,10 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( return maybeItem; } -void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, - cmBTStringRange entries, - std::string const& config, - cmGeneratorTarget const* headTarget, - LinkInterfaceFor interfaceFor, - cmLinkInterface& iface) const +void cmGeneratorTarget::ExpandLinkItems( + std::string const& prop, cmBTStringRange entries, std::string const& config, + cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor, + LinkInterfaceField field, cmLinkInterface& iface) const { if (entries.empty()) { return; @@ -6698,9 +6723,19 @@ void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, this, headTarget->LinkerLanguage)); for (std::string const& lib : libs) { if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( - lib, cge->GetBacktrace(), &scope, LookupSelf::No)) { + 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(); @@ -6803,8 +6838,8 @@ void cmGeneratorTarget::ComputeLinkInterface( emitted.insert(lib); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - cmLinkImplementation const* impl = - this->GetLinkImplementation(config, secondPass); + cmLinkImplementation const* impl = this->GetLinkImplementation( + config, LinkInterfaceFor::Link, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { if (emitted.insert(lib).second) { if (lib.Target) { @@ -6826,15 +6861,16 @@ void cmGeneratorTarget::ComputeLinkInterface( this->GetPolicyStatusCMP0022() == cmPolicies::OLD) { // The link implementation is the default link interface. cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibrariesInternal(config, headTarget); + this->GetLinkImplementationLibrariesInternal(config, headTarget, + LinkInterfaceFor::Link); iface.ImplementationIsInterface = true; iface.WrongConfigLibraries = impl->WrongConfigLibraries; } if (this->LinkLanguagePropagatesToDependents()) { // Targets using this archive need its language runtime libraries. - if (cmLinkImplementation const* impl = - this->GetLinkImplementation(config, secondPass)) { + if (cmLinkImplementation const* impl = this->GetLinkImplementation( + config, LinkInterfaceFor::Link, secondPass)) { iface.Languages = impl->Languages; } } @@ -7171,7 +7207,9 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( this->GetPolicyStatusCMP0022() != cmPolicies::WARN); if (cmp0022NEW) { // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. - haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty(); + 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. @@ -7236,15 +7274,24 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( 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, iface); + 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, iface); + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); } // If the link interface is explicit, do not fall back to the link impl. @@ -7254,7 +7301,8 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // The link implementation is the default link interface. if (cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibrariesInternal(config, headTarget)) { + this->GetLinkImplementationLibrariesInternal(config, headTarget, + interfaceFor)) { iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(), impl->Libraries.end()); if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN && @@ -7264,7 +7312,8 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( cmLinkInterface ifaceNew; this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(), config, - headTarget, interfaceFor, ifaceNew); + headTarget, interfaceFor, + LinkInterfaceField::Libraries, ifaceNew); if (ifaceNew.Libraries != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); std::string newLibraries = cmJoin(ifaceNew.Libraries, ";"); @@ -7404,8 +7453,17 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( iface.LibrariesDone = true; iface.Multiplicity = info->Multiplicity; cmExpandList(info->Languages, iface.Languages); + 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, iface); + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); LookupLinkItemScope scope{ this->LocalGenerator }; for (std::string const& dep : deps) { @@ -7498,6 +7556,14 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, } } } + 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) { info.LibName = *loc; @@ -7615,27 +7681,30 @@ cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( } const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( - const std::string& config) const + const std::string& config, LinkInterfaceFor implFor) const { - return this->GetLinkImplementation(config, false); + return this->GetLinkImplementation(config, implFor, false); } const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( - const std::string& config, bool secondPass) const + const std::string& config, LinkInterfaceFor implFor, bool secondPass) const { // There is no link implementation for targets that cannot compile sources. if (!this->CanCompileSources()) { return nullptr; } - cmOptionalLinkImplementation& impl = - this->LinkImplMap[cmSystemTools::UpperCase(config)][this]; + HeadToLinkImplementationMap& hm = + (implFor == LinkInterfaceFor::Usage + ? this->GetHeadToLinkImplementationUsageRequirementsMap(config) + : this->GetHeadToLinkImplementationMap(config)); + cmOptionalLinkImplementation& impl = hm[this]; if (secondPass) { impl = cmOptionalLinkImplementation(); } if (!impl.LibrariesDone) { impl.LibrariesDone = true; - this->ComputeLinkImplementationLibraries(config, impl, this); + this->ComputeLinkImplementationLibraries(config, impl, this, implFor); } if (!impl.LanguagesDone) { impl.LanguagesDone = true; @@ -7645,6 +7714,21 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( return &impl; } +cmGeneratorTarget::HeadToLinkImplementationMap& +cmGeneratorTarget::GetHeadToLinkImplementationMap( + std::string const& config) const +{ + return this->LinkImplMap[cmSystemTools::UpperCase(config)]; +} + +cmGeneratorTarget::HeadToLinkImplementationMap& +cmGeneratorTarget::GetHeadToLinkImplementationUsageRequirementsMap( + std::string const& config) const +{ + return this + ->LinkImplUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)]; +} + bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode( std::vector<cmSourceFile*>& files) const { @@ -7885,7 +7969,7 @@ bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const return true; } if (cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibraries(config)) { + this->GetLinkImplementationLibraries(config, LinkInterfaceFor::Link)) { return !impl->Libraries.empty(); } return false; @@ -7893,14 +7977,15 @@ bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const cmLinkImplementationLibraries const* cmGeneratorTarget::GetLinkImplementationLibraries( - const std::string& config) const + const std::string& config, LinkInterfaceFor implFor) const { - return this->GetLinkImplementationLibrariesInternal(config, this); + return this->GetLinkImplementationLibrariesInternal(config, this, implFor); } cmLinkImplementationLibraries const* cmGeneratorTarget::GetLinkImplementationLibrariesInternal( - const std::string& config, cmGeneratorTarget const* head) const + const std::string& config, cmGeneratorTarget const* head, + LinkInterfaceFor implFor) const { // There is no link implementation for targets that cannot compile sources. if (!this->CanCompileSources()) { @@ -7909,7 +7994,9 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( // Populate the link implementation libraries for this configuration. HeadToLinkImplementationMap& hm = - this->LinkImplMap[cmSystemTools::UpperCase(config)]; + (implFor == LinkInterfaceFor::Usage + ? this->GetHeadToLinkImplementationUsageRequirementsMap(config) + : this->GetHeadToLinkImplementationMap(config)); // If the link implementation does not depend on the head target // then re-use the one from the head we computed first. @@ -7920,7 +8007,7 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( cmOptionalLinkImplementation& impl = hm[head]; if (!impl.LibrariesDone) { impl.LibrariesDone = true; - this->ComputeLinkImplementationLibraries(config, impl, head); + this->ComputeLinkImplementationLibraries(config, impl, head, implFor); } return &impl; } @@ -7931,9 +8018,118 @@ bool cmGeneratorTarget::IsNullImpliedByLinkLibraries( return cm::contains(this->LinkImplicitNullProperties, p); } +namespace { +class TransitiveLinkImpl +{ + cmGeneratorTarget const* Self; + std::string const& Config; + LinkInterfaceFor ImplFor; + 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, + LinkInterfaceFor implFor, cmLinkImplementation& impl) + : Self(self) + , Config(config) + , ImplFor(implFor) + , 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, this->ImplFor); + 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, + LinkInterfaceFor implFor, + cmLinkImplementation& impl) +{ + TransitiveLinkImpl transitiveLinkImpl(self, config, implFor, impl); + transitiveLinkImpl.Compute(); +} +} + void cmGeneratorTarget::ComputeLinkImplementationLibraries( const std::string& config, cmOptionalLinkImplementation& impl, - cmGeneratorTarget const* head) const + cmGeneratorTarget const* head, LinkInterfaceFor implFor) const { cmLocalGenerator const* lg = this->LocalGenerator; cmMakefile const* mf = lg->GetMakefile(); @@ -7944,6 +8140,20 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( // Keep this logic in sync with ExpandLinkItems. cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, nullptr); + // The $<LINK_ONLY> expression may be used to specify link dependencies + // that are otherwise excluded from usage requirements. + if (implFor == LinkInterfaceFor::Usage) { + switch (this->GetPolicyStatusCMP0131()) { + case cmPolicies::WARN: + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + dagChecker.SetTransitivePropertiesOnly(); + break; + } + } cmGeneratorExpression ge(entry.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(entry.Value); @@ -8037,6 +8247,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, implFor, impl); + } + // Get the list of configurations considered to be DEBUG. std::vector<std::string> debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); @@ -8295,3 +8510,217 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( // has to be set manually for C# targets. return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native; } + +bool cmGeneratorTarget::AddHeaderSetVerification() +{ + if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) { + return true; + } + + if (this->GetType() != cmStateEnums::STATIC_LIBRARY && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::UNKNOWN_LIBRARY && + this->GetType() != cmStateEnums::OBJECT_LIBRARY && + this->GetType() != cmStateEnums::INTERFACE_LIBRARY && + !this->IsExecutableWithExports()) { + return true; + } + + auto verifyValue = this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY"); + const bool all = verifyValue.IsEmpty(); + std::set<std::string> verifySet; + if (!all) { + auto verifyList = cmExpandedList(verifyValue); + verifySet.insert(verifyList.begin(), verifyList.end()); + } + + cmTarget* verifyTarget = nullptr; + cmTarget* allVerifyTarget = + this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse( + "all_verify_interface_header_sets", true); + + auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries(); + + std::set<cmFileSet*> fileSets; + for (auto const& entry : interfaceFileSetEntries) { + for (auto const& name : cmExpandedList(entry.Value)) { + if (all || verifySet.count(name)) { + fileSets.insert(this->Target->GetFileSet(name)); + verifySet.erase(name); + } + } + } + if (!verifySet.empty()) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"", + this->GetName(), + "\" contained the following header sets that are nonexistent " + "or not INTERFACE:\n ", + cmJoin(verifySet, "\n "))); + return false; + } + + cm::optional<std::set<std::string>> languages; + for (auto* fileSet : fileSets) { + auto dirCges = fileSet->CompileDirectoryEntries(); + auto fileCges = fileSet->CompileFileEntries(); + + static auto const contextSensitive = + [](const std::unique_ptr<cmCompiledGeneratorExpression>& cge) { + return cge->GetHadContextSensitiveCondition(); + }; + bool dirCgesContextSensitive = false; + bool fileCgesContextSensitive = false; + + std::vector<std::string> dirs; + std::map<std::string, std::vector<std::string>> filesPerDir; + bool first = true; + for (auto const& config : this->Makefile->GetGeneratorConfigs( + cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) { + if (first || dirCgesContextSensitive) { + dirs = fileSet->EvaluateDirectoryEntries(dirCges, this->LocalGenerator, + config, this); + dirCgesContextSensitive = + std::any_of(dirCges.begin(), dirCges.end(), contextSensitive); + } + if (first || fileCgesContextSensitive) { + filesPerDir.clear(); + for (auto const& fileCge : fileCges) { + fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, + this->LocalGenerator, config, this); + if (fileCge->GetHadContextSensitiveCondition()) { + fileCgesContextSensitive = true; + } + } + } + + for (auto const& files : filesPerDir) { + for (auto const& file : files.second) { + std::string filename = this->GenerateHeaderSetVerificationFile( + *this->Makefile->GetOrCreateSource(file), files.first, languages); + if (filename.empty()) { + continue; + } + + if (!verifyTarget) { + { + cmMakefile::PolicyPushPop polScope(this->Makefile); + this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW); + verifyTarget = this->Makefile->AddLibrary( + cmStrCat(this->GetName(), "_verify_interface_header_sets"), + cmStateEnums::OBJECT_LIBRARY, {}, true); + } + + verifyTarget->AddLinkLibrary( + *this->Makefile, this->GetName(), + cmTargetLinkLibraryType::GENERAL_LibraryType); + verifyTarget->SetProperty("AUTOMOC", "OFF"); + verifyTarget->SetProperty("AUTORCC", "OFF"); + verifyTarget->SetProperty("AUTOUIC", "OFF"); + verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); + verifyTarget->SetProperty("UNITY_BUILD", "OFF"); + cm::optional<std::map<std::string, cmValue>> + perConfigCompileDefinitions; + verifyTarget->FinalizeTargetConfiguration( + this->Makefile->GetCompileDefinitionsEntries(), + perConfigCompileDefinitions); + + if (!allVerifyTarget) { + allVerifyTarget = this->GlobalGenerator->GetMakefiles() + .front() + ->AddNewUtilityTarget( + "all_verify_interface_header_sets", true); + } + + allVerifyTarget->AddUtility(verifyTarget->GetName(), false); + } + + if (fileCgesContextSensitive) { + filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, ">"); + } + verifyTarget->AddSource(filename); + } + } + + if (!dirCgesContextSensitive && !fileCgesContextSensitive) { + break; + } + first = false; + } + } + + if (verifyTarget) { + this->LocalGenerator->AddGeneratorTarget( + cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator)); + } + + return true; +} + +std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile( + cmSourceFile& source, const std::string& dir, + cm::optional<std::set<std::string>>& languages) const +{ + std::string extension; + std::string language = source.GetOrDetermineLanguage(); + + if (language.empty()) { + if (!languages) { + languages.emplace(); + for (auto const& tgtSource : this->GetAllConfigSources()) { + auto const& tgtSourceLanguage = + tgtSource.Source->GetOrDetermineLanguage(); + if (tgtSourceLanguage == "CXX") { + languages->insert("CXX"); + break; // C++ overrides everything else, so we don't need to keep + // checking. + } + if (tgtSourceLanguage == "C") { + languages->insert("C"); + } + } + + if (languages->empty()) { + std::vector<std::string> languagesVector; + this->GlobalGenerator->GetEnabledLanguages(languagesVector); + languages->insert(languagesVector.begin(), languagesVector.end()); + } + } + + if (languages->count("CXX")) { + language = "CXX"; + } else if (languages->count("C")) { + language = "C"; + } + } + + if (language == "C") { + extension = ".c"; + } else if (language == "CXX") { + extension = ".cxx"; + } else { + return ""; + } + + std::string headerFilename = dir; + if (!headerFilename.empty()) { + headerFilename += '/'; + } + headerFilename += source.GetLocation().GetName(); + + auto filename = cmStrCat( + this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->GetName(), + "_verify_interface_header_sets/", headerFilename, extension); + auto* verificationSource = this->Makefile->GetOrCreateSource(filename); + verificationSource->SetProperty("LANGUAGE", language); + + cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename)); + + cmGeneratedFileStream fout(filename); + fout.SetCopyIfDifferent(true); + fout << "#include <" << headerFilename << ">\n"; + fout.close(); + + return filename; +} |
