cmGeneratorExpressionEvaluator.cxx 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2012 Stephen Kelly <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmMakefile.h"
  11. #include "cmGeneratorExpressionEvaluator.h"
  12. #include "cmGeneratorExpressionParser.h"
  13. #include "cmGeneratorExpressionDAGChecker.h"
  14. #include "cmGeneratorExpression.h"
  15. #include <cmsys/String.h>
  16. #include <assert.h>
  17. //----------------------------------------------------------------------------
  18. #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
  19. static
  20. #endif
  21. void reportError(cmGeneratorExpressionContext *context,
  22. const std::string &expr, const std::string &result)
  23. {
  24. context->HadError = true;
  25. if (context->Quiet)
  26. {
  27. return;
  28. }
  29. cmOStringStream e;
  30. e << "Error evaluating generator expression:\n"
  31. << " " << expr << "\n"
  32. << result;
  33. context->Makefile->GetCMakeInstance()
  34. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  35. context->Backtrace);
  36. }
  37. //----------------------------------------------------------------------------
  38. struct cmGeneratorExpressionNode
  39. {
  40. virtual ~cmGeneratorExpressionNode() {}
  41. virtual bool GeneratesContent() const { return true; }
  42. virtual bool RequiresLiteralInput() const { return false; }
  43. virtual bool AcceptsSingleArbitraryContentParameter() const
  44. { return false; }
  45. virtual int NumExpectedParameters() const { return 1; }
  46. virtual std::string Evaluate(const std::vector<std::string> &parameters,
  47. cmGeneratorExpressionContext *context,
  48. const GeneratorExpressionContent *content,
  49. cmGeneratorExpressionDAGChecker *dagChecker
  50. ) const = 0;
  51. };
  52. //----------------------------------------------------------------------------
  53. static const struct ZeroNode : public cmGeneratorExpressionNode
  54. {
  55. ZeroNode() {}
  56. virtual bool GeneratesContent() const { return false; }
  57. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  58. std::string Evaluate(const std::vector<std::string> &,
  59. cmGeneratorExpressionContext *,
  60. const GeneratorExpressionContent *,
  61. cmGeneratorExpressionDAGChecker *) const
  62. {
  63. // Unreachable
  64. return std::string();
  65. }
  66. } zeroNode;
  67. //----------------------------------------------------------------------------
  68. static const struct OneNode : public cmGeneratorExpressionNode
  69. {
  70. OneNode() {}
  71. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  72. std::string Evaluate(const std::vector<std::string> &,
  73. cmGeneratorExpressionContext *,
  74. const GeneratorExpressionContent *,
  75. cmGeneratorExpressionDAGChecker *) const
  76. {
  77. // Unreachable
  78. return std::string();
  79. }
  80. } oneNode;
  81. //----------------------------------------------------------------------------
  82. static const struct OneNode buildInterfaceNode;
  83. //----------------------------------------------------------------------------
  84. static const struct ZeroNode installInterfaceNode;
  85. //----------------------------------------------------------------------------
  86. #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
  87. static const struct OP ## Node : public cmGeneratorExpressionNode \
  88. { \
  89. OP ## Node () {} \
  90. /* We let -1 carry the meaning 'at least one' */ \
  91. virtual int NumExpectedParameters() const { return -1; } \
  92. \
  93. std::string Evaluate(const std::vector<std::string> &parameters, \
  94. cmGeneratorExpressionContext *context, \
  95. const GeneratorExpressionContent *content, \
  96. cmGeneratorExpressionDAGChecker *) const \
  97. { \
  98. std::vector<std::string>::const_iterator it = parameters.begin(); \
  99. const std::vector<std::string>::const_iterator end = parameters.end(); \
  100. for ( ; it != end; ++it) \
  101. { \
  102. if (*it == #FAILURE_VALUE) \
  103. { \
  104. return #FAILURE_VALUE; \
  105. } \
  106. else if (*it != #SUCCESS_VALUE) \
  107. { \
  108. reportError(context, content->GetOriginalExpression(), \
  109. "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
  110. return std::string(); \
  111. } \
  112. } \
  113. return #SUCCESS_VALUE; \
  114. } \
  115. } OPNAME;
  116. BOOLEAN_OP_NODE(andNode, AND, 1, 0)
  117. BOOLEAN_OP_NODE(orNode, OR, 0, 1)
  118. #undef BOOLEAN_OP_NODE
  119. //----------------------------------------------------------------------------
  120. static const struct NotNode : public cmGeneratorExpressionNode
  121. {
  122. NotNode() {}
  123. std::string Evaluate(const std::vector<std::string> &parameters,
  124. cmGeneratorExpressionContext *context,
  125. const GeneratorExpressionContent *content,
  126. cmGeneratorExpressionDAGChecker *) const
  127. {
  128. if (*parameters.begin() != "0" && *parameters.begin() != "1")
  129. {
  130. reportError(context, content->GetOriginalExpression(),
  131. "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
  132. return std::string();
  133. }
  134. return *parameters.begin() == "0" ? "1" : "0";
  135. }
  136. } notNode;
  137. //----------------------------------------------------------------------------
  138. static const struct BoolNode : public cmGeneratorExpressionNode
  139. {
  140. BoolNode() {}
  141. virtual int NumExpectedParameters() const { return 1; }
  142. std::string Evaluate(const std::vector<std::string> &parameters,
  143. cmGeneratorExpressionContext *,
  144. const GeneratorExpressionContent *,
  145. cmGeneratorExpressionDAGChecker *) const
  146. {
  147. return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
  148. }
  149. } boolNode;
  150. //----------------------------------------------------------------------------
  151. static const struct StrEqualNode : public cmGeneratorExpressionNode
  152. {
  153. StrEqualNode() {}
  154. virtual int NumExpectedParameters() const { return 2; }
  155. std::string Evaluate(const std::vector<std::string> &parameters,
  156. cmGeneratorExpressionContext *,
  157. const GeneratorExpressionContent *,
  158. cmGeneratorExpressionDAGChecker *) const
  159. {
  160. return *parameters.begin() == parameters[1] ? "1" : "0";
  161. }
  162. } strEqualNode;
  163. //----------------------------------------------------------------------------
  164. static const struct Angle_RNode : public cmGeneratorExpressionNode
  165. {
  166. Angle_RNode() {}
  167. virtual int NumExpectedParameters() const { return 0; }
  168. std::string Evaluate(const std::vector<std::string> &,
  169. cmGeneratorExpressionContext *,
  170. const GeneratorExpressionContent *,
  171. cmGeneratorExpressionDAGChecker *) const
  172. {
  173. return ">";
  174. }
  175. } angle_rNode;
  176. //----------------------------------------------------------------------------
  177. static const struct CommaNode : public cmGeneratorExpressionNode
  178. {
  179. CommaNode() {}
  180. virtual int NumExpectedParameters() const { return 0; }
  181. std::string Evaluate(const std::vector<std::string> &,
  182. cmGeneratorExpressionContext *,
  183. const GeneratorExpressionContent *,
  184. cmGeneratorExpressionDAGChecker *) const
  185. {
  186. return ",";
  187. }
  188. } commaNode;
  189. //----------------------------------------------------------------------------
  190. static const struct ConfigurationNode : public cmGeneratorExpressionNode
  191. {
  192. ConfigurationNode() {}
  193. virtual int NumExpectedParameters() const { return 0; }
  194. std::string Evaluate(const std::vector<std::string> &,
  195. cmGeneratorExpressionContext *context,
  196. const GeneratorExpressionContent *,
  197. cmGeneratorExpressionDAGChecker *) const
  198. {
  199. context->HadContextSensitiveCondition = true;
  200. return context->Config ? context->Config : "";
  201. }
  202. } configurationNode;
  203. //----------------------------------------------------------------------------
  204. static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
  205. {
  206. ConfigurationTestNode() {}
  207. virtual int NumExpectedParameters() const { return 1; }
  208. std::string Evaluate(const std::vector<std::string> &parameters,
  209. cmGeneratorExpressionContext *context,
  210. const GeneratorExpressionContent *content,
  211. cmGeneratorExpressionDAGChecker *) const
  212. {
  213. cmsys::RegularExpression configValidator;
  214. configValidator.compile("^[A-Za-z0-9_]*$");
  215. if (!configValidator.find(parameters.begin()->c_str()))
  216. {
  217. reportError(context, content->GetOriginalExpression(),
  218. "Expression syntax not recognized.");
  219. return std::string();
  220. }
  221. context->HadContextSensitiveCondition = true;
  222. if (!context->Config)
  223. {
  224. return parameters.front().empty() ? "1" : "0";
  225. }
  226. if (cmsysString_strcasecmp(parameters.begin()->c_str(),
  227. context->Config) == 0)
  228. {
  229. return "1";
  230. }
  231. if (context->CurrentTarget
  232. && context->CurrentTarget->IsImported())
  233. {
  234. const char* loc = 0;
  235. const char* imp = 0;
  236. std::string suffix;
  237. return context->CurrentTarget->GetMappedConfig(context->Config,
  238. &loc,
  239. &imp,
  240. suffix) ? "1" : "0";
  241. }
  242. return "0";
  243. }
  244. } configurationTestNode;
  245. static const struct TargetDefinedNode : public cmGeneratorExpressionNode
  246. {
  247. TargetDefinedNode() {}
  248. virtual int NumExpectedParameters() const { return 1; }
  249. std::string Evaluate(const std::vector<std::string> &parameters,
  250. cmGeneratorExpressionContext *context,
  251. const GeneratorExpressionContent *,
  252. cmGeneratorExpressionDAGChecker *) const
  253. {
  254. return context->Makefile->FindTargetToUse(parameters.front().c_str())
  255. ? "1" : "0";
  256. }
  257. } targetDefinedNode;
  258. //----------------------------------------------------------------------------
  259. static const char* targetPropertyTransitiveWhitelist[] = {
  260. "INTERFACE_INCLUDE_DIRECTORIES"
  261. , "INTERFACE_COMPILE_DEFINITIONS"
  262. };
  263. //----------------------------------------------------------------------------
  264. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  265. {
  266. TargetPropertyNode() {}
  267. // This node handles errors on parameter count itself.
  268. virtual int NumExpectedParameters() const { return -1; }
  269. std::string Evaluate(const std::vector<std::string> &parameters,
  270. cmGeneratorExpressionContext *context,
  271. const GeneratorExpressionContent *content,
  272. cmGeneratorExpressionDAGChecker *dagCheckerParent
  273. ) const
  274. {
  275. if (parameters.size() != 1 && parameters.size() != 2)
  276. {
  277. reportError(context, content->GetOriginalExpression(),
  278. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  279. return std::string();
  280. }
  281. cmsys::RegularExpression propertyNameValidator;
  282. propertyNameValidator.compile("^[A-Za-z0-9_]+$");
  283. cmTarget* target = context->HeadTarget;
  284. std::string propertyName = *parameters.begin();
  285. if (!target && parameters.size() == 1)
  286. {
  287. reportError(context, content->GetOriginalExpression(),
  288. "$<TARGET_PROPERTY:prop> may only be used with targets. It may not "
  289. "be used with add_custom_command. Specify the target to read a "
  290. "property from using the $<TARGET_PROPERTY:tgt,prop> signature "
  291. "instead.");
  292. return std::string();
  293. }
  294. if (parameters.size() == 2)
  295. {
  296. if (parameters.begin()->empty() && parameters[1].empty())
  297. {
  298. reportError(context, content->GetOriginalExpression(),
  299. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  300. "target name and property name.");
  301. return std::string();
  302. }
  303. if (parameters.begin()->empty())
  304. {
  305. reportError(context, content->GetOriginalExpression(),
  306. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  307. "target name.");
  308. return std::string();
  309. }
  310. std::string targetName = parameters.front();
  311. propertyName = parameters[1];
  312. if (!cmGeneratorExpression::IsValidTargetName(targetName))
  313. {
  314. if (!propertyNameValidator.find(propertyName.c_str()))
  315. {
  316. ::reportError(context, content->GetOriginalExpression(),
  317. "Target name and property name not supported.");
  318. return std::string();
  319. }
  320. ::reportError(context, content->GetOriginalExpression(),
  321. "Target name not supported.");
  322. return std::string();
  323. }
  324. target = context->Makefile->FindTargetToUse(
  325. targetName.c_str());
  326. if (!target)
  327. {
  328. cmOStringStream e;
  329. e << "Target \""
  330. << targetName
  331. << "\" not found.";
  332. reportError(context, content->GetOriginalExpression(), e.str());
  333. return std::string();
  334. }
  335. }
  336. if (target == context->HeadTarget)
  337. {
  338. // Keep track of the properties seen while processing.
  339. // The evaluation of the LINK_LIBRARIES generator expressions
  340. // will check this to ensure that properties form a DAG.
  341. context->SeenTargetProperties.insert(propertyName);
  342. }
  343. if (propertyName.empty())
  344. {
  345. reportError(context, content->GetOriginalExpression(),
  346. "$<TARGET_PROPERTY:...> expression requires a non-empty property "
  347. "name.");
  348. return std::string();
  349. }
  350. if (!propertyNameValidator.find(propertyName.c_str()))
  351. {
  352. ::reportError(context, content->GetOriginalExpression(),
  353. "Property name not supported.");
  354. return std::string();
  355. }
  356. assert(target);
  357. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  358. target->GetName(),
  359. propertyName,
  360. content,
  361. dagCheckerParent);
  362. switch (dagChecker.check())
  363. {
  364. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  365. dagChecker.reportError(context, content->GetOriginalExpression());
  366. return std::string();
  367. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  368. // No error. We just skip cyclic references.
  369. return std::string();
  370. case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
  371. for (size_t i = 0;
  372. i < (sizeof(targetPropertyTransitiveWhitelist) /
  373. sizeof(*targetPropertyTransitiveWhitelist));
  374. ++i)
  375. {
  376. if (targetPropertyTransitiveWhitelist[i] == propertyName)
  377. {
  378. // No error. We're not going to find anything new here.
  379. return std::string();
  380. }
  381. }
  382. case cmGeneratorExpressionDAGChecker::DAG:
  383. break;
  384. }
  385. const char *prop = target->GetProperty(propertyName.c_str());
  386. if (!prop)
  387. {
  388. if (target->IsImported())
  389. {
  390. return std::string();
  391. }
  392. if (dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries())
  393. {
  394. return std::string();
  395. }
  396. if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
  397. context->Config))
  398. {
  399. context->HadContextSensitiveCondition = true;
  400. return target->GetLinkInterfaceDependentBoolProperty(
  401. propertyName,
  402. context->Config) ? "1" : "0";
  403. }
  404. if (target->IsLinkInterfaceDependentStringProperty(propertyName,
  405. context->Config))
  406. {
  407. context->HadContextSensitiveCondition = true;
  408. const char *propContent =
  409. target->GetLinkInterfaceDependentStringProperty(
  410. propertyName,
  411. context->Config);
  412. return propContent ? propContent : "";
  413. }
  414. return std::string();
  415. }
  416. for (size_t i = 0;
  417. i < (sizeof(targetPropertyTransitiveWhitelist) /
  418. sizeof(*targetPropertyTransitiveWhitelist));
  419. ++i)
  420. {
  421. if (targetPropertyTransitiveWhitelist[i] == propertyName)
  422. {
  423. cmGeneratorExpression ge(context->Backtrace);
  424. cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
  425. std::string result = cge->Evaluate(context->Makefile,
  426. context->Config,
  427. context->Quiet,
  428. context->HeadTarget,
  429. target,
  430. &dagChecker);
  431. if (cge->GetHadContextSensitiveCondition())
  432. {
  433. context->HadContextSensitiveCondition = true;
  434. }
  435. return result;
  436. }
  437. }
  438. return prop;
  439. }
  440. } targetPropertyNode;
  441. //----------------------------------------------------------------------------
  442. static const struct TargetNameNode : public cmGeneratorExpressionNode
  443. {
  444. TargetNameNode() {}
  445. virtual bool GeneratesContent() const { return true; }
  446. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  447. virtual bool RequiresLiteralInput() const { return true; }
  448. std::string Evaluate(const std::vector<std::string> &parameters,
  449. cmGeneratorExpressionContext *,
  450. const GeneratorExpressionContent *,
  451. cmGeneratorExpressionDAGChecker *) const
  452. {
  453. return parameters.front();
  454. }
  455. virtual int NumExpectedParameters() const { return 1; }
  456. } targetNameNode;
  457. //----------------------------------------------------------------------------
  458. static const char* targetPolicyWhitelist[] = {
  459. "CMP0003"
  460. , "CMP0004"
  461. , "CMP0008"
  462. , "CMP0020"
  463. };
  464. cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
  465. {
  466. #define RETURN_POLICY(POLICY) \
  467. if (strcmp(policy, #POLICY) == 0) \
  468. { \
  469. return tgt->GetPolicyStatus ## POLICY (); \
  470. } \
  471. RETURN_POLICY(CMP0003)
  472. RETURN_POLICY(CMP0004)
  473. RETURN_POLICY(CMP0008)
  474. RETURN_POLICY(CMP0020)
  475. #undef RETURN_POLICY
  476. assert("!Unreachable code. Not a valid policy");
  477. return cmPolicies::WARN;
  478. }
  479. cmPolicies::PolicyID policyForString(const char *policy_id)
  480. {
  481. #define RETURN_POLICY_ID(POLICY_ID) \
  482. if (strcmp(policy_id, #POLICY_ID) == 0) \
  483. { \
  484. return cmPolicies:: POLICY_ID; \
  485. } \
  486. RETURN_POLICY_ID(CMP0003)
  487. RETURN_POLICY_ID(CMP0004)
  488. RETURN_POLICY_ID(CMP0008)
  489. RETURN_POLICY_ID(CMP0020)
  490. #undef RETURN_POLICY_ID
  491. assert("!Unreachable code. Not a valid policy");
  492. return cmPolicies::CMP0002;
  493. }
  494. //----------------------------------------------------------------------------
  495. static const struct TargetPolicyNode : public cmGeneratorExpressionNode
  496. {
  497. TargetPolicyNode() {}
  498. virtual int NumExpectedParameters() const { return 1; }
  499. std::string Evaluate(const std::vector<std::string> &parameters,
  500. cmGeneratorExpressionContext *context ,
  501. const GeneratorExpressionContent *content,
  502. cmGeneratorExpressionDAGChecker *) const
  503. {
  504. if (!context->HeadTarget)
  505. {
  506. reportError(context, content->GetOriginalExpression(),
  507. "$<TARGET_POLICY:prop> may only be used with targets. It may not "
  508. "be used with add_custom_command.");
  509. return std::string();
  510. }
  511. context->HadContextSensitiveCondition = true;
  512. for (size_t i = 0;
  513. i < (sizeof(targetPolicyWhitelist) /
  514. sizeof(*targetPolicyWhitelist));
  515. ++i)
  516. {
  517. const char *policy = targetPolicyWhitelist[i];
  518. if (parameters.front() == policy)
  519. {
  520. cmMakefile *mf = context->HeadTarget->GetMakefile();
  521. switch(statusForTarget(context->HeadTarget, policy))
  522. {
  523. case cmPolicies::WARN:
  524. mf->IssueMessage(cmake::AUTHOR_WARNING,
  525. mf->GetPolicies()->
  526. GetPolicyWarning(policyForString(policy)));
  527. case cmPolicies::REQUIRED_IF_USED:
  528. case cmPolicies::REQUIRED_ALWAYS:
  529. case cmPolicies::OLD:
  530. return "0";
  531. case cmPolicies::NEW:
  532. return "1";
  533. }
  534. }
  535. }
  536. reportError(context, content->GetOriginalExpression(),
  537. "$<TARGET_POLICY:prop> may only be used with a limited number of "
  538. "policies. Currently it may be used with policies CMP0003, CMP0004, "
  539. "CMP0008 and CMP0020."
  540. );
  541. return std::string();
  542. }
  543. } targetPolicyNode;
  544. //----------------------------------------------------------------------------
  545. static const struct InstallPrefixNode : public cmGeneratorExpressionNode
  546. {
  547. InstallPrefixNode() {}
  548. virtual bool GeneratesContent() const { return true; }
  549. virtual int NumExpectedParameters() const { return 0; }
  550. std::string Evaluate(const std::vector<std::string> &,
  551. cmGeneratorExpressionContext *context,
  552. const GeneratorExpressionContent *content,
  553. cmGeneratorExpressionDAGChecker *) const
  554. {
  555. reportError(context, content->GetOriginalExpression(),
  556. "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
  557. "should never be evaluated.");
  558. return std::string();
  559. }
  560. } installPrefixNode;
  561. //----------------------------------------------------------------------------
  562. static const struct LinkedNode : public cmGeneratorExpressionNode
  563. {
  564. LinkedNode() {}
  565. virtual bool GeneratesContent() const { return true; }
  566. virtual int NumExpectedParameters() const { return 1; }
  567. virtual bool RequiresLiteralInput() const { return true; }
  568. std::string Evaluate(const std::vector<std::string> &parameters,
  569. cmGeneratorExpressionContext *context,
  570. const GeneratorExpressionContent *content,
  571. cmGeneratorExpressionDAGChecker *dagChecker) const
  572. {
  573. if (dagChecker->EvaluatingIncludeDirectories())
  574. {
  575. return this->GetInterfaceProperty(parameters.front(),
  576. "INCLUDE_DIRECTORIES",
  577. context, content, dagChecker);
  578. }
  579. if (dagChecker->EvaluatingCompileDefinitions())
  580. {
  581. return this->GetInterfaceProperty(parameters.front(),
  582. "COMPILE_DEFINITIONS",
  583. context, content, dagChecker);
  584. }
  585. reportError(context, content->GetOriginalExpression(),
  586. "$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and "
  587. "COMPILE_DEFINITIONS properties.");
  588. return std::string();
  589. }
  590. private:
  591. std::string GetInterfaceProperty(const std::string &item,
  592. const std::string &prop,
  593. cmGeneratorExpressionContext *context,
  594. const GeneratorExpressionContent *content,
  595. cmGeneratorExpressionDAGChecker *dagCheckerParent) const
  596. {
  597. cmTarget *target = context->CurrentTarget
  598. ->GetMakefile()->FindTargetToUse(item.c_str());
  599. if (!target)
  600. {
  601. return std::string();
  602. }
  603. std::string propertyName = "INTERFACE_" + prop;
  604. const char *propContent = target->GetProperty(propertyName.c_str());
  605. if (!propContent)
  606. {
  607. return std::string();
  608. }
  609. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  610. target->GetName(),
  611. propertyName,
  612. content,
  613. dagCheckerParent);
  614. switch (dagChecker.check())
  615. {
  616. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  617. dagChecker.reportError(context, content->GetOriginalExpression());
  618. return std::string();
  619. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  620. // No error. We just skip cyclic references.
  621. return std::string();
  622. case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
  623. // No error. We're not going to find anything new here.
  624. return std::string();
  625. case cmGeneratorExpressionDAGChecker::DAG:
  626. break;
  627. }
  628. cmGeneratorExpression ge(context->Backtrace);
  629. cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propContent);
  630. std::string result = cge->Evaluate(context->Makefile,
  631. context->Config,
  632. context->Quiet,
  633. context->HeadTarget,
  634. target,
  635. &dagChecker);
  636. if (cge->GetHadContextSensitiveCondition())
  637. {
  638. context->HadContextSensitiveCondition = true;
  639. }
  640. return result;
  641. }
  642. } linkedNode;
  643. //----------------------------------------------------------------------------
  644. template<bool linker, bool soname>
  645. struct TargetFilesystemArtifactResultCreator
  646. {
  647. static std::string Create(cmTarget* target,
  648. cmGeneratorExpressionContext *context,
  649. const GeneratorExpressionContent *content);
  650. };
  651. //----------------------------------------------------------------------------
  652. template<>
  653. struct TargetFilesystemArtifactResultCreator<false, true>
  654. {
  655. static std::string Create(cmTarget* target,
  656. cmGeneratorExpressionContext *context,
  657. const GeneratorExpressionContent *content)
  658. {
  659. // The target soname file (.so.1).
  660. if(target->IsDLLPlatform())
  661. {
  662. ::reportError(context, content->GetOriginalExpression(),
  663. "TARGET_SONAME_FILE is not allowed "
  664. "for DLL target platforms.");
  665. return std::string();
  666. }
  667. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  668. {
  669. ::reportError(context, content->GetOriginalExpression(),
  670. "TARGET_SONAME_FILE is allowed only for "
  671. "SHARED libraries.");
  672. return std::string();
  673. }
  674. std::string result = target->GetDirectory(context->Config);
  675. result += "/";
  676. result += target->GetSOName(context->Config);
  677. return result;
  678. }
  679. };
  680. //----------------------------------------------------------------------------
  681. template<>
  682. struct TargetFilesystemArtifactResultCreator<true, false>
  683. {
  684. static std::string Create(cmTarget* target,
  685. cmGeneratorExpressionContext *context,
  686. const GeneratorExpressionContent *content)
  687. {
  688. // The file used to link to the target (.so, .lib, .a).
  689. if(!target->IsLinkable())
  690. {
  691. ::reportError(context, content->GetOriginalExpression(),
  692. "TARGET_LINKER_FILE is allowed only for libraries and "
  693. "executables with ENABLE_EXPORTS.");
  694. return std::string();
  695. }
  696. return target->GetFullPath(context->Config,
  697. target->HasImportLibrary());
  698. }
  699. };
  700. //----------------------------------------------------------------------------
  701. template<>
  702. struct TargetFilesystemArtifactResultCreator<false, false>
  703. {
  704. static std::string Create(cmTarget* target,
  705. cmGeneratorExpressionContext *context,
  706. const GeneratorExpressionContent *)
  707. {
  708. return target->GetFullPath(context->Config, false, true);
  709. }
  710. };
  711. //----------------------------------------------------------------------------
  712. template<bool dirQual, bool nameQual>
  713. struct TargetFilesystemArtifactResultGetter
  714. {
  715. static std::string Get(const std::string &result);
  716. };
  717. //----------------------------------------------------------------------------
  718. template<>
  719. struct TargetFilesystemArtifactResultGetter<false, true>
  720. {
  721. static std::string Get(const std::string &result)
  722. { return cmSystemTools::GetFilenameName(result); }
  723. };
  724. //----------------------------------------------------------------------------
  725. template<>
  726. struct TargetFilesystemArtifactResultGetter<true, false>
  727. {
  728. static std::string Get(const std::string &result)
  729. { return cmSystemTools::GetFilenamePath(result); }
  730. };
  731. //----------------------------------------------------------------------------
  732. template<>
  733. struct TargetFilesystemArtifactResultGetter<false, false>
  734. {
  735. static std::string Get(const std::string &result)
  736. { return result; }
  737. };
  738. //----------------------------------------------------------------------------
  739. template<bool linker, bool soname, bool dirQual, bool nameQual>
  740. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  741. {
  742. TargetFilesystemArtifact() {}
  743. virtual int NumExpectedParameters() const { return 1; }
  744. std::string Evaluate(const std::vector<std::string> &parameters,
  745. cmGeneratorExpressionContext *context,
  746. const GeneratorExpressionContent *content,
  747. cmGeneratorExpressionDAGChecker *) const
  748. {
  749. // Lookup the referenced target.
  750. std::string name = *parameters.begin();
  751. if (!cmGeneratorExpression::IsValidTargetName(name))
  752. {
  753. ::reportError(context, content->GetOriginalExpression(),
  754. "Expression syntax not recognized.");
  755. return std::string();
  756. }
  757. cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
  758. if(!target)
  759. {
  760. ::reportError(context, content->GetOriginalExpression(),
  761. "No target \"" + name + "\"");
  762. return std::string();
  763. }
  764. if(target->GetType() >= cmTarget::UTILITY &&
  765. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  766. {
  767. ::reportError(context, content->GetOriginalExpression(),
  768. "Target \"" + name + "\" is not an executable or library.");
  769. return std::string();
  770. }
  771. context->Targets.insert(target);
  772. std::string result =
  773. TargetFilesystemArtifactResultCreator<linker, soname>::Create(
  774. target,
  775. context,
  776. content);
  777. if (context->HadError)
  778. {
  779. return std::string();
  780. }
  781. return
  782. TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
  783. }
  784. };
  785. //----------------------------------------------------------------------------
  786. static const
  787. TargetFilesystemArtifact<false, false, false, false> targetFileNode;
  788. static const
  789. TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
  790. static const
  791. TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
  792. static const
  793. TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
  794. static const
  795. TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
  796. static const
  797. TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
  798. static const
  799. TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
  800. static const
  801. TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
  802. static const
  803. TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
  804. //----------------------------------------------------------------------------
  805. static const
  806. cmGeneratorExpressionNode* GetNode(const std::string &identifier)
  807. {
  808. if (identifier == "0")
  809. return &zeroNode;
  810. else if (identifier == "1")
  811. return &oneNode;
  812. else if (identifier == "AND")
  813. return &andNode;
  814. else if (identifier == "OR")
  815. return &orNode;
  816. else if (identifier == "NOT")
  817. return &notNode;
  818. else if (identifier == "CONFIGURATION")
  819. return &configurationNode;
  820. else if (identifier == "CONFIG")
  821. return &configurationTestNode;
  822. else if (identifier == "TARGET_FILE")
  823. return &targetFileNode;
  824. else if (identifier == "TARGET_LINKER_FILE")
  825. return &targetLinkerFileNode;
  826. else if (identifier == "TARGET_SONAME_FILE")
  827. return &targetSoNameFileNode;
  828. else if (identifier == "TARGET_FILE_NAME")
  829. return &targetFileNameNode;
  830. else if (identifier == "TARGET_LINKER_FILE_NAME")
  831. return &targetLinkerFileNameNode;
  832. else if (identifier == "TARGET_SONAME_FILE_NAME")
  833. return &targetSoNameFileNameNode;
  834. else if (identifier == "TARGET_FILE_DIR")
  835. return &targetFileDirNode;
  836. else if (identifier == "TARGET_LINKER_FILE_DIR")
  837. return &targetLinkerFileDirNode;
  838. else if (identifier == "TARGET_SONAME_FILE_DIR")
  839. return &targetSoNameFileDirNode;
  840. else if (identifier == "STREQUAL")
  841. return &strEqualNode;
  842. else if (identifier == "BOOL")
  843. return &boolNode;
  844. else if (identifier == "ANGLE-R")
  845. return &angle_rNode;
  846. else if (identifier == "COMMA")
  847. return &commaNode;
  848. else if (identifier == "TARGET_PROPERTY")
  849. return &targetPropertyNode;
  850. else if (identifier == "TARGET_NAME")
  851. return &targetNameNode;
  852. else if (identifier == "TARGET_POLICY")
  853. return &targetPolicyNode;
  854. else if (identifier == "BUILD_INTERFACE")
  855. return &buildInterfaceNode;
  856. else if (identifier == "INSTALL_INTERFACE")
  857. return &installInterfaceNode;
  858. else if (identifier == "TARGET_DEFINED")
  859. return &targetDefinedNode;
  860. else if (identifier == "INSTALL_PREFIX")
  861. return &installPrefixNode;
  862. else if (identifier == "LINKED")
  863. return &linkedNode;
  864. return 0;
  865. }
  866. //----------------------------------------------------------------------------
  867. GeneratorExpressionContent::GeneratorExpressionContent(
  868. const char *startContent,
  869. unsigned int length)
  870. : StartContent(startContent), ContentLength(length)
  871. {
  872. }
  873. //----------------------------------------------------------------------------
  874. std::string GeneratorExpressionContent::GetOriginalExpression() const
  875. {
  876. return std::string(this->StartContent, this->ContentLength);
  877. }
  878. //----------------------------------------------------------------------------
  879. std::string GeneratorExpressionContent::Evaluate(
  880. cmGeneratorExpressionContext *context,
  881. cmGeneratorExpressionDAGChecker *dagChecker) const
  882. {
  883. std::string identifier;
  884. {
  885. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  886. = this->IdentifierChildren.begin();
  887. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  888. = this->IdentifierChildren.end();
  889. for ( ; it != end; ++it)
  890. {
  891. identifier += (*it)->Evaluate(context, dagChecker);
  892. if (context->HadError)
  893. {
  894. return std::string();
  895. }
  896. }
  897. }
  898. const cmGeneratorExpressionNode *node = GetNode(identifier);
  899. if (!node)
  900. {
  901. reportError(context, this->GetOriginalExpression(),
  902. "Expression did not evaluate to a known generator expression");
  903. return std::string();
  904. }
  905. if (!node->GeneratesContent())
  906. {
  907. if (node->AcceptsSingleArbitraryContentParameter())
  908. {
  909. if (this->ParamChildren.empty())
  910. {
  911. reportError(context, this->GetOriginalExpression(),
  912. "$<" + identifier + "> expression requires a parameter.");
  913. }
  914. }
  915. else
  916. {
  917. std::vector<std::string> parameters;
  918. this->EvaluateParameters(node, identifier, context, dagChecker,
  919. parameters);
  920. }
  921. return std::string();
  922. }
  923. if (node->AcceptsSingleArbitraryContentParameter())
  924. {
  925. std::string result;
  926. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  927. pit = this->ParamChildren.begin();
  928. const
  929. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  930. pend = this->ParamChildren.end();
  931. for ( ; pit != pend; ++pit)
  932. {
  933. if (!result.empty())
  934. {
  935. result += ",";
  936. }
  937. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  938. = pit->begin();
  939. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  940. = pit->end();
  941. for ( ; it != end; ++it)
  942. {
  943. if (node->RequiresLiteralInput())
  944. {
  945. if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
  946. {
  947. reportError(context, this->GetOriginalExpression(),
  948. "$<" + identifier + "> expression requires literal input.");
  949. return std::string();
  950. }
  951. }
  952. result += (*it)->Evaluate(context, dagChecker);
  953. if (context->HadError)
  954. {
  955. return std::string();
  956. }
  957. }
  958. }
  959. if (node->RequiresLiteralInput())
  960. {
  961. std::vector<std::string> parameters;
  962. parameters.push_back(result);
  963. return node->Evaluate(parameters, context, this, dagChecker);
  964. }
  965. return result;
  966. }
  967. std::vector<std::string> parameters;
  968. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  969. if (context->HadError)
  970. {
  971. return std::string();
  972. }
  973. return node->Evaluate(parameters, context, this, dagChecker);
  974. }
  975. //----------------------------------------------------------------------------
  976. std::string GeneratorExpressionContent::EvaluateParameters(
  977. const cmGeneratorExpressionNode *node,
  978. const std::string &identifier,
  979. cmGeneratorExpressionContext *context,
  980. cmGeneratorExpressionDAGChecker *dagChecker,
  981. std::vector<std::string> &parameters) const
  982. {
  983. {
  984. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  985. pit = this->ParamChildren.begin();
  986. const
  987. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  988. pend = this->ParamChildren.end();
  989. for ( ; pit != pend; ++pit)
  990. {
  991. std::string parameter;
  992. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  993. pit->begin();
  994. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  995. pit->end();
  996. for ( ; it != end; ++it)
  997. {
  998. parameter += (*it)->Evaluate(context, dagChecker);
  999. if (context->HadError)
  1000. {
  1001. return std::string();
  1002. }
  1003. }
  1004. parameters.push_back(parameter);
  1005. }
  1006. }
  1007. int numExpected = node->NumExpectedParameters();
  1008. if ((numExpected != -1 && (unsigned int)numExpected != parameters.size()))
  1009. {
  1010. if (numExpected == 0)
  1011. {
  1012. reportError(context, this->GetOriginalExpression(),
  1013. "$<" + identifier + "> expression requires no parameters.");
  1014. }
  1015. else if (numExpected == 1)
  1016. {
  1017. reportError(context, this->GetOriginalExpression(),
  1018. "$<" + identifier + "> expression requires "
  1019. "exactly one parameter.");
  1020. }
  1021. else
  1022. {
  1023. cmOStringStream e;
  1024. e << "$<" + identifier + "> expression requires "
  1025. << numExpected
  1026. << " comma separated parameters, but got "
  1027. << parameters.size() << " instead.";
  1028. reportError(context, this->GetOriginalExpression(), e.str());
  1029. }
  1030. return std::string();
  1031. }
  1032. if (numExpected == -1 && parameters.empty())
  1033. {
  1034. reportError(context, this->GetOriginalExpression(), "$<" + identifier
  1035. + "> expression requires at least one parameter.");
  1036. }
  1037. return std::string();
  1038. }
  1039. //----------------------------------------------------------------------------
  1040. static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
  1041. {
  1042. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  1043. = c.begin();
  1044. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  1045. = c.end();
  1046. for ( ; it != end; ++it)
  1047. {
  1048. delete *it;
  1049. }
  1050. }
  1051. //----------------------------------------------------------------------------
  1052. GeneratorExpressionContent::~GeneratorExpressionContent()
  1053. {
  1054. deleteAll(this->IdentifierChildren);
  1055. typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
  1056. typedef std::vector<cmGeneratorExpressionToken> TokenVector;
  1057. std::vector<EvaluatorVector>::const_iterator pit =
  1058. this->ParamChildren.begin();
  1059. const std::vector<EvaluatorVector>::const_iterator pend =
  1060. this->ParamChildren.end();
  1061. for ( ; pit != pend; ++pit)
  1062. {
  1063. deleteAll(*pit);
  1064. }
  1065. }