summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-07-23 14:01:13 (GMT)
committerBrad King <brad.king@kitware.com>2019-07-23 14:44:19 (GMT)
commit1d3841b6003d4f1a45e79f6b9e6d6357514905f1 (patch)
tree750424fd2e4726f489c8f5c894300ffc65da3db4 /Source
parentb5460f99315f8e6a6bdc985ebc0ca18dd8a294a8 (diff)
downloadCMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.zip
CMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.tar.gz
CMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.tar.bz2
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
Diffstat (limited to 'Source')
-rw-r--r--Source/cmGeneratorTarget.cxx47
-rw-r--r--Source/cmGeneratorTarget.h5
2 files changed, 52 insertions, 0 deletions
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;