diff options
-rw-r--r-- | Help/manual/cmake-properties.7.rst | 2 | ||||
-rw-r--r-- | Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst | 4 | ||||
-rw-r--r-- | Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst | 17 | ||||
-rw-r--r-- | Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst | 17 | ||||
-rw-r--r-- | Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst | 5 | ||||
-rw-r--r-- | Source/cmExportFileGenerator.cxx | 14 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 44 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 209 | ||||
-rw-r--r-- | Source/cmTarget.h | 8 | ||||
-rw-r--r-- | Tests/CompatibleInterface/CMakeLists.txt | 22 | ||||
-rw-r--r-- | Tests/CompatibleInterface/main.cpp | 13 |
11 files changed, 339 insertions, 16 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index bb3acff..658da20 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -76,6 +76,8 @@ Properties on Targets /prop_tgt/BUNDLE_EXTENSION /prop_tgt/BUNDLE /prop_tgt/COMPATIBLE_INTERFACE_BOOL + /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX + /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN /prop_tgt/COMPATIBLE_INTERFACE_STRING /prop_tgt/COMPILE_DEFINITIONS_CONFIG /prop_tgt/COMPILE_DEFINITIONS diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst index 7f95ef0..83c18f1 100644 --- a/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst +++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst @@ -14,4 +14,6 @@ property is set, then it must have the same boolean value as all others, and if the property is not set, then it is ignored. Note that for each dependee, the set of properties from this property must not intersect with the set of properties from the -COMPATIBLE_INTERFACE_STRING property. +:prop_tgt:`COMPATIBLE_INTERFACE_STRING`, +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN` or +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` property. diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst new file mode 100644 index 0000000..2fe748e --- /dev/null +++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst @@ -0,0 +1,17 @@ +COMPATIBLE_INTERFACE_NUMBER_MAX +------------------------------- + +Properties whose maximum value from the link interface will be used. + +The COMPATIBLE_INTERFACE_NUMBER_MAX property may contain a list of +properties for this target whose maximum value may be read at generate time +when evaluated in the INTERFACE of all linked dependees. For example, if a +property "FOO" appears in the list, then for each dependee, the +"INTERFACE_FOO" property content in all of its dependencies will be compared +with each other and with the "FOO" property in the depender. When reading +the FOO property at generate time, the maximum value will be returned. +If the property is not set, then it is ignored. Note that for each +dependee, the set of properties from this property must not intersect +with the set of properties from the :prop_tgt:`COMPATIBLE_INTERFACE_BOOL`, +:prop_tgt:`COMPATIBLE_INTERFACE_STRING` or +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN` property. diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst new file mode 100644 index 0000000..7fe384b --- /dev/null +++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst @@ -0,0 +1,17 @@ +COMPATIBLE_INTERFACE_NUMBER_MIN +------------------------------- + +Properties whose maximum value from the link interface will be used. + +The COMPATIBLE_INTERFACE_NUMBER_MIN property may contain a list of +properties for this target whose minimum value may be read at generate time +when evaluated in the INTERFACE of all linked dependees. For example, if a +property "FOO" appears in the list, then for each dependee, the +"INTERFACE_FOO" property content in all of its dependencies will be compared +with each other and with the "FOO" property in the depender. When reading +the FOO property at generate time, the minimum value will be returned. +If the property is not set, then it is ignored. Note that for each +dependee, the set of properties from this property must not intersect +with the set of properties from the :prop_tgt:`COMPATIBLE_INTERFACE_BOOL`, +:prop_tgt:`COMPATIBLE_INTERFACE_STRING` or +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` property. diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst index a461f76..f3fb43d 100644 --- a/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst +++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst @@ -11,5 +11,6 @@ property "FOO" appears in the list, then for each dependee, the equal with each other, and with the "FOO" property in the dependee. If the property is not set, then it is ignored. Note that for each dependee, the set of properties from this property must not intersect -with the set of properties from the COMPATIBLE_INTERFACE_BOOL -property. +with the set of properties from the :prop_tgt:`COMPATIBLE_INTERFACE_BOOL`, +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN` or +:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` property. diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index b01e499..65f1cc6 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -411,6 +411,12 @@ void getCompatibleInterfaceProperties(cmTarget *target, getPropertyContents(li->Target, "COMPATIBLE_INTERFACE_STRING", ifaceProperties); + getPropertyContents(li->Target, + "COMPATIBLE_INTERFACE_NUMBER_MIN", + ifaceProperties); + getPropertyContents(li->Target, + "COMPATIBLE_INTERFACE_NUMBER_MAX", + ifaceProperties); } } @@ -423,11 +429,19 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( target, properties); this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", target, properties); + this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MIN", + target, properties); + this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MAX", + target, properties); std::set<std::string> ifaceProperties; getPropertyContents(target, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties); getPropertyContents(target, "COMPATIBLE_INTERFACE_STRING", ifaceProperties); + getPropertyContents(target, "COMPATIBLE_INTERFACE_NUMBER_MIN", + ifaceProperties); + getPropertyContents(target, "COMPATIBLE_INTERFACE_NUMBER_MAX", + ifaceProperties); getCompatibleInterfaceProperties(target, ifaceProperties, 0); diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 33863f4..f92c18e 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -980,10 +980,54 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode context->Config); return propContent ? propContent : ""; } + if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName, + context->Config)) + { + context->HadContextSensitiveCondition = true; + const char *propContent = + target->GetLinkInterfaceDependentNumberMinProperty( + propertyName, + context->Config); + return propContent ? propContent : ""; + } + if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName, + context->Config)) + { + context->HadContextSensitiveCondition = true; + const char *propContent = + target->GetLinkInterfaceDependentNumberMaxProperty( + propertyName, + context->Config); + return propContent ? propContent : ""; + } return linkedTargetsContent; } + if (!target->IsImported() + && dagCheckerParent && !dagCheckerParent->EvaluatingLinkLibraries()) + { + if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName, + context->Config)) + { + context->HadContextSensitiveCondition = true; + const char *propContent = + target->GetLinkInterfaceDependentNumberMinProperty( + propertyName, + context->Config); + return propContent ? propContent : ""; + } + if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName, + context->Config)) + { + context->HadContextSensitiveCondition = true; + const char *propContent = + target->GetLinkInterfaceDependentNumberMaxProperty( + propertyName, + context->Config); + return propContent ? propContent : ""; + } + } for (size_t i = 1; i < cmArraySize(targetPropertyTransitiveWhitelist); ++i) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 91a7be8..c42ba95 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -4453,7 +4453,9 @@ const char *getTypedProperty<const char *>(cmTarget *tgt, const char *prop, enum CompatibleType { BoolType, - StringType + StringType, + NumberMinType, + NumberMaxType }; //---------------------------------------------------------------------------- @@ -4474,6 +4476,38 @@ const char * consistentStringProperty(const char *lhs, const char *rhs) return strcmp(lhs, rhs) == 0 ? lhs : 0; } +#if defined(_MSC_VER) && _MSC_VER <= 1200 +template<typename T> const T& +cmMaximum(const T& l, const T& r) {return l > r ? l : r;} +template<typename T> const T& +cmMinimum(const T& l, const T& r) {return l < r ? l : r;} +#else +#define cmMinimum std::min +#define cmMaximum std::max +#endif + +//---------------------------------------------------------------------------- +const char * consistentNumberProperty(const char *lhs, const char *rhs, + CompatibleType t) +{ + double lnum; + double rnum; + if(sscanf(lhs, "%lg", &lnum) != 1 || + sscanf(rhs, "%lg", &rnum) != 1) + { + return 0; + } + + if (t == NumberMaxType) + { + return cmMaximum(lnum, rnum) == lnum ? lhs : rhs; + } + else + { + return cmMinimum(lnum, rnum) == lnum ? lhs : rhs; + } +} + //---------------------------------------------------------------------------- template<> const char* consistentProperty(const char *lhs, const char *rhs, @@ -4498,6 +4532,9 @@ const char* consistentProperty(const char *lhs, const char *rhs, return 0; case StringType: return consistentStringProperty(lhs, rhs); + case NumberMinType: + case NumberMaxType: + return consistentNumberProperty(lhs, rhs, t); } assert(!"Unreachable!"); return 0; @@ -4686,6 +4723,30 @@ const char * cmTarget::GetLinkInterfaceDependentStringProperty( } //---------------------------------------------------------------------------- +const char * cmTarget::GetLinkInterfaceDependentNumberMinProperty( + const std::string &p, + const char *config) +{ + return checkInterfacePropertyCompatibility<const char *>(this, + p, + config, + "empty", + NumberMinType, 0); +} + +//---------------------------------------------------------------------------- +const char * cmTarget::GetLinkInterfaceDependentNumberMaxProperty( + const std::string &p, + const char *config) +{ + return checkInterfacePropertyCompatibility<const char *>(this, + p, + config, + "empty", + NumberMaxType, 0); +} + +//---------------------------------------------------------------------------- bool isLinkDependentProperty(cmTarget *tgt, const std::string &p, const char *interfaceProperty, const char *config) @@ -4754,6 +4815,30 @@ bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p, } //---------------------------------------------------------------------------- +bool cmTarget::IsLinkInterfaceDependentNumberMinProperty(const std::string &p, + const char *config) +{ + if (this->TargetTypeValue == OBJECT_LIBRARY) + { + return false; + } + return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_NUMBER_MIN", + config); +} + +//---------------------------------------------------------------------------- +bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, + const char *config) +{ + if (this->TargetTypeValue == OBJECT_LIBRARY) + { + return false; + } + return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_NUMBER_MAX", + config); +} + +//---------------------------------------------------------------------------- void cmTarget::GetLanguages(std::set<cmStdString>& languages) const { for(std::vector<cmSourceFile*>::const_iterator @@ -5759,6 +5844,10 @@ const char * getLinkInterfaceDependentProperty(cmTarget *tgt, return 0; case StringType: return tgt->GetLinkInterfaceDependentStringProperty(prop, config); + case NumberMinType: + return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config); + case NumberMaxType: + return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config); } assert(!"Unreachable!"); return 0; @@ -5812,6 +5901,50 @@ void checkPropertyConsistency(cmTarget *depender, cmTarget *dependee, } } +static cmStdString intersect(const std::set<cmStdString> &s1, + const std::set<cmStdString> &s2) +{ + std::set<cmStdString> intersect; + std::set_intersection(s1.begin(),s1.end(), + s2.begin(),s2.end(), + std::inserter(intersect,intersect.begin())); + if (!intersect.empty()) + { + return *intersect.begin(); + } + return ""; +} +static cmStdString intersect(const std::set<cmStdString> &s1, + const std::set<cmStdString> &s2, + const std::set<cmStdString> &s3) +{ + cmStdString result; + result = intersect(s1, s2); + if (!result.empty()) + return result; + result = intersect(s1, s3); + if (!result.empty()) + return result; + return intersect(s2, s3); +} +static cmStdString intersect(const std::set<cmStdString> &s1, + const std::set<cmStdString> &s2, + const std::set<cmStdString> &s3, + const std::set<cmStdString> &s4) +{ + cmStdString result; + result = intersect(s1, s2); + if (!result.empty()) + return result; + result = intersect(s1, s3); + if (!result.empty()) + return result; + result = intersect(s1, s4); + if (!result.empty()) + return result; + return intersect(s2, s3, s4); +} + //---------------------------------------------------------------------------- void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, const char* config) @@ -5820,6 +5953,8 @@ void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, std::set<cmStdString> emittedBools; std::set<cmStdString> emittedStrings; + std::set<cmStdString> emittedMinNumbers; + std::set<cmStdString> emittedMaxNumbers; for(cmComputeLinkInformation::ItemVector::const_iterator li = deps.begin(); @@ -5845,23 +5980,71 @@ void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, { return; } + checkPropertyConsistency<const char *>(this, li->Target, + "COMPATIBLE_INTERFACE_NUMBER_MIN", + emittedMinNumbers, config, + NumberMinType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency<const char *>(this, li->Target, + "COMPATIBLE_INTERFACE_NUMBER_MAX", + emittedMaxNumbers, config, + NumberMaxType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } } - for(std::set<cmStdString>::const_iterator li = emittedBools.begin(); - li != emittedBools.end(); ++li) + std::string prop = intersect(emittedBools, + emittedStrings, + emittedMinNumbers, + emittedMaxNumbers); + + if (!prop.empty()) { - const std::set<cmStdString>::const_iterator si = emittedStrings.find(*li); - if (si != emittedStrings.end()) + std::set<std::string> props; + std::set<cmStdString>::const_iterator i = emittedBools.find(prop); + if (i != emittedBools.end()) { - cmOStringStream e; - e << "Property \"" << *li << "\" appears in both the " - "COMPATIBLE_INTERFACE_BOOL and the COMPATIBLE_INTERFACE_STRING " - "property in the dependencies of target \"" << this->GetName() << - "\". This is not allowed. A property may only require compatibility " - "in a boolean interpretation or a string interpretation, but not both."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - break; + props.insert("COMPATIBLE_INTERFACE_BOOL"); + } + i = emittedStrings.find(prop); + if (i != emittedStrings.end()) + { + props.insert("COMPATIBLE_INTERFACE_STRING"); } + i = emittedMinNumbers.find(prop); + if (i != emittedMinNumbers.end()) + { + props.insert("COMPATIBLE_INTERFACE_NUMBER_MIN"); + } + i = emittedMaxNumbers.find(prop); + if (i != emittedMaxNumbers.end()) + { + props.insert("COMPATIBLE_INTERFACE_NUMBER_MAX"); + } + + std::string propsString = *props.begin(); + props.erase(props.begin()); + while (props.size() > 1) + { + propsString += ", " + *props.begin(); + props.erase(props.begin()); + } + if (props.size() == 1) + { + propsString += " and the " + *props.begin(); + } + cmOStringStream e; + e << "Property \"" << prop << "\" appears in both the " + << propsString << + " property in the dependencies of target \"" << this->GetName() << + "\". This is not allowed. A property may only require compatibility " + "in a boolean interpretation or a string interpretation, but not both."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index e8f4e08..9d62f5f 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -536,12 +536,20 @@ public: const char *config); bool IsLinkInterfaceDependentStringProperty(const std::string &p, const char *config); + bool IsLinkInterfaceDependentNumberMinProperty(const std::string &p, + const char *config); + bool IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, + const char *config); bool GetLinkInterfaceDependentBoolProperty(const std::string &p, const char *config); const char *GetLinkInterfaceDependentStringProperty(const std::string &p, const char *config); + const char *GetLinkInterfaceDependentNumberMinProperty(const std::string &p, + const char *config); + const char *GetLinkInterfaceDependentNumberMaxProperty(const std::string &p, + const char *config); std::string GetDebugGeneratorExpressions(const std::string &value, cmTarget::LinkLibraryType llt); diff --git a/Tests/CompatibleInterface/CMakeLists.txt b/Tests/CompatibleInterface/CMakeLists.txt index 5ee9fd7..8186c61 100644 --- a/Tests/CompatibleInterface/CMakeLists.txt +++ b/Tests/CompatibleInterface/CMakeLists.txt @@ -20,11 +20,25 @@ set_property(TARGET iface1 APPEND PROPERTY STRING_PROP2 STRING_PROP3 ) +set_property(TARGET iface1 APPEND PROPERTY + COMPATIBLE_INTERFACE_NUMBER_MIN + NUMBER_MIN_PROP1 + NUMBER_MIN_PROP2 +) +set_property(TARGET iface1 APPEND PROPERTY + COMPATIBLE_INTERFACE_NUMBER_MAX + NUMBER_MAX_PROP1 + NUMBER_MAX_PROP2 +) set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP1 ON) set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP2 ON) set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP1 prop1) set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP2 prop2) +set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP1 100) +set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP2 200) +set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP1 100) +set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP2 200) add_executable(CompatibleInterface main.cpp) target_link_libraries(CompatibleInterface iface1) @@ -33,6 +47,10 @@ set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP2 ON) set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP3 ON) set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2) set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3) +set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP1 50) +set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP2 250) +set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP1 50) +set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP2 250) target_compile_definitions(CompatibleInterface PRIVATE @@ -42,6 +60,10 @@ target_compile_definitions(CompatibleInterface $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP1>,prop1>:STRING_PROP1> $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP2>,prop2>:STRING_PROP2> $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP3>,prop3>:STRING_PROP3> + $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP1>,50>:NUMBER_MIN_PROP1=50> + $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP2>,200>:NUMBER_MIN_PROP2=200> + $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP1>,100>:NUMBER_MAX_PROP1=100> + $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP2>,250>:NUMBER_MAX_PROP2=250> ) diff --git a/Tests/CompatibleInterface/main.cpp b/Tests/CompatibleInterface/main.cpp index f5e6e38..fa299e9 100644 --- a/Tests/CompatibleInterface/main.cpp +++ b/Tests/CompatibleInterface/main.cpp @@ -23,6 +23,19 @@ #error Expected STRING_PROP3 #endif +template<bool test> +struct CMakeStaticAssert; + +template<> +struct CMakeStaticAssert<true> {}; + +enum { + NumericMaxTest1 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP1 == 100>), + NumericMaxTest2 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP2 == 250>), + NumericMinTest1 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP1 == 50>), + NumericMinTest2 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP2 == 200>) +}; + #include "iface2.h" int main(int argc, char **argv) |