cmGeneratorExpressionEvaluator.cxx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  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. //----------------------------------------------------------------------------
  17. #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
  18. static
  19. #endif
  20. void reportError(cmGeneratorExpressionContext *context,
  21. const std::string &expr, const std::string &result)
  22. {
  23. context->HadError = true;
  24. if (context->Quiet)
  25. {
  26. return;
  27. }
  28. cmOStringStream e;
  29. e << "Error evaluating generator expression:\n"
  30. << " " << expr << "\n"
  31. << result;
  32. context->Makefile->GetCMakeInstance()
  33. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  34. context->Backtrace);
  35. }
  36. //----------------------------------------------------------------------------
  37. struct cmGeneratorExpressionNode
  38. {
  39. virtual ~cmGeneratorExpressionNode() {}
  40. virtual bool GeneratesContent() const { return true; }
  41. virtual bool RequiresLiteralInput() const { return false; }
  42. virtual bool AcceptsSingleArbitraryContentParameter() const
  43. { return false; }
  44. virtual int NumExpectedParameters() const { return 1; }
  45. virtual std::string Evaluate(const std::vector<std::string> &parameters,
  46. cmGeneratorExpressionContext *context,
  47. const GeneratorExpressionContent *content,
  48. cmGeneratorExpressionDAGChecker *dagChecker
  49. ) const = 0;
  50. };
  51. //----------------------------------------------------------------------------
  52. static const struct ZeroNode : public cmGeneratorExpressionNode
  53. {
  54. ZeroNode() {}
  55. virtual bool GeneratesContent() const { return false; }
  56. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  57. std::string Evaluate(const std::vector<std::string> &,
  58. cmGeneratorExpressionContext *,
  59. const GeneratorExpressionContent *,
  60. cmGeneratorExpressionDAGChecker *) const
  61. {
  62. // Unreachable
  63. return std::string();
  64. }
  65. } zeroNode;
  66. //----------------------------------------------------------------------------
  67. static const struct OneNode : public cmGeneratorExpressionNode
  68. {
  69. OneNode() {}
  70. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  71. std::string Evaluate(const std::vector<std::string> &,
  72. cmGeneratorExpressionContext *,
  73. const GeneratorExpressionContent *,
  74. cmGeneratorExpressionDAGChecker *) const
  75. {
  76. // Unreachable
  77. return std::string();
  78. }
  79. } oneNode;
  80. //----------------------------------------------------------------------------
  81. static const struct OneNode buildInterfaceNode;
  82. //----------------------------------------------------------------------------
  83. static const struct ZeroNode installInterfaceNode;
  84. //----------------------------------------------------------------------------
  85. #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
  86. static const struct OP ## Node : public cmGeneratorExpressionNode \
  87. { \
  88. OP ## Node () {} \
  89. /* We let -1 carry the meaning 'at least one' */ \
  90. virtual int NumExpectedParameters() const { return -1; } \
  91. \
  92. std::string Evaluate(const std::vector<std::string> &parameters, \
  93. cmGeneratorExpressionContext *context, \
  94. const GeneratorExpressionContent *content, \
  95. cmGeneratorExpressionDAGChecker *) const \
  96. { \
  97. std::vector<std::string>::const_iterator it = parameters.begin(); \
  98. const std::vector<std::string>::const_iterator end = parameters.end(); \
  99. for ( ; it != end; ++it) \
  100. { \
  101. if (*it == #FAILURE_VALUE) \
  102. { \
  103. return #FAILURE_VALUE; \
  104. } \
  105. else if (*it != #SUCCESS_VALUE) \
  106. { \
  107. reportError(context, content->GetOriginalExpression(), \
  108. "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
  109. return std::string(); \
  110. } \
  111. } \
  112. return #SUCCESS_VALUE; \
  113. } \
  114. } OPNAME;
  115. BOOLEAN_OP_NODE(andNode, AND, 1, 0)
  116. BOOLEAN_OP_NODE(orNode, OR, 0, 1)
  117. #undef BOOLEAN_OP_NODE
  118. //----------------------------------------------------------------------------
  119. static const struct NotNode : public cmGeneratorExpressionNode
  120. {
  121. NotNode() {}
  122. std::string Evaluate(const std::vector<std::string> &parameters,
  123. cmGeneratorExpressionContext *context,
  124. const GeneratorExpressionContent *content,
  125. cmGeneratorExpressionDAGChecker *) const
  126. {
  127. if (*parameters.begin() != "0" && *parameters.begin() != "1")
  128. {
  129. reportError(context, content->GetOriginalExpression(),
  130. "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
  131. return std::string();
  132. }
  133. return *parameters.begin() == "0" ? "1" : "0";
  134. }
  135. } notNode;
  136. //----------------------------------------------------------------------------
  137. static const struct BoolNode : public cmGeneratorExpressionNode
  138. {
  139. BoolNode() {}
  140. virtual int NumExpectedParameters() const { return 1; }
  141. std::string Evaluate(const std::vector<std::string> &parameters,
  142. cmGeneratorExpressionContext *,
  143. const GeneratorExpressionContent *,
  144. cmGeneratorExpressionDAGChecker *) const
  145. {
  146. return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
  147. }
  148. } boolNode;
  149. //----------------------------------------------------------------------------
  150. static const struct StrEqualNode : public cmGeneratorExpressionNode
  151. {
  152. StrEqualNode() {}
  153. virtual int NumExpectedParameters() const { return 2; }
  154. std::string Evaluate(const std::vector<std::string> &parameters,
  155. cmGeneratorExpressionContext *,
  156. const GeneratorExpressionContent *,
  157. cmGeneratorExpressionDAGChecker *) const
  158. {
  159. return *parameters.begin() == parameters[1] ? "1" : "0";
  160. }
  161. } strEqualNode;
  162. //----------------------------------------------------------------------------
  163. static const struct Angle_RNode : public cmGeneratorExpressionNode
  164. {
  165. Angle_RNode() {}
  166. virtual int NumExpectedParameters() const { return 0; }
  167. std::string Evaluate(const std::vector<std::string> &,
  168. cmGeneratorExpressionContext *,
  169. const GeneratorExpressionContent *,
  170. cmGeneratorExpressionDAGChecker *) const
  171. {
  172. return ">";
  173. }
  174. } angle_rNode;
  175. //----------------------------------------------------------------------------
  176. static const struct CommaNode : public cmGeneratorExpressionNode
  177. {
  178. CommaNode() {}
  179. virtual int NumExpectedParameters() const { return 0; }
  180. std::string Evaluate(const std::vector<std::string> &,
  181. cmGeneratorExpressionContext *,
  182. const GeneratorExpressionContent *,
  183. cmGeneratorExpressionDAGChecker *) const
  184. {
  185. return ",";
  186. }
  187. } commaNode;
  188. //----------------------------------------------------------------------------
  189. static const struct ConfigurationNode : public cmGeneratorExpressionNode
  190. {
  191. ConfigurationNode() {}
  192. virtual int NumExpectedParameters() const { return 0; }
  193. std::string Evaluate(const std::vector<std::string> &,
  194. cmGeneratorExpressionContext *context,
  195. const GeneratorExpressionContent *,
  196. cmGeneratorExpressionDAGChecker *) const
  197. {
  198. return context->Config ? context->Config : "";
  199. }
  200. } configurationNode;
  201. //----------------------------------------------------------------------------
  202. static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
  203. {
  204. ConfigurationTestNode() {}
  205. virtual int NumExpectedParameters() const { return 1; }
  206. std::string Evaluate(const std::vector<std::string> &parameters,
  207. cmGeneratorExpressionContext *context,
  208. const GeneratorExpressionContent *content,
  209. cmGeneratorExpressionDAGChecker *) const
  210. {
  211. cmsys::RegularExpression configValidator;
  212. configValidator.compile("^[A-Za-z0-9_]*$");
  213. if (!configValidator.find(parameters.begin()->c_str()))
  214. {
  215. reportError(context, content->GetOriginalExpression(),
  216. "Expression syntax not recognized.");
  217. return std::string();
  218. }
  219. if (!context->Config)
  220. {
  221. return parameters.front().empty() ? "1" : "0";
  222. }
  223. if (cmsysString_strcasecmp(parameters.begin()->c_str(),
  224. context->Config) == 0)
  225. {
  226. return "1";
  227. }
  228. if (context->CurrentTarget
  229. && context->CurrentTarget->IsImported())
  230. {
  231. const char* loc = 0;
  232. const char* imp = 0;
  233. std::string suffix;
  234. return context->CurrentTarget->GetMappedConfig(context->Config,
  235. &loc,
  236. &imp,
  237. suffix) ? "1" : "0";
  238. }
  239. return "0";
  240. }
  241. } configurationTestNode;
  242. //----------------------------------------------------------------------------
  243. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  244. {
  245. TargetPropertyNode() {}
  246. // This node handles errors on parameter count itself.
  247. virtual int NumExpectedParameters() const { return -1; }
  248. std::string Evaluate(const std::vector<std::string> &parameters,
  249. cmGeneratorExpressionContext *context,
  250. const GeneratorExpressionContent *content,
  251. cmGeneratorExpressionDAGChecker *dagCheckerParent
  252. ) const
  253. {
  254. if (parameters.size() != 1 && parameters.size() != 2)
  255. {
  256. reportError(context, content->GetOriginalExpression(),
  257. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  258. return std::string();
  259. }
  260. cmsys::RegularExpression targetNameValidator;
  261. // The ':' is supported to allow use with IMPORTED targets. At least
  262. // Qt 4 and 5 IMPORTED targets use ':' as the namespace delimiter.
  263. targetNameValidator.compile("^[A-Za-z0-9_.:-]+$");
  264. cmsys::RegularExpression propertyNameValidator;
  265. propertyNameValidator.compile("^[A-Za-z0-9_]+$");
  266. cmTarget* target = context->HeadTarget;
  267. std::string propertyName = *parameters.begin();
  268. if (parameters.size() == 2)
  269. {
  270. if (parameters.begin()->empty() && parameters[1].empty())
  271. {
  272. reportError(context, content->GetOriginalExpression(),
  273. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  274. "target name and property name.");
  275. return std::string();
  276. }
  277. if (parameters.begin()->empty())
  278. {
  279. reportError(context, content->GetOriginalExpression(),
  280. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  281. "target name.");
  282. return std::string();
  283. }
  284. std::string targetName = parameters.front();
  285. propertyName = parameters[1];
  286. if (!targetNameValidator.find(targetName.c_str()))
  287. {
  288. if (!propertyNameValidator.find(propertyName.c_str()))
  289. {
  290. ::reportError(context, content->GetOriginalExpression(),
  291. "Target name and property name not supported.");
  292. return std::string();
  293. }
  294. ::reportError(context, content->GetOriginalExpression(),
  295. "Target name not supported.");
  296. return std::string();
  297. }
  298. target = context->Makefile->FindTargetToUse(
  299. targetName.c_str());
  300. if (!target)
  301. {
  302. cmOStringStream e;
  303. e << "Target \""
  304. << targetName
  305. << "\" not found.";
  306. reportError(context, content->GetOriginalExpression(), e.str());
  307. return std::string();
  308. }
  309. }
  310. if (propertyName.empty())
  311. {
  312. reportError(context, content->GetOriginalExpression(),
  313. "$<TARGET_PROPERTY:...> expression requires a non-empty property "
  314. "name.");
  315. return std::string();
  316. }
  317. if (!propertyNameValidator.find(propertyName.c_str()))
  318. {
  319. ::reportError(context, content->GetOriginalExpression(),
  320. "Property name not supported.");
  321. return std::string();
  322. }
  323. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  324. target->GetName(),
  325. propertyName,
  326. content,
  327. dagCheckerParent);
  328. switch (dagChecker.check())
  329. {
  330. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  331. dagChecker.reportError(context, content->GetOriginalExpression());
  332. return std::string();
  333. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  334. // No error. We just skip cyclic references.
  335. return std::string();
  336. case cmGeneratorExpressionDAGChecker::DAG:
  337. break;
  338. }
  339. const char *prop = target->GetProperty(propertyName.c_str());
  340. return prop ? prop : "";
  341. }
  342. } targetPropertyNode;
  343. //----------------------------------------------------------------------------
  344. static const struct TargetNameNode : public cmGeneratorExpressionNode
  345. {
  346. TargetNameNode() {}
  347. virtual bool GeneratesContent() const { return true; }
  348. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  349. virtual bool RequiresLiteralInput() const { return true; }
  350. std::string Evaluate(const std::vector<std::string> &parameters,
  351. cmGeneratorExpressionContext *,
  352. const GeneratorExpressionContent *,
  353. cmGeneratorExpressionDAGChecker *) const
  354. {
  355. return parameters.front();
  356. }
  357. virtual int NumExpectedParameters() const { return 1; }
  358. } targetNameNode;
  359. //----------------------------------------------------------------------------
  360. template<bool linker, bool soname>
  361. struct TargetFilesystemArtifactResultCreator
  362. {
  363. static std::string Create(cmTarget* target,
  364. cmGeneratorExpressionContext *context,
  365. const GeneratorExpressionContent *content);
  366. };
  367. //----------------------------------------------------------------------------
  368. template<>
  369. struct TargetFilesystemArtifactResultCreator<false, true>
  370. {
  371. static std::string Create(cmTarget* target,
  372. cmGeneratorExpressionContext *context,
  373. const GeneratorExpressionContent *content)
  374. {
  375. // The target soname file (.so.1).
  376. if(target->IsDLLPlatform())
  377. {
  378. ::reportError(context, content->GetOriginalExpression(),
  379. "TARGET_SONAME_FILE is not allowed "
  380. "for DLL target platforms.");
  381. return std::string();
  382. }
  383. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  384. {
  385. ::reportError(context, content->GetOriginalExpression(),
  386. "TARGET_SONAME_FILE is allowed only for "
  387. "SHARED libraries.");
  388. return std::string();
  389. }
  390. std::string result = target->GetDirectory(context->Config);
  391. result += "/";
  392. result += target->GetSOName(context->Config);
  393. return result;
  394. }
  395. };
  396. //----------------------------------------------------------------------------
  397. template<>
  398. struct TargetFilesystemArtifactResultCreator<true, false>
  399. {
  400. static std::string Create(cmTarget* target,
  401. cmGeneratorExpressionContext *context,
  402. const GeneratorExpressionContent *content)
  403. {
  404. // The file used to link to the target (.so, .lib, .a).
  405. if(!target->IsLinkable())
  406. {
  407. ::reportError(context, content->GetOriginalExpression(),
  408. "TARGET_LINKER_FILE is allowed only for libraries and "
  409. "executables with ENABLE_EXPORTS.");
  410. return std::string();
  411. }
  412. return target->GetFullPath(context->Config,
  413. target->HasImportLibrary());
  414. }
  415. };
  416. //----------------------------------------------------------------------------
  417. template<>
  418. struct TargetFilesystemArtifactResultCreator<false, false>
  419. {
  420. static std::string Create(cmTarget* target,
  421. cmGeneratorExpressionContext *context,
  422. const GeneratorExpressionContent *)
  423. {
  424. return target->GetFullPath(context->Config, false, true);
  425. }
  426. };
  427. //----------------------------------------------------------------------------
  428. template<bool dirQual, bool nameQual>
  429. struct TargetFilesystemArtifactResultGetter
  430. {
  431. static std::string Get(const std::string &result);
  432. };
  433. //----------------------------------------------------------------------------
  434. template<>
  435. struct TargetFilesystemArtifactResultGetter<false, true>
  436. {
  437. static std::string Get(const std::string &result)
  438. { return cmSystemTools::GetFilenameName(result); }
  439. };
  440. //----------------------------------------------------------------------------
  441. template<>
  442. struct TargetFilesystemArtifactResultGetter<true, false>
  443. {
  444. static std::string Get(const std::string &result)
  445. { return cmSystemTools::GetFilenamePath(result); }
  446. };
  447. //----------------------------------------------------------------------------
  448. template<>
  449. struct TargetFilesystemArtifactResultGetter<false, false>
  450. {
  451. static std::string Get(const std::string &result)
  452. { return result; }
  453. };
  454. //----------------------------------------------------------------------------
  455. template<bool linker, bool soname, bool dirQual, bool nameQual>
  456. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  457. {
  458. TargetFilesystemArtifact() {}
  459. virtual int NumExpectedParameters() const { return 1; }
  460. std::string Evaluate(const std::vector<std::string> &parameters,
  461. cmGeneratorExpressionContext *context,
  462. const GeneratorExpressionContent *content,
  463. cmGeneratorExpressionDAGChecker *) const
  464. {
  465. // Lookup the referenced target.
  466. std::string name = *parameters.begin();
  467. cmsys::RegularExpression targetValidator;
  468. // The ':' is supported to allow use with IMPORTED targets.
  469. targetValidator.compile("^[A-Za-z0-9_.:-]+$");
  470. if (!targetValidator.find(name.c_str()))
  471. {
  472. ::reportError(context, content->GetOriginalExpression(),
  473. "Expression syntax not recognized.");
  474. return std::string();
  475. }
  476. cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
  477. if(!target)
  478. {
  479. ::reportError(context, content->GetOriginalExpression(),
  480. "No target \"" + name + "\"");
  481. return std::string();
  482. }
  483. if(target->GetType() >= cmTarget::UTILITY &&
  484. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  485. {
  486. ::reportError(context, content->GetOriginalExpression(),
  487. "Target \"" + name + "\" is not an executable or library.");
  488. return std::string();
  489. }
  490. context->Targets.insert(target);
  491. std::string result =
  492. TargetFilesystemArtifactResultCreator<linker, soname>::Create(
  493. target,
  494. context,
  495. content);
  496. if (context->HadError)
  497. {
  498. return std::string();
  499. }
  500. return
  501. TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
  502. }
  503. };
  504. //----------------------------------------------------------------------------
  505. static const
  506. TargetFilesystemArtifact<false, false, false, false> targetFileNode;
  507. static const
  508. TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
  509. static const
  510. TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
  511. static const
  512. TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
  513. static const
  514. TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
  515. static const
  516. TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
  517. static const
  518. TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
  519. static const
  520. TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
  521. static const
  522. TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
  523. //----------------------------------------------------------------------------
  524. static const
  525. cmGeneratorExpressionNode* GetNode(const std::string &identifier)
  526. {
  527. if (identifier == "0")
  528. return &zeroNode;
  529. else if (identifier == "1")
  530. return &oneNode;
  531. else if (identifier == "AND")
  532. return &andNode;
  533. else if (identifier == "OR")
  534. return &orNode;
  535. else if (identifier == "NOT")
  536. return &notNode;
  537. else if (identifier == "CONFIGURATION")
  538. return &configurationNode;
  539. else if (identifier == "CONFIG")
  540. return &configurationTestNode;
  541. else if (identifier == "TARGET_FILE")
  542. return &targetFileNode;
  543. else if (identifier == "TARGET_LINKER_FILE")
  544. return &targetLinkerFileNode;
  545. else if (identifier == "TARGET_SONAME_FILE")
  546. return &targetSoNameFileNode;
  547. else if (identifier == "TARGET_FILE_NAME")
  548. return &targetFileNameNode;
  549. else if (identifier == "TARGET_LINKER_FILE_NAME")
  550. return &targetLinkerFileNameNode;
  551. else if (identifier == "TARGET_SONAME_FILE_NAME")
  552. return &targetSoNameFileNameNode;
  553. else if (identifier == "TARGET_FILE_DIR")
  554. return &targetFileDirNode;
  555. else if (identifier == "TARGET_LINKER_FILE_DIR")
  556. return &targetLinkerFileDirNode;
  557. else if (identifier == "TARGET_SONAME_FILE_DIR")
  558. return &targetSoNameFileDirNode;
  559. else if (identifier == "STREQUAL")
  560. return &strEqualNode;
  561. else if (identifier == "BOOL")
  562. return &boolNode;
  563. else if (identifier == "ANGLE-R")
  564. return &angle_rNode;
  565. else if (identifier == "COMMA")
  566. return &commaNode;
  567. else if (identifier == "TARGET_PROPERTY")
  568. return &targetPropertyNode;
  569. else if (identifier == "TARGET_NAME")
  570. return &targetNameNode;
  571. else if (identifier == "BUILD_INTERFACE")
  572. return &buildInterfaceNode;
  573. else if (identifier == "INSTALL_INTERFACE")
  574. return &installInterfaceNode;
  575. return 0;
  576. }
  577. //----------------------------------------------------------------------------
  578. GeneratorExpressionContent::GeneratorExpressionContent(
  579. const char *startContent,
  580. unsigned int length)
  581. : StartContent(startContent), ContentLength(length)
  582. {
  583. }
  584. //----------------------------------------------------------------------------
  585. std::string GeneratorExpressionContent::GetOriginalExpression() const
  586. {
  587. return std::string(this->StartContent, this->ContentLength);
  588. }
  589. //----------------------------------------------------------------------------
  590. std::string GeneratorExpressionContent::Evaluate(
  591. cmGeneratorExpressionContext *context,
  592. cmGeneratorExpressionDAGChecker *dagChecker) const
  593. {
  594. std::string identifier;
  595. {
  596. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  597. = this->IdentifierChildren.begin();
  598. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  599. = this->IdentifierChildren.end();
  600. for ( ; it != end; ++it)
  601. {
  602. identifier += (*it)->Evaluate(context, dagChecker);
  603. if (context->HadError)
  604. {
  605. return std::string();
  606. }
  607. }
  608. }
  609. const cmGeneratorExpressionNode *node = GetNode(identifier);
  610. if (!node)
  611. {
  612. reportError(context, this->GetOriginalExpression(),
  613. "Expression did not evaluate to a known generator expression");
  614. return std::string();
  615. }
  616. if (!node->GeneratesContent())
  617. {
  618. if (node->AcceptsSingleArbitraryContentParameter())
  619. {
  620. if (this->ParamChildren.empty())
  621. {
  622. reportError(context, this->GetOriginalExpression(),
  623. "$<" + identifier + "> expression requires a parameter.");
  624. }
  625. }
  626. else
  627. {
  628. std::vector<std::string> parameters;
  629. this->EvaluateParameters(node, identifier, context, dagChecker,
  630. parameters);
  631. }
  632. return std::string();
  633. }
  634. if (node->AcceptsSingleArbitraryContentParameter())
  635. {
  636. std::string result;
  637. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  638. pit = this->ParamChildren.begin();
  639. const
  640. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  641. pend = this->ParamChildren.end();
  642. for ( ; pit != pend; ++pit)
  643. {
  644. if (!result.empty())
  645. {
  646. result += ",";
  647. }
  648. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  649. = pit->begin();
  650. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  651. = pit->end();
  652. for ( ; it != end; ++it)
  653. {
  654. if (node->RequiresLiteralInput())
  655. {
  656. if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
  657. {
  658. reportError(context, this->GetOriginalExpression(),
  659. "$<" + identifier + "> expression requires literal input.");
  660. return std::string();
  661. }
  662. }
  663. result += (*it)->Evaluate(context, dagChecker);
  664. if (context->HadError)
  665. {
  666. return std::string();
  667. }
  668. }
  669. }
  670. if (node->RequiresLiteralInput())
  671. {
  672. std::vector<std::string> parameters;
  673. parameters.push_back(result);
  674. return node->Evaluate(parameters, context, this, dagChecker);
  675. }
  676. return result;
  677. }
  678. std::vector<std::string> parameters;
  679. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  680. if (context->HadError)
  681. {
  682. return std::string();
  683. }
  684. return node->Evaluate(parameters, context, this, dagChecker);
  685. }
  686. //----------------------------------------------------------------------------
  687. std::string GeneratorExpressionContent::EvaluateParameters(
  688. const cmGeneratorExpressionNode *node,
  689. const std::string &identifier,
  690. cmGeneratorExpressionContext *context,
  691. cmGeneratorExpressionDAGChecker *dagChecker,
  692. std::vector<std::string> &parameters) const
  693. {
  694. {
  695. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  696. pit = this->ParamChildren.begin();
  697. const
  698. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  699. pend = this->ParamChildren.end();
  700. for ( ; pit != pend; ++pit)
  701. {
  702. std::string parameter;
  703. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  704. pit->begin();
  705. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  706. pit->end();
  707. for ( ; it != end; ++it)
  708. {
  709. parameter += (*it)->Evaluate(context, dagChecker);
  710. if (context->HadError)
  711. {
  712. return std::string();
  713. }
  714. }
  715. parameters.push_back(parameter);
  716. }
  717. }
  718. int numExpected = node->NumExpectedParameters();
  719. if ((numExpected != -1 && (unsigned int)numExpected != parameters.size()))
  720. {
  721. if (numExpected == 0)
  722. {
  723. reportError(context, this->GetOriginalExpression(),
  724. "$<" + identifier + "> expression requires no parameters.");
  725. }
  726. else if (numExpected == 1)
  727. {
  728. reportError(context, this->GetOriginalExpression(),
  729. "$<" + identifier + "> expression requires "
  730. "exactly one parameter.");
  731. }
  732. else
  733. {
  734. cmOStringStream e;
  735. e << "$<" + identifier + "> expression requires "
  736. << numExpected
  737. << " comma separated parameters, but got "
  738. << parameters.size() << " instead.";
  739. reportError(context, this->GetOriginalExpression(), e.str());
  740. }
  741. return std::string();
  742. }
  743. if (numExpected == -1 && parameters.empty())
  744. {
  745. reportError(context, this->GetOriginalExpression(), "$<" + identifier
  746. + "> expression requires at least one parameter.");
  747. }
  748. return std::string();
  749. }
  750. //----------------------------------------------------------------------------
  751. static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
  752. {
  753. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  754. = c.begin();
  755. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  756. = c.end();
  757. for ( ; it != end; ++it)
  758. {
  759. delete *it;
  760. }
  761. }
  762. //----------------------------------------------------------------------------
  763. GeneratorExpressionContent::~GeneratorExpressionContent()
  764. {
  765. deleteAll(this->IdentifierChildren);
  766. typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
  767. typedef std::vector<cmGeneratorExpressionToken> TokenVector;
  768. std::vector<EvaluatorVector>::const_iterator pit =
  769. this->ParamChildren.begin();
  770. const std::vector<EvaluatorVector>::const_iterator pend =
  771. this->ParamChildren.end();
  772. for ( ; pit != pend; ++pit)
  773. {
  774. deleteAll(*pit);
  775. }
  776. }