cmGeneratorExpressionEvaluator.cxx 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  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. enum {
  41. DynamicParameters = 0,
  42. OneOrMoreParameters = -1,
  43. ZeroOrMoreParameters = -2
  44. };
  45. virtual ~cmGeneratorExpressionNode() {}
  46. virtual bool GeneratesContent() const { return true; }
  47. virtual bool RequiresLiteralInput() const { return false; }
  48. virtual bool AcceptsArbitraryContentParameter() const
  49. { return false; }
  50. virtual int NumExpectedParameters() const { return 1; }
  51. virtual std::string Evaluate(const std::vector<std::string> &parameters,
  52. cmGeneratorExpressionContext *context,
  53. const GeneratorExpressionContent *content,
  54. cmGeneratorExpressionDAGChecker *dagChecker
  55. ) const = 0;
  56. };
  57. //----------------------------------------------------------------------------
  58. static const struct ZeroNode : public cmGeneratorExpressionNode
  59. {
  60. ZeroNode() {}
  61. virtual bool GeneratesContent() const { return false; }
  62. virtual bool AcceptsArbitraryContentParameter() const { return true; }
  63. std::string Evaluate(const std::vector<std::string> &,
  64. cmGeneratorExpressionContext *,
  65. const GeneratorExpressionContent *,
  66. cmGeneratorExpressionDAGChecker *) const
  67. {
  68. // Unreachable
  69. return std::string();
  70. }
  71. } zeroNode;
  72. //----------------------------------------------------------------------------
  73. static const struct OneNode : public cmGeneratorExpressionNode
  74. {
  75. OneNode() {}
  76. virtual bool AcceptsArbitraryContentParameter() const { return true; }
  77. std::string Evaluate(const std::vector<std::string> &,
  78. cmGeneratorExpressionContext *,
  79. const GeneratorExpressionContent *,
  80. cmGeneratorExpressionDAGChecker *) const
  81. {
  82. // Unreachable
  83. return std::string();
  84. }
  85. } oneNode;
  86. //----------------------------------------------------------------------------
  87. static const struct OneNode buildInterfaceNode;
  88. //----------------------------------------------------------------------------
  89. static const struct ZeroNode installInterfaceNode;
  90. //----------------------------------------------------------------------------
  91. #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
  92. static const struct OP ## Node : public cmGeneratorExpressionNode \
  93. { \
  94. OP ## Node () {} \
  95. virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
  96. \
  97. std::string Evaluate(const std::vector<std::string> &parameters, \
  98. cmGeneratorExpressionContext *context, \
  99. const GeneratorExpressionContent *content, \
  100. cmGeneratorExpressionDAGChecker *) const \
  101. { \
  102. std::vector<std::string>::const_iterator it = parameters.begin(); \
  103. const std::vector<std::string>::const_iterator end = parameters.end(); \
  104. for ( ; it != end; ++it) \
  105. { \
  106. if (*it == #FAILURE_VALUE) \
  107. { \
  108. return #FAILURE_VALUE; \
  109. } \
  110. else if (*it != #SUCCESS_VALUE) \
  111. { \
  112. reportError(context, content->GetOriginalExpression(), \
  113. "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
  114. return std::string(); \
  115. } \
  116. } \
  117. return #SUCCESS_VALUE; \
  118. } \
  119. } OPNAME;
  120. BOOLEAN_OP_NODE(andNode, AND, 1, 0)
  121. BOOLEAN_OP_NODE(orNode, OR, 0, 1)
  122. #undef BOOLEAN_OP_NODE
  123. //----------------------------------------------------------------------------
  124. static const struct NotNode : public cmGeneratorExpressionNode
  125. {
  126. NotNode() {}
  127. std::string Evaluate(const std::vector<std::string> &parameters,
  128. cmGeneratorExpressionContext *context,
  129. const GeneratorExpressionContent *content,
  130. cmGeneratorExpressionDAGChecker *) const
  131. {
  132. if (*parameters.begin() != "0" && *parameters.begin() != "1")
  133. {
  134. reportError(context, content->GetOriginalExpression(),
  135. "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
  136. return std::string();
  137. }
  138. return *parameters.begin() == "0" ? "1" : "0";
  139. }
  140. } notNode;
  141. //----------------------------------------------------------------------------
  142. static const struct BoolNode : public cmGeneratorExpressionNode
  143. {
  144. BoolNode() {}
  145. virtual int NumExpectedParameters() const { return 1; }
  146. std::string Evaluate(const std::vector<std::string> &parameters,
  147. cmGeneratorExpressionContext *,
  148. const GeneratorExpressionContent *,
  149. cmGeneratorExpressionDAGChecker *) const
  150. {
  151. return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
  152. }
  153. } boolNode;
  154. //----------------------------------------------------------------------------
  155. static const struct StrEqualNode : public cmGeneratorExpressionNode
  156. {
  157. StrEqualNode() {}
  158. virtual int NumExpectedParameters() const { return 2; }
  159. std::string Evaluate(const std::vector<std::string> &parameters,
  160. cmGeneratorExpressionContext *,
  161. const GeneratorExpressionContent *,
  162. cmGeneratorExpressionDAGChecker *) const
  163. {
  164. return *parameters.begin() == parameters[1] ? "1" : "0";
  165. }
  166. } strEqualNode;
  167. //----------------------------------------------------------------------------
  168. static const struct Angle_RNode : public cmGeneratorExpressionNode
  169. {
  170. Angle_RNode() {}
  171. virtual int NumExpectedParameters() const { return 0; }
  172. std::string Evaluate(const std::vector<std::string> &,
  173. cmGeneratorExpressionContext *,
  174. const GeneratorExpressionContent *,
  175. cmGeneratorExpressionDAGChecker *) const
  176. {
  177. return ">";
  178. }
  179. } angle_rNode;
  180. //----------------------------------------------------------------------------
  181. static const struct CommaNode : public cmGeneratorExpressionNode
  182. {
  183. CommaNode() {}
  184. virtual int NumExpectedParameters() const { return 0; }
  185. std::string Evaluate(const std::vector<std::string> &,
  186. cmGeneratorExpressionContext *,
  187. const GeneratorExpressionContent *,
  188. cmGeneratorExpressionDAGChecker *) const
  189. {
  190. return ",";
  191. }
  192. } commaNode;
  193. //----------------------------------------------------------------------------
  194. static const struct SemicolonNode : public cmGeneratorExpressionNode
  195. {
  196. SemicolonNode() {}
  197. virtual int NumExpectedParameters() const { return 0; }
  198. std::string Evaluate(const std::vector<std::string> &,
  199. cmGeneratorExpressionContext *,
  200. const GeneratorExpressionContent *,
  201. cmGeneratorExpressionDAGChecker *) const
  202. {
  203. return ";";
  204. }
  205. } semicolonNode;
  206. //----------------------------------------------------------------------------
  207. struct CompilerIdNode : public cmGeneratorExpressionNode
  208. {
  209. CompilerIdNode() {}
  210. virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
  211. std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
  212. cmGeneratorExpressionContext *context,
  213. const GeneratorExpressionContent *content,
  214. cmGeneratorExpressionDAGChecker *,
  215. const std::string &lang) const
  216. {
  217. const char *compilerId = context->Makefile ?
  218. context->Makefile->GetSafeDefinition((
  219. "CMAKE_" + lang + "_COMPILER_ID").c_str()) : "";
  220. if (parameters.size() == 0)
  221. {
  222. return compilerId ? compilerId : "";
  223. }
  224. else
  225. {
  226. cmsys::RegularExpression compilerIdValidator;
  227. compilerIdValidator.compile("^[A-Za-z0-9_]*$");
  228. if (!compilerIdValidator.find(parameters.begin()->c_str()))
  229. {
  230. reportError(context, content->GetOriginalExpression(),
  231. "Expression syntax not recognized.");
  232. return std::string();
  233. }
  234. if (!compilerId)
  235. {
  236. return parameters.front().empty() ? "1" : "0";
  237. }
  238. if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0)
  239. {
  240. return "1";
  241. }
  242. return "0";
  243. }
  244. }
  245. };
  246. //----------------------------------------------------------------------------
  247. static const struct CCompilerIdNode : public CompilerIdNode
  248. {
  249. CCompilerIdNode() {}
  250. std::string Evaluate(const std::vector<std::string> &parameters,
  251. cmGeneratorExpressionContext *context,
  252. const GeneratorExpressionContent *content,
  253. cmGeneratorExpressionDAGChecker *dagChecker) const
  254. {
  255. if (parameters.size() != 0 && parameters.size() != 1)
  256. {
  257. reportError(context, content->GetOriginalExpression(),
  258. "$<C_COMPILER_ID> expression requires one or two parameters");
  259. return std::string();
  260. }
  261. if (!context->HeadTarget)
  262. {
  263. reportError(context, content->GetOriginalExpression(),
  264. "$<C_COMPILER_ID> may only be used with targets. It may not "
  265. "be used with add_custom_command.");
  266. }
  267. return this->EvaluateWithLanguage(parameters, context, content,
  268. dagChecker, "C");
  269. }
  270. } cCompilerIdNode;
  271. //----------------------------------------------------------------------------
  272. static const struct CXXCompilerIdNode : public CompilerIdNode
  273. {
  274. CXXCompilerIdNode() {}
  275. std::string Evaluate(const std::vector<std::string> &parameters,
  276. cmGeneratorExpressionContext *context,
  277. const GeneratorExpressionContent *content,
  278. cmGeneratorExpressionDAGChecker *dagChecker) const
  279. {
  280. if (parameters.size() != 0 && parameters.size() != 1)
  281. {
  282. reportError(context, content->GetOriginalExpression(),
  283. "$<CXX_COMPILER_ID> expression requires one or two parameters");
  284. return std::string();
  285. }
  286. if (!context->HeadTarget)
  287. {
  288. reportError(context, content->GetOriginalExpression(),
  289. "$<CXX_COMPILER_ID> may only be used with targets. It may not "
  290. "be used with add_custom_command.");
  291. }
  292. return this->EvaluateWithLanguage(parameters, context, content,
  293. dagChecker, "CXX");
  294. }
  295. } cxxCompilerIdNode;
  296. //----------------------------------------------------------------------------
  297. static const struct ConfigurationNode : public cmGeneratorExpressionNode
  298. {
  299. ConfigurationNode() {}
  300. virtual int NumExpectedParameters() const { return 0; }
  301. std::string Evaluate(const std::vector<std::string> &,
  302. cmGeneratorExpressionContext *context,
  303. const GeneratorExpressionContent *,
  304. cmGeneratorExpressionDAGChecker *) const
  305. {
  306. context->HadContextSensitiveCondition = true;
  307. return context->Config ? context->Config : "";
  308. }
  309. } configurationNode;
  310. //----------------------------------------------------------------------------
  311. static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
  312. {
  313. ConfigurationTestNode() {}
  314. virtual int NumExpectedParameters() const { return 1; }
  315. std::string Evaluate(const std::vector<std::string> &parameters,
  316. cmGeneratorExpressionContext *context,
  317. const GeneratorExpressionContent *content,
  318. cmGeneratorExpressionDAGChecker *) const
  319. {
  320. cmsys::RegularExpression configValidator;
  321. configValidator.compile("^[A-Za-z0-9_]*$");
  322. if (!configValidator.find(parameters.begin()->c_str()))
  323. {
  324. reportError(context, content->GetOriginalExpression(),
  325. "Expression syntax not recognized.");
  326. return std::string();
  327. }
  328. context->HadContextSensitiveCondition = true;
  329. if (!context->Config)
  330. {
  331. return parameters.front().empty() ? "1" : "0";
  332. }
  333. if (cmsysString_strcasecmp(parameters.begin()->c_str(),
  334. context->Config) == 0)
  335. {
  336. return "1";
  337. }
  338. if (context->CurrentTarget
  339. && context->CurrentTarget->IsImported())
  340. {
  341. const char* loc = 0;
  342. const char* imp = 0;
  343. std::string suffix;
  344. return context->CurrentTarget->GetMappedConfig(context->Config,
  345. &loc,
  346. &imp,
  347. suffix) ? "1" : "0";
  348. }
  349. return "0";
  350. }
  351. } configurationTestNode;
  352. //----------------------------------------------------------------------------
  353. static const struct LinkLanguageNode : public cmGeneratorExpressionNode
  354. {
  355. LinkLanguageNode() {}
  356. virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
  357. std::string Evaluate(const std::vector<std::string> &parameters,
  358. cmGeneratorExpressionContext *context,
  359. const GeneratorExpressionContent *content,
  360. cmGeneratorExpressionDAGChecker *) const
  361. {
  362. if (parameters.size() != 0 && parameters.size() != 1)
  363. {
  364. reportError(context, content->GetOriginalExpression(),
  365. "$<LINK_LANGUAGE> expression requires one or two parameters");
  366. return std::string();
  367. }
  368. cmTarget* target = context->HeadTarget;
  369. if (!target)
  370. {
  371. reportError(context, content->GetOriginalExpression(),
  372. "$<LINK_LANGUAGE> may only be used with targets. It may not "
  373. "be used with add_custom_command.");
  374. }
  375. const char *lang = target->GetLinkerLanguage(context->Config);
  376. if (parameters.size() == 0)
  377. {
  378. return lang ? lang : "";
  379. }
  380. else
  381. {
  382. cmsys::RegularExpression langValidator;
  383. langValidator.compile("^[A-Za-z0-9_]*$");
  384. if (!langValidator.find(parameters.begin()->c_str()))
  385. {
  386. reportError(context, content->GetOriginalExpression(),
  387. "Expression syntax not recognized.");
  388. return std::string();
  389. }
  390. if (!lang)
  391. {
  392. return parameters.front().empty() ? "1" : "0";
  393. }
  394. if (strcmp(parameters.begin()->c_str(), lang) == 0)
  395. {
  396. return "1";
  397. }
  398. return "0";
  399. }
  400. }
  401. } linkLanguageNode;
  402. static const struct JoinNode : public cmGeneratorExpressionNode
  403. {
  404. JoinNode() {}
  405. virtual int NumExpectedParameters() const { return 2; }
  406. virtual bool AcceptsArbitraryContentParameter() const { return true; }
  407. std::string Evaluate(const std::vector<std::string> &parameters,
  408. cmGeneratorExpressionContext *,
  409. const GeneratorExpressionContent *,
  410. cmGeneratorExpressionDAGChecker *) const
  411. {
  412. std::string result;
  413. std::vector<std::string> list;
  414. cmSystemTools::ExpandListArgument(parameters.front(), list);
  415. std::string sep;
  416. for(std::vector<std::string>::const_iterator li = list.begin();
  417. li != list.end(); ++li)
  418. {
  419. result += sep + *li;
  420. sep = parameters[1];
  421. }
  422. return result;
  423. }
  424. } joinNode;
  425. #define TRANSITIVE_PROPERTY_NAME(PROPERTY) \
  426. , #PROPERTY
  427. //----------------------------------------------------------------------------
  428. static const char* targetPropertyTransitiveWhitelist[] = {
  429. 0
  430. CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
  431. };
  432. std::string getLinkedTargetsContent(const std::vector<std::string> &libraries,
  433. cmTarget *target,
  434. cmTarget *headTarget,
  435. cmGeneratorExpressionContext *context,
  436. cmGeneratorExpressionDAGChecker *dagChecker,
  437. const std::string &interfacePropertyName)
  438. {
  439. cmGeneratorExpression ge(context->Backtrace);
  440. std::string sep;
  441. std::string depString;
  442. for (std::vector<std::string>::const_iterator
  443. it = libraries.begin();
  444. it != libraries.end(); ++it)
  445. {
  446. if (*it == target->GetName())
  447. {
  448. // Broken code can have a target in its own link interface.
  449. // Don't follow such link interface entries so as not to create a
  450. // self-referencing loop.
  451. continue;
  452. }
  453. if (context->Makefile->FindTargetToUse(it->c_str()))
  454. {
  455. depString +=
  456. sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">";
  457. sep = ";";
  458. }
  459. }
  460. cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString);
  461. std::string linkedTargetsContent = cge->Evaluate(context->Makefile,
  462. context->Config,
  463. context->Quiet,
  464. headTarget,
  465. target,
  466. dagChecker);
  467. if (cge->GetHadContextSensitiveCondition())
  468. {
  469. context->HadContextSensitiveCondition = true;
  470. }
  471. return linkedTargetsContent;
  472. }
  473. //----------------------------------------------------------------------------
  474. struct TransitiveWhitelistCompare
  475. {
  476. explicit TransitiveWhitelistCompare(const std::string &needle)
  477. : Needle(needle) {}
  478. bool operator() (const char *item)
  479. { return strcmp(item, this->Needle.c_str()) == 0; }
  480. private:
  481. std::string Needle;
  482. };
  483. //----------------------------------------------------------------------------
  484. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  485. {
  486. TargetPropertyNode() {}
  487. // This node handles errors on parameter count itself.
  488. virtual int NumExpectedParameters() const { return OneOrMoreParameters; }
  489. std::string Evaluate(const std::vector<std::string> &parameters,
  490. cmGeneratorExpressionContext *context,
  491. const GeneratorExpressionContent *content,
  492. cmGeneratorExpressionDAGChecker *dagCheckerParent
  493. ) const
  494. {
  495. if (parameters.size() != 1 && parameters.size() != 2)
  496. {
  497. reportError(context, content->GetOriginalExpression(),
  498. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  499. return std::string();
  500. }
  501. cmsys::RegularExpression propertyNameValidator;
  502. propertyNameValidator.compile("^[A-Za-z0-9_]+$");
  503. cmTarget* target = context->HeadTarget;
  504. std::string propertyName = *parameters.begin();
  505. if (!target && parameters.size() == 1)
  506. {
  507. reportError(context, content->GetOriginalExpression(),
  508. "$<TARGET_PROPERTY:prop> may only be used with targets. It may not "
  509. "be used with add_custom_command. Specify the target to read a "
  510. "property from using the $<TARGET_PROPERTY:tgt,prop> signature "
  511. "instead.");
  512. return std::string();
  513. }
  514. if (parameters.size() == 2)
  515. {
  516. if (parameters.begin()->empty() && parameters[1].empty())
  517. {
  518. reportError(context, content->GetOriginalExpression(),
  519. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  520. "target name and property name.");
  521. return std::string();
  522. }
  523. if (parameters.begin()->empty())
  524. {
  525. reportError(context, content->GetOriginalExpression(),
  526. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  527. "target name.");
  528. return std::string();
  529. }
  530. std::string targetName = parameters.front();
  531. propertyName = parameters[1];
  532. if (!cmGeneratorExpression::IsValidTargetName(targetName))
  533. {
  534. if (!propertyNameValidator.find(propertyName.c_str()))
  535. {
  536. ::reportError(context, content->GetOriginalExpression(),
  537. "Target name and property name not supported.");
  538. return std::string();
  539. }
  540. ::reportError(context, content->GetOriginalExpression(),
  541. "Target name not supported.");
  542. return std::string();
  543. }
  544. target = context->Makefile->FindTargetToUse(
  545. targetName.c_str());
  546. if (!target)
  547. {
  548. cmOStringStream e;
  549. e << "Target \""
  550. << targetName
  551. << "\" not found.";
  552. reportError(context, content->GetOriginalExpression(), e.str());
  553. return std::string();
  554. }
  555. context->AllTargets.insert(target);
  556. }
  557. if (target == context->HeadTarget)
  558. {
  559. // Keep track of the properties seen while processing.
  560. // The evaluation of the LINK_LIBRARIES generator expressions
  561. // will check this to ensure that properties have one consistent
  562. // value for all evaluations.
  563. context->SeenTargetProperties.insert(propertyName);
  564. }
  565. if (propertyName.empty())
  566. {
  567. reportError(context, content->GetOriginalExpression(),
  568. "$<TARGET_PROPERTY:...> expression requires a non-empty property "
  569. "name.");
  570. return std::string();
  571. }
  572. if (!propertyNameValidator.find(propertyName.c_str()))
  573. {
  574. ::reportError(context, content->GetOriginalExpression(),
  575. "Property name not supported.");
  576. return std::string();
  577. }
  578. assert(target);
  579. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  580. target->GetName(),
  581. propertyName,
  582. content,
  583. dagCheckerParent);
  584. switch (dagChecker.check())
  585. {
  586. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  587. dagChecker.reportError(context, content->GetOriginalExpression());
  588. return std::string();
  589. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  590. // No error. We just skip cyclic references.
  591. return std::string();
  592. case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
  593. for (size_t i = 1;
  594. i < (sizeof(targetPropertyTransitiveWhitelist) /
  595. sizeof(*targetPropertyTransitiveWhitelist));
  596. ++i)
  597. {
  598. if (targetPropertyTransitiveWhitelist[i] == propertyName)
  599. {
  600. // No error. We're not going to find anything new here.
  601. return std::string();
  602. }
  603. }
  604. case cmGeneratorExpressionDAGChecker::DAG:
  605. break;
  606. }
  607. const char *prop = target->GetProperty(propertyName.c_str());
  608. if (dagCheckerParent)
  609. {
  610. if (dagCheckerParent->EvaluatingLinkLibraries())
  611. {
  612. if(!prop)
  613. {
  614. return std::string();
  615. }
  616. }
  617. else
  618. {
  619. #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) \
  620. dagCheckerParent->METHOD () ||
  621. assert(
  622. CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
  623. ASSERT_TRANSITIVE_PROPERTY_METHOD)
  624. false);
  625. }
  626. }
  627. std::string linkedTargetsContent;
  628. std::string interfacePropertyName;
  629. if (propertyName == "INTERFACE_INCLUDE_DIRECTORIES"
  630. || propertyName == "INCLUDE_DIRECTORIES")
  631. {
  632. interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES";
  633. }
  634. else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS"
  635. || propertyName == "COMPILE_DEFINITIONS"
  636. || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0)
  637. {
  638. interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
  639. }
  640. else if (propertyName == "INTERFACE_COMPILE_OPTIONS"
  641. || propertyName == "COMPILE_OPTIONS")
  642. {
  643. interfacePropertyName = "INTERFACE_COMPILE_OPTIONS";
  644. }
  645. cmTarget *headTarget = context->HeadTarget ? context->HeadTarget : target;
  646. const char **transBegin = targetPropertyTransitiveWhitelist + 1;
  647. const char **transEnd = targetPropertyTransitiveWhitelist
  648. + (sizeof(targetPropertyTransitiveWhitelist) /
  649. sizeof(*targetPropertyTransitiveWhitelist));
  650. if (std::find_if(transBegin, transEnd,
  651. TransitiveWhitelistCompare(propertyName)) != transEnd)
  652. {
  653. const cmTarget::LinkInterface *iface = target->GetLinkInterface(
  654. context->Config,
  655. headTarget);
  656. if(iface)
  657. {
  658. linkedTargetsContent =
  659. getLinkedTargetsContent(iface->Libraries, target,
  660. headTarget,
  661. context, &dagChecker,
  662. interfacePropertyName);
  663. }
  664. }
  665. else if (std::find_if(transBegin, transEnd,
  666. TransitiveWhitelistCompare(interfacePropertyName)) != transEnd)
  667. {
  668. const cmTarget::LinkImplementation *impl = target->GetLinkImplementation(
  669. context->Config,
  670. headTarget);
  671. if(impl)
  672. {
  673. linkedTargetsContent =
  674. getLinkedTargetsContent(impl->Libraries, target,
  675. headTarget,
  676. context, &dagChecker,
  677. interfacePropertyName);
  678. }
  679. }
  680. linkedTargetsContent =
  681. cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
  682. if (!prop)
  683. {
  684. if (target->IsImported())
  685. {
  686. return linkedTargetsContent;
  687. }
  688. if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
  689. context->Config))
  690. {
  691. context->HadContextSensitiveCondition = true;
  692. return target->GetLinkInterfaceDependentBoolProperty(
  693. propertyName,
  694. context->Config) ? "1" : "0";
  695. }
  696. if (target->IsLinkInterfaceDependentStringProperty(propertyName,
  697. context->Config))
  698. {
  699. context->HadContextSensitiveCondition = true;
  700. const char *propContent =
  701. target->GetLinkInterfaceDependentStringProperty(
  702. propertyName,
  703. context->Config);
  704. return propContent ? propContent : "";
  705. }
  706. return linkedTargetsContent;
  707. }
  708. for (size_t i = 1;
  709. i < (sizeof(targetPropertyTransitiveWhitelist) /
  710. sizeof(*targetPropertyTransitiveWhitelist));
  711. ++i)
  712. {
  713. if (targetPropertyTransitiveWhitelist[i] == interfacePropertyName)
  714. {
  715. cmGeneratorExpression ge(context->Backtrace);
  716. cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
  717. std::string result = cge->Evaluate(context->Makefile,
  718. context->Config,
  719. context->Quiet,
  720. headTarget,
  721. target,
  722. &dagChecker);
  723. if (cge->GetHadContextSensitiveCondition())
  724. {
  725. context->HadContextSensitiveCondition = true;
  726. }
  727. if (!linkedTargetsContent.empty())
  728. {
  729. result += (result.empty() ? "" : ";") + linkedTargetsContent;
  730. }
  731. return result;
  732. }
  733. }
  734. return prop;
  735. }
  736. } targetPropertyNode;
  737. //----------------------------------------------------------------------------
  738. static const struct TargetNameNode : public cmGeneratorExpressionNode
  739. {
  740. TargetNameNode() {}
  741. virtual bool GeneratesContent() const { return true; }
  742. virtual bool AcceptsArbitraryContentParameter() const { return true; }
  743. virtual bool RequiresLiteralInput() const { return true; }
  744. std::string Evaluate(const std::vector<std::string> &parameters,
  745. cmGeneratorExpressionContext *,
  746. const GeneratorExpressionContent *,
  747. cmGeneratorExpressionDAGChecker *) const
  748. {
  749. return parameters.front();
  750. }
  751. virtual int NumExpectedParameters() const { return 1; }
  752. } targetNameNode;
  753. //----------------------------------------------------------------------------
  754. static const char* targetPolicyWhitelist[] = {
  755. "CMP0003"
  756. , "CMP0004"
  757. , "CMP0008"
  758. , "CMP0020"
  759. };
  760. cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
  761. {
  762. #define RETURN_POLICY(POLICY) \
  763. if (strcmp(policy, #POLICY) == 0) \
  764. { \
  765. return tgt->GetPolicyStatus ## POLICY (); \
  766. } \
  767. RETURN_POLICY(CMP0003)
  768. RETURN_POLICY(CMP0004)
  769. RETURN_POLICY(CMP0008)
  770. RETURN_POLICY(CMP0020)
  771. #undef RETURN_POLICY
  772. assert("!Unreachable code. Not a valid policy");
  773. return cmPolicies::WARN;
  774. }
  775. cmPolicies::PolicyID policyForString(const char *policy_id)
  776. {
  777. #define RETURN_POLICY_ID(POLICY_ID) \
  778. if (strcmp(policy_id, #POLICY_ID) == 0) \
  779. { \
  780. return cmPolicies:: POLICY_ID; \
  781. } \
  782. RETURN_POLICY_ID(CMP0003)
  783. RETURN_POLICY_ID(CMP0004)
  784. RETURN_POLICY_ID(CMP0008)
  785. RETURN_POLICY_ID(CMP0020)
  786. #undef RETURN_POLICY_ID
  787. assert("!Unreachable code. Not a valid policy");
  788. return cmPolicies::CMP0002;
  789. }
  790. //----------------------------------------------------------------------------
  791. static const struct TargetPolicyNode : public cmGeneratorExpressionNode
  792. {
  793. TargetPolicyNode() {}
  794. virtual int NumExpectedParameters() const { return 1; }
  795. std::string Evaluate(const std::vector<std::string> &parameters,
  796. cmGeneratorExpressionContext *context ,
  797. const GeneratorExpressionContent *content,
  798. cmGeneratorExpressionDAGChecker *) const
  799. {
  800. if (!context->HeadTarget)
  801. {
  802. reportError(context, content->GetOriginalExpression(),
  803. "$<TARGET_POLICY:prop> may only be used with targets. It may not "
  804. "be used with add_custom_command.");
  805. return std::string();
  806. }
  807. context->HadContextSensitiveCondition = true;
  808. for (size_t i = 0;
  809. i < (sizeof(targetPolicyWhitelist) /
  810. sizeof(*targetPolicyWhitelist));
  811. ++i)
  812. {
  813. const char *policy = targetPolicyWhitelist[i];
  814. if (parameters.front() == policy)
  815. {
  816. cmMakefile *mf = context->HeadTarget->GetMakefile();
  817. switch(statusForTarget(context->HeadTarget, policy))
  818. {
  819. case cmPolicies::WARN:
  820. mf->IssueMessage(cmake::AUTHOR_WARNING,
  821. mf->GetPolicies()->
  822. GetPolicyWarning(policyForString(policy)));
  823. case cmPolicies::REQUIRED_IF_USED:
  824. case cmPolicies::REQUIRED_ALWAYS:
  825. case cmPolicies::OLD:
  826. return "0";
  827. case cmPolicies::NEW:
  828. return "1";
  829. }
  830. }
  831. }
  832. reportError(context, content->GetOriginalExpression(),
  833. "$<TARGET_POLICY:prop> may only be used with a limited number of "
  834. "policies. Currently it may be used with policies CMP0003, CMP0004, "
  835. "CMP0008 and CMP0020."
  836. );
  837. return std::string();
  838. }
  839. } targetPolicyNode;
  840. //----------------------------------------------------------------------------
  841. static const struct InstallPrefixNode : public cmGeneratorExpressionNode
  842. {
  843. InstallPrefixNode() {}
  844. virtual bool GeneratesContent() const { return true; }
  845. virtual int NumExpectedParameters() const { return 0; }
  846. std::string Evaluate(const std::vector<std::string> &,
  847. cmGeneratorExpressionContext *context,
  848. const GeneratorExpressionContent *content,
  849. cmGeneratorExpressionDAGChecker *) const
  850. {
  851. reportError(context, content->GetOriginalExpression(),
  852. "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
  853. "should never be evaluated.");
  854. return std::string();
  855. }
  856. } installPrefixNode;
  857. //----------------------------------------------------------------------------
  858. template<bool linker, bool soname>
  859. struct TargetFilesystemArtifactResultCreator
  860. {
  861. static std::string Create(cmTarget* target,
  862. cmGeneratorExpressionContext *context,
  863. const GeneratorExpressionContent *content);
  864. };
  865. //----------------------------------------------------------------------------
  866. template<>
  867. struct TargetFilesystemArtifactResultCreator<false, true>
  868. {
  869. static std::string Create(cmTarget* target,
  870. cmGeneratorExpressionContext *context,
  871. const GeneratorExpressionContent *content)
  872. {
  873. // The target soname file (.so.1).
  874. if(target->IsDLLPlatform())
  875. {
  876. ::reportError(context, content->GetOriginalExpression(),
  877. "TARGET_SONAME_FILE is not allowed "
  878. "for DLL target platforms.");
  879. return std::string();
  880. }
  881. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  882. {
  883. ::reportError(context, content->GetOriginalExpression(),
  884. "TARGET_SONAME_FILE is allowed only for "
  885. "SHARED libraries.");
  886. return std::string();
  887. }
  888. std::string result = target->GetDirectory(context->Config);
  889. result += "/";
  890. result += target->GetSOName(context->Config);
  891. return result;
  892. }
  893. };
  894. //----------------------------------------------------------------------------
  895. template<>
  896. struct TargetFilesystemArtifactResultCreator<true, false>
  897. {
  898. static std::string Create(cmTarget* target,
  899. cmGeneratorExpressionContext *context,
  900. const GeneratorExpressionContent *content)
  901. {
  902. // The file used to link to the target (.so, .lib, .a).
  903. if(!target->IsLinkable())
  904. {
  905. ::reportError(context, content->GetOriginalExpression(),
  906. "TARGET_LINKER_FILE is allowed only for libraries and "
  907. "executables with ENABLE_EXPORTS.");
  908. return std::string();
  909. }
  910. return target->GetFullPath(context->Config,
  911. target->HasImportLibrary());
  912. }
  913. };
  914. //----------------------------------------------------------------------------
  915. template<>
  916. struct TargetFilesystemArtifactResultCreator<false, false>
  917. {
  918. static std::string Create(cmTarget* target,
  919. cmGeneratorExpressionContext *context,
  920. const GeneratorExpressionContent *)
  921. {
  922. return target->GetFullPath(context->Config, false, true);
  923. }
  924. };
  925. //----------------------------------------------------------------------------
  926. template<bool dirQual, bool nameQual>
  927. struct TargetFilesystemArtifactResultGetter
  928. {
  929. static std::string Get(const std::string &result);
  930. };
  931. //----------------------------------------------------------------------------
  932. template<>
  933. struct TargetFilesystemArtifactResultGetter<false, true>
  934. {
  935. static std::string Get(const std::string &result)
  936. { return cmSystemTools::GetFilenameName(result); }
  937. };
  938. //----------------------------------------------------------------------------
  939. template<>
  940. struct TargetFilesystemArtifactResultGetter<true, false>
  941. {
  942. static std::string Get(const std::string &result)
  943. { return cmSystemTools::GetFilenamePath(result); }
  944. };
  945. //----------------------------------------------------------------------------
  946. template<>
  947. struct TargetFilesystemArtifactResultGetter<false, false>
  948. {
  949. static std::string Get(const std::string &result)
  950. { return result; }
  951. };
  952. //----------------------------------------------------------------------------
  953. template<bool linker, bool soname, bool dirQual, bool nameQual>
  954. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  955. {
  956. TargetFilesystemArtifact() {}
  957. virtual int NumExpectedParameters() const { return 1; }
  958. std::string Evaluate(const std::vector<std::string> &parameters,
  959. cmGeneratorExpressionContext *context,
  960. const GeneratorExpressionContent *content,
  961. cmGeneratorExpressionDAGChecker *) const
  962. {
  963. // Lookup the referenced target.
  964. std::string name = *parameters.begin();
  965. if (!cmGeneratorExpression::IsValidTargetName(name))
  966. {
  967. ::reportError(context, content->GetOriginalExpression(),
  968. "Expression syntax not recognized.");
  969. return std::string();
  970. }
  971. cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
  972. if(!target)
  973. {
  974. ::reportError(context, content->GetOriginalExpression(),
  975. "No target \"" + name + "\"");
  976. return std::string();
  977. }
  978. if(target->GetType() >= cmTarget::UTILITY &&
  979. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  980. {
  981. ::reportError(context, content->GetOriginalExpression(),
  982. "Target \"" + name + "\" is not an executable or library.");
  983. return std::string();
  984. }
  985. context->DependTargets.insert(target);
  986. context->AllTargets.insert(target);
  987. std::string result =
  988. TargetFilesystemArtifactResultCreator<linker, soname>::Create(
  989. target,
  990. context,
  991. content);
  992. if (context->HadError)
  993. {
  994. return std::string();
  995. }
  996. return
  997. TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
  998. }
  999. };
  1000. //----------------------------------------------------------------------------
  1001. static const
  1002. TargetFilesystemArtifact<false, false, false, false> targetFileNode;
  1003. static const
  1004. TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
  1005. static const
  1006. TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
  1007. static const
  1008. TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
  1009. static const
  1010. TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
  1011. static const
  1012. TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
  1013. static const
  1014. TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
  1015. static const
  1016. TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
  1017. static const
  1018. TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
  1019. //----------------------------------------------------------------------------
  1020. static const
  1021. cmGeneratorExpressionNode* GetNode(const std::string &identifier)
  1022. {
  1023. if (identifier == "0")
  1024. return &zeroNode;
  1025. else if (identifier == "1")
  1026. return &oneNode;
  1027. else if (identifier == "AND")
  1028. return &andNode;
  1029. else if (identifier == "OR")
  1030. return &orNode;
  1031. else if (identifier == "NOT")
  1032. return &notNode;
  1033. else if (identifier == "C_COMPILER_ID")
  1034. return &cCompilerIdNode;
  1035. else if (identifier == "CXX_COMPILER_ID")
  1036. return &cxxCompilerIdNode;
  1037. else if (identifier == "CONFIGURATION")
  1038. return &configurationNode;
  1039. else if (identifier == "CONFIG")
  1040. return &configurationTestNode;
  1041. else if (identifier == "LINK_LANGUAGE")
  1042. return &linkLanguageNode;
  1043. else if (identifier == "TARGET_FILE")
  1044. return &targetFileNode;
  1045. else if (identifier == "TARGET_LINKER_FILE")
  1046. return &targetLinkerFileNode;
  1047. else if (identifier == "TARGET_SONAME_FILE")
  1048. return &targetSoNameFileNode;
  1049. else if (identifier == "TARGET_FILE_NAME")
  1050. return &targetFileNameNode;
  1051. else if (identifier == "TARGET_LINKER_FILE_NAME")
  1052. return &targetLinkerFileNameNode;
  1053. else if (identifier == "TARGET_SONAME_FILE_NAME")
  1054. return &targetSoNameFileNameNode;
  1055. else if (identifier == "TARGET_FILE_DIR")
  1056. return &targetFileDirNode;
  1057. else if (identifier == "TARGET_LINKER_FILE_DIR")
  1058. return &targetLinkerFileDirNode;
  1059. else if (identifier == "TARGET_SONAME_FILE_DIR")
  1060. return &targetSoNameFileDirNode;
  1061. else if (identifier == "STREQUAL")
  1062. return &strEqualNode;
  1063. else if (identifier == "BOOL")
  1064. return &boolNode;
  1065. else if (identifier == "ANGLE-R")
  1066. return &angle_rNode;
  1067. else if (identifier == "COMMA")
  1068. return &commaNode;
  1069. else if (identifier == "SEMICOLON")
  1070. return &semicolonNode;
  1071. else if (identifier == "TARGET_PROPERTY")
  1072. return &targetPropertyNode;
  1073. else if (identifier == "TARGET_NAME")
  1074. return &targetNameNode;
  1075. else if (identifier == "TARGET_POLICY")
  1076. return &targetPolicyNode;
  1077. else if (identifier == "BUILD_INTERFACE")
  1078. return &buildInterfaceNode;
  1079. else if (identifier == "INSTALL_INTERFACE")
  1080. return &installInterfaceNode;
  1081. else if (identifier == "INSTALL_PREFIX")
  1082. return &installPrefixNode;
  1083. else if (identifier == "JOIN")
  1084. return &joinNode;
  1085. return 0;
  1086. }
  1087. //----------------------------------------------------------------------------
  1088. GeneratorExpressionContent::GeneratorExpressionContent(
  1089. const char *startContent,
  1090. unsigned int length)
  1091. : StartContent(startContent), ContentLength(length)
  1092. {
  1093. }
  1094. //----------------------------------------------------------------------------
  1095. std::string GeneratorExpressionContent::GetOriginalExpression() const
  1096. {
  1097. return std::string(this->StartContent, this->ContentLength);
  1098. }
  1099. //----------------------------------------------------------------------------
  1100. std::string GeneratorExpressionContent::ProcessArbitraryContent(
  1101. const cmGeneratorExpressionNode *node,
  1102. const std::string &identifier,
  1103. cmGeneratorExpressionContext *context,
  1104. cmGeneratorExpressionDAGChecker *dagChecker,
  1105. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  1106. pit) const
  1107. {
  1108. std::string result;
  1109. const
  1110. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  1111. pend = this->ParamChildren.end();
  1112. for ( ; pit != pend; ++pit)
  1113. {
  1114. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  1115. = pit->begin();
  1116. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  1117. = pit->end();
  1118. for ( ; it != end; ++it)
  1119. {
  1120. if (node->RequiresLiteralInput())
  1121. {
  1122. if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
  1123. {
  1124. reportError(context, this->GetOriginalExpression(),
  1125. "$<" + identifier + "> expression requires literal input.");
  1126. return std::string();
  1127. }
  1128. }
  1129. result += (*it)->Evaluate(context, dagChecker);
  1130. if (context->HadError)
  1131. {
  1132. return std::string();
  1133. }
  1134. }
  1135. if ((pit + 1) != pend)
  1136. {
  1137. result += ",";
  1138. }
  1139. }
  1140. if (node->RequiresLiteralInput())
  1141. {
  1142. std::vector<std::string> parameters;
  1143. parameters.push_back(result);
  1144. return node->Evaluate(parameters, context, this, dagChecker);
  1145. }
  1146. return result;
  1147. }
  1148. //----------------------------------------------------------------------------
  1149. std::string GeneratorExpressionContent::Evaluate(
  1150. cmGeneratorExpressionContext *context,
  1151. cmGeneratorExpressionDAGChecker *dagChecker) const
  1152. {
  1153. std::string identifier;
  1154. {
  1155. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  1156. = this->IdentifierChildren.begin();
  1157. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  1158. = this->IdentifierChildren.end();
  1159. for ( ; it != end; ++it)
  1160. {
  1161. identifier += (*it)->Evaluate(context, dagChecker);
  1162. if (context->HadError)
  1163. {
  1164. return std::string();
  1165. }
  1166. }
  1167. }
  1168. const cmGeneratorExpressionNode *node = GetNode(identifier);
  1169. if (!node)
  1170. {
  1171. reportError(context, this->GetOriginalExpression(),
  1172. "Expression did not evaluate to a known generator expression");
  1173. return std::string();
  1174. }
  1175. if (!node->GeneratesContent())
  1176. {
  1177. if (node->NumExpectedParameters() == 1
  1178. && node->AcceptsArbitraryContentParameter())
  1179. {
  1180. if (this->ParamChildren.empty())
  1181. {
  1182. reportError(context, this->GetOriginalExpression(),
  1183. "$<" + identifier + "> expression requires a parameter.");
  1184. }
  1185. }
  1186. else
  1187. {
  1188. std::vector<std::string> parameters;
  1189. this->EvaluateParameters(node, identifier, context, dagChecker,
  1190. parameters);
  1191. }
  1192. return std::string();
  1193. }
  1194. if (node->NumExpectedParameters() == 1
  1195. && node->AcceptsArbitraryContentParameter())
  1196. {
  1197. return this->ProcessArbitraryContent(node, identifier, context,
  1198. dagChecker,
  1199. this->ParamChildren.begin());
  1200. }
  1201. std::vector<std::string> parameters;
  1202. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  1203. if (context->HadError)
  1204. {
  1205. return std::string();
  1206. }
  1207. return node->Evaluate(parameters, context, this, dagChecker);
  1208. }
  1209. //----------------------------------------------------------------------------
  1210. std::string GeneratorExpressionContent::EvaluateParameters(
  1211. const cmGeneratorExpressionNode *node,
  1212. const std::string &identifier,
  1213. cmGeneratorExpressionContext *context,
  1214. cmGeneratorExpressionDAGChecker *dagChecker,
  1215. std::vector<std::string> &parameters) const
  1216. {
  1217. const int numExpected = node->NumExpectedParameters();
  1218. {
  1219. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  1220. pit = this->ParamChildren.begin();
  1221. const
  1222. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  1223. pend = this->ParamChildren.end();
  1224. const bool acceptsArbitraryContent
  1225. = node->AcceptsArbitraryContentParameter();
  1226. for ( ; pit != pend; ++pit)
  1227. {
  1228. std::string parameter;
  1229. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  1230. pit->begin();
  1231. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  1232. pit->end();
  1233. for ( ; it != end; ++it)
  1234. {
  1235. parameter += (*it)->Evaluate(context, dagChecker);
  1236. if (context->HadError)
  1237. {
  1238. return std::string();
  1239. }
  1240. }
  1241. parameters.push_back(parameter);
  1242. if (acceptsArbitraryContent
  1243. && parameters.size() == (unsigned int)numExpected - 1)
  1244. {
  1245. assert(pit != pend);
  1246. std::string lastParam = this->ProcessArbitraryContent(node, identifier,
  1247. context,
  1248. dagChecker,
  1249. pit + 1);
  1250. parameters.push_back(lastParam);
  1251. return std::string();
  1252. }
  1253. }
  1254. }
  1255. if ((numExpected > cmGeneratorExpressionNode::DynamicParameters
  1256. && (unsigned int)numExpected != parameters.size()))
  1257. {
  1258. if (numExpected == 0)
  1259. {
  1260. reportError(context, this->GetOriginalExpression(),
  1261. "$<" + identifier + "> expression requires no parameters.");
  1262. }
  1263. else if (numExpected == 1)
  1264. {
  1265. reportError(context, this->GetOriginalExpression(),
  1266. "$<" + identifier + "> expression requires "
  1267. "exactly one parameter.");
  1268. }
  1269. else
  1270. {
  1271. cmOStringStream e;
  1272. e << "$<" + identifier + "> expression requires "
  1273. << numExpected
  1274. << " comma separated parameters, but got "
  1275. << parameters.size() << " instead.";
  1276. reportError(context, this->GetOriginalExpression(), e.str());
  1277. }
  1278. return std::string();
  1279. }
  1280. if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
  1281. && parameters.empty())
  1282. {
  1283. reportError(context, this->GetOriginalExpression(), "$<" + identifier
  1284. + "> expression requires at least one parameter.");
  1285. }
  1286. return std::string();
  1287. }
  1288. //----------------------------------------------------------------------------
  1289. static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
  1290. {
  1291. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  1292. = c.begin();
  1293. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  1294. = c.end();
  1295. for ( ; it != end; ++it)
  1296. {
  1297. delete *it;
  1298. }
  1299. }
  1300. //----------------------------------------------------------------------------
  1301. GeneratorExpressionContent::~GeneratorExpressionContent()
  1302. {
  1303. deleteAll(this->IdentifierChildren);
  1304. typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
  1305. std::vector<EvaluatorVector>::const_iterator pit =
  1306. this->ParamChildren.begin();
  1307. const std::vector<EvaluatorVector>::const_iterator pend =
  1308. this->ParamChildren.end();
  1309. for ( ; pit != pend; ++pit)
  1310. {
  1311. deleteAll(*pit);
  1312. }
  1313. }