cmGeneratorTarget_CompatibleInterface.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. /* clang-format off */
  4. #include "cmGeneratorTarget.h"
  5. /* clang-format on */
  6. #include <algorithm>
  7. #include <cassert>
  8. #include <cerrno>
  9. #include <cstdlib>
  10. #include <cstring>
  11. #include <iterator>
  12. #include <map>
  13. #include <set>
  14. #include <sstream>
  15. #include <string>
  16. #include <utility>
  17. #include <vector>
  18. #include <cm/memory>
  19. #include <cmext/algorithm>
  20. #include "cmComputeLinkInformation.h"
  21. #include "cmGeneratorExpression.h"
  22. #include "cmList.h"
  23. #include "cmLocalGenerator.h"
  24. #include "cmMessageType.h"
  25. #include "cmRange.h"
  26. #include "cmStateTypes.h"
  27. #include "cmStringAlgorithms.h"
  28. #include "cmSystemTools.h"
  29. #include "cmValue.h"
  30. const cmGeneratorTarget::CompatibleInterfacesBase&
  31. cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
  32. {
  33. cmGeneratorTarget::CompatibleInterfaces& compat =
  34. this->CompatibleInterfacesMap[config];
  35. if (!compat.Done) {
  36. compat.Done = true;
  37. compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
  38. compat.PropsString.insert("AUTOUIC_OPTIONS");
  39. std::vector<cmGeneratorTarget const*> const& deps =
  40. this->GetLinkImplementationClosure(config);
  41. for (cmGeneratorTarget const* li : deps) {
  42. #define CM_READ_COMPATIBLE_INTERFACE(X, x) \
  43. if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
  44. cmList props(*prop); \
  45. compat.Props##x.insert(props.begin(), props.end()); \
  46. }
  47. CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
  48. CM_READ_COMPATIBLE_INTERFACE(STRING, String)
  49. CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
  50. CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
  51. #undef CM_READ_COMPATIBLE_INTERFACE
  52. }
  53. }
  54. return compat;
  55. }
  56. bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
  57. const std::string& p, const std::string& config) const
  58. {
  59. if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
  60. this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  61. return false;
  62. }
  63. return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
  64. }
  65. bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
  66. const std::string& p, const std::string& config) const
  67. {
  68. if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
  69. this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  70. return false;
  71. }
  72. return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
  73. }
  74. bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
  75. const std::string& p, const std::string& config) const
  76. {
  77. if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
  78. this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  79. return false;
  80. }
  81. return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
  82. }
  83. bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
  84. const std::string& p, const std::string& config) const
  85. {
  86. if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
  87. this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  88. return false;
  89. }
  90. return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
  91. }
  92. enum CompatibleType
  93. {
  94. BoolType,
  95. StringType,
  96. NumberMinType,
  97. NumberMaxType
  98. };
  99. template <typename PropertyType>
  100. PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
  101. const std::string& prop,
  102. const std::string& config,
  103. CompatibleType, PropertyType*);
  104. template <>
  105. bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
  106. const std::string& prop,
  107. const std::string& config,
  108. CompatibleType /*unused*/,
  109. bool* /*unused*/)
  110. {
  111. return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
  112. }
  113. template <>
  114. const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
  115. const std::string& prop,
  116. const std::string& config,
  117. CompatibleType t,
  118. const char** /*unused*/)
  119. {
  120. switch (t) {
  121. case BoolType:
  122. assert(false &&
  123. "String compatibility check function called for boolean");
  124. return nullptr;
  125. case StringType:
  126. return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
  127. case NumberMinType:
  128. return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
  129. case NumberMaxType:
  130. return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
  131. }
  132. assert(false && "Unreachable!");
  133. return nullptr;
  134. }
  135. template <typename PropertyType>
  136. void checkPropertyConsistency(cmGeneratorTarget const* depender,
  137. cmGeneratorTarget const* dependee,
  138. const std::string& propName,
  139. std::set<std::string>& emitted,
  140. const std::string& config, CompatibleType t,
  141. PropertyType* /*unused*/)
  142. {
  143. cmValue prop = dependee->GetProperty(propName);
  144. if (!prop) {
  145. return;
  146. }
  147. cmList props{ *prop };
  148. std::string pdir =
  149. cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
  150. for (std::string const& p : props) {
  151. std::string pname = cmSystemTools::HelpFileName(p);
  152. std::string pfile = pdir + pname + ".rst";
  153. if (cmSystemTools::FileExists(pfile, true)) {
  154. std::ostringstream e;
  155. e << "Target \"" << dependee->GetName() << "\" has property \"" << p
  156. << "\" listed in its " << propName
  157. << " property. "
  158. "This is not allowed. Only user-defined properties may appear "
  159. "listed in the "
  160. << propName << " property.";
  161. depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
  162. e.str());
  163. return;
  164. }
  165. if (emitted.insert(p).second) {
  166. getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
  167. nullptr);
  168. if (cmSystemTools::GetErrorOccurredFlag()) {
  169. return;
  170. }
  171. }
  172. }
  173. }
  174. namespace {
  175. std::string intersect(const std::set<std::string>& s1,
  176. const std::set<std::string>& s2)
  177. {
  178. std::set<std::string> intersect;
  179. std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
  180. std::inserter(intersect, intersect.begin()));
  181. if (!intersect.empty()) {
  182. return *intersect.begin();
  183. }
  184. return "";
  185. }
  186. std::string intersect(const std::set<std::string>& s1,
  187. const std::set<std::string>& s2,
  188. const std::set<std::string>& s3)
  189. {
  190. std::string result;
  191. result = intersect(s1, s2);
  192. if (!result.empty()) {
  193. return result;
  194. }
  195. result = intersect(s1, s3);
  196. if (!result.empty()) {
  197. return result;
  198. }
  199. return intersect(s2, s3);
  200. }
  201. std::string intersect(const std::set<std::string>& s1,
  202. const std::set<std::string>& s2,
  203. const std::set<std::string>& s3,
  204. const std::set<std::string>& s4)
  205. {
  206. std::string result;
  207. result = intersect(s1, s2);
  208. if (!result.empty()) {
  209. return result;
  210. }
  211. result = intersect(s1, s3);
  212. if (!result.empty()) {
  213. return result;
  214. }
  215. result = intersect(s1, s4);
  216. if (!result.empty()) {
  217. return result;
  218. }
  219. return intersect(s2, s3, s4);
  220. }
  221. }
  222. void cmGeneratorTarget::CheckPropertyCompatibility(
  223. cmComputeLinkInformation& info, const std::string& config) const
  224. {
  225. const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
  226. std::set<std::string> emittedBools;
  227. static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
  228. std::set<std::string> emittedStrings;
  229. static const std::string strString = "COMPATIBLE_INTERFACE_STRING";
  230. std::set<std::string> emittedMinNumbers;
  231. static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
  232. std::set<std::string> emittedMaxNumbers;
  233. static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
  234. for (auto const& dep : deps) {
  235. if (!dep.Target || dep.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  236. continue;
  237. }
  238. checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
  239. config, BoolType, nullptr);
  240. if (cmSystemTools::GetErrorOccurredFlag()) {
  241. return;
  242. }
  243. checkPropertyConsistency<const char*>(this, dep.Target, strString,
  244. emittedStrings, config, StringType,
  245. nullptr);
  246. if (cmSystemTools::GetErrorOccurredFlag()) {
  247. return;
  248. }
  249. checkPropertyConsistency<const char*>(this, dep.Target, strNumMin,
  250. emittedMinNumbers, config,
  251. NumberMinType, nullptr);
  252. if (cmSystemTools::GetErrorOccurredFlag()) {
  253. return;
  254. }
  255. checkPropertyConsistency<const char*>(this, dep.Target, strNumMax,
  256. emittedMaxNumbers, config,
  257. NumberMaxType, nullptr);
  258. if (cmSystemTools::GetErrorOccurredFlag()) {
  259. return;
  260. }
  261. }
  262. std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
  263. emittedMaxNumbers);
  264. if (!prop.empty()) {
  265. // Use a sorted std::vector to keep the error message sorted.
  266. std::vector<std::string> props;
  267. auto i = emittedBools.find(prop);
  268. if (i != emittedBools.end()) {
  269. props.push_back(strBool);
  270. }
  271. i = emittedStrings.find(prop);
  272. if (i != emittedStrings.end()) {
  273. props.push_back(strString);
  274. }
  275. i = emittedMinNumbers.find(prop);
  276. if (i != emittedMinNumbers.end()) {
  277. props.push_back(strNumMin);
  278. }
  279. i = emittedMaxNumbers.find(prop);
  280. if (i != emittedMaxNumbers.end()) {
  281. props.push_back(strNumMax);
  282. }
  283. std::sort(props.begin(), props.end());
  284. std::string propsString = cmStrCat(
  285. cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
  286. std::ostringstream e;
  287. e << "Property \"" << prop << "\" appears in both the " << propsString
  288. << " property in the dependencies of target \"" << this->GetName()
  289. << "\". This is not allowed. A property may only require "
  290. "compatibility "
  291. "in a boolean interpretation, a numeric minimum, a numeric maximum "
  292. "or a "
  293. "string interpretation, but not a mixture.";
  294. this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
  295. }
  296. }
  297. template <typename PropertyType>
  298. std::string valueAsString(PropertyType);
  299. template <>
  300. std::string valueAsString<bool>(bool value)
  301. {
  302. return value ? "TRUE" : "FALSE";
  303. }
  304. template <>
  305. std::string valueAsString<const char*>(const char* value)
  306. {
  307. return value ? value : "(unset)";
  308. }
  309. template <>
  310. std::string valueAsString<std::string>(std::string value)
  311. {
  312. return value;
  313. }
  314. template <>
  315. std::string valueAsString<cmValue>(cmValue value)
  316. {
  317. return value ? *value : std::string("(unset)");
  318. }
  319. template <>
  320. std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
  321. {
  322. return "(unset)";
  323. }
  324. static std::string compatibilityType(CompatibleType t)
  325. {
  326. switch (t) {
  327. case BoolType:
  328. return "Boolean compatibility";
  329. case StringType:
  330. return "String compatibility";
  331. case NumberMaxType:
  332. return "Numeric maximum compatibility";
  333. case NumberMinType:
  334. return "Numeric minimum compatibility";
  335. }
  336. assert(false && "Unreachable!");
  337. return "";
  338. }
  339. static std::string compatibilityAgree(CompatibleType t, bool dominant)
  340. {
  341. switch (t) {
  342. case BoolType:
  343. case StringType:
  344. return dominant ? "(Disagree)\n" : "(Agree)\n";
  345. case NumberMaxType:
  346. case NumberMinType:
  347. return dominant ? "(Dominant)\n" : "(Ignored)\n";
  348. }
  349. assert(false && "Unreachable!");
  350. return "";
  351. }
  352. template <typename PropertyType>
  353. PropertyType getTypedProperty(
  354. cmGeneratorTarget const* tgt, const std::string& prop,
  355. cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
  356. template <>
  357. bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
  358. const std::string& prop,
  359. cmGeneratorExpressionInterpreter* genexInterpreter)
  360. {
  361. if (genexInterpreter == nullptr) {
  362. return tgt->GetPropertyAsBool(prop);
  363. }
  364. cmValue value = tgt->GetProperty(prop);
  365. return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
  366. }
  367. template <>
  368. const char* getTypedProperty<const char*>(
  369. cmGeneratorTarget const* tgt, const std::string& prop,
  370. cmGeneratorExpressionInterpreter* genexInterpreter)
  371. {
  372. cmValue value = tgt->GetProperty(prop);
  373. if (genexInterpreter == nullptr) {
  374. return value.GetCStr();
  375. }
  376. return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
  377. }
  378. template <>
  379. std::string getTypedProperty<std::string>(
  380. cmGeneratorTarget const* tgt, const std::string& prop,
  381. cmGeneratorExpressionInterpreter* genexInterpreter)
  382. {
  383. cmValue value = tgt->GetProperty(prop);
  384. if (genexInterpreter == nullptr) {
  385. return valueAsString(value);
  386. }
  387. return genexInterpreter->Evaluate(value ? *value : "", prop);
  388. }
  389. template <typename PropertyType>
  390. PropertyType impliedValue(PropertyType);
  391. template <>
  392. bool impliedValue<bool>(bool /*unused*/)
  393. {
  394. return false;
  395. }
  396. template <>
  397. const char* impliedValue<const char*>(const char* /*unused*/)
  398. {
  399. return "";
  400. }
  401. template <>
  402. std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
  403. {
  404. return std::string();
  405. }
  406. template <typename PropertyType>
  407. std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
  408. PropertyType rhs,
  409. CompatibleType t);
  410. template <>
  411. std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
  412. CompatibleType /*unused*/)
  413. {
  414. return { lhs == rhs, lhs };
  415. }
  416. static std::pair<bool, const char*> consistentStringProperty(const char* lhs,
  417. const char* rhs)
  418. {
  419. const bool b = strcmp(lhs, rhs) == 0;
  420. return { b, b ? lhs : nullptr };
  421. }
  422. static std::pair<bool, std::string> consistentStringProperty(
  423. const std::string& lhs, const std::string& rhs)
  424. {
  425. const bool b = lhs == rhs;
  426. return { b, b ? lhs : valueAsString(nullptr) };
  427. }
  428. static std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
  429. const char* rhs,
  430. CompatibleType t)
  431. {
  432. char* pEnd;
  433. long lnum = strtol(lhs, &pEnd, 0);
  434. if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
  435. return { false, nullptr };
  436. }
  437. long rnum = strtol(rhs, &pEnd, 0);
  438. if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
  439. return { false, nullptr };
  440. }
  441. if (t == NumberMaxType) {
  442. return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
  443. }
  444. return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
  445. }
  446. template <>
  447. std::pair<bool, const char*> consistentProperty(const char* lhs,
  448. const char* rhs,
  449. CompatibleType t)
  450. {
  451. if (!lhs && !rhs) {
  452. return { true, lhs };
  453. }
  454. if (!lhs) {
  455. return { true, rhs };
  456. }
  457. if (!rhs) {
  458. return { true, lhs };
  459. }
  460. switch (t) {
  461. case BoolType: {
  462. bool same = cmIsOn(lhs) == cmIsOn(rhs);
  463. return { same, same ? lhs : nullptr };
  464. }
  465. case StringType:
  466. return consistentStringProperty(lhs, rhs);
  467. case NumberMinType:
  468. case NumberMaxType:
  469. return consistentNumberProperty(lhs, rhs, t);
  470. }
  471. assert(false && "Unreachable!");
  472. return { false, nullptr };
  473. }
  474. static std::pair<bool, std::string> consistentProperty(const std::string& lhs,
  475. const std::string& rhs,
  476. CompatibleType t)
  477. {
  478. const std::string null_ptr = valueAsString(nullptr);
  479. if (lhs == null_ptr && rhs == null_ptr) {
  480. return { true, lhs };
  481. }
  482. if (lhs == null_ptr) {
  483. return { true, rhs };
  484. }
  485. if (rhs == null_ptr) {
  486. return { true, lhs };
  487. }
  488. switch (t) {
  489. case BoolType: {
  490. bool same = cmIsOn(lhs) == cmIsOn(rhs);
  491. return { same, same ? lhs : null_ptr };
  492. }
  493. case StringType:
  494. return consistentStringProperty(lhs, rhs);
  495. case NumberMinType:
  496. case NumberMaxType: {
  497. auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
  498. return { value.first,
  499. value.first ? std::string(value.second) : null_ptr };
  500. }
  501. }
  502. assert(false && "Unreachable!");
  503. return { false, null_ptr };
  504. }
  505. template <typename PropertyType>
  506. PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
  507. const std::string& p,
  508. const std::string& config,
  509. const char* defaultValue,
  510. CompatibleType t,
  511. PropertyType* /*unused*/)
  512. {
  513. PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
  514. std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
  515. const bool explicitlySet = cm::contains(headPropKeys, p);
  516. const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
  517. assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
  518. std::vector<cmGeneratorTarget const*> const& deps =
  519. tgt->GetLinkImplementationClosure(config);
  520. if (deps.empty()) {
  521. return propContent;
  522. }
  523. bool propInitialized = explicitlySet;
  524. std::string report = cmStrCat(" * Target \"", tgt->GetName());
  525. if (explicitlySet) {
  526. report += "\" has property content \"";
  527. report += valueAsString<PropertyType>(propContent);
  528. report += "\"\n";
  529. } else if (impliedByUse) {
  530. report += "\" property is implied by use.\n";
  531. } else {
  532. report += "\" property not set.\n";
  533. }
  534. std::string interfaceProperty = "INTERFACE_" + p;
  535. std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
  536. if (p == "POSITION_INDEPENDENT_CODE") {
  537. // Corresponds to EvaluatingPICExpression.
  538. genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
  539. tgt->GetLocalGenerator(), config, tgt);
  540. }
  541. for (cmGeneratorTarget const* theTarget : deps) {
  542. // An error should be reported if one dependency
  543. // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
  544. // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
  545. // target itself has a POSITION_INDEPENDENT_CODE which disagrees
  546. // with a dependency.
  547. std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
  548. const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty);
  549. PropertyType ifacePropContent = getTypedProperty<PropertyType>(
  550. theTarget, interfaceProperty, genexInterpreter.get());
  551. std::string reportEntry;
  552. if (ifaceIsSet) {
  553. reportEntry += " * Target \"";
  554. reportEntry += theTarget->GetName();
  555. reportEntry += "\" property value \"";
  556. reportEntry += valueAsString<PropertyType>(ifacePropContent);
  557. reportEntry += "\" ";
  558. }
  559. if (explicitlySet) {
  560. if (ifaceIsSet) {
  561. std::pair<bool, PropertyType> consistent =
  562. consistentProperty(propContent, ifacePropContent, t);
  563. report += reportEntry;
  564. report += compatibilityAgree(t, propContent != consistent.second);
  565. if (!consistent.first) {
  566. std::ostringstream e;
  567. e << "Property " << p << " on target \"" << tgt->GetName()
  568. << "\" does\nnot match the "
  569. "INTERFACE_"
  570. << p
  571. << " property requirement\nof "
  572. "dependency \""
  573. << theTarget->GetName() << "\".\n";
  574. cmSystemTools::Error(e.str());
  575. break;
  576. }
  577. propContent = consistent.second;
  578. continue;
  579. }
  580. // Explicitly set on target and not set in iface. Can't disagree.
  581. continue;
  582. }
  583. if (impliedByUse) {
  584. propContent = impliedValue<PropertyType>(propContent);
  585. if (ifaceIsSet) {
  586. std::pair<bool, PropertyType> consistent =
  587. consistentProperty(propContent, ifacePropContent, t);
  588. report += reportEntry;
  589. report += compatibilityAgree(t, propContent != consistent.second);
  590. if (!consistent.first) {
  591. std::ostringstream e;
  592. e << "Property " << p << " on target \"" << tgt->GetName()
  593. << "\" is\nimplied to be " << defaultValue
  594. << " because it was used to determine the link libraries\n"
  595. "already. The INTERFACE_"
  596. << p << " property on\ndependency \"" << theTarget->GetName()
  597. << "\" is in conflict.\n";
  598. cmSystemTools::Error(e.str());
  599. break;
  600. }
  601. propContent = consistent.second;
  602. continue;
  603. }
  604. // Implicitly set on target and not set in iface. Can't disagree.
  605. continue;
  606. }
  607. if (ifaceIsSet) {
  608. if (propInitialized) {
  609. std::pair<bool, PropertyType> consistent =
  610. consistentProperty(propContent, ifacePropContent, t);
  611. report += reportEntry;
  612. report += compatibilityAgree(t, propContent != consistent.second);
  613. if (!consistent.first) {
  614. std::ostringstream e;
  615. e << "The INTERFACE_" << p << " property of \""
  616. << theTarget->GetName() << "\" does\nnot agree with the value of "
  617. << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
  618. cmSystemTools::Error(e.str());
  619. break;
  620. }
  621. propContent = consistent.second;
  622. continue;
  623. }
  624. report += reportEntry + "(Interface set)\n";
  625. propContent = ifacePropContent;
  626. propInitialized = true;
  627. } else {
  628. // Not set. Nothing to agree on.
  629. continue;
  630. }
  631. }
  632. tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
  633. report, compatibilityType(t));
  634. return propContent;
  635. }
  636. bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
  637. const std::string& p, const std::string& config) const
  638. {
  639. return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
  640. BoolType, nullptr);
  641. }
  642. std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
  643. const std::string& p, const std::string& config) const
  644. {
  645. return checkInterfacePropertyCompatibility<std::string>(
  646. this, p, config, "FALSE", BoolType, nullptr);
  647. }
  648. const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
  649. const std::string& p, const std::string& config) const
  650. {
  651. return checkInterfacePropertyCompatibility<const char*>(
  652. this, p, config, "empty", StringType, nullptr);
  653. }
  654. const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
  655. const std::string& p, const std::string& config) const
  656. {
  657. return checkInterfacePropertyCompatibility<const char*>(
  658. this, p, config, "empty", NumberMinType, nullptr);
  659. }
  660. const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
  661. const std::string& p, const std::string& config) const
  662. {
  663. return checkInterfacePropertyCompatibility<const char*>(
  664. this, p, config, "empty", NumberMaxType, nullptr);
  665. }