This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake".
The branch, master has been updated via d9156c387c60bc15523a27bba83809ec9fa2a8bf (commit) via 8df10447a18d6479160189509a248a465d6e967c (commit) via 52ea0c4676e2e9893312a9f73609603129cd6886 (commit) via 838278f4babe248eeb302f98651662ef8d94c7e6 (commit) via 3b113cc131a2c477a29960676cccb697994353ec (commit) via 1d3841b6003d4f1a45e79f6b9e6d6357514905f1 (commit) via b5460f99315f8e6a6bdc985ebc0ca18dd8a294a8 (commit) via ad2b3a32d1b54716d1e87ae89db8c31d614a4730 (commit) via 11fa818ecda0b50446aef891b06976973005e94b (commit) via 0239bf8ac88bb8ae9d8945be506cee2c9adb08f5 (commit) via 7caebeb0e4babc41e5c84b4ce0ea70adcfdea4a1 (commit) via b2785a0fbdcfa703f3ad3aaa2949ec7db55a27d9 (commit) from 467e6ac728cefa484f9e9369a7da4d05b04ec403 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d9156c387c60bc15523a27bba83809ec9fa2a8bf commit d9156c387c60bc15523a27bba83809ec9fa2a8bf Merge: 8df1044 838278f Author: Brad King <brad.k...@kitware.com> AuthorDate: Fri Jul 26 07:37:55 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Fri Jul 26 07:37:55 2019 -0400 Merge branch 'release-3.15' https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8df10447a18d6479160189509a248a465d6e967c commit 8df10447a18d6479160189509a248a465d6e967c Merge: 52ea0c4 3b113cc Author: Brad King <brad.k...@kitware.com> AuthorDate: Fri Jul 26 11:37:10 2019 +0000 Commit: Kitware Robot <kwro...@kitware.com> CommitDate: Fri Jul 26 07:37:19 2019 -0400 Merge topic 'doc-relnotes-3.15' 3b113cc131 Help: Add 3.15.1 release notes Acked-by: Kitware Robot <kwro...@kitware.com> Merge-request: !3608 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=52ea0c4676e2e9893312a9f73609603129cd6886 commit 52ea0c4676e2e9893312a9f73609603129cd6886 Merge: 467e6ac 1d3841b Author: Brad King <brad.k...@kitware.com> AuthorDate: Fri Jul 26 11:29:53 2019 +0000 Commit: Kitware Robot <kwro...@kitware.com> CommitDate: Fri Jul 26 07:33:27 2019 -0400 Merge topic 'optimize-usage-requirements' 1d3841b600 Genex: Memoize usage requirement TARGET_PROPERTY existence b5460f9931 cmLinkItem: Expose HadHeadSensitiveCondition in cmLinkInterfaceLibraries ad2b3a32d1 Genex: Optimize build setting TARGET_PROPERTY evaluation 11fa818ecd Genex: Optimize usage requirement TARGET_PROPERTY recursion 0239bf8ac8 Genex: In TARGET_PROPERTY check for usage reqs in link libs earlier 7caebeb0e4 Genex: Re-order TARGET_PROPERTY logic to de-duplicate checks b2785a0fbd Genex: Move TARGET_PROPERTY linked targets evaluation to end Acked-by: Kitware Robot <kwro...@kitware.com> Acked-by: Cristian Adam <cristian.a...@gmail.com> Merge-request: !3589 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1d3841b6003d4f1a45e79f6b9e6d6357514905f1 commit 1d3841b6003d4f1a45e79f6b9e6d6357514905f1 Author: Brad King <brad.k...@kitware.com> AuthorDate: Tue Jul 23 10:01:13 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Tue Jul 23 10:44:19 2019 -0400 Genex: Memoize usage requirement TARGET_PROPERTY existence For each usage requirement (such as `INTERFACE_COMPILE_DEFINITIONS` or `INTERFACE_INCLUDE_DIRECTORIES`), the value of the generator expression `$<TARGET_PROPERTY:target,prop>` includes the values of the same property from the transitive closure of link libraries of the target. In cases that a target's transitive closure of dependencies does not depend on the target being linked (the "head" target), we can memoize whether or not a usage requirement property exists at all for that target. When a usage requirement does not exist for a target, we can skip evaluating it for every consuming target. Fixes: #18964, #18965 diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b22d8b6..7c41045 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1143,12 +1143,59 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const return this->Target->GetPropertyAsBool(prop); } +bool cmGeneratorTarget::MaybeHaveInterfaceProperty( + std::string const& prop, cmGeneratorExpressionContext* context) const +{ + std::string const key = prop + '@' + context->Config; + auto i = this->MaybeInterfacePropertyExists.find(key); + if (i == this->MaybeInterfacePropertyExists.end()) { + // Insert an entry now in case there is a cycle. + i = this->MaybeInterfacePropertyExists.emplace(key, false).first; + bool& maybeInterfaceProp = i->second; + + // If this target itself has a non-empty property value, we are done. + const char* p = this->GetProperty(prop); + maybeInterfaceProp = p && *p; + + // Otherwise, recurse to interface dependencies. + if (!maybeInterfaceProp) { + cmGeneratorTarget const* headTarget = + context->HeadTarget ? context->HeadTarget : this; + if (cmLinkInterfaceLibraries const* iface = + this->GetLinkInterfaceLibraries(context->Config, headTarget, + true)) { + if (iface->HadHeadSensitiveCondition) { + // With a different head target we may get to a library with + // this interface property. + maybeInterfaceProp = true; + } else { + // The transitive interface libraries do not depend on the + // head target, so we can follow them. + for (cmLinkItem const& lib : iface->Libraries) { + if (lib.Target && + lib.Target->MaybeHaveInterfaceProperty(prop, context)) { + maybeInterfaceProp = true; + break; + } + } + } + } + } + } + return i->second; +} + std::string cmGeneratorTarget::EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagCheckerParent) const { std::string result; + // If the property does not appear transitively at all, we are done. + if (!this->MaybeHaveInterfaceProperty(prop, context)) { + return result; + } + // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is // a subset of TargetPropertyNode::Evaluate without stringify/parse steps // but sufficient for transitive interface properties. diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index b875c40..3874738 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -14,6 +14,7 @@ #include <set> #include <stddef.h> #include <string> +#include <unordered_map> #include <utility> #include <vector> @@ -856,6 +857,10 @@ private: mutable std::vector<AllConfigSource> AllConfigSources; void ComputeAllConfigSources() const; + mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists; + bool MaybeHaveInterfaceProperty(std::string const& prop, + cmGeneratorExpressionContext* context) const; + std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries; std::vector<TargetPropertyEntry*> CompileOptionsEntries; std::vector<TargetPropertyEntry*> CompileFeaturesEntries; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b5460f99315f8e6a6bdc985ebc0ca18dd8a294a8 commit b5460f99315f8e6a6bdc985ebc0ca18dd8a294a8 Author: Brad King <brad.k...@kitware.com> AuthorDate: Tue Jul 23 09:52:33 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Tue Jul 23 10:06:35 2019 -0400 cmLinkItem: Expose HadHeadSensitiveCondition in cmLinkInterfaceLibraries Clients may be able to avoid repeating work if they know the transitive link interface libraries do not depend on what is linking them. diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 5b635b5..6450c62 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -58,6 +58,9 @@ struct cmLinkInterfaceLibraries { // Libraries listed in the interface. std::vector<cmLinkItem> Libraries; + + // Whether the list depends on a genex referencing the head target. + bool HadHeadSensitiveCondition = false; }; struct cmLinkInterface : public cmLinkInterfaceLibraries @@ -84,7 +87,6 @@ struct cmOptionalLinkInterface : public cmLinkInterface bool LibrariesDone = false; bool AllDone = false; bool Exists = false; - bool HadHeadSensitiveCondition = false; const char* ExplicitLibraries = nullptr; }; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ad2b3a32d1b54716d1e87ae89db8c31d614a4730 commit ad2b3a32d1b54716d1e87ae89db8c31d614a4730 Author: Brad King <brad.k...@kitware.com> AuthorDate: Sun Jul 21 07:58:29 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Tue Jul 23 06:50:31 2019 -0400 Genex: Optimize build setting TARGET_PROPERTY evaluation For each build setting property (such as `COMPILE_DEFINITIONS` or `INCLUDE_DIRECTORIES`), the value of `$<TARGET_PROPERTY:target,prop>` includes the values of the corresponding `INTERFACE_*` usage requirement property from the transitive closure of link libraries of the target. Previously we computed this by constructing a generator expression string like `$<TARGET_PROPERTY:lib,INTERFACE_COMPILE_DEFINITIONS>` and recursively evaluating it with the generator expression engine. Avoid the string construction and parsing by using the dedicated evaluation method `cmGeneratorTarget::EvaluateInterfaceProperty`. Issue: #18964, #18965 diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 8d02b68..49d0c47 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1038,37 +1038,38 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode } } languageAndIdNode; -template <typename T> std::string getLinkedTargetsContent( - std::vector<T> const& libraries, cmGeneratorTarget const* target, - cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext* context, - cmGeneratorExpressionDAGChecker* dagChecker, - const std::string& interfacePropertyName) -{ - std::string linkedTargetsContent; - std::string sep; - std::string depString; - for (T const& l : libraries) { - // Broken code can have a target in its own link interface. - // Don't follow such link interface entries so as not to create a - // self-referencing loop. - if (l.Target && l.Target != target) { - std::string uniqueName = - target->GetGlobalGenerator()->IndexGeneratorTargetUniquely(l.Target); - depString += sep + "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + - interfacePropertyName + ">"; - sep = ";"; - } - } - if (!depString.empty()) { - linkedTargetsContent = - cmGeneratorExpressionNode::EvaluateDependentExpression( - depString, target->GetLocalGenerator(), context, headTarget, target, - dagChecker); - } - linkedTargetsContent = - cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent); - return linkedTargetsContent; + cmGeneratorTarget const* target, std::string const& prop, + cmGeneratorExpressionContext* context, + cmGeneratorExpressionDAGChecker* dagChecker) +{ + std::string result; + if (cmLinkImplementationLibraries const* impl = + target->GetLinkImplementationLibraries(context->Config)) { + for (cmLinkImplItem const& lib : impl->Libraries) { + if (lib.Target) { + // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our + // caller's property and hand-evaluate it as if it were compiled. + // Create a context as cmCompiledGeneratorExpression::Evaluate does. + cmGeneratorExpressionContext libContext( + target->GetLocalGenerator(), context->Config, context->Quiet, target, + target, context->EvaluateForBuildsystem, lib.Backtrace, + context->Language); + std::string libResult = + lib.Target->EvaluateInterfaceProperty(prop, &libContext, dagChecker); + if (!libResult.empty()) { + if (result.empty()) { + result = std::move(libResult); + } else { + result.reserve(result.size() + 1 + libResult.size()); + result += ";"; + result += libResult; + } + } + } + } + } + return result; } static const struct TargetPropertyNode : public cmGeneratorExpressionNode @@ -1331,16 +1332,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } if (!interfacePropertyName.empty()) { - cmGeneratorTarget const* headTarget = target; - result = this->EvaluateDependentExpression( - result, context->LG, context, headTarget, target, &dagChecker); - std::string linkedTargetsContent; - if (cmLinkImplementationLibraries const* impl = - target->GetLinkImplementationLibraries(context->Config)) { - linkedTargetsContent = - getLinkedTargetsContent(impl->Libraries, target, target, context, - &dagChecker, interfacePropertyName); - } + result = this->EvaluateDependentExpression(result, context->LG, context, + target, target, &dagChecker); + std::string linkedTargetsContent = getLinkedTargetsContent( + target, interfacePropertyName, context, &dagChecker); if (!linkedTargetsContent.empty()) { result += (result.empty() ? "" : ";") + linkedTargetsContent; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 21da2fd..b22d8b6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1227,23 +1227,17 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, headTarget->GetLinkImplementationLibraries(config)) { for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target) { - std::string uniqueName = - headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( - lib.Target); - std::string genex = - "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + prop + ">"; - cmGeneratorExpression ge(lib.Backtrace); - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); - cge->SetEvaluateForBuildsystem(true); - EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); + // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our + // caller's property and hand-evaluate it as if it were compiled. + // Create a context as cmCompiledGeneratorExpression::Evaluate does. + cmGeneratorExpressionContext context( + headTarget->GetLocalGenerator(), config, false, headTarget, + headTarget, true, lib.Backtrace, lang); cmSystemTools::ExpandListArgument( - cge->Evaluate(headTarget->GetLocalGenerator(), config, false, - headTarget, dagChecker, lang), + lib.Target->EvaluateInterfaceProperty(prop, &context, dagChecker), ee.Values); - if (cge->GetHadContextSensitiveCondition()) { - ee.ContextDependent = true; - } + ee.ContextDependent = context.HadContextSensitiveCondition; entries.emplace_back(std::move(ee)); } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=11fa818ecda0b50446aef891b06976973005e94b commit 11fa818ecda0b50446aef891b06976973005e94b Author: Brad King <brad.k...@kitware.com> AuthorDate: Sun Jul 21 07:57:08 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Tue Jul 23 06:46:34 2019 -0400 Genex: Optimize usage requirement TARGET_PROPERTY recursion In large projects the generation process spends a lot of time evaluating usage requirements through transitive interface properties on targets. This can be seen in a contrived example with deep dependencies: set(prev "") foreach(i RANGE 1 500) add_library(a${i} a.c) target_compile_definitions(a${i} PUBLIC A${i}) target_link_libraries(a${i} PUBLIC ${prev}) set(prev a${i}) endforeach() For each usage requirement (such as `INTERFACE_COMPILE_DEFINITIONS` or `INTERFACE_INCLUDE_DIRECTORIES`), the value of the generator expression `$<TARGET_PROPERTY:target,prop>` includes the values of the same property from the transitive closure of link libraries of the target. Previously we computed this by constructing a generator expression string like `$<TARGET_PROPERTY:lib,INTERFACE_COMPILE_DEFINITIONS>` and recursively evaluating it with the generator expression engine. Avoid the string construction and parsing by creating and using a dedicated evaluation method `cmGeneratorTarget::EvaluateInterfaceProperty` that looks up the properties directly. Issue: #18964, #18965 diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index b268ea2..8d02b68 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1243,6 +1243,11 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } } + if (isInterfaceProperty) { + return target->EvaluateInterfaceProperty(propertyName, context, + dagCheckerParent); + } + cmGeneratorExpressionDAGChecker dagChecker( context->Backtrace, target, propertyName, content, dagCheckerParent); @@ -1254,10 +1259,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode // No error. We just skip cyclic references. return std::string(); case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: - if (isInterfaceProperty) { - // No error. We're not going to find anything new here. - return std::string(); - } + // We handle transitive properties above. For non-transitive + // properties we accept repeats anyway. case cmGeneratorExpressionDAGChecker::DAG: break; } @@ -1328,27 +1331,15 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } if (!interfacePropertyName.empty()) { - cmGeneratorTarget const* headTarget = - context->HeadTarget && isInterfaceProperty ? context->HeadTarget - : target; + cmGeneratorTarget const* headTarget = target; result = this->EvaluateDependentExpression( result, context->LG, context, headTarget, target, &dagChecker); std::string linkedTargetsContent; - if (isInterfaceProperty) { - if (cmLinkInterfaceLibraries const* iface = - target->GetLinkInterfaceLibraries(context->Config, headTarget, - true)) { - linkedTargetsContent = getLinkedTargetsContent( - iface->Libraries, target, headTarget, context, &dagChecker, - interfacePropertyName); - } - } else { - if (cmLinkImplementationLibraries const* impl = - target->GetLinkImplementationLibraries(context->Config)) { - linkedTargetsContent = - getLinkedTargetsContent(impl->Libraries, target, target, context, - &dagChecker, interfacePropertyName); - } + if (cmLinkImplementationLibraries const* impl = + target->GetLinkImplementationLibraries(context->Config)) { + linkedTargetsContent = + getLinkedTargetsContent(impl->Libraries, target, target, context, + &dagChecker, interfacePropertyName); } if (!linkedTargetsContent.empty()) { result += (result.empty() ? "" : ";") + linkedTargetsContent; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 6e6c917..21da2fd 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -22,7 +22,9 @@ #include "cmCustomCommandGenerator.h" #include "cmCustomCommandLines.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionDAGChecker.h" +#include "cmGeneratorExpressionNode.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -1141,6 +1143,79 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const return this->Target->GetPropertyAsBool(prop); } +std::string cmGeneratorTarget::EvaluateInterfaceProperty( + std::string const& prop, cmGeneratorExpressionContext* context, + cmGeneratorExpressionDAGChecker* dagCheckerParent) const +{ + std::string result; + + // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is + // a subset of TargetPropertyNode::Evaluate without stringify/parse steps + // but sufficient for transitive interface properties. + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop, + nullptr, dagCheckerParent); + switch (dagChecker.Check()) { + case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: + dagChecker.ReportError( + context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">"); + return result; + case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: + // No error. We just skip cyclic references. + return result; + case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: + // No error. We have already seen this transitive property. + return result; + case cmGeneratorExpressionDAGChecker::DAG: + break; + } + + cmGeneratorTarget const* headTarget = + context->HeadTarget ? context->HeadTarget : this; + + if (const char* p = this->GetProperty(prop)) { + result = cmGeneratorExpressionNode::EvaluateDependentExpression( + p, context->LG, context, headTarget, this, &dagChecker); + } + + if (cmLinkInterfaceLibraries const* iface = + this->GetLinkInterfaceLibraries(context->Config, headTarget, true)) { + for (cmLinkItem const& lib : iface->Libraries) { + // Broken code can have a target in its own link interface. + // Don't follow such link interface entries so as not to create a + // self-referencing loop. + if (lib.Target && lib.Target != this) { + // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the + // above property and hand-evaluate it as if it were compiled. + // Create a context as cmCompiledGeneratorExpression::Evaluate does. + cmGeneratorExpressionContext libContext( + context->LG, context->Config, context->Quiet, headTarget, this, + context->EvaluateForBuildsystem, context->Backtrace, + context->Language); + std::string libResult = cmGeneratorExpression::StripEmptyListElements( + lib.Target->EvaluateInterfaceProperty(prop, &libContext, + &dagChecker)); + if (!libResult.empty()) { + if (result.empty()) { + result = std::move(libResult); + } else { + result.reserve(result.size() + 1 + libResult.size()); + result += ";"; + result += libResult; + } + } + context->HadContextSensitiveCondition = + context->HadContextSensitiveCondition || + libContext.HadContextSensitiveCondition; + context->HadHeadSensitiveCondition = + context->HadHeadSensitiveCondition || + libContext.HadHeadSensitiveCondition; + } + } + } + + return result; +} + namespace { void AddInterfaceEntries(cmGeneratorTarget const* headTarget, std::string const& config, std::string const& prop, diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index e86535d..b875c40 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -25,6 +25,9 @@ class cmMakefile; class cmSourceFile; class cmTarget; +struct cmGeneratorExpressionContext; +struct cmGeneratorExpressionDAGChecker; + class cmGeneratorTarget { public: @@ -674,6 +677,10 @@ public: class TargetPropertyEntry; + std::string EvaluateInterfaceProperty( + std::string const& prop, cmGeneratorExpressionContext* context, + cmGeneratorExpressionDAGChecker* dagCheckerParent) const; + bool HaveInstallTreeRPATH(const std::string& config) const; bool GetBuildRPATH(const std::string& config, std::string& rpath) const; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0239bf8ac88bb8ae9d8945be506cee2c9adb08f5 commit 0239bf8ac88bb8ae9d8945be506cee2c9adb08f5 Author: Brad King <brad.k...@kitware.com> AuthorDate: Sat Jul 20 19:29:13 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Sun Jul 21 08:17:04 2019 -0400 Genex: In TARGET_PROPERTY check for usage reqs in link libs earlier diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index b027cd4..b268ea2 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1219,6 +1219,30 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } #undef POPULATE_INTERFACE_PROPERTY_NAME + bool evaluatingLinkLibraries = false; + + if (dagCheckerParent) { + if (dagCheckerParent->EvaluatingGenexExpression() || + dagCheckerParent->EvaluatingPICExpression()) { + // No check required. + } else if (dagCheckerParent->EvaluatingLinkLibraries()) { + evaluatingLinkLibraries = true; + if (!interfacePropertyName.empty()) { + reportError( + context, content->GetOriginalExpression(), + "$<TARGET_PROPERTY:...> expression in link libraries " + "evaluation depends on target property which is transitive " + "over the link libraries, creating a recursion."); + return std::string(); + } + } else { +#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() || + assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( + ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy) +#undef ASSERT_TRANSITIVE_PROPERTY_METHOD + } + } + cmGeneratorExpressionDAGChecker dagChecker( context->Backtrace, target, propertyName, content, dagCheckerParent); @@ -1243,31 +1267,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode if (const char* p = target->GetProperty(propertyName)) { result = p; haveProp = true; - } - - if (dagCheckerParent) { - if (dagCheckerParent->EvaluatingGenexExpression() || - dagCheckerParent->EvaluatingPICExpression()) { - // No check required. - } else if (dagCheckerParent->EvaluatingLinkLibraries()) { - if (!interfacePropertyName.empty()) { - reportError( - context, content->GetOriginalExpression(), - "$<TARGET_PROPERTY:...> expression in link libraries " - "evaluation depends on target property which is transitive " - "over the link libraries, creating a recursion."); - return std::string(); - } - - if (!haveProp) { - return std::string(); - } - } else { -#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() || - assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( - ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy) -#undef ASSERT_TRANSITIVE_PROPERTY_METHOD - } + } else if (evaluatingLinkLibraries) { + return std::string(); } if (!haveProp && !target->IsImported() && https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7caebeb0e4babc41e5c84b4ce0ea70adcfdea4a1 commit 7caebeb0e4babc41e5c84b4ce0ea70adcfdea4a1 Author: Brad King <brad.k...@kitware.com> AuthorDate: Sat Jul 20 17:30:31 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Sun Jul 21 08:14:27 2019 -0400 Genex: Re-order TARGET_PROPERTY logic to de-duplicate checks Check for usage requirement properties early enough to avoid duplicate checks in other conditions. diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 1973e99..b027cd4 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1038,14 +1038,6 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode } } languageAndIdNode; -#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY - -static const char* targetPropertyTransitiveWhitelist[] = { - nullptr CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME) -}; - -#undef TRANSITIVE_PROPERTY_NAME - template <typename T> std::string getLinkedTargetsContent( std::vector<T> const& libraries, cmGeneratorTarget const* target, @@ -1205,6 +1197,28 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return target->GetLinkerLanguage(context->Config); } + std::string interfacePropertyName; + bool isInterfaceProperty = false; + +#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ + if (propertyName == #prop) { \ + interfacePropertyName = "INTERFACE_" #prop; \ + } else if (propertyName == "INTERFACE_" #prop) { \ + interfacePropertyName = "INTERFACE_" #prop; \ + isInterfaceProperty = true; \ + } else + + CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) + // Note that the above macro terminates with an else + /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { + cmPolicies::PolicyStatus polSt = + context->LG->GetPolicyStatus(cmPolicies::CMP0043); + if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { + interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; + } + } +#undef POPULATE_INTERFACE_PROPERTY_NAME + cmGeneratorExpressionDAGChecker dagChecker( context->Backtrace, target, propertyName, content, dagCheckerParent); @@ -1216,12 +1230,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode // No error. We just skip cyclic references. return std::string(); case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: - for (size_t i = 1; i < cm::size(targetPropertyTransitiveWhitelist); - ++i) { - if (targetPropertyTransitiveWhitelist[i] == propertyName) { - // No error. We're not going to find anything new here. - return std::string(); - } + if (isInterfaceProperty) { + // No error. We're not going to find anything new here. + return std::string(); } case cmGeneratorExpressionDAGChecker::DAG: break; @@ -1239,10 +1250,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode dagCheckerParent->EvaluatingPICExpression()) { // No check required. } else if (dagCheckerParent->EvaluatingLinkLibraries()) { -#define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \ - (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) || - if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME( - TRANSITIVE_PROPERTY_COMPARE) false) { // NOLINT(*) + if (!interfacePropertyName.empty()) { reportError( context, content->GetOriginalExpression(), "$<TARGET_PROPERTY:...> expression in link libraries " @@ -1250,42 +1258,18 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode "over the link libraries, creating a recursion."); return std::string(); } -#undef TRANSITIVE_PROPERTY_COMPARE if (!haveProp) { return std::string(); } } else { #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() || - assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy) #undef ASSERT_TRANSITIVE_PROPERTY_METHOD } } - std::string interfacePropertyName; - bool isInterfaceProperty = false; - -#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ - if (propertyName == #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - } else if (propertyName == "INTERFACE_" #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - isInterfaceProperty = true; \ - } else - - CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) - // Note that the above macro terminates with an else - /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { - cmPolicies::PolicyStatus polSt = - context->LG->GetPolicyStatus(cmPolicies::CMP0043); - if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; - } - } -#undef POPULATE_INTERFACE_PROPERTY_NAME - if (!haveProp && !target->IsImported() && target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { if (target->IsLinkInterfaceDependentBoolProperty(propertyName, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b2785a0fbdcfa703f3ad3aaa2949ec7db55a27d9 commit b2785a0fbdcfa703f3ad3aaa2949ec7db55a27d9 Author: Brad King <brad.k...@kitware.com> AuthorDate: Sat Jul 20 16:09:03 2019 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Sun Jul 21 07:47:27 2019 -0400 Genex: Move TARGET_PROPERTY linked targets evaluation to end diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index d828dac..1973e99 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1227,10 +1227,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode break; } - std::string prop; + std::string result; bool haveProp = false; if (const char* p = target->GetProperty(propertyName)) { - prop = p; + result = p; haveProp = true; } @@ -1264,8 +1264,6 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } } - std::string linkedTargetsContent; - std::string interfacePropertyName; bool isInterfaceProperty = false; @@ -1287,32 +1285,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } } #undef POPULATE_INTERFACE_PROPERTY_NAME - cmGeneratorTarget const* headTarget = - context->HeadTarget && isInterfaceProperty ? context->HeadTarget - : target; - - if (isInterfaceProperty) { - if (cmLinkInterfaceLibraries const* iface = - target->GetLinkInterfaceLibraries(context->Config, headTarget, - true)) { - linkedTargetsContent = - getLinkedTargetsContent(iface->Libraries, target, headTarget, - context, &dagChecker, interfacePropertyName); - } - } else if (!interfacePropertyName.empty()) { - if (cmLinkImplementationLibraries const* impl = - target->GetLinkImplementationLibraries(context->Config)) { - linkedTargetsContent = - getLinkedTargetsContent(impl->Libraries, target, target, context, - &dagChecker, interfacePropertyName); - } - } - if (!haveProp) { - if (target->IsImported() || - target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - return linkedTargetsContent; - } + if (!haveProp && !target->IsImported() && + target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { if (target->IsLinkInterfaceDependentBoolProperty(propertyName, context->Config)) { context->HadContextSensitiveCondition = true; @@ -1345,8 +1320,6 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode context->Config); return propContent ? propContent : ""; } - - return linkedTargetsContent; } if (!target->IsImported() && dagCheckerParent && @@ -1368,15 +1341,35 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return propContent ? propContent : ""; } } + if (!interfacePropertyName.empty()) { - std::string result = this->EvaluateDependentExpression( - prop, context->LG, context, headTarget, target, &dagChecker); + cmGeneratorTarget const* headTarget = + context->HeadTarget && isInterfaceProperty ? context->HeadTarget + : target; + result = this->EvaluateDependentExpression( + result, context->LG, context, headTarget, target, &dagChecker); + std::string linkedTargetsContent; + if (isInterfaceProperty) { + if (cmLinkInterfaceLibraries const* iface = + target->GetLinkInterfaceLibraries(context->Config, headTarget, + true)) { + linkedTargetsContent = getLinkedTargetsContent( + iface->Libraries, target, headTarget, context, &dagChecker, + interfacePropertyName); + } + } else { + if (cmLinkImplementationLibraries const* impl = + target->GetLinkImplementationLibraries(context->Config)) { + linkedTargetsContent = + getLinkedTargetsContent(impl->Libraries, target, target, context, + &dagChecker, interfacePropertyName); + } + } if (!linkedTargetsContent.empty()) { result += (result.empty() ? "" : ";") + linkedTargetsContent; } - return result; } - return prop; + return result; } } targetPropertyNode; ----------------------------------------------------------------------- Summary of changes: Help/release/3.15.rst | 17 +++ Source/cmGeneratorExpressionNode.cxx | 208 +++++++++++++++-------------------- Source/cmGeneratorTarget.cxx | 144 +++++++++++++++++++++--- Source/cmGeneratorTarget.h | 12 ++ Source/cmLinkItem.h | 4 +- 5 files changed, 248 insertions(+), 137 deletions(-) hooks/post-receive -- CMake _______________________________________________ Cmake-commits mailing list Cmake-commits@cmake.org https://cmake.org/mailman/listinfo/cmake-commits