cmGeneratorExpressionEvaluator.cxx 36 KB

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