diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 845c052eb..1f3effb5f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1524,6 +1524,240 @@ bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty( return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0; } +template +PropertyType getLinkInterfaceDependentProperty(cmTarget const* tgt, + const std::string& prop, + const std::string& config, + cmTarget::CompatibleType, + PropertyType *); + +template<> +bool getLinkInterfaceDependentProperty(cmTarget const* tgt, + const std::string& prop, + const std::string& config, + cmTarget::CompatibleType, bool *) +{ + return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); +} + +template<> +const char * getLinkInterfaceDependentProperty(cmTarget const* tgt, + const std::string& prop, + const std::string& config, + cmTarget::CompatibleType t, + const char **) +{ + switch(t) + { + case cmTarget::BoolType: + assert(0 && "String compatibility check function called for boolean"); + return 0; + case cmTarget::StringType: + return tgt->GetLinkInterfaceDependentStringProperty(prop, config); + case cmTarget::NumberMinType: + return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config); + case cmTarget::NumberMaxType: + return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config); + } + assert(0 && "Unreachable!"); + return 0; +} + +//---------------------------------------------------------------------------- +template +void checkPropertyConsistency(cmTarget const* depender, + cmTarget const* dependee, + const std::string& propName, + std::set &emitted, + const std::string& config, + cmTarget::CompatibleType t, + PropertyType *) +{ + const char *prop = dependee->GetProperty(propName); + if (!prop) + { + return; + } + + std::vector props; + cmSystemTools::ExpandListArgument(prop, props); + std::string pdir = + dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT"); + pdir += "/Help/prop_tgt/"; + + for(std::vector::iterator pi = props.begin(); + pi != props.end(); ++pi) + { + std::string pname = cmSystemTools::HelpFileName(*pi); + std::string pfile = pdir + pname + ".rst"; + if(cmSystemTools::FileExists(pfile.c_str(), true)) + { + std::ostringstream e; + e << "Target \"" << dependee->GetName() << "\" has property \"" + << *pi << "\" listed in its " << propName << " property. " + "This is not allowed. Only user-defined properties may appear " + "listed in the " << propName << " property."; + depender->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + if(emitted.insert(*pi).second) + { + getLinkInterfaceDependentProperty(depender, *pi, config, + t, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + } + } +} + +static std::string intersect(const std::set &s1, + const std::set &s2) +{ + std::set 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 std::string intersect(const std::set &s1, + const std::set &s2, + const std::set &s3) +{ + std::string result; + result = intersect(s1, s2); + if (!result.empty()) + return result; + result = intersect(s1, s3); + if (!result.empty()) + return result; + return intersect(s2, s3); +} + +static std::string intersect(const std::set &s1, + const std::set &s2, + const std::set &s3, + const std::set &s4) +{ + std::string 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 cmGeneratorTarget::CheckPropertyCompatibility( + cmComputeLinkInformation *info, const std::string& config) const +{ + const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); + + std::set emittedBools; + static std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; + std::set emittedStrings; + static std::string strString = "COMPATIBLE_INTERFACE_STRING"; + std::set emittedMinNumbers; + static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; + std::set emittedMaxNumbers; + static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; + + for(cmComputeLinkInformation::ItemVector::const_iterator li = + deps.begin(); li != deps.end(); ++li) + { + if (!li->Target) + { + continue; + } + + checkPropertyConsistency(this->Target, li->Target, + strBool, + emittedBools, config, cmTarget::BoolType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency(this->Target, li->Target, + strString, + emittedStrings, config, + cmTarget::StringType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency(this->Target, li->Target, + strNumMin, + emittedMinNumbers, config, + cmTarget::NumberMinType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency(this->Target, li->Target, + strNumMax, + emittedMaxNumbers, config, + cmTarget::NumberMaxType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + } + + std::string prop = intersect(emittedBools, + emittedStrings, + emittedMinNumbers, + emittedMaxNumbers); + + if (!prop.empty()) + { + // Use a sorted std::vector to keep the error message sorted. + std::vector props; + std::set::const_iterator i = emittedBools.find(prop); + if (i != emittedBools.end()) + { + props.push_back(strBool); + } + i = emittedStrings.find(prop); + if (i != emittedStrings.end()) + { + props.push_back(strString); + } + i = emittedMinNumbers.find(prop); + if (i != emittedMinNumbers.end()) + { + props.push_back(strNumMin); + } + i = emittedMaxNumbers.find(prop); + if (i != emittedMaxNumbers.end()) + { + props.push_back(strNumMax); + } + std::sort(props.begin(), props.end()); + + std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", "); + propsString += " and the " + props.back(); + + std::ostringstream 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, a numeric minimum, a numeric maximum or a " + "string interpretation, but not a mixture."; + this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str()); + } +} //---------------------------------------------------------------------------- cmComputeLinkInformation* @@ -1550,7 +1784,7 @@ cmGeneratorTarget::GetLinkInformation(const std::string& config) const if (info) { - this->Target->CheckPropertyCompatibility(info, config); + this->CheckPropertyCompatibility(info, config); } } return i->second; diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index e53f0984f..ae86e19fb 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -222,6 +222,9 @@ private: cmTargetLinkInformationMap; mutable cmTargetLinkInformationMap LinkInformation; + void CheckPropertyCompatibility(cmComputeLinkInformation *info, + const std::string& config) const; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d8904eade..b1655453d 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -4554,23 +4554,16 @@ const char *getTypedProperty(cmTarget const* tgt, return tgt->GetProperty(prop); } -enum CompatibleType -{ - BoolType, - StringType, - NumberMinType, - NumberMaxType -}; - //---------------------------------------------------------------------------- template std::pair consistentProperty(PropertyType lhs, PropertyType rhs, - CompatibleType t); + cmTarget::CompatibleType t); //---------------------------------------------------------------------------- template<> -std::pair consistentProperty(bool lhs, bool rhs, CompatibleType) +std::pair consistentProperty(bool lhs, bool rhs, + cmTarget::CompatibleType) { return std::make_pair(lhs == rhs, lhs); } @@ -4585,8 +4578,8 @@ std::pair consistentStringProperty(const char *lhs, //---------------------------------------------------------------------------- std::pair consistentNumberProperty(const char *lhs, - const char *rhs, - CompatibleType t) + const char *rhs, + cmTarget::CompatibleType t) { char *pEnd; @@ -4604,7 +4597,7 @@ std::pair consistentNumberProperty(const char *lhs, return std::pair(false, null_ptr); } - if (t == NumberMaxType) + if (t == cmTarget::NumberMaxType) { return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs); } @@ -4618,7 +4611,7 @@ std::pair consistentNumberProperty(const char *lhs, template<> std::pair consistentProperty(const char *lhs, const char *rhs, - CompatibleType t) + cmTarget::CompatibleType t) { if (!lhs && !rhs) { @@ -4637,13 +4630,13 @@ std::pair consistentProperty(const char *lhs, switch(t) { - case BoolType: + case cmTarget::BoolType: assert(0 && "consistentProperty for strings called with BoolType"); return std::pair(false, null_ptr); - case StringType: + case cmTarget::StringType: return consistentStringProperty(lhs, rhs); - case NumberMinType: - case NumberMaxType: + case cmTarget::NumberMinType: + case cmTarget::NumberMaxType: return consistentNumberProperty(lhs, rhs, t); } assert(0 && "Unreachable!"); @@ -4718,17 +4711,17 @@ cmTarget::ReportPropertyOrigin(const std::string &p, } //---------------------------------------------------------------------------- -std::string compatibilityType(CompatibleType t) +std::string compatibilityType(cmTarget::CompatibleType t) { switch(t) { - case BoolType: + case cmTarget::BoolType: return "Boolean compatibility"; - case StringType: + case cmTarget::StringType: return "String compatibility"; - case NumberMaxType: + case cmTarget::NumberMaxType: return "Numeric maximum compatibility"; - case NumberMinType: + case cmTarget::NumberMinType: return "Numeric minimum compatibility"; } assert(0 && "Unreachable!"); @@ -4736,15 +4729,15 @@ std::string compatibilityType(CompatibleType t) } //---------------------------------------------------------------------------- -std::string compatibilityAgree(CompatibleType t, bool dominant) +std::string compatibilityAgree(cmTarget::CompatibleType t, bool dominant) { switch(t) { - case BoolType: - case StringType: + case cmTarget::BoolType: + case cmTarget::StringType: return dominant ? "(Disagree)\n" : "(Agree)\n"; - case NumberMaxType: - case NumberMinType: + case cmTarget::NumberMaxType: + case cmTarget::NumberMinType: return dominant ? "(Dominant)\n" : "(Ignored)\n"; } assert(0 && "Unreachable!"); @@ -4757,7 +4750,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, const std::string &p, const std::string& config, const char *defaultValue, - CompatibleType t, + cmTarget::CompatibleType t, PropertyType *) { PropertyType propContent = getTypedProperty(tgt, p); @@ -6224,240 +6217,6 @@ std::string cmTarget::CheckCMP0004(std::string const& item) const return lib; } -template -PropertyType getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType, - PropertyType *); - -template<> -bool getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType, bool *) -{ - return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); -} - -template<> -const char * getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType t, - const char **) -{ - switch(t) - { - case BoolType: - assert(0 && "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(0 && "Unreachable!"); - return 0; -} - -//---------------------------------------------------------------------------- -template -void checkPropertyConsistency(cmTarget const* depender, - cmTarget const* dependee, - const std::string& propName, - std::set &emitted, - const std::string& config, - CompatibleType t, - PropertyType *) -{ - const char *prop = dependee->GetProperty(propName); - if (!prop) - { - return; - } - - std::vector props; - cmSystemTools::ExpandListArgument(prop, props); - std::string pdir = - dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT"); - pdir += "/Help/prop_tgt/"; - - for(std::vector::iterator pi = props.begin(); - pi != props.end(); ++pi) - { - std::string pname = cmSystemTools::HelpFileName(*pi); - std::string pfile = pdir + pname + ".rst"; - if(cmSystemTools::FileExists(pfile.c_str(), true)) - { - std::ostringstream e; - e << "Target \"" << dependee->GetName() << "\" has property \"" - << *pi << "\" listed in its " << propName << " property. " - "This is not allowed. Only user-defined properties may appear " - "listed in the " << propName << " property."; - depender->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str()); - return; - } - if(emitted.insert(*pi).second) - { - getLinkInterfaceDependentProperty(depender, *pi, config, - t, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - } - } -} - -static std::string intersect(const std::set &s1, - const std::set &s2) -{ - std::set 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 std::string intersect(const std::set &s1, - const std::set &s2, - const std::set &s3) -{ - std::string result; - result = intersect(s1, s2); - if (!result.empty()) - return result; - result = intersect(s1, s3); - if (!result.empty()) - return result; - return intersect(s2, s3); -} -static std::string intersect(const std::set &s1, - const std::set &s2, - const std::set &s3, - const std::set &s4) -{ - std::string 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 std::string& config) const -{ - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); - - std::set emittedBools; - static std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; - std::set emittedStrings; - static std::string strString = "COMPATIBLE_INTERFACE_STRING"; - std::set emittedMinNumbers; - static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; - std::set emittedMaxNumbers; - static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; - - for(cmComputeLinkInformation::ItemVector::const_iterator li = - deps.begin(); - li != deps.end(); ++li) - { - if (!li->Target) - { - continue; - } - - checkPropertyConsistency(this, li->Target, - strBool, - emittedBools, config, BoolType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency(this, li->Target, - strString, - emittedStrings, config, - StringType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency(this, li->Target, - strNumMin, - emittedMinNumbers, config, - NumberMinType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency(this, li->Target, - strNumMax, - emittedMaxNumbers, config, - NumberMaxType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - } - - std::string prop = intersect(emittedBools, - emittedStrings, - emittedMinNumbers, - emittedMaxNumbers); - - if (!prop.empty()) - { - // Use a sorted std::vector to keep the error message sorted. - std::vector props; - std::set::const_iterator i = emittedBools.find(prop); - if (i != emittedBools.end()) - { - props.push_back(strBool); - } - i = emittedStrings.find(prop); - if (i != emittedStrings.end()) - { - props.push_back(strString); - } - i = emittedMinNumbers.find(prop); - if (i != emittedMinNumbers.end()) - { - props.push_back(strNumMin); - } - i = emittedMaxNumbers.find(prop); - if (i != emittedMaxNumbers.end()) - { - props.push_back(strNumMax); - } - std::sort(props.begin(), props.end()); - - std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", "); - propsString += " and the " + props.back(); - - std::ostringstream 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, a numeric minimum, a numeric maximum or a " - "string interpretation, but not a mixture."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } -} - //---------------------------------------------------------------------------- std::string cmTarget::GetFrameworkDirectory(const std::string& config, bool rootDir) const diff --git a/Source/cmTarget.h b/Source/cmTarget.h index e3410aa95..8af74efdb 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -590,6 +590,14 @@ public: return this->LinkLibrariesForVS6;} #endif + enum CompatibleType + { + BoolType, + StringType, + NumberMinType, + NumberMaxType + }; + private: bool HandleLocationPropertyPolicy(cmMakefile* context) const; @@ -754,9 +762,6 @@ private: struct CompileInfo; CompileInfo const* GetCompileInfo(const std::string& config) const; - void CheckPropertyCompatibility(cmComputeLinkInformation *info, - const std::string& config) const; - LinkInterface const* GetImportLinkInterface(const std::string& config, cmTarget const* head, bool usage_requirements_only) const;