cmGeneratorExpressionEvaluator.cxx 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  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 char* targetPropertyTransitiveWhitelist[] = {
  244. "INTERFACE_INCLUDE_DIRECTORIES"
  245. , "INTERFACE_COMPILE_DEFINITIONS"
  246. };
  247. //----------------------------------------------------------------------------
  248. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  249. {
  250. TargetPropertyNode() {}
  251. // This node handles errors on parameter count itself.
  252. virtual int NumExpectedParameters() const { return -1; }
  253. std::string Evaluate(const std::vector<std::string> &parameters,
  254. cmGeneratorExpressionContext *context,
  255. const GeneratorExpressionContent *content,
  256. cmGeneratorExpressionDAGChecker *dagCheckerParent
  257. ) const
  258. {
  259. if (parameters.size() != 1 && parameters.size() != 2)
  260. {
  261. reportError(context, content->GetOriginalExpression(),
  262. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  263. return std::string();
  264. }
  265. cmsys::RegularExpression targetNameValidator;
  266. // The ':' is supported to allow use with IMPORTED targets. At least
  267. // Qt 4 and 5 IMPORTED targets use ':' as the namespace delimiter.
  268. targetNameValidator.compile("^[A-Za-z0-9_.:-]+$");
  269. cmsys::RegularExpression propertyNameValidator;
  270. propertyNameValidator.compile("^[A-Za-z0-9_]+$");
  271. cmTarget* target = context->HeadTarget;
  272. std::string propertyName = *parameters.begin();
  273. if (parameters.size() == 2)
  274. {
  275. if (parameters.begin()->empty() && parameters[1].empty())
  276. {
  277. reportError(context, content->GetOriginalExpression(),
  278. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  279. "target name and property name.");
  280. return std::string();
  281. }
  282. if (parameters.begin()->empty())
  283. {
  284. reportError(context, content->GetOriginalExpression(),
  285. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  286. "target name.");
  287. return std::string();
  288. }
  289. std::string targetName = parameters.front();
  290. propertyName = parameters[1];
  291. if (!targetNameValidator.find(targetName.c_str()))
  292. {
  293. if (!propertyNameValidator.find(propertyName.c_str()))
  294. {
  295. ::reportError(context, content->GetOriginalExpression(),
  296. "Target name and property name not supported.");
  297. return std::string();
  298. }
  299. ::reportError(context, content->GetOriginalExpression(),
  300. "Target name not supported.");
  301. return std::string();
  302. }
  303. target = context->Makefile->FindTargetToUse(
  304. targetName.c_str());
  305. if (!target)
  306. {
  307. cmOStringStream e;
  308. e << "Target \""
  309. << targetName
  310. << "\" not found.";
  311. reportError(context, content->GetOriginalExpression(), e.str());
  312. return std::string();
  313. }
  314. }
  315. if (propertyName.empty())
  316. {
  317. reportError(context, content->GetOriginalExpression(),
  318. "$<TARGET_PROPERTY:...> expression requires a non-empty property "
  319. "name.");
  320. return std::string();
  321. }
  322. if (!propertyNameValidator.find(propertyName.c_str()))
  323. {
  324. ::reportError(context, content->GetOriginalExpression(),
  325. "Property name not supported.");
  326. return std::string();
  327. }
  328. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  329. target->GetName(),
  330. propertyName,
  331. content,
  332. dagCheckerParent);
  333. switch (dagChecker.check())
  334. {
  335. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  336. dagChecker.reportError(context, content->GetOriginalExpression());
  337. return std::string();
  338. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  339. // No error. We just skip cyclic references.
  340. return std::string();
  341. case cmGeneratorExpressionDAGChecker::DAG:
  342. break;
  343. }
  344. const char *prop = target->GetProperty(propertyName.c_str());
  345. if (!prop)
  346. {
  347. return std::string();
  348. }
  349. for (size_t i = 0;
  350. i < (sizeof(targetPropertyTransitiveWhitelist) /
  351. sizeof(*targetPropertyTransitiveWhitelist));
  352. ++i)
  353. {
  354. if (targetPropertyTransitiveWhitelist[i] == propertyName)
  355. {
  356. cmGeneratorExpression ge(context->Backtrace);
  357. return ge.Parse(prop)->Evaluate(context->Makefile,
  358. context->Config,
  359. context->Quiet,
  360. context->HeadTarget,
  361. target,
  362. &dagChecker);
  363. }
  364. }
  365. return prop;
  366. }
  367. } targetPropertyNode;
  368. //----------------------------------------------------------------------------
  369. static const struct TargetNameNode : public cmGeneratorExpressionNode
  370. {
  371. TargetNameNode() {}
  372. virtual bool GeneratesContent() const { return true; }
  373. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  374. virtual bool RequiresLiteralInput() const { return true; }
  375. std::string Evaluate(const std::vector<std::string> &parameters,
  376. cmGeneratorExpressionContext *,
  377. const GeneratorExpressionContent *,
  378. cmGeneratorExpressionDAGChecker *) const
  379. {
  380. return parameters.front();
  381. }
  382. virtual int NumExpectedParameters() const { return 1; }
  383. } targetNameNode;
  384. //----------------------------------------------------------------------------
  385. template<bool linker, bool soname>
  386. struct TargetFilesystemArtifactResultCreator
  387. {
  388. static std::string Create(cmTarget* target,
  389. cmGeneratorExpressionContext *context,
  390. const GeneratorExpressionContent *content);
  391. };
  392. //----------------------------------------------------------------------------
  393. template<>
  394. struct TargetFilesystemArtifactResultCreator<false, true>
  395. {
  396. static std::string Create(cmTarget* target,
  397. cmGeneratorExpressionContext *context,
  398. const GeneratorExpressionContent *content)
  399. {
  400. // The target soname file (.so.1).
  401. if(target->IsDLLPlatform())
  402. {
  403. ::reportError(context, content->GetOriginalExpression(),
  404. "TARGET_SONAME_FILE is not allowed "
  405. "for DLL target platforms.");
  406. return std::string();
  407. }
  408. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  409. {
  410. ::reportError(context, content->GetOriginalExpression(),
  411. "TARGET_SONAME_FILE is allowed only for "
  412. "SHARED libraries.");
  413. return std::string();
  414. }
  415. std::string result = target->GetDirectory(context->Config);
  416. result += "/";
  417. result += target->GetSOName(context->Config);
  418. return result;
  419. }
  420. };
  421. //----------------------------------------------------------------------------
  422. template<>
  423. struct TargetFilesystemArtifactResultCreator<true, false>
  424. {
  425. static std::string Create(cmTarget* target,
  426. cmGeneratorExpressionContext *context,
  427. const GeneratorExpressionContent *content)
  428. {
  429. // The file used to link to the target (.so, .lib, .a).
  430. if(!target->IsLinkable())
  431. {
  432. ::reportError(context, content->GetOriginalExpression(),
  433. "TARGET_LINKER_FILE is allowed only for libraries and "
  434. "executables with ENABLE_EXPORTS.");
  435. return std::string();
  436. }
  437. return target->GetFullPath(context->Config,
  438. target->HasImportLibrary());
  439. }
  440. };
  441. //----------------------------------------------------------------------------
  442. template<>
  443. struct TargetFilesystemArtifactResultCreator<false, false>
  444. {
  445. static std::string Create(cmTarget* target,
  446. cmGeneratorExpressionContext *context,
  447. const GeneratorExpressionContent *)
  448. {
  449. return target->GetFullPath(context->Config, false, true);
  450. }
  451. };
  452. //----------------------------------------------------------------------------
  453. template<bool dirQual, bool nameQual>
  454. struct TargetFilesystemArtifactResultGetter
  455. {
  456. static std::string Get(const std::string &result);
  457. };
  458. //----------------------------------------------------------------------------
  459. template<>
  460. struct TargetFilesystemArtifactResultGetter<false, true>
  461. {
  462. static std::string Get(const std::string &result)
  463. { return cmSystemTools::GetFilenameName(result); }
  464. };
  465. //----------------------------------------------------------------------------
  466. template<>
  467. struct TargetFilesystemArtifactResultGetter<true, false>
  468. {
  469. static std::string Get(const std::string &result)
  470. { return cmSystemTools::GetFilenamePath(result); }
  471. };
  472. //----------------------------------------------------------------------------
  473. template<>
  474. struct TargetFilesystemArtifactResultGetter<false, false>
  475. {
  476. static std::string Get(const std::string &result)
  477. { return result; }
  478. };
  479. //----------------------------------------------------------------------------
  480. template<bool linker, bool soname, bool dirQual, bool nameQual>
  481. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  482. {
  483. TargetFilesystemArtifact() {}
  484. virtual int NumExpectedParameters() const { return 1; }
  485. std::string Evaluate(const std::vector<std::string> &parameters,
  486. cmGeneratorExpressionContext *context,
  487. const GeneratorExpressionContent *content,
  488. cmGeneratorExpressionDAGChecker *) const
  489. {
  490. // Lookup the referenced target.
  491. std::string name = *parameters.begin();
  492. cmsys::RegularExpression targetValidator;
  493. // The ':' is supported to allow use with IMPORTED targets.
  494. targetValidator.compile("^[A-Za-z0-9_.:-]+$");
  495. if (!targetValidator.find(name.c_str()))
  496. {
  497. ::reportError(context, content->GetOriginalExpression(),
  498. "Expression syntax not recognized.");
  499. return std::string();
  500. }
  501. cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
  502. if(!target)
  503. {
  504. ::reportError(context, content->GetOriginalExpression(),
  505. "No target \"" + name + "\"");
  506. return std::string();
  507. }
  508. if(target->GetType() >= cmTarget::UTILITY &&
  509. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  510. {
  511. ::reportError(context, content->GetOriginalExpression(),
  512. "Target \"" + name + "\" is not an executable or library.");
  513. return std::string();
  514. }
  515. context->Targets.insert(target);
  516. std::string result =
  517. TargetFilesystemArtifactResultCreator<linker, soname>::Create(
  518. target,
  519. context,
  520. content);
  521. if (context->HadError)
  522. {
  523. return std::string();
  524. }
  525. return
  526. TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
  527. }
  528. };
  529. //----------------------------------------------------------------------------
  530. static const
  531. TargetFilesystemArtifact<false, false, false, false> targetFileNode;
  532. static const
  533. TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
  534. static const
  535. TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
  536. static const
  537. TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
  538. static const
  539. TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
  540. static const
  541. TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
  542. static const
  543. TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
  544. static const
  545. TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
  546. static const
  547. TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
  548. //----------------------------------------------------------------------------
  549. static const
  550. cmGeneratorExpressionNode* GetNode(const std::string &identifier)
  551. {
  552. if (identifier == "0")
  553. return &zeroNode;
  554. else if (identifier == "1")
  555. return &oneNode;
  556. else if (identifier == "AND")
  557. return &andNode;
  558. else if (identifier == "OR")
  559. return &orNode;
  560. else if (identifier == "NOT")
  561. return &notNode;
  562. else if (identifier == "CONFIGURATION")
  563. return &configurationNode;
  564. else if (identifier == "CONFIG")
  565. return &configurationTestNode;
  566. else if (identifier == "TARGET_FILE")
  567. return &targetFileNode;
  568. else if (identifier == "TARGET_LINKER_FILE")
  569. return &targetLinkerFileNode;
  570. else if (identifier == "TARGET_SONAME_FILE")
  571. return &targetSoNameFileNode;
  572. else if (identifier == "TARGET_FILE_NAME")
  573. return &targetFileNameNode;
  574. else if (identifier == "TARGET_LINKER_FILE_NAME")
  575. return &targetLinkerFileNameNode;
  576. else if (identifier == "TARGET_SONAME_FILE_NAME")
  577. return &targetSoNameFileNameNode;
  578. else if (identifier == "TARGET_FILE_DIR")
  579. return &targetFileDirNode;
  580. else if (identifier == "TARGET_LINKER_FILE_DIR")
  581. return &targetLinkerFileDirNode;
  582. else if (identifier == "TARGET_SONAME_FILE_DIR")
  583. return &targetSoNameFileDirNode;
  584. else if (identifier == "STREQUAL")
  585. return &strEqualNode;
  586. else if (identifier == "BOOL")
  587. return &boolNode;
  588. else if (identifier == "ANGLE-R")
  589. return &angle_rNode;
  590. else if (identifier == "COMMA")
  591. return &commaNode;
  592. else if (identifier == "TARGET_PROPERTY")
  593. return &targetPropertyNode;
  594. else if (identifier == "TARGET_NAME")
  595. return &targetNameNode;
  596. else if (identifier == "BUILD_INTERFACE")
  597. return &buildInterfaceNode;
  598. else if (identifier == "INSTALL_INTERFACE")
  599. return &installInterfaceNode;
  600. return 0;
  601. }
  602. //----------------------------------------------------------------------------
  603. GeneratorExpressionContent::GeneratorExpressionContent(
  604. const char *startContent,
  605. unsigned int length)
  606. : StartContent(startContent), ContentLength(length)
  607. {
  608. }
  609. //----------------------------------------------------------------------------
  610. std::string GeneratorExpressionContent::GetOriginalExpression() const
  611. {
  612. return std::string(this->StartContent, this->ContentLength);
  613. }
  614. //----------------------------------------------------------------------------
  615. std::string GeneratorExpressionContent::Evaluate(
  616. cmGeneratorExpressionContext *context,
  617. cmGeneratorExpressionDAGChecker *dagChecker) const
  618. {
  619. std::string identifier;
  620. {
  621. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  622. = this->IdentifierChildren.begin();
  623. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  624. = this->IdentifierChildren.end();
  625. for ( ; it != end; ++it)
  626. {
  627. identifier += (*it)->Evaluate(context, dagChecker);
  628. if (context->HadError)
  629. {
  630. return std::string();
  631. }
  632. }
  633. }
  634. const cmGeneratorExpressionNode *node = GetNode(identifier);
  635. if (!node)
  636. {
  637. reportError(context, this->GetOriginalExpression(),
  638. "Expression did not evaluate to a known generator expression");
  639. return std::string();
  640. }
  641. if (!node->GeneratesContent())
  642. {
  643. if (node->AcceptsSingleArbitraryContentParameter())
  644. {
  645. if (this->ParamChildren.empty())
  646. {
  647. reportError(context, this->GetOriginalExpression(),
  648. "$<" + identifier + "> expression requires a parameter.");
  649. }
  650. }
  651. else
  652. {
  653. std::vector<std::string> parameters;
  654. this->EvaluateParameters(node, identifier, context, dagChecker,
  655. parameters);
  656. }
  657. return std::string();
  658. }
  659. if (node->AcceptsSingleArbitraryContentParameter())
  660. {
  661. std::string result;
  662. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  663. pit = this->ParamChildren.begin();
  664. const
  665. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  666. pend = this->ParamChildren.end();
  667. for ( ; pit != pend; ++pit)
  668. {
  669. if (!result.empty())
  670. {
  671. result += ",";
  672. }
  673. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  674. = pit->begin();
  675. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  676. = pit->end();
  677. for ( ; it != end; ++it)
  678. {
  679. if (node->RequiresLiteralInput())
  680. {
  681. if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
  682. {
  683. reportError(context, this->GetOriginalExpression(),
  684. "$<" + identifier + "> expression requires literal input.");
  685. return std::string();
  686. }
  687. }
  688. result += (*it)->Evaluate(context, dagChecker);
  689. if (context->HadError)
  690. {
  691. return std::string();
  692. }
  693. }
  694. }
  695. if (node->RequiresLiteralInput())
  696. {
  697. std::vector<std::string> parameters;
  698. parameters.push_back(result);
  699. return node->Evaluate(parameters, context, this, dagChecker);
  700. }
  701. return result;
  702. }
  703. std::vector<std::string> parameters;
  704. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  705. if (context->HadError)
  706. {
  707. return std::string();
  708. }
  709. return node->Evaluate(parameters, context, this, dagChecker);
  710. }
  711. //----------------------------------------------------------------------------
  712. std::string GeneratorExpressionContent::EvaluateParameters(
  713. const cmGeneratorExpressionNode *node,
  714. const std::string &identifier,
  715. cmGeneratorExpressionContext *context,
  716. cmGeneratorExpressionDAGChecker *dagChecker,
  717. std::vector<std::string> &parameters) const
  718. {
  719. {
  720. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  721. pit = this->ParamChildren.begin();
  722. const
  723. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  724. pend = this->ParamChildren.end();
  725. for ( ; pit != pend; ++pit)
  726. {
  727. std::string parameter;
  728. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  729. pit->begin();
  730. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  731. pit->end();
  732. for ( ; it != end; ++it)
  733. {
  734. parameter += (*it)->Evaluate(context, dagChecker);
  735. if (context->HadError)
  736. {
  737. return std::string();
  738. }
  739. }
  740. parameters.push_back(parameter);
  741. }
  742. }
  743. int numExpected = node->NumExpectedParameters();
  744. if ((numExpected != -1 && (unsigned int)numExpected != parameters.size()))
  745. {
  746. if (numExpected == 0)
  747. {
  748. reportError(context, this->GetOriginalExpression(),
  749. "$<" + identifier + "> expression requires no parameters.");
  750. }
  751. else if (numExpected == 1)
  752. {
  753. reportError(context, this->GetOriginalExpression(),
  754. "$<" + identifier + "> expression requires "
  755. "exactly one parameter.");
  756. }
  757. else
  758. {
  759. cmOStringStream e;
  760. e << "$<" + identifier + "> expression requires "
  761. << numExpected
  762. << " comma separated parameters, but got "
  763. << parameters.size() << " instead.";
  764. reportError(context, this->GetOriginalExpression(), e.str());
  765. }
  766. return std::string();
  767. }
  768. if (numExpected == -1 && parameters.empty())
  769. {
  770. reportError(context, this->GetOriginalExpression(), "$<" + identifier
  771. + "> expression requires at least one parameter.");
  772. }
  773. return std::string();
  774. }
  775. //----------------------------------------------------------------------------
  776. static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
  777. {
  778. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  779. = c.begin();
  780. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  781. = c.end();
  782. for ( ; it != end; ++it)
  783. {
  784. delete *it;
  785. }
  786. }
  787. //----------------------------------------------------------------------------
  788. GeneratorExpressionContent::~GeneratorExpressionContent()
  789. {
  790. deleteAll(this->IdentifierChildren);
  791. typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
  792. typedef std::vector<cmGeneratorExpressionToken> TokenVector;
  793. std::vector<EvaluatorVector>::const_iterator pit =
  794. this->ParamChildren.begin();
  795. const std::vector<EvaluatorVector>::const_iterator pend =
  796. this->ParamChildren.end();
  797. for ( ; pit != pend; ++pit)
  798. {
  799. deleteAll(*pit);
  800. }
  801. }