|
|
@@ -4455,26 +4455,107 @@ const char *getTypedProperty<const char *>(cmTarget *tgt, const char *prop,
|
|
|
return tgt->GetProperty(prop);
|
|
|
}
|
|
|
|
|
|
+enum CompatibleType
|
|
|
+{
|
|
|
+ BoolType,
|
|
|
+ StringType,
|
|
|
+ NumberMinType,
|
|
|
+ NumberMaxType
|
|
|
+};
|
|
|
+
|
|
|
//----------------------------------------------------------------------------
|
|
|
template<typename PropertyType>
|
|
|
-bool consistentProperty(PropertyType lhs, PropertyType rhs);
|
|
|
+PropertyType consistentProperty(PropertyType lhs, PropertyType rhs,
|
|
|
+ CompatibleType t);
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
template<>
|
|
|
-bool consistentProperty(bool lhs, bool rhs)
|
|
|
+bool consistentProperty(bool lhs, bool rhs, CompatibleType)
|
|
|
{
|
|
|
return lhs == rhs;
|
|
|
}
|
|
|
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+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<>
|
|
|
-bool consistentProperty(const char *lhs, const char *rhs)
|
|
|
+const char* consistentProperty(const char *lhs, const char *rhs,
|
|
|
+ CompatibleType t)
|
|
|
{
|
|
|
if (!lhs && !rhs)
|
|
|
- return true;
|
|
|
- if (!lhs || !rhs)
|
|
|
- return false;
|
|
|
- return strcmp(lhs, rhs) == 0;
|
|
|
+ {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ if (!lhs)
|
|
|
+ {
|
|
|
+ return rhs ? rhs : "";
|
|
|
+ }
|
|
|
+ if (!rhs)
|
|
|
+ {
|
|
|
+ return lhs ? lhs : "";
|
|
|
+ }
|
|
|
+ switch(t)
|
|
|
+ {
|
|
|
+ case BoolType:
|
|
|
+ assert(!"consistentProperty for strings called with BoolType");
|
|
|
+ return 0;
|
|
|
+ case StringType:
|
|
|
+ return consistentStringProperty(lhs, rhs);
|
|
|
+ case NumberMinType:
|
|
|
+ case NumberMaxType:
|
|
|
+ return consistentNumberProperty(lhs, rhs, t);
|
|
|
+ }
|
|
|
+ assert(!"Unreachable!");
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+template<typename PropertyType>
|
|
|
+PropertyType impliedValue(PropertyType);
|
|
|
+template<>
|
|
|
+bool impliedValue<bool>(bool)
|
|
|
+{
|
|
|
+ return false;
|
|
|
+}
|
|
|
+template<>
|
|
|
+const char* impliedValue<const char*>(const char*)
|
|
|
+{
|
|
|
+ return "";
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
@@ -4483,6 +4564,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
const std::string &p,
|
|
|
const char *config,
|
|
|
const char *defaultValue,
|
|
|
+ CompatibleType t,
|
|
|
PropertyType *)
|
|
|
{
|
|
|
PropertyType propContent = getTypedProperty<PropertyType>(tgt, p.c_str(),
|
|
|
@@ -4528,7 +4610,9 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
{
|
|
|
if (ifaceIsSet)
|
|
|
{
|
|
|
- if (!consistentProperty(propContent, ifacePropContent))
|
|
|
+ PropertyType consistent = consistentProperty(propContent,
|
|
|
+ ifacePropContent, t);
|
|
|
+ if (!consistent)
|
|
|
{
|
|
|
cmOStringStream e;
|
|
|
e << "Property " << p << " on target \""
|
|
|
@@ -4541,6 +4625,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
else
|
|
|
{
|
|
|
// Agree
|
|
|
+ propContent = consistent;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
@@ -4552,9 +4637,12 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
}
|
|
|
else if (impliedByUse)
|
|
|
{
|
|
|
+ propContent = impliedValue<PropertyType>(propContent);
|
|
|
if (ifaceIsSet)
|
|
|
{
|
|
|
- if (!consistentProperty(propContent, ifacePropContent))
|
|
|
+ PropertyType consistent = consistentProperty(propContent,
|
|
|
+ ifacePropContent, t);
|
|
|
+ if (!consistent)
|
|
|
{
|
|
|
cmOStringStream e;
|
|
|
e << "Property " << p << " on target \""
|
|
|
@@ -4568,6 +4656,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
else
|
|
|
{
|
|
|
// Agree
|
|
|
+ propContent = consistent;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
@@ -4583,7 +4672,9 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
{
|
|
|
if (propInitialized)
|
|
|
{
|
|
|
- if (!consistentProperty(propContent, ifacePropContent))
|
|
|
+ PropertyType consistent = consistentProperty(propContent,
|
|
|
+ ifacePropContent, t);
|
|
|
+ if (!consistent)
|
|
|
{
|
|
|
cmOStringStream e;
|
|
|
e << "The INTERFACE_" << p << " property of \""
|
|
|
@@ -4596,6 +4687,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
|
|
|
else
|
|
|
{
|
|
|
// Agree.
|
|
|
+ propContent = consistent;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
@@ -4620,7 +4712,7 @@ bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
|
|
|
const char *config)
|
|
|
{
|
|
|
return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
|
|
|
- 0);
|
|
|
+ BoolType, 0);
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
@@ -4631,7 +4723,32 @@ const char * cmTarget::GetLinkInterfaceDependentStringProperty(
|
|
|
return checkInterfacePropertyCompatibility<const char *>(this,
|
|
|
p,
|
|
|
config,
|
|
|
- "empty", 0);
|
|
|
+ "empty",
|
|
|
+ StringType, 0);
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+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);
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
@@ -4702,6 +4819,30 @@ bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p,
|
|
|
config);
|
|
|
}
|
|
|
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+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
|
|
|
{
|
|
|
@@ -5680,23 +5821,39 @@ template<typename PropertyType>
|
|
|
PropertyType getLinkInterfaceDependentProperty(cmTarget *tgt,
|
|
|
const std::string prop,
|
|
|
const char *config,
|
|
|
+ CompatibleType,
|
|
|
PropertyType *);
|
|
|
|
|
|
template<>
|
|
|
bool getLinkInterfaceDependentProperty(cmTarget *tgt,
|
|
|
- const std::string prop,
|
|
|
- const char *config, bool *)
|
|
|
+ const std::string prop,
|
|
|
+ const char *config,
|
|
|
+ CompatibleType, bool *)
|
|
|
{
|
|
|
return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
|
|
|
}
|
|
|
|
|
|
template<>
|
|
|
const char * getLinkInterfaceDependentProperty(cmTarget *tgt,
|
|
|
- const std::string prop,
|
|
|
- const char *config,
|
|
|
- const char **)
|
|
|
+ const std::string prop,
|
|
|
+ const char *config,
|
|
|
+ CompatibleType t,
|
|
|
+ const char **)
|
|
|
{
|
|
|
- return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
|
|
|
+ switch(t)
|
|
|
+ {
|
|
|
+ case BoolType:
|
|
|
+ assert(!"String compatibility check function called for boolean");
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
@@ -5705,6 +5862,7 @@ void checkPropertyConsistency(cmTarget *depender, cmTarget *dependee,
|
|
|
const char *propName,
|
|
|
std::set<cmStdString> &emitted,
|
|
|
const char *config,
|
|
|
+ CompatibleType t,
|
|
|
PropertyType *)
|
|
|
{
|
|
|
const char *prop = dependee->GetProperty(propName);
|
|
|
@@ -5737,7 +5895,7 @@ void checkPropertyConsistency(cmTarget *depender, cmTarget *dependee,
|
|
|
if(emitted.insert(*pi).second)
|
|
|
{
|
|
|
getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config,
|
|
|
- 0);
|
|
|
+ t, 0);
|
|
|
if (cmSystemTools::GetErrorOccuredFlag())
|
|
|
{
|
|
|
return;
|
|
|
@@ -5746,6 +5904,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)
|
|
|
@@ -5754,6 +5956,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();
|
|
|
@@ -5766,35 +5970,84 @@ void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info,
|
|
|
|
|
|
checkPropertyConsistency<bool>(this, li->Target,
|
|
|
"COMPATIBLE_INTERFACE_BOOL",
|
|
|
- emittedBools, config, 0);
|
|
|
+ emittedBools, config, BoolType, 0);
|
|
|
if (cmSystemTools::GetErrorOccuredFlag())
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
checkPropertyConsistency<const char *>(this, li->Target,
|
|
|
"COMPATIBLE_INTERFACE_STRING",
|
|
|
- emittedStrings, config, 0);
|
|
|
+ emittedStrings, config,
|
|
|
+ StringType, 0);
|
|
|
+ if (cmSystemTools::GetErrorOccuredFlag())
|
|
|
+ {
|
|
|
+ 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());
|
|
|
}
|
|
|
}
|
|
|
|