| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| /* clang-format off */ | |
| #include "cmGeneratorTarget.h" | |
| /* clang-format on */ | |
| #include <algorithm> | |
| #include <cassert> | |
| #include <cerrno> | |
| #include <cstddef> | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include <iterator> | |
| #include <map> | |
| #include <set> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <cm/memory> | |
| #include <cmext/algorithm> | |
| #include "cmComputeLinkInformation.h" | |
| #include "cmGeneratorExpression.h" | |
| #include "cmList.h" | |
| #include "cmLocalGenerator.h" | |
| #include "cmMessageType.h" | |
| #include "cmRange.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmTargetTypes.h" | |
| #include "cmUnreachable.h" | |
| #include "cmValue.h" | |
| namespace { | |
| using UseTo = cmGeneratorTarget::UseTo; | |
| } | |
| cmGeneratorTarget::CompatibleInterfacesBase const& | |
| cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const | |
| { | |
| cmGeneratorTarget::CompatibleInterfaces& compat = | |
| this->CompatibleInterfacesMap[config]; | |
| if (!compat.Done) { | |
| compat.Done = true; | |
| compat.PropsBool.insert("POSITION_INDEPENDENT_CODE"); | |
| compat.PropsString.insert("AUTOUIC_OPTIONS"); | |
| std::vector<cmGeneratorTarget const*> const& deps = | |
| this->GetLinkImplementationClosure(config, UseTo::Compile); | |
| for (cmGeneratorTarget const* li : deps) { | |
| #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ | |
| if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ | |
| cmList props(*prop); \ | |
| compat.Props##x.insert(props.begin(), props.end()); \ | |
| } | |
| CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) | |
| CM_READ_COMPATIBLE_INTERFACE(STRING, String) | |
| CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin) | |
| CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax) | |
| #undef CM_READ_COMPATIBLE_INTERFACE | |
| } | |
| } | |
| return compat; | |
| } | |
| bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| if (this->GetType() == cm::TargetType::OBJECT_LIBRARY || | |
| this->GetType() == cm::TargetType::INTERFACE_LIBRARY) { | |
| return false; | |
| } | |
| return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0; | |
| } | |
| bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| if (this->GetType() == cm::TargetType::OBJECT_LIBRARY || | |
| this->GetType() == cm::TargetType::INTERFACE_LIBRARY) { | |
| return false; | |
| } | |
| return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0; | |
| } | |
| bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| if (this->GetType() == cm::TargetType::OBJECT_LIBRARY || | |
| this->GetType() == cm::TargetType::INTERFACE_LIBRARY) { | |
| return false; | |
| } | |
| return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0; | |
| } | |
| bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| if (this->GetType() == cm::TargetType::OBJECT_LIBRARY || | |
| this->GetType() == cm::TargetType::INTERFACE_LIBRARY) { | |
| return false; | |
| } | |
| return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0; | |
| } | |
| enum CompatibleType | |
| { | |
| BoolType, | |
| StringType, | |
| NumberMinType, | |
| NumberMaxType | |
| }; | |
| template <typename PropertyType> | |
| PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, | |
| std::string const& prop, | |
| std::string const& config, | |
| CompatibleType, PropertyType*); | |
| template <> | |
| bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, | |
| std::string const& prop, | |
| std::string const& config, | |
| CompatibleType /*unused*/, | |
| bool* /*unused*/) | |
| { | |
| return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); | |
| } | |
| template <> | |
| char const* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, | |
| std::string const& prop, | |
| std::string const& config, | |
| CompatibleType t, | |
| char const** /*unused*/) | |
| { | |
| switch (t) { | |
| case BoolType: | |
| CM_UNREACHABLE; | |
| return nullptr; | |
| case StringType: | |
| return tgt->GetLinkInterfaceDependentStringProperty(prop, config); | |
| case NumberMinType: | |
| return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config); | |
| case NumberMaxType: | |
| return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config); | |
| } | |
| CM_UNREACHABLE; | |
| return nullptr; | |
| } | |
| template <typename PropertyType> | |
| void checkPropertyConsistency(cmGeneratorTarget const* depender, | |
| cmGeneratorTarget const* dependee, | |
| std::string const& propName, | |
| std::set<std::string>& emitted, | |
| std::string const& config, CompatibleType t, | |
| PropertyType* /*unused*/) | |
| { | |
| cmValue prop = dependee->GetProperty(propName); | |
| if (!prop) { | |
| return; | |
| } | |
| cmList props{ *prop }; | |
| std::string pdir = | |
| cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/"); | |
| for (std::string const& p : props) { | |
| std::string pname = cmSystemTools::HelpFileName(p); | |
| std::string pfile = cmStrCat(pdir, pname, ".rst"); | |
| if (cmSystemTools::FileExists(pfile, true)) { | |
| depender->GetLocalGenerator()->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Target \"", dependee->GetName(), "\" has property \"", p, | |
| "\" listed in its ", propName, | |
| " property. " | |
| "This is not allowed. Only user-defined properties may " | |
| "appear listed in the ", | |
| propName, " property.")); | |
| return; | |
| } | |
| if (emitted.insert(p).second) { | |
| getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t, | |
| nullptr); | |
| if (cmSystemTools::GetErrorOccurredFlag()) { | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| namespace { | |
| std::string intersect(std::set<std::string> const& s1, | |
| std::set<std::string> const& s2) | |
| { | |
| std::set<std::string> intersect; | |
| std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), | |
| std::inserter(intersect, intersect.begin())); | |
| if (!intersect.empty()) { | |
| return *intersect.begin(); | |
| } | |
| return ""; | |
| } | |
| std::string intersect(std::set<std::string> const& s1, | |
| std::set<std::string> const& s2, | |
| std::set<std::string> const& 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); | |
| } | |
| std::string intersect(std::set<std::string> const& s1, | |
| std::set<std::string> const& s2, | |
| std::set<std::string> const& s3, | |
| std::set<std::string> const& 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, std::string const& config) const | |
| { | |
| cmComputeLinkInformation::ItemVector const& deps = info.GetItems(); | |
| std::set<std::string> emittedBools; | |
| static std::string const strBool = "COMPATIBLE_INTERFACE_BOOL"; | |
| std::set<std::string> emittedStrings; | |
| static std::string const strString = "COMPATIBLE_INTERFACE_STRING"; | |
| std::set<std::string> emittedMinNumbers; | |
| static std::string const strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; | |
| std::set<std::string> emittedMaxNumbers; | |
| static std::string const strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; | |
| for (auto const& dep : deps) { | |
| if (!dep.Target || | |
| dep.Target->GetType() == cm::TargetType::OBJECT_LIBRARY) { | |
| continue; | |
| } | |
| checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools, | |
| config, BoolType, nullptr); | |
| if (cmSystemTools::GetErrorOccurredFlag()) { | |
| return; | |
| } | |
| checkPropertyConsistency<char const*>(this, dep.Target, strString, | |
| emittedStrings, config, StringType, | |
| nullptr); | |
| if (cmSystemTools::GetErrorOccurredFlag()) { | |
| return; | |
| } | |
| checkPropertyConsistency<char const*>(this, dep.Target, strNumMin, | |
| emittedMinNumbers, config, | |
| NumberMinType, nullptr); | |
| if (cmSystemTools::GetErrorOccurredFlag()) { | |
| return; | |
| } | |
| checkPropertyConsistency<char const*>(this, dep.Target, strNumMax, | |
| emittedMaxNumbers, config, | |
| NumberMaxType, nullptr); | |
| if (cmSystemTools::GetErrorOccurredFlag()) { | |
| 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<std::string> props; | |
| auto 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 = cmStrCat( | |
| cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back()); | |
| this->LocalGenerator->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("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.")); | |
| } | |
| } | |
| template <typename PropertyType> | |
| std::string valueAsString(PropertyType); | |
| template <> | |
| std::string valueAsString<bool>(bool value) | |
| { | |
| return value ? "TRUE" : "FALSE"; | |
| } | |
| template <> | |
| std::string valueAsString<char const*>(char const* value) | |
| { | |
| return value ? value : "(unset)"; | |
| } | |
| template <> | |
| std::string valueAsString<std::string>(std::string value) | |
| { | |
| return value; | |
| } | |
| template <> | |
| std::string valueAsString<cmValue>(cmValue value) | |
| { | |
| return value ? *value : std::string("(unset)"); | |
| } | |
| template <> | |
| std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/) | |
| { | |
| return "(unset)"; | |
| } | |
| static std::string compatibilityType(CompatibleType t) | |
| { | |
| switch (t) { | |
| case BoolType: | |
| return "Boolean compatibility"; | |
| case StringType: | |
| return "String compatibility"; | |
| case NumberMaxType: | |
| return "Numeric maximum compatibility"; | |
| case NumberMinType: | |
| return "Numeric minimum compatibility"; | |
| } | |
| CM_UNREACHABLE; | |
| return ""; | |
| } | |
| static std::string compatibilityAgree(CompatibleType t, bool dominant) | |
| { | |
| switch (t) { | |
| case BoolType: | |
| case StringType: | |
| return dominant ? "(Disagree)\n" : "(Agree)\n"; | |
| case NumberMaxType: | |
| case NumberMinType: | |
| return dominant ? "(Dominant)\n" : "(Ignored)\n"; | |
| } | |
| CM_UNREACHABLE; | |
| return ""; | |
| } | |
| template <typename PropertyType> | |
| PropertyType getTypedProperty( | |
| cmGeneratorTarget const* tgt, std::string const& prop, | |
| cmGeneratorExpressionInterpreter* genexInterpreter = nullptr); | |
| template <> | |
| bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, | |
| std::string const& prop, | |
| cmGeneratorExpressionInterpreter* genexInterpreter) | |
| { | |
| if (!genexInterpreter) { | |
| return tgt->GetPropertyAsBool(prop); | |
| } | |
| cmValue value = tgt->GetProperty(prop); | |
| return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop)); | |
| } | |
| template <> | |
| char const* getTypedProperty<char const*>( | |
| cmGeneratorTarget const* tgt, std::string const& prop, | |
| cmGeneratorExpressionInterpreter* genexInterpreter) | |
| { | |
| cmValue value = tgt->GetProperty(prop); | |
| if (!genexInterpreter) { | |
| return value.GetCStr(); | |
| } | |
| return genexInterpreter->Evaluate(value ? *value : "", prop).c_str(); | |
| } | |
| template <> | |
| std::string getTypedProperty<std::string>( | |
| cmGeneratorTarget const* tgt, std::string const& prop, | |
| cmGeneratorExpressionInterpreter* genexInterpreter) | |
| { | |
| cmValue value = tgt->GetProperty(prop); | |
| if (!genexInterpreter) { | |
| return valueAsString(value); | |
| } | |
| return genexInterpreter->Evaluate(value ? *value : "", prop); | |
| } | |
| template <typename PropertyType> | |
| PropertyType impliedValue(PropertyType); | |
| template <> | |
| bool impliedValue<bool>(bool /*unused*/) | |
| { | |
| return false; | |
| } | |
| template <> | |
| char const* impliedValue<char const*>(char const* /*unused*/) | |
| { | |
| return ""; | |
| } | |
| template <> | |
| std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*) | |
| { | |
| return std::string(); | |
| } | |
| template <typename PropertyType> | |
| std::pair<bool, PropertyType> consistentProperty(PropertyType lhs, | |
| PropertyType rhs, | |
| CompatibleType t); | |
| template <> | |
| std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, | |
| CompatibleType /*unused*/) | |
| { | |
| return { lhs == rhs, lhs }; | |
| } | |
| static std::pair<bool, char const*> consistentStringProperty(char const* lhs, | |
| char const* rhs) | |
| { | |
| bool const b = strcmp(lhs, rhs) == 0; | |
| return { b, b ? lhs : nullptr }; | |
| } | |
| static std::pair<bool, std::string> consistentStringProperty( | |
| std::string const& lhs, std::string const& rhs) | |
| { | |
| bool const b = lhs == rhs; | |
| return { b, b ? lhs : valueAsString(nullptr) }; | |
| } | |
| static std::pair<bool, char const*> consistentNumberProperty(char const* lhs, | |
| char const* rhs, | |
| CompatibleType t) | |
| { | |
| char* pEnd; | |
| long lnum = strtol(lhs, &pEnd, 0); | |
| if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) { | |
| return { false, nullptr }; | |
| } | |
| long rnum = strtol(rhs, &pEnd, 0); | |
| if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) { | |
| return { false, nullptr }; | |
| } | |
| if (t == NumberMaxType) { | |
| return { true, std::max(lnum, rnum) == lnum ? lhs : rhs }; | |
| } | |
| return { true, std::min(lnum, rnum) == lnum ? lhs : rhs }; | |
| } | |
| template <> | |
| std::pair<bool, char const*> consistentProperty(char const* lhs, | |
| char const* rhs, | |
| CompatibleType t) | |
| { | |
| if (!lhs && !rhs) { | |
| return { true, lhs }; | |
| } | |
| if (!lhs) { | |
| return { true, rhs }; | |
| } | |
| if (!rhs) { | |
| return { true, lhs }; | |
| } | |
| switch (t) { | |
| case BoolType: { | |
| bool same = cmIsOn(lhs) == cmIsOn(rhs); | |
| return { same, same ? lhs : nullptr }; | |
| } | |
| case StringType: | |
| return consistentStringProperty(lhs, rhs); | |
| case NumberMinType: | |
| case NumberMaxType: | |
| return consistentNumberProperty(lhs, rhs, t); | |
| } | |
| CM_UNREACHABLE; | |
| return { false, nullptr }; | |
| } | |
| static std::pair<bool, std::string> consistentProperty(std::string const& lhs, | |
| std::string const& rhs, | |
| CompatibleType t) | |
| { | |
| std::string const null_ptr = valueAsString(nullptr); | |
| if (lhs == null_ptr && rhs == null_ptr) { | |
| return { true, lhs }; | |
| } | |
| if (lhs == null_ptr) { | |
| return { true, rhs }; | |
| } | |
| if (rhs == null_ptr) { | |
| return { true, lhs }; | |
| } | |
| switch (t) { | |
| case BoolType: { | |
| bool same = cmIsOn(lhs) == cmIsOn(rhs); | |
| return { same, same ? lhs : null_ptr }; | |
| } | |
| case StringType: | |
| return consistentStringProperty(lhs, rhs); | |
| case NumberMinType: | |
| case NumberMaxType: { | |
| auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t); | |
| return { value.first, | |
| value.first ? std::string(value.second) : null_ptr }; | |
| } | |
| } | |
| CM_UNREACHABLE; | |
| return { false, null_ptr }; | |
| } | |
| template <typename PropertyType> | |
| PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, | |
| std::string const& p, | |
| std::string const& config, | |
| char const* defaultValue, | |
| CompatibleType t, | |
| PropertyType* /*unused*/) | |
| { | |
| PropertyType propContent = getTypedProperty<PropertyType>(tgt, p); | |
| std::vector<std::string> headPropKeys = tgt->GetPropertyKeys(); | |
| bool const explicitlySet = cm::contains(headPropKeys, p); | |
| bool const impliedByUse = tgt->IsNullImpliedByLinkLibraries(p); | |
| assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); | |
| std::vector<cmGeneratorTarget const*> const& deps = | |
| tgt->GetLinkImplementationClosure(config, UseTo::Compile); | |
| if (deps.empty()) { | |
| return propContent; | |
| } | |
| bool propInitialized = explicitlySet; | |
| std::string report = cmStrCat(" * Target \"", tgt->GetName()); | |
| if (explicitlySet) { | |
| report += "\" has property content \""; | |
| report += valueAsString<PropertyType>(propContent); | |
| report += "\"\n"; | |
| } else if (impliedByUse) { | |
| report += "\" property is implied by use.\n"; | |
| } else { | |
| report += "\" property not set.\n"; | |
| } | |
| std::string interfaceProperty = "INTERFACE_" + p; | |
| std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter; | |
| if (p == "POSITION_INDEPENDENT_CODE") { | |
| // Corresponds to EvaluatingPICExpression. | |
| genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>( | |
| tgt->GetLocalGenerator(), config, tgt); | |
| } | |
| for (cmGeneratorTarget const* theTarget : deps) { | |
| // An error should be reported if one dependency | |
| // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other | |
| // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the | |
| // target itself has a POSITION_INDEPENDENT_CODE which disagrees | |
| // with a dependency. | |
| std::vector<std::string> propKeys = theTarget->GetPropertyKeys(); | |
| bool const ifaceIsSet = cm::contains(propKeys, interfaceProperty); | |
| PropertyType ifacePropContent = getTypedProperty<PropertyType>( | |
| theTarget, interfaceProperty, genexInterpreter.get()); | |
| std::string reportEntry; | |
| if (ifaceIsSet) { | |
| reportEntry += " * Target \""; | |
| reportEntry += theTarget->GetName(); | |
| reportEntry += "\" property value \""; | |
| reportEntry += valueAsString<PropertyType>(ifacePropContent); | |
| reportEntry += "\" "; | |
| } | |
| if (explicitlySet) { | |
| if (ifaceIsSet) { | |
| std::pair<bool, PropertyType> consistent = | |
| consistentProperty(propContent, ifacePropContent, t); | |
| report += reportEntry; | |
| report += compatibilityAgree(t, propContent != consistent.second); | |
| if (!consistent.first) { | |
| cmSystemTools::Error( | |
| cmStrCat("Property ", p, " on target \"", tgt->GetName(), | |
| "\" does\nnot match the INTERFACE_", p, | |
| " property requirement\nof dependency \"", | |
| theTarget->GetName(), "\".\n")); | |
| break; | |
| } | |
| propContent = consistent.second; | |
| continue; | |
| } | |
| // Explicitly set on target and not set in iface. Can't disagree. | |
| continue; | |
| } | |
| if (impliedByUse) { | |
| propContent = impliedValue<PropertyType>(propContent); | |
| if (ifaceIsSet) { | |
| std::pair<bool, PropertyType> consistent = | |
| consistentProperty(propContent, ifacePropContent, t); | |
| report += reportEntry; | |
| report += compatibilityAgree(t, propContent != consistent.second); | |
| if (!consistent.first) { | |
| cmSystemTools::Error( | |
| cmStrCat("Property ", p, " on target \"", tgt->GetName(), | |
| "\" is\nimplied to be ", defaultValue, | |
| " because it was used to determine the link libraries\n" | |
| "already. The INTERFACE_", | |
| p, " property on\ndependency \"", theTarget->GetName(), | |
| "\" is in conflict.\n")); | |
| break; | |
| } | |
| propContent = consistent.second; | |
| continue; | |
| } | |
| // Implicitly set on target and not set in iface. Can't disagree. | |
| continue; | |
| } | |
| if (ifaceIsSet) { | |
| if (propInitialized) { | |
| std::pair<bool, PropertyType> consistent = | |
| consistentProperty(propContent, ifacePropContent, t); | |
| report = | |
| cmStrCat(std::move(report), reportEntry, | |
| compatibilityAgree(t, propContent != consistent.second)); | |
| if (!consistent.first) { | |
| cmSystemTools::Error(cmStrCat( | |
| "The INTERFACE_", p, " property of \"", theTarget->GetName(), | |
| "\" does\nnot agree with the value of ", p, | |
| " already determined\nfor \"", tgt->GetName(), "\".\n")); | |
| break; | |
| } | |
| propContent = consistent.second; | |
| continue; | |
| } | |
| report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n"); | |
| propContent = ifacePropContent; | |
| propInitialized = true; | |
| } else { | |
| // Not set. Nothing to agree on. | |
| continue; | |
| } | |
| } | |
| tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent), | |
| report, compatibilityType(t)); | |
| return propContent; | |
| } | |
| bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE", | |
| BoolType, nullptr); | |
| } | |
| std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| return checkInterfacePropertyCompatibility<std::string>( | |
| this, p, config, "FALSE", BoolType, nullptr); | |
| } | |
| char const* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| return checkInterfacePropertyCompatibility<char const*>( | |
| this, p, config, "empty", StringType, nullptr); | |
| } | |
| char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| return checkInterfacePropertyCompatibility<char const*>( | |
| this, p, config, "empty", NumberMinType, nullptr); | |
| } | |
| char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty( | |
| std::string const& p, std::string const& config) const | |
| { | |
| return checkInterfacePropertyCompatibility<char const*>( | |
| this, p, config, "empty", NumberMaxType, nullptr); | |
| } |