cmGeneratorExpressionNode.cxx 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmGeneratorExpressionNode.h"
  4. #include "cmAlgorithms.h"
  5. #include "cmGeneratorExpression.h"
  6. #include "cmGeneratorExpressionContext.h"
  7. #include "cmGeneratorExpressionDAGChecker.h"
  8. #include "cmGeneratorExpressionEvaluator.h"
  9. #include "cmGeneratorTarget.h"
  10. #include "cmGlobalGenerator.h"
  11. #include "cmLinkItem.h"
  12. #include "cmLocalGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmMessageType.h"
  15. #include "cmOutputConverter.h"
  16. #include "cmPolicies.h"
  17. #include "cmStateTypes.h"
  18. #include "cmSystemTools.h"
  19. #include "cmTarget.h"
  20. #include "cmake.h"
  21. #include "cmsys/RegularExpression.hxx"
  22. #include "cmsys/String.h"
  23. #include <algorithm>
  24. #include <assert.h>
  25. #include <errno.h>
  26. #include <map>
  27. #include <memory> // IWYU pragma: keep
  28. #include <set>
  29. #include <sstream>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <utility>
  33. std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
  34. std::string const& prop, cmLocalGenerator* lg,
  35. cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget,
  36. cmGeneratorTarget const* currentTarget,
  37. cmGeneratorExpressionDAGChecker* dagChecker)
  38. {
  39. cmGeneratorExpression ge(context->Backtrace);
  40. std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
  41. cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
  42. std::string result =
  43. cge->Evaluate(lg, context->Config, context->Quiet, headTarget,
  44. currentTarget, dagChecker, context->Language);
  45. if (cge->GetHadContextSensitiveCondition()) {
  46. context->HadContextSensitiveCondition = true;
  47. }
  48. if (cge->GetHadHeadSensitiveCondition()) {
  49. context->HadHeadSensitiveCondition = true;
  50. }
  51. return result;
  52. }
  53. static const struct ZeroNode : public cmGeneratorExpressionNode
  54. {
  55. ZeroNode() {} // NOLINT(modernize-use-equals-default)
  56. bool GeneratesContent() const override { return false; }
  57. bool AcceptsArbitraryContentParameter() const override { return true; }
  58. std::string Evaluate(
  59. const std::vector<std::string>& /*parameters*/,
  60. cmGeneratorExpressionContext* /*context*/,
  61. const GeneratorExpressionContent* /*content*/,
  62. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  63. {
  64. return std::string();
  65. }
  66. } zeroNode;
  67. static const struct OneNode : public cmGeneratorExpressionNode
  68. {
  69. OneNode() {} // NOLINT(modernize-use-equals-default)
  70. bool AcceptsArbitraryContentParameter() const override { return true; }
  71. std::string Evaluate(
  72. const std::vector<std::string>& parameters,
  73. cmGeneratorExpressionContext* /*context*/,
  74. const GeneratorExpressionContent* /*content*/,
  75. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  76. {
  77. return parameters.front();
  78. }
  79. } oneNode;
  80. static const struct OneNode buildInterfaceNode;
  81. static const struct ZeroNode installInterfaceNode;
  82. #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
  83. static const struct OP##Node : public cmGeneratorExpressionNode \
  84. { \
  85. OP##Node() {} /* NOLINT(modernize-use-equals-default) */ \
  86. virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
  87. \
  88. std::string Evaluate(const std::vector<std::string>& parameters, \
  89. cmGeneratorExpressionContext* context, \
  90. const GeneratorExpressionContent* content, \
  91. cmGeneratorExpressionDAGChecker*) const \
  92. { \
  93. for (std::string const& param : parameters) { \
  94. if (param == #FAILURE_VALUE) { \
  95. return #FAILURE_VALUE; \
  96. } \
  97. if (param != #SUCCESS_VALUE) { \
  98. reportError(context, content->GetOriginalExpression(), \
  99. "Parameters to $<" #OP \
  100. "> must resolve to either '0' or '1'."); \
  101. return std::string(); \
  102. } \
  103. } \
  104. return #SUCCESS_VALUE; \
  105. } \
  106. } OPNAME;
  107. BOOLEAN_OP_NODE(andNode, AND, 1, 0)
  108. BOOLEAN_OP_NODE(orNode, OR, 0, 1)
  109. #undef BOOLEAN_OP_NODE
  110. static const struct NotNode : public cmGeneratorExpressionNode
  111. {
  112. NotNode() {} // NOLINT(modernize-use-equals-default)
  113. std::string Evaluate(
  114. const std::vector<std::string>& parameters,
  115. cmGeneratorExpressionContext* context,
  116. const GeneratorExpressionContent* content,
  117. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  118. {
  119. if (parameters.front() != "0" && parameters.front() != "1") {
  120. reportError(
  121. context, content->GetOriginalExpression(),
  122. "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
  123. return std::string();
  124. }
  125. return parameters.front() == "0" ? "1" : "0";
  126. }
  127. } notNode;
  128. static const struct BoolNode : public cmGeneratorExpressionNode
  129. {
  130. BoolNode() {} // NOLINT(modernize-use-equals-default)
  131. int NumExpectedParameters() const override { return 1; }
  132. std::string Evaluate(
  133. const std::vector<std::string>& parameters,
  134. cmGeneratorExpressionContext* /*context*/,
  135. const GeneratorExpressionContent* /*content*/,
  136. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  137. {
  138. return !cmSystemTools::IsOff(parameters.front()) ? "1" : "0";
  139. }
  140. } boolNode;
  141. static const struct IfNode : public cmGeneratorExpressionNode
  142. {
  143. IfNode() {} // NOLINT(modernize-use-equals-default)
  144. int NumExpectedParameters() const override { return 3; }
  145. std::string Evaluate(const std::vector<std::string>& parameters,
  146. cmGeneratorExpressionContext* context,
  147. const GeneratorExpressionContent* content,
  148. cmGeneratorExpressionDAGChecker*) const override
  149. {
  150. if (parameters[0] != "1" && parameters[0] != "0") {
  151. reportError(context, content->GetOriginalExpression(),
  152. "First parameter to $<IF> must resolve to exactly one '0' "
  153. "or '1' value.");
  154. return std::string();
  155. }
  156. return parameters[0] == "1" ? parameters[1] : parameters[2];
  157. }
  158. } ifNode;
  159. static const struct StrEqualNode : public cmGeneratorExpressionNode
  160. {
  161. StrEqualNode() {} // NOLINT(modernize-use-equals-default)
  162. int NumExpectedParameters() const override { return 2; }
  163. std::string Evaluate(
  164. const std::vector<std::string>& parameters,
  165. cmGeneratorExpressionContext* /*context*/,
  166. const GeneratorExpressionContent* /*content*/,
  167. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  168. {
  169. return parameters.front() == parameters[1] ? "1" : "0";
  170. }
  171. } strEqualNode;
  172. static const struct EqualNode : public cmGeneratorExpressionNode
  173. {
  174. EqualNode() {} // NOLINT(modernize-use-equals-default)
  175. int NumExpectedParameters() const override { return 2; }
  176. std::string Evaluate(
  177. const std::vector<std::string>& parameters,
  178. cmGeneratorExpressionContext* context,
  179. const GeneratorExpressionContent* content,
  180. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  181. {
  182. char* pEnd;
  183. int base = 0;
  184. bool flipSign = false;
  185. const char* lhs = parameters[0].c_str();
  186. if (cmHasLiteralPrefix(lhs, "0b") || cmHasLiteralPrefix(lhs, "0B")) {
  187. base = 2;
  188. lhs += 2;
  189. }
  190. if (cmHasLiteralPrefix(lhs, "-0b") || cmHasLiteralPrefix(lhs, "-0B")) {
  191. base = 2;
  192. lhs += 3;
  193. flipSign = true;
  194. }
  195. if (cmHasLiteralPrefix(lhs, "+0b") || cmHasLiteralPrefix(lhs, "+0B")) {
  196. base = 2;
  197. lhs += 3;
  198. }
  199. long lnum = strtol(lhs, &pEnd, base);
  200. if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
  201. reportError(context, content->GetOriginalExpression(),
  202. "$<EQUAL> parameter " + parameters[0] +
  203. " is not a valid integer.");
  204. return std::string();
  205. }
  206. if (flipSign) {
  207. lnum = -lnum;
  208. }
  209. base = 0;
  210. flipSign = false;
  211. const char* rhs = parameters[1].c_str();
  212. if (cmHasLiteralPrefix(rhs, "0b") || cmHasLiteralPrefix(rhs, "0B")) {
  213. base = 2;
  214. rhs += 2;
  215. }
  216. if (cmHasLiteralPrefix(rhs, "-0b") || cmHasLiteralPrefix(rhs, "-0B")) {
  217. base = 2;
  218. rhs += 3;
  219. flipSign = true;
  220. }
  221. if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) {
  222. base = 2;
  223. rhs += 3;
  224. }
  225. long rnum = strtol(rhs, &pEnd, base);
  226. if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
  227. reportError(context, content->GetOriginalExpression(),
  228. "$<EQUAL> parameter " + parameters[1] +
  229. " is not a valid integer.");
  230. return std::string();
  231. }
  232. if (flipSign) {
  233. rnum = -rnum;
  234. }
  235. return lnum == rnum ? "1" : "0";
  236. }
  237. } equalNode;
  238. static const struct InListNode : public cmGeneratorExpressionNode
  239. {
  240. InListNode() {} // NOLINT(modernize-use-equals-default)
  241. int NumExpectedParameters() const override { return 2; }
  242. std::string Evaluate(
  243. const std::vector<std::string>& parameters,
  244. cmGeneratorExpressionContext* context,
  245. const GeneratorExpressionContent* /*content*/,
  246. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  247. {
  248. std::vector<std::string> values, checkValues;
  249. bool check = false;
  250. switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
  251. case cmPolicies::WARN:
  252. if (parameters.front().empty()) {
  253. check = true;
  254. cmSystemTools::ExpandListArgument(parameters[1], checkValues, true);
  255. }
  256. CM_FALLTHROUGH;
  257. case cmPolicies::OLD:
  258. cmSystemTools::ExpandListArgument(parameters[1], values);
  259. if (check && values != checkValues) {
  260. std::ostringstream e;
  261. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
  262. << "\nSearch Item:\n \"" << parameters.front()
  263. << "\"\nList:\n \"" << parameters[1] << "\"\n";
  264. context->LG->GetCMakeInstance()->IssueMessage(
  265. MessageType ::AUTHOR_WARNING, e.str(), context->Backtrace);
  266. return "0";
  267. }
  268. if (values.empty()) {
  269. return "0";
  270. }
  271. break;
  272. case cmPolicies::REQUIRED_IF_USED:
  273. case cmPolicies::REQUIRED_ALWAYS:
  274. case cmPolicies::NEW:
  275. cmSystemTools::ExpandListArgument(parameters[1], values, true);
  276. break;
  277. }
  278. return std::find(values.cbegin(), values.cend(), parameters.front()) ==
  279. values.cend()
  280. ? "0"
  281. : "1";
  282. }
  283. } inListNode;
  284. static const struct TargetExistsNode : public cmGeneratorExpressionNode
  285. {
  286. TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
  287. int NumExpectedParameters() const override { return 1; }
  288. std::string Evaluate(
  289. const std::vector<std::string>& parameters,
  290. cmGeneratorExpressionContext* context,
  291. const GeneratorExpressionContent* content,
  292. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  293. {
  294. if (parameters.size() != 1) {
  295. reportError(context, content->GetOriginalExpression(),
  296. "$<TARGET_EXISTS:...> expression requires one parameter");
  297. return std::string();
  298. }
  299. std::string targetName = parameters.front();
  300. if (targetName.empty() ||
  301. !cmGeneratorExpression::IsValidTargetName(targetName)) {
  302. reportError(context, content->GetOriginalExpression(),
  303. "$<TARGET_EXISTS:tgt> expression requires a non-empty "
  304. "valid target name.");
  305. return std::string();
  306. }
  307. return context->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0";
  308. }
  309. } targetExistsNode;
  310. static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
  311. {
  312. TargetNameIfExistsNode() {} // NOLINT(modernize-use-equals-default)
  313. int NumExpectedParameters() const override { return 1; }
  314. std::string Evaluate(
  315. const std::vector<std::string>& parameters,
  316. cmGeneratorExpressionContext* context,
  317. const GeneratorExpressionContent* content,
  318. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  319. {
  320. if (parameters.size() != 1) {
  321. reportError(context, content->GetOriginalExpression(),
  322. "$<TARGET_NAME_IF_EXISTS:...> expression requires one "
  323. "parameter");
  324. return std::string();
  325. }
  326. std::string targetName = parameters.front();
  327. if (targetName.empty() ||
  328. !cmGeneratorExpression::IsValidTargetName(targetName)) {
  329. reportError(context, content->GetOriginalExpression(),
  330. "$<TARGET_NAME_IF_EXISTS:tgt> expression requires a "
  331. "non-empty valid target name.");
  332. return std::string();
  333. }
  334. return context->LG->GetMakefile()->FindTargetToUse(targetName)
  335. ? targetName
  336. : std::string();
  337. }
  338. } targetNameIfExistsNode;
  339. struct GenexEvaluator : public cmGeneratorExpressionNode
  340. {
  341. GenexEvaluator() {} // NOLINT(modernize-use-equals-default)
  342. protected:
  343. std::string EvaluateExpression(
  344. const std::string& genexOperator, const std::string& expression,
  345. cmGeneratorExpressionContext* context,
  346. const GeneratorExpressionContent* content,
  347. cmGeneratorExpressionDAGChecker* dagCheckerParent) const
  348. {
  349. if (context->HeadTarget) {
  350. cmGeneratorExpressionDAGChecker dagChecker(
  351. context->Backtrace, context->HeadTarget, genexOperator, content,
  352. dagCheckerParent);
  353. switch (dagChecker.Check()) {
  354. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  355. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
  356. dagChecker.ReportError(context, content->GetOriginalExpression());
  357. return std::string();
  358. }
  359. case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
  360. case cmGeneratorExpressionDAGChecker::DAG:
  361. break;
  362. }
  363. return this->EvaluateDependentExpression(
  364. expression, context->LG, context, context->HeadTarget,
  365. context->CurrentTarget, &dagChecker);
  366. }
  367. return this->EvaluateDependentExpression(
  368. expression, context->LG, context, context->HeadTarget,
  369. context->CurrentTarget, dagCheckerParent);
  370. }
  371. };
  372. static const struct TargetGenexEvalNode : public GenexEvaluator
  373. {
  374. TargetGenexEvalNode() {} // NOLINT(modernize-use-equals-default)
  375. int NumExpectedParameters() const override { return 2; }
  376. bool AcceptsArbitraryContentParameter() const override { return true; }
  377. std::string Evaluate(
  378. const std::vector<std::string>& parameters,
  379. cmGeneratorExpressionContext* context,
  380. const GeneratorExpressionContent* content,
  381. cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
  382. {
  383. const std::string& targetName = parameters.front();
  384. if (targetName.empty() ||
  385. !cmGeneratorExpression::IsValidTargetName(targetName)) {
  386. reportError(context, content->GetOriginalExpression(),
  387. "$<TARGET_GENEX_EVAL:tgt, ...> expression requires a "
  388. "non-empty valid target name.");
  389. return std::string();
  390. }
  391. const auto* target = context->LG->FindGeneratorTargetToUse(targetName);
  392. if (!target) {
  393. std::ostringstream e;
  394. e << "$<TARGET_GENEX_EVAL:tgt, ...> target \"" << targetName
  395. << "\" not found.";
  396. reportError(context, content->GetOriginalExpression(), e.str());
  397. return std::string();
  398. }
  399. const std::string& expression = parameters[1];
  400. if (expression.empty()) {
  401. return expression;
  402. }
  403. cmGeneratorExpressionContext targetContext(
  404. context->LG, context->Config, context->Quiet, target, target,
  405. context->EvaluateForBuildsystem, context->Backtrace, context->Language);
  406. return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
  407. &targetContext, content, dagCheckerParent);
  408. }
  409. } targetGenexEvalNode;
  410. static const struct GenexEvalNode : public GenexEvaluator
  411. {
  412. GenexEvalNode() {} // NOLINT(modernize-use-equals-default)
  413. int NumExpectedParameters() const override { return 1; }
  414. bool AcceptsArbitraryContentParameter() const override { return true; }
  415. std::string Evaluate(
  416. const std::vector<std::string>& parameters,
  417. cmGeneratorExpressionContext* context,
  418. const GeneratorExpressionContent* content,
  419. cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
  420. {
  421. const std::string& expression = parameters[0];
  422. if (expression.empty()) {
  423. return expression;
  424. }
  425. return this->EvaluateExpression("GENEX_EVAL", expression, context, content,
  426. dagCheckerParent);
  427. }
  428. } genexEvalNode;
  429. static const struct LowerCaseNode : public cmGeneratorExpressionNode
  430. {
  431. LowerCaseNode() {} // NOLINT(modernize-use-equals-default)
  432. bool AcceptsArbitraryContentParameter() const override { return true; }
  433. std::string Evaluate(
  434. const std::vector<std::string>& parameters,
  435. cmGeneratorExpressionContext* /*context*/,
  436. const GeneratorExpressionContent* /*content*/,
  437. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  438. {
  439. return cmSystemTools::LowerCase(parameters.front());
  440. }
  441. } lowerCaseNode;
  442. static const struct UpperCaseNode : public cmGeneratorExpressionNode
  443. {
  444. UpperCaseNode() {} // NOLINT(modernize-use-equals-default)
  445. bool AcceptsArbitraryContentParameter() const override { return true; }
  446. std::string Evaluate(
  447. const std::vector<std::string>& parameters,
  448. cmGeneratorExpressionContext* /*context*/,
  449. const GeneratorExpressionContent* /*content*/,
  450. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  451. {
  452. return cmSystemTools::UpperCase(parameters.front());
  453. }
  454. } upperCaseNode;
  455. static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
  456. {
  457. MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
  458. bool AcceptsArbitraryContentParameter() const override { return true; }
  459. std::string Evaluate(
  460. const std::vector<std::string>& parameters,
  461. cmGeneratorExpressionContext* /*context*/,
  462. const GeneratorExpressionContent* /*content*/,
  463. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  464. {
  465. return cmSystemTools::MakeCidentifier(parameters.front());
  466. }
  467. } makeCIdentifierNode;
  468. static const struct Angle_RNode : public cmGeneratorExpressionNode
  469. {
  470. Angle_RNode() {} // NOLINT(modernize-use-equals-default)
  471. int NumExpectedParameters() const override { return 0; }
  472. std::string Evaluate(
  473. const std::vector<std::string>& /*parameters*/,
  474. cmGeneratorExpressionContext* /*context*/,
  475. const GeneratorExpressionContent* /*content*/,
  476. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  477. {
  478. return ">";
  479. }
  480. } angle_rNode;
  481. static const struct CommaNode : public cmGeneratorExpressionNode
  482. {
  483. CommaNode() {} // NOLINT(modernize-use-equals-default)
  484. int NumExpectedParameters() const override { return 0; }
  485. std::string Evaluate(
  486. const std::vector<std::string>& /*parameters*/,
  487. cmGeneratorExpressionContext* /*context*/,
  488. const GeneratorExpressionContent* /*content*/,
  489. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  490. {
  491. return ",";
  492. }
  493. } commaNode;
  494. static const struct SemicolonNode : public cmGeneratorExpressionNode
  495. {
  496. SemicolonNode() {} // NOLINT(modernize-use-equals-default)
  497. int NumExpectedParameters() const override { return 0; }
  498. std::string Evaluate(
  499. const std::vector<std::string>& /*parameters*/,
  500. cmGeneratorExpressionContext* /*context*/,
  501. const GeneratorExpressionContent* /*content*/,
  502. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  503. {
  504. return ";";
  505. }
  506. } semicolonNode;
  507. struct CompilerIdNode : public cmGeneratorExpressionNode
  508. {
  509. CompilerIdNode() {} // NOLINT(modernize-use-equals-default)
  510. int NumExpectedParameters() const override { return OneOrZeroParameters; }
  511. std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
  512. cmGeneratorExpressionContext* context,
  513. const GeneratorExpressionContent* content,
  514. cmGeneratorExpressionDAGChecker* /*unused*/,
  515. const std::string& lang) const
  516. {
  517. std::string const& compilerId =
  518. context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
  519. "_COMPILER_ID");
  520. if (parameters.empty()) {
  521. return compilerId;
  522. }
  523. static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
  524. if (!compilerIdValidator.find(parameters.front())) {
  525. reportError(context, content->GetOriginalExpression(),
  526. "Expression syntax not recognized.");
  527. return std::string();
  528. }
  529. if (compilerId.empty()) {
  530. return parameters.front().empty() ? "1" : "0";
  531. }
  532. if (strcmp(parameters.front().c_str(), compilerId.c_str()) == 0) {
  533. return "1";
  534. }
  535. if (cmsysString_strcasecmp(parameters.front().c_str(),
  536. compilerId.c_str()) == 0) {
  537. switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
  538. case cmPolicies::WARN: {
  539. std::ostringstream e;
  540. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
  541. context->LG->GetCMakeInstance()->IssueMessage(
  542. MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
  543. CM_FALLTHROUGH;
  544. }
  545. case cmPolicies::OLD:
  546. return "1";
  547. case cmPolicies::NEW:
  548. case cmPolicies::REQUIRED_ALWAYS:
  549. case cmPolicies::REQUIRED_IF_USED:
  550. break;
  551. }
  552. }
  553. return "0";
  554. }
  555. };
  556. static const struct CCompilerIdNode : public CompilerIdNode
  557. {
  558. CCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
  559. std::string Evaluate(
  560. const std::vector<std::string>& parameters,
  561. cmGeneratorExpressionContext* context,
  562. const GeneratorExpressionContent* content,
  563. cmGeneratorExpressionDAGChecker* dagChecker) const override
  564. {
  565. if (!context->HeadTarget) {
  566. reportError(
  567. context, content->GetOriginalExpression(),
  568. "$<C_COMPILER_ID> may only be used with binary targets. It may "
  569. "not be used with add_custom_command or add_custom_target.");
  570. return std::string();
  571. }
  572. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  573. "C");
  574. }
  575. } cCompilerIdNode;
  576. static const struct CXXCompilerIdNode : public CompilerIdNode
  577. {
  578. CXXCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
  579. std::string Evaluate(
  580. const std::vector<std::string>& parameters,
  581. cmGeneratorExpressionContext* context,
  582. const GeneratorExpressionContent* content,
  583. cmGeneratorExpressionDAGChecker* dagChecker) const override
  584. {
  585. if (!context->HeadTarget) {
  586. reportError(
  587. context, content->GetOriginalExpression(),
  588. "$<CXX_COMPILER_ID> may only be used with binary targets. It may "
  589. "not be used with add_custom_command or add_custom_target.");
  590. return std::string();
  591. }
  592. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  593. "CXX");
  594. }
  595. } cxxCompilerIdNode;
  596. static const struct FortranCompilerIdNode : public CompilerIdNode
  597. {
  598. FortranCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
  599. std::string Evaluate(
  600. const std::vector<std::string>& parameters,
  601. cmGeneratorExpressionContext* context,
  602. const GeneratorExpressionContent* content,
  603. cmGeneratorExpressionDAGChecker* dagChecker) const override
  604. {
  605. if (!context->HeadTarget) {
  606. reportError(
  607. context, content->GetOriginalExpression(),
  608. "$<Fortran_COMPILER_ID> may only be used with binary targets. It may "
  609. "not be used with add_custom_command or add_custom_target.");
  610. return std::string();
  611. }
  612. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  613. "Fortran");
  614. }
  615. } fortranCompilerIdNode;
  616. struct CompilerVersionNode : public cmGeneratorExpressionNode
  617. {
  618. CompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
  619. int NumExpectedParameters() const override { return OneOrZeroParameters; }
  620. std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
  621. cmGeneratorExpressionContext* context,
  622. const GeneratorExpressionContent* content,
  623. cmGeneratorExpressionDAGChecker* /*unused*/,
  624. const std::string& lang) const
  625. {
  626. std::string const& compilerVersion =
  627. context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
  628. "_COMPILER_VERSION");
  629. if (parameters.empty()) {
  630. return compilerVersion;
  631. }
  632. static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
  633. if (!compilerIdValidator.find(parameters.front())) {
  634. reportError(context, content->GetOriginalExpression(),
  635. "Expression syntax not recognized.");
  636. return std::string();
  637. }
  638. if (compilerVersion.empty()) {
  639. return parameters.front().empty() ? "1" : "0";
  640. }
  641. return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
  642. parameters.front().c_str(),
  643. compilerVersion.c_str())
  644. ? "1"
  645. : "0";
  646. }
  647. };
  648. static const struct CCompilerVersionNode : public CompilerVersionNode
  649. {
  650. CCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
  651. std::string Evaluate(
  652. const std::vector<std::string>& parameters,
  653. cmGeneratorExpressionContext* context,
  654. const GeneratorExpressionContent* content,
  655. cmGeneratorExpressionDAGChecker* dagChecker) const override
  656. {
  657. if (!context->HeadTarget) {
  658. reportError(
  659. context, content->GetOriginalExpression(),
  660. "$<C_COMPILER_VERSION> may only be used with binary targets. It "
  661. "may not be used with add_custom_command or add_custom_target.");
  662. return std::string();
  663. }
  664. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  665. "C");
  666. }
  667. } cCompilerVersionNode;
  668. static const struct CxxCompilerVersionNode : public CompilerVersionNode
  669. {
  670. CxxCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
  671. std::string Evaluate(
  672. const std::vector<std::string>& parameters,
  673. cmGeneratorExpressionContext* context,
  674. const GeneratorExpressionContent* content,
  675. cmGeneratorExpressionDAGChecker* dagChecker) const override
  676. {
  677. if (!context->HeadTarget) {
  678. reportError(
  679. context, content->GetOriginalExpression(),
  680. "$<CXX_COMPILER_VERSION> may only be used with binary targets. It "
  681. "may not be used with add_custom_command or add_custom_target.");
  682. return std::string();
  683. }
  684. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  685. "CXX");
  686. }
  687. } cxxCompilerVersionNode;
  688. static const struct FortranCompilerVersionNode : public CompilerVersionNode
  689. {
  690. FortranCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
  691. std::string Evaluate(
  692. const std::vector<std::string>& parameters,
  693. cmGeneratorExpressionContext* context,
  694. const GeneratorExpressionContent* content,
  695. cmGeneratorExpressionDAGChecker* dagChecker) const override
  696. {
  697. if (!context->HeadTarget) {
  698. reportError(
  699. context, content->GetOriginalExpression(),
  700. "$<Fortran_COMPILER_VERSION> may only be used with binary targets. "
  701. "It may not be used with add_custom_command or add_custom_target.");
  702. return std::string();
  703. }
  704. return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
  705. "Fortran");
  706. }
  707. } fortranCompilerVersionNode;
  708. struct PlatformIdNode : public cmGeneratorExpressionNode
  709. {
  710. PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
  711. int NumExpectedParameters() const override { return OneOrZeroParameters; }
  712. std::string Evaluate(
  713. const std::vector<std::string>& parameters,
  714. cmGeneratorExpressionContext* context,
  715. const GeneratorExpressionContent* /*content*/,
  716. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  717. {
  718. std::string const& platformId =
  719. context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
  720. if (parameters.empty()) {
  721. return platformId;
  722. }
  723. if (platformId.empty()) {
  724. return parameters.front().empty() ? "1" : "0";
  725. }
  726. if (parameters.front() == platformId) {
  727. return "1";
  728. }
  729. return "0";
  730. }
  731. } platformIdNode;
  732. static const struct VersionGreaterNode : public cmGeneratorExpressionNode
  733. {
  734. VersionGreaterNode() {} // NOLINT(modernize-use-equals-default)
  735. int NumExpectedParameters() const override { return 2; }
  736. std::string Evaluate(
  737. const std::vector<std::string>& parameters,
  738. cmGeneratorExpressionContext* /*context*/,
  739. const GeneratorExpressionContent* /*content*/,
  740. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  741. {
  742. return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
  743. parameters.front().c_str(),
  744. parameters[1].c_str())
  745. ? "1"
  746. : "0";
  747. }
  748. } versionGreaterNode;
  749. static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode
  750. {
  751. VersionGreaterEqNode() {} // NOLINT(modernize-use-equals-default)
  752. int NumExpectedParameters() const override { return 2; }
  753. std::string Evaluate(
  754. const std::vector<std::string>& parameters,
  755. cmGeneratorExpressionContext* /*context*/,
  756. const GeneratorExpressionContent* /*content*/,
  757. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  758. {
  759. return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
  760. parameters.front().c_str(),
  761. parameters[1].c_str())
  762. ? "1"
  763. : "0";
  764. }
  765. } versionGreaterEqNode;
  766. static const struct VersionLessNode : public cmGeneratorExpressionNode
  767. {
  768. VersionLessNode() {} // NOLINT(modernize-use-equals-default)
  769. int NumExpectedParameters() const override { return 2; }
  770. std::string Evaluate(
  771. const std::vector<std::string>& parameters,
  772. cmGeneratorExpressionContext* /*context*/,
  773. const GeneratorExpressionContent* /*content*/,
  774. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  775. {
  776. return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
  777. parameters.front().c_str(),
  778. parameters[1].c_str())
  779. ? "1"
  780. : "0";
  781. }
  782. } versionLessNode;
  783. static const struct VersionLessEqNode : public cmGeneratorExpressionNode
  784. {
  785. VersionLessEqNode() {} // NOLINT(modernize-use-equals-default)
  786. int NumExpectedParameters() const override { return 2; }
  787. std::string Evaluate(
  788. const std::vector<std::string>& parameters,
  789. cmGeneratorExpressionContext* /*context*/,
  790. const GeneratorExpressionContent* /*content*/,
  791. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  792. {
  793. return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL,
  794. parameters.front().c_str(),
  795. parameters[1].c_str())
  796. ? "1"
  797. : "0";
  798. }
  799. } versionLessEqNode;
  800. static const struct VersionEqualNode : public cmGeneratorExpressionNode
  801. {
  802. VersionEqualNode() {} // NOLINT(modernize-use-equals-default)
  803. int NumExpectedParameters() const override { return 2; }
  804. std::string Evaluate(
  805. const std::vector<std::string>& parameters,
  806. cmGeneratorExpressionContext* /*context*/,
  807. const GeneratorExpressionContent* /*content*/,
  808. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  809. {
  810. return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
  811. parameters.front().c_str(),
  812. parameters[1].c_str())
  813. ? "1"
  814. : "0";
  815. }
  816. } versionEqualNode;
  817. static const struct LinkOnlyNode : public cmGeneratorExpressionNode
  818. {
  819. LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
  820. std::string Evaluate(
  821. const std::vector<std::string>& parameters,
  822. cmGeneratorExpressionContext* context,
  823. const GeneratorExpressionContent* content,
  824. cmGeneratorExpressionDAGChecker* dagChecker) const override
  825. {
  826. if (!dagChecker) {
  827. reportError(context, content->GetOriginalExpression(),
  828. "$<LINK_ONLY:...> may only be used for linking");
  829. return std::string();
  830. }
  831. if (!dagChecker->GetTransitivePropertiesOnly()) {
  832. return parameters.front();
  833. }
  834. return std::string();
  835. }
  836. } linkOnlyNode;
  837. static const struct ConfigurationNode : public cmGeneratorExpressionNode
  838. {
  839. ConfigurationNode() {} // NOLINT(modernize-use-equals-default)
  840. int NumExpectedParameters() const override { return 0; }
  841. std::string Evaluate(
  842. const std::vector<std::string>& /*parameters*/,
  843. cmGeneratorExpressionContext* context,
  844. const GeneratorExpressionContent* /*content*/,
  845. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  846. {
  847. context->HadContextSensitiveCondition = true;
  848. return context->Config;
  849. }
  850. } configurationNode;
  851. static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
  852. {
  853. ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default)
  854. int NumExpectedParameters() const override { return OneOrZeroParameters; }
  855. std::string Evaluate(
  856. const std::vector<std::string>& parameters,
  857. cmGeneratorExpressionContext* context,
  858. const GeneratorExpressionContent* content,
  859. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  860. {
  861. if (parameters.empty()) {
  862. return configurationNode.Evaluate(parameters, context, content, nullptr);
  863. }
  864. static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
  865. if (!configValidator.find(parameters.front())) {
  866. reportError(context, content->GetOriginalExpression(),
  867. "Expression syntax not recognized.");
  868. return std::string();
  869. }
  870. context->HadContextSensitiveCondition = true;
  871. if (context->Config.empty()) {
  872. return parameters.front().empty() ? "1" : "0";
  873. }
  874. if (cmsysString_strcasecmp(parameters.front().c_str(),
  875. context->Config.c_str()) == 0) {
  876. return "1";
  877. }
  878. if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
  879. const char* loc = nullptr;
  880. const char* imp = nullptr;
  881. std::string suffix;
  882. if (context->CurrentTarget->Target->GetMappedConfig(
  883. context->Config, &loc, &imp, suffix)) {
  884. // This imported target has an appropriate location
  885. // for this (possibly mapped) config.
  886. // Check if there is a proper config mapping for the tested config.
  887. std::vector<std::string> mappedConfigs;
  888. std::string mapProp = "MAP_IMPORTED_CONFIG_";
  889. mapProp += cmSystemTools::UpperCase(context->Config);
  890. if (const char* mapValue =
  891. context->CurrentTarget->GetProperty(mapProp)) {
  892. cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue),
  893. mappedConfigs);
  894. return std::find(mappedConfigs.begin(), mappedConfigs.end(),
  895. cmSystemTools::UpperCase(parameters.front())) !=
  896. mappedConfigs.end()
  897. ? "1"
  898. : "0";
  899. }
  900. }
  901. }
  902. return "0";
  903. }
  904. } configurationTestNode;
  905. static const struct JoinNode : public cmGeneratorExpressionNode
  906. {
  907. JoinNode() {} // NOLINT(modernize-use-equals-default)
  908. int NumExpectedParameters() const override { return 2; }
  909. bool AcceptsArbitraryContentParameter() const override { return true; }
  910. std::string Evaluate(
  911. const std::vector<std::string>& parameters,
  912. cmGeneratorExpressionContext* /*context*/,
  913. const GeneratorExpressionContent* /*content*/,
  914. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  915. {
  916. std::vector<std::string> list;
  917. cmSystemTools::ExpandListArgument(parameters.front(), list);
  918. return cmJoin(list, parameters[1]);
  919. }
  920. } joinNode;
  921. static const struct CompileLanguageNode : public cmGeneratorExpressionNode
  922. {
  923. CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
  924. int NumExpectedParameters() const override { return OneOrZeroParameters; }
  925. std::string Evaluate(
  926. const std::vector<std::string>& parameters,
  927. cmGeneratorExpressionContext* context,
  928. const GeneratorExpressionContent* content,
  929. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  930. {
  931. if (context->Language.empty()) {
  932. reportError(
  933. context, content->GetOriginalExpression(),
  934. "$<COMPILE_LANGUAGE:...> may only be used to specify include "
  935. "directories, compile definitions, compile options, and to evaluate "
  936. "components of the file(GENERATE) command.");
  937. return std::string();
  938. }
  939. cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
  940. std::string genName = gg->GetName();
  941. if (genName.find("Makefiles") == std::string::npos &&
  942. genName.find("Ninja") == std::string::npos &&
  943. genName.find("Visual Studio") == std::string::npos &&
  944. genName.find("Xcode") == std::string::npos &&
  945. genName.find("Watcom WMake") == std::string::npos) {
  946. reportError(context, content->GetOriginalExpression(),
  947. "$<COMPILE_LANGUAGE:...> not supported for this generator.");
  948. return std::string();
  949. }
  950. if (parameters.empty()) {
  951. return context->Language;
  952. }
  953. return context->Language == parameters.front() ? "1" : "0";
  954. }
  955. } languageNode;
  956. #define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY
  957. static const char* targetPropertyTransitiveWhitelist[] = {
  958. nullptr CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
  959. };
  960. #undef TRANSITIVE_PROPERTY_NAME
  961. template <typename T>
  962. std::string getLinkedTargetsContent(
  963. std::vector<T> const& libraries, cmGeneratorTarget const* target,
  964. cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext* context,
  965. cmGeneratorExpressionDAGChecker* dagChecker,
  966. const std::string& interfacePropertyName)
  967. {
  968. std::string linkedTargetsContent;
  969. std::string sep;
  970. std::string depString;
  971. for (T const& l : libraries) {
  972. // Broken code can have a target in its own link interface.
  973. // Don't follow such link interface entries so as not to create a
  974. // self-referencing loop.
  975. if (l.Target && l.Target != target) {
  976. std::string uniqueName =
  977. target->GetGlobalGenerator()->IndexGeneratorTargetUniquely(l.Target);
  978. depString += sep + "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," +
  979. interfacePropertyName + ">";
  980. sep = ";";
  981. }
  982. }
  983. if (!depString.empty()) {
  984. linkedTargetsContent =
  985. cmGeneratorExpressionNode::EvaluateDependentExpression(
  986. depString, target->GetLocalGenerator(), context, headTarget, target,
  987. dagChecker);
  988. }
  989. linkedTargetsContent =
  990. cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
  991. return linkedTargetsContent;
  992. }
  993. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  994. {
  995. TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
  996. // This node handles errors on parameter count itself.
  997. int NumExpectedParameters() const override { return OneOrMoreParameters; }
  998. std::string Evaluate(
  999. const std::vector<std::string>& parameters,
  1000. cmGeneratorExpressionContext* context,
  1001. const GeneratorExpressionContent* content,
  1002. cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
  1003. {
  1004. if (parameters.size() != 1 && parameters.size() != 2) {
  1005. reportError(
  1006. context, content->GetOriginalExpression(),
  1007. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  1008. return std::string();
  1009. }
  1010. static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
  1011. cmGeneratorTarget const* target = context->HeadTarget;
  1012. std::string propertyName = parameters.front();
  1013. if (parameters.size() == 1) {
  1014. context->HadHeadSensitiveCondition = true;
  1015. }
  1016. if (!target && parameters.size() == 1) {
  1017. reportError(
  1018. context, content->GetOriginalExpression(),
  1019. "$<TARGET_PROPERTY:prop> may only be used with binary targets. "
  1020. "It may not be used with add_custom_command or add_custom_target. "
  1021. "Specify the target to read a property from using the "
  1022. "$<TARGET_PROPERTY:tgt,prop> signature instead.");
  1023. return std::string();
  1024. }
  1025. if (parameters.size() == 2) {
  1026. if (parameters.front().empty() && parameters[1].empty()) {
  1027. reportError(
  1028. context, content->GetOriginalExpression(),
  1029. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  1030. "target name and property name.");
  1031. return std::string();
  1032. }
  1033. if (parameters.front().empty()) {
  1034. reportError(
  1035. context, content->GetOriginalExpression(),
  1036. "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
  1037. "target name.");
  1038. return std::string();
  1039. }
  1040. std::string targetName = parameters.front();
  1041. propertyName = parameters[1];
  1042. if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
  1043. if (!propertyNameValidator.find(propertyName)) {
  1044. ::reportError(context, content->GetOriginalExpression(),
  1045. "Target name and property name not supported.");
  1046. return std::string();
  1047. }
  1048. ::reportError(context, content->GetOriginalExpression(),
  1049. "Target name not supported.");
  1050. return std::string();
  1051. }
  1052. static const std::string propALIASED_TARGET = "ALIASED_TARGET";
  1053. if (propertyName == propALIASED_TARGET) {
  1054. if (context->LG->GetMakefile()->IsAlias(targetName)) {
  1055. if (cmGeneratorTarget* tgt =
  1056. context->LG->FindGeneratorTargetToUse(targetName)) {
  1057. return tgt->GetName();
  1058. }
  1059. }
  1060. return "";
  1061. }
  1062. target = context->LG->FindGeneratorTargetToUse(targetName);
  1063. if (!target) {
  1064. std::ostringstream e;
  1065. e << "Target \"" << targetName << "\" not found.";
  1066. reportError(context, content->GetOriginalExpression(), e.str());
  1067. return std::string();
  1068. }
  1069. context->AllTargets.insert(target);
  1070. }
  1071. if (target == context->HeadTarget) {
  1072. // Keep track of the properties seen while processing.
  1073. // The evaluation of the LINK_LIBRARIES generator expressions
  1074. // will check this to ensure that properties have one consistent
  1075. // value for all evaluations.
  1076. context->SeenTargetProperties.insert(propertyName);
  1077. }
  1078. if (propertyName == "SOURCES") {
  1079. context->SourceSensitiveTargets.insert(target);
  1080. }
  1081. if (propertyName.empty()) {
  1082. reportError(
  1083. context, content->GetOriginalExpression(),
  1084. "$<TARGET_PROPERTY:...> expression requires a non-empty property "
  1085. "name.");
  1086. return std::string();
  1087. }
  1088. if (!propertyNameValidator.find(propertyName)) {
  1089. ::reportError(context, content->GetOriginalExpression(),
  1090. "Property name not supported.");
  1091. return std::string();
  1092. }
  1093. assert(target);
  1094. if (propertyName == "LINKER_LANGUAGE") {
  1095. if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
  1096. (dagCheckerParent->EvaluatingLinkLibraries() ||
  1097. dagCheckerParent->EvaluatingSources())) {
  1098. reportError(
  1099. context, content->GetOriginalExpression(),
  1100. "LINKER_LANGUAGE target property can not be used while evaluating "
  1101. "link libraries for a static library");
  1102. return std::string();
  1103. }
  1104. return target->GetLinkerLanguage(context->Config);
  1105. }
  1106. cmGeneratorExpressionDAGChecker dagChecker(
  1107. context->Backtrace, target, propertyName, content, dagCheckerParent);
  1108. switch (dagChecker.Check()) {
  1109. case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
  1110. dagChecker.ReportError(context, content->GetOriginalExpression());
  1111. return std::string();
  1112. case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
  1113. // No error. We just skip cyclic references.
  1114. return std::string();
  1115. case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
  1116. for (size_t i = 1; i < cm::size(targetPropertyTransitiveWhitelist);
  1117. ++i) {
  1118. if (targetPropertyTransitiveWhitelist[i] == propertyName) {
  1119. // No error. We're not going to find anything new here.
  1120. return std::string();
  1121. }
  1122. }
  1123. case cmGeneratorExpressionDAGChecker::DAG:
  1124. break;
  1125. }
  1126. const char* prop = target->GetProperty(propertyName);
  1127. if (dagCheckerParent) {
  1128. if (dagCheckerParent->EvaluatingGenexExpression() ||
  1129. dagCheckerParent->EvaluatingPICExpression()) {
  1130. // No check required.
  1131. } else if (dagCheckerParent->EvaluatingLinkLibraries()) {
  1132. #define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \
  1133. (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) ||
  1134. if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(
  1135. TRANSITIVE_PROPERTY_COMPARE) false) { // NOLINT(*)
  1136. reportError(
  1137. context, content->GetOriginalExpression(),
  1138. "$<TARGET_PROPERTY:...> expression in link libraries "
  1139. "evaluation depends on target property which is transitive "
  1140. "over the link libraries, creating a recursion.");
  1141. return std::string();
  1142. }
  1143. #undef TRANSITIVE_PROPERTY_COMPARE
  1144. if (!prop) {
  1145. return std::string();
  1146. }
  1147. } else {
  1148. #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
  1149. assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
  1150. ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy)
  1151. #undef ASSERT_TRANSITIVE_PROPERTY_METHOD
  1152. }
  1153. }
  1154. std::string linkedTargetsContent;
  1155. std::string interfacePropertyName;
  1156. bool isInterfaceProperty = false;
  1157. #define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
  1158. if (propertyName == #prop) { \
  1159. interfacePropertyName = "INTERFACE_" #prop; \
  1160. } else if (propertyName == "INTERFACE_" #prop) { \
  1161. interfacePropertyName = "INTERFACE_" #prop; \
  1162. isInterfaceProperty = true; \
  1163. } else
  1164. CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
  1165. // Note that the above macro terminates with an else
  1166. /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) {
  1167. cmPolicies::PolicyStatus polSt =
  1168. context->LG->GetPolicyStatus(cmPolicies::CMP0043);
  1169. if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
  1170. interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
  1171. }
  1172. }
  1173. #undef POPULATE_INTERFACE_PROPERTY_NAME
  1174. cmGeneratorTarget const* headTarget =
  1175. context->HeadTarget && isInterfaceProperty ? context->HeadTarget
  1176. : target;
  1177. if (isInterfaceProperty) {
  1178. if (cmLinkInterfaceLibraries const* iface =
  1179. target->GetLinkInterfaceLibraries(context->Config, headTarget,
  1180. true)) {
  1181. linkedTargetsContent =
  1182. getLinkedTargetsContent(iface->Libraries, target, headTarget,
  1183. context, &dagChecker, interfacePropertyName);
  1184. }
  1185. } else if (!interfacePropertyName.empty()) {
  1186. if (cmLinkImplementationLibraries const* impl =
  1187. target->GetLinkImplementationLibraries(context->Config)) {
  1188. linkedTargetsContent =
  1189. getLinkedTargetsContent(impl->Libraries, target, target, context,
  1190. &dagChecker, interfacePropertyName);
  1191. }
  1192. }
  1193. if (!prop) {
  1194. if (target->IsImported() ||
  1195. target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  1196. return linkedTargetsContent;
  1197. }
  1198. if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
  1199. context->Config)) {
  1200. context->HadContextSensitiveCondition = true;
  1201. return target->GetLinkInterfaceDependentBoolProperty(propertyName,
  1202. context->Config)
  1203. ? "1"
  1204. : "0";
  1205. }
  1206. if (target->IsLinkInterfaceDependentStringProperty(propertyName,
  1207. context->Config)) {
  1208. context->HadContextSensitiveCondition = true;
  1209. const char* propContent =
  1210. target->GetLinkInterfaceDependentStringProperty(propertyName,
  1211. context->Config);
  1212. return propContent ? propContent : "";
  1213. }
  1214. if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
  1215. context->Config)) {
  1216. context->HadContextSensitiveCondition = true;
  1217. const char* propContent =
  1218. target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
  1219. context->Config);
  1220. return propContent ? propContent : "";
  1221. }
  1222. if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
  1223. context->Config)) {
  1224. context->HadContextSensitiveCondition = true;
  1225. const char* propContent =
  1226. target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
  1227. context->Config);
  1228. return propContent ? propContent : "";
  1229. }
  1230. return linkedTargetsContent;
  1231. }
  1232. if (!target->IsImported() && dagCheckerParent &&
  1233. !dagCheckerParent->EvaluatingLinkLibraries()) {
  1234. if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
  1235. context->Config)) {
  1236. context->HadContextSensitiveCondition = true;
  1237. const char* propContent =
  1238. target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
  1239. context->Config);
  1240. return propContent ? propContent : "";
  1241. }
  1242. if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
  1243. context->Config)) {
  1244. context->HadContextSensitiveCondition = true;
  1245. const char* propContent =
  1246. target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
  1247. context->Config);
  1248. return propContent ? propContent : "";
  1249. }
  1250. }
  1251. if (!interfacePropertyName.empty()) {
  1252. std::string result = this->EvaluateDependentExpression(
  1253. prop, context->LG, context, headTarget, target, &dagChecker);
  1254. if (!linkedTargetsContent.empty()) {
  1255. result += (result.empty() ? "" : ";") + linkedTargetsContent;
  1256. }
  1257. return result;
  1258. }
  1259. return prop;
  1260. }
  1261. } targetPropertyNode;
  1262. static const struct TargetNameNode : public cmGeneratorExpressionNode
  1263. {
  1264. TargetNameNode() {} // NOLINT(modernize-use-equals-default)
  1265. bool GeneratesContent() const override { return true; }
  1266. bool AcceptsArbitraryContentParameter() const override { return true; }
  1267. bool RequiresLiteralInput() const override { return true; }
  1268. std::string Evaluate(
  1269. const std::vector<std::string>& parameters,
  1270. cmGeneratorExpressionContext* /*context*/,
  1271. const GeneratorExpressionContent* /*content*/,
  1272. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  1273. {
  1274. return parameters.front();
  1275. }
  1276. int NumExpectedParameters() const override { return 1; }
  1277. } targetNameNode;
  1278. static const struct TargetObjectsNode : public cmGeneratorExpressionNode
  1279. {
  1280. TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
  1281. std::string Evaluate(
  1282. const std::vector<std::string>& parameters,
  1283. cmGeneratorExpressionContext* context,
  1284. const GeneratorExpressionContent* content,
  1285. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  1286. {
  1287. std::string tgtName = parameters.front();
  1288. cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
  1289. if (!gt) {
  1290. std::ostringstream e;
  1291. e << "Objects of target \"" << tgtName
  1292. << "\" referenced but no such target exists.";
  1293. reportError(context, content->GetOriginalExpression(), e.str());
  1294. return std::string();
  1295. }
  1296. if (gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
  1297. std::ostringstream e;
  1298. e << "Objects of target \"" << tgtName
  1299. << "\" referenced but is not an OBJECT library.";
  1300. reportError(context, content->GetOriginalExpression(), e.str());
  1301. return std::string();
  1302. }
  1303. if (!context->EvaluateForBuildsystem) {
  1304. cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
  1305. std::string reason;
  1306. if (!gg->HasKnownObjectFileLocation(&reason)) {
  1307. std::ostringstream e;
  1308. e << "The evaluation of the TARGET_OBJECTS generator expression "
  1309. "is only suitable for consumption by CMake (limited"
  1310. << reason
  1311. << "). "
  1312. "It is not suitable for writing out elsewhere.";
  1313. reportError(context, content->GetOriginalExpression(), e.str());
  1314. return std::string();
  1315. }
  1316. }
  1317. std::vector<std::string> objects;
  1318. if (gt->IsImported()) {
  1319. const char* loc = nullptr;
  1320. const char* imp = nullptr;
  1321. std::string suffix;
  1322. if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) {
  1323. cmSystemTools::ExpandListArgument(loc, objects);
  1324. }
  1325. context->HadContextSensitiveCondition = true;
  1326. } else {
  1327. gt->GetTargetObjectNames(context->Config, objects);
  1328. std::string obj_dir;
  1329. if (context->EvaluateForBuildsystem) {
  1330. // Use object file directory with buildsystem placeholder.
  1331. obj_dir = gt->ObjectDirectory;
  1332. // Here we assume that the set of object files produced
  1333. // by an object library does not vary with configuration
  1334. // and do not set HadContextSensitiveCondition to true.
  1335. } else {
  1336. // Use object file directory with per-config location.
  1337. obj_dir = gt->GetObjectDirectory(context->Config);
  1338. context->HadContextSensitiveCondition = true;
  1339. }
  1340. for (std::string& o : objects) {
  1341. o = obj_dir + o;
  1342. }
  1343. }
  1344. // Create the cmSourceFile instances in the referencing directory.
  1345. cmMakefile* mf = context->LG->GetMakefile();
  1346. for (std::string& o : objects) {
  1347. mf->AddTargetObject(tgtName, o);
  1348. }
  1349. return cmJoin(objects, ";");
  1350. }
  1351. } targetObjectsNode;
  1352. static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
  1353. {
  1354. CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
  1355. int NumExpectedParameters() const override { return OneOrMoreParameters; }
  1356. std::string Evaluate(
  1357. const std::vector<std::string>& parameters,
  1358. cmGeneratorExpressionContext* context,
  1359. const GeneratorExpressionContent* content,
  1360. cmGeneratorExpressionDAGChecker* dagChecker) const override
  1361. {
  1362. cmGeneratorTarget const* target = context->HeadTarget;
  1363. if (!target) {
  1364. reportError(
  1365. context, content->GetOriginalExpression(),
  1366. "$<COMPILE_FEATURE> may only be used with binary targets. It may "
  1367. "not be used with add_custom_command or add_custom_target.");
  1368. return std::string();
  1369. }
  1370. context->HadHeadSensitiveCondition = true;
  1371. typedef std::map<std::string, std::vector<std::string>> LangMap;
  1372. static LangMap availableFeatures;
  1373. LangMap testedFeatures;
  1374. for (std::string const& p : parameters) {
  1375. std::string error;
  1376. std::string lang;
  1377. if (!context->LG->GetMakefile()->CompileFeatureKnown(
  1378. context->HeadTarget->Target, p, lang, &error)) {
  1379. reportError(context, content->GetOriginalExpression(), error);
  1380. return std::string();
  1381. }
  1382. testedFeatures[lang].push_back(p);
  1383. if (availableFeatures.find(lang) == availableFeatures.end()) {
  1384. const char* featuresKnown =
  1385. context->LG->GetMakefile()->CompileFeaturesAvailable(lang, &error);
  1386. if (!featuresKnown) {
  1387. reportError(context, content->GetOriginalExpression(), error);
  1388. return std::string();
  1389. }
  1390. cmSystemTools::ExpandListArgument(featuresKnown,
  1391. availableFeatures[lang]);
  1392. }
  1393. }
  1394. bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
  1395. for (auto const& lit : testedFeatures) {
  1396. std::vector<std::string> const& langAvailable =
  1397. availableFeatures[lit.first];
  1398. const char* standardDefault = context->LG->GetMakefile()->GetDefinition(
  1399. "CMAKE_" + lit.first + "_STANDARD_DEFAULT");
  1400. for (std::string const& it : lit.second) {
  1401. if (std::find(langAvailable.begin(), langAvailable.end(), it) ==
  1402. langAvailable.end()) {
  1403. return "0";
  1404. }
  1405. if (standardDefault && !*standardDefault) {
  1406. // This compiler has no notion of language standard levels.
  1407. // All features known for the language are always available.
  1408. continue;
  1409. }
  1410. if (!context->LG->GetMakefile()->HaveStandardAvailable(
  1411. target->Target, lit.first, it)) {
  1412. if (evalLL) {
  1413. const char* l = target->GetProperty(lit.first + "_STANDARD");
  1414. if (!l) {
  1415. l = standardDefault;
  1416. }
  1417. assert(l);
  1418. context->MaxLanguageStandard[target][lit.first] = l;
  1419. } else {
  1420. return "0";
  1421. }
  1422. }
  1423. }
  1424. }
  1425. return "1";
  1426. }
  1427. } compileFeaturesNode;
  1428. static const char* targetPolicyWhitelist[] = {
  1429. nullptr
  1430. #define TARGET_POLICY_STRING(POLICY) , #POLICY
  1431. CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
  1432. #undef TARGET_POLICY_STRING
  1433. };
  1434. cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
  1435. const char* policy)
  1436. {
  1437. #define RETURN_POLICY(POLICY) \
  1438. if (strcmp(policy, #POLICY) == 0) { \
  1439. return tgt->GetPolicyStatus##POLICY(); \
  1440. }
  1441. CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
  1442. #undef RETURN_POLICY
  1443. assert(false && "Unreachable code. Not a valid policy");
  1444. return cmPolicies::WARN;
  1445. }
  1446. cmPolicies::PolicyID policyForString(const char* policy_id)
  1447. {
  1448. #define RETURN_POLICY_ID(POLICY_ID) \
  1449. if (strcmp(policy_id, #POLICY_ID) == 0) { \
  1450. return cmPolicies::POLICY_ID; \
  1451. }
  1452. CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
  1453. #undef RETURN_POLICY_ID
  1454. assert(false && "Unreachable code. Not a valid policy");
  1455. return cmPolicies::CMP0002;
  1456. }
  1457. static const struct TargetPolicyNode : public cmGeneratorExpressionNode
  1458. {
  1459. TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
  1460. int NumExpectedParameters() const override { return 1; }
  1461. std::string Evaluate(
  1462. const std::vector<std::string>& parameters,
  1463. cmGeneratorExpressionContext* context,
  1464. const GeneratorExpressionContent* content,
  1465. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  1466. {
  1467. if (!context->HeadTarget) {
  1468. reportError(
  1469. context, content->GetOriginalExpression(),
  1470. "$<TARGET_POLICY:prop> may only be used with binary targets. It "
  1471. "may not be used with add_custom_command or add_custom_target.");
  1472. return std::string();
  1473. }
  1474. context->HadContextSensitiveCondition = true;
  1475. context->HadHeadSensitiveCondition = true;
  1476. for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
  1477. const char* policy = targetPolicyWhitelist[i];
  1478. if (parameters.front() == policy) {
  1479. cmLocalGenerator* lg = context->HeadTarget->GetLocalGenerator();
  1480. switch (statusForTarget(context->HeadTarget, policy)) {
  1481. case cmPolicies::WARN:
  1482. lg->IssueMessage(
  1483. MessageType::AUTHOR_WARNING,
  1484. cmPolicies::GetPolicyWarning(policyForString(policy)));
  1485. CM_FALLTHROUGH;
  1486. case cmPolicies::REQUIRED_IF_USED:
  1487. case cmPolicies::REQUIRED_ALWAYS:
  1488. case cmPolicies::OLD:
  1489. return "0";
  1490. case cmPolicies::NEW:
  1491. return "1";
  1492. }
  1493. }
  1494. }
  1495. reportError(
  1496. context, content->GetOriginalExpression(),
  1497. "$<TARGET_POLICY:prop> may only be used with a limited number of "
  1498. "policies. Currently it may be used with the following policies:\n"
  1499. #define STRINGIFY_HELPER(X) #X
  1500. #define STRINGIFY(X) STRINGIFY_HELPER(X)
  1501. #define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
  1502. CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
  1503. #undef TARGET_POLICY_LIST_ITEM
  1504. );
  1505. return std::string();
  1506. }
  1507. } targetPolicyNode;
  1508. static const struct InstallPrefixNode : public cmGeneratorExpressionNode
  1509. {
  1510. InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
  1511. bool GeneratesContent() const override { return true; }
  1512. int NumExpectedParameters() const override { return 0; }
  1513. std::string Evaluate(
  1514. const std::vector<std::string>& /*parameters*/,
  1515. cmGeneratorExpressionContext* context,
  1516. const GeneratorExpressionContent* content,
  1517. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  1518. {
  1519. reportError(context, content->GetOriginalExpression(),
  1520. "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
  1521. "should never be evaluated.");
  1522. return std::string();
  1523. }
  1524. } installPrefixNode;
  1525. class ArtifactDirTag;
  1526. class ArtifactLinkerTag;
  1527. class ArtifactNameTag;
  1528. class ArtifactPathTag;
  1529. class ArtifactPdbTag;
  1530. class ArtifactSonameTag;
  1531. class ArtifactBundleDirTag;
  1532. class ArtifactBundleContentDirTag;
  1533. template <typename ArtifactT>
  1534. struct TargetFilesystemArtifactResultCreator
  1535. {
  1536. static std::string Create(cmGeneratorTarget* target,
  1537. cmGeneratorExpressionContext* context,
  1538. const GeneratorExpressionContent* content);
  1539. };
  1540. template <>
  1541. struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
  1542. {
  1543. static std::string Create(cmGeneratorTarget* target,
  1544. cmGeneratorExpressionContext* context,
  1545. const GeneratorExpressionContent* content)
  1546. {
  1547. // The target soname file (.so.1).
  1548. if (target->IsDLLPlatform()) {
  1549. ::reportError(context, content->GetOriginalExpression(),
  1550. "TARGET_SONAME_FILE is not allowed "
  1551. "for DLL target platforms.");
  1552. return std::string();
  1553. }
  1554. if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
  1555. ::reportError(context, content->GetOriginalExpression(),
  1556. "TARGET_SONAME_FILE is allowed only for "
  1557. "SHARED libraries.");
  1558. return std::string();
  1559. }
  1560. std::string result = target->GetDirectory(context->Config);
  1561. result += "/";
  1562. result += target->GetSOName(context->Config);
  1563. return result;
  1564. }
  1565. };
  1566. template <>
  1567. struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
  1568. {
  1569. static std::string Create(cmGeneratorTarget* target,
  1570. cmGeneratorExpressionContext* context,
  1571. const GeneratorExpressionContent* content)
  1572. {
  1573. if (target->IsImported()) {
  1574. ::reportError(context, content->GetOriginalExpression(),
  1575. "TARGET_PDB_FILE not allowed for IMPORTED targets.");
  1576. return std::string();
  1577. }
  1578. std::string language = target->GetLinkerLanguage(context->Config);
  1579. std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
  1580. if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
  1581. ::reportError(context, content->GetOriginalExpression(),
  1582. "TARGET_PDB_FILE is not supported by the target linker.");
  1583. return std::string();
  1584. }
  1585. cmStateEnums::TargetType targetType = target->GetType();
  1586. if (targetType != cmStateEnums::SHARED_LIBRARY &&
  1587. targetType != cmStateEnums::MODULE_LIBRARY &&
  1588. targetType != cmStateEnums::EXECUTABLE) {
  1589. ::reportError(context, content->GetOriginalExpression(),
  1590. "TARGET_PDB_FILE is allowed only for "
  1591. "targets with linker created artifacts.");
  1592. return std::string();
  1593. }
  1594. std::string result = target->GetPDBDirectory(context->Config);
  1595. result += "/";
  1596. result += target->GetPDBName(context->Config);
  1597. return result;
  1598. }
  1599. };
  1600. template <>
  1601. struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
  1602. {
  1603. static std::string Create(cmGeneratorTarget* target,
  1604. cmGeneratorExpressionContext* context,
  1605. const GeneratorExpressionContent* content)
  1606. {
  1607. // The file used to link to the target (.so, .lib, .a).
  1608. if (!target->IsLinkable()) {
  1609. ::reportError(context, content->GetOriginalExpression(),
  1610. "TARGET_LINKER_FILE is allowed only for libraries and "
  1611. "executables with ENABLE_EXPORTS.");
  1612. return std::string();
  1613. }
  1614. cmStateEnums::ArtifactType artifact =
  1615. target->HasImportLibrary(context->Config)
  1616. ? cmStateEnums::ImportLibraryArtifact
  1617. : cmStateEnums::RuntimeBinaryArtifact;
  1618. return target->GetFullPath(context->Config, artifact);
  1619. }
  1620. };
  1621. template <>
  1622. struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
  1623. {
  1624. static std::string Create(cmGeneratorTarget* target,
  1625. cmGeneratorExpressionContext* context,
  1626. const GeneratorExpressionContent* content)
  1627. {
  1628. if (target->IsImported()) {
  1629. ::reportError(context, content->GetOriginalExpression(),
  1630. "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
  1631. return std::string();
  1632. }
  1633. if (!target->IsBundleOnApple()) {
  1634. ::reportError(context, content->GetOriginalExpression(),
  1635. "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
  1636. return std::string();
  1637. }
  1638. std::string outpath = target->GetDirectory(context->Config) + '/';
  1639. return target->BuildBundleDirectory(outpath, context->Config,
  1640. cmGeneratorTarget::BundleDirLevel);
  1641. }
  1642. };
  1643. template <>
  1644. struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
  1645. {
  1646. static std::string Create(cmGeneratorTarget* target,
  1647. cmGeneratorExpressionContext* context,
  1648. const GeneratorExpressionContent* content)
  1649. {
  1650. if (target->IsImported()) {
  1651. ::reportError(
  1652. context, content->GetOriginalExpression(),
  1653. "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
  1654. return std::string();
  1655. }
  1656. if (!target->IsBundleOnApple()) {
  1657. ::reportError(
  1658. context, content->GetOriginalExpression(),
  1659. "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
  1660. return std::string();
  1661. }
  1662. std::string outpath = target->GetDirectory(context->Config) + '/';
  1663. return target->BuildBundleDirectory(outpath, context->Config,
  1664. cmGeneratorTarget::ContentLevel);
  1665. }
  1666. };
  1667. template <>
  1668. struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
  1669. {
  1670. static std::string Create(cmGeneratorTarget* target,
  1671. cmGeneratorExpressionContext* context,
  1672. const GeneratorExpressionContent* /*unused*/)
  1673. {
  1674. return target->GetFullPath(context->Config,
  1675. cmStateEnums::RuntimeBinaryArtifact, true);
  1676. }
  1677. };
  1678. template <typename ArtifactT>
  1679. struct TargetFilesystemArtifactResultGetter
  1680. {
  1681. static std::string Get(const std::string& result);
  1682. };
  1683. template <>
  1684. struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
  1685. {
  1686. static std::string Get(const std::string& result)
  1687. {
  1688. return cmSystemTools::GetFilenameName(result);
  1689. }
  1690. };
  1691. template <>
  1692. struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
  1693. {
  1694. static std::string Get(const std::string& result)
  1695. {
  1696. return cmSystemTools::GetFilenamePath(result);
  1697. }
  1698. };
  1699. template <>
  1700. struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
  1701. {
  1702. static std::string Get(const std::string& result) { return result; }
  1703. };
  1704. template <typename ArtifactT, typename ComponentT>
  1705. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  1706. {
  1707. TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
  1708. int NumExpectedParameters() const override { return 1; }
  1709. std::string Evaluate(
  1710. const std::vector<std::string>& parameters,
  1711. cmGeneratorExpressionContext* context,
  1712. const GeneratorExpressionContent* content,
  1713. cmGeneratorExpressionDAGChecker* dagChecker) const override
  1714. {
  1715. // Lookup the referenced target.
  1716. std::string name = parameters.front();
  1717. if (!cmGeneratorExpression::IsValidTargetName(name)) {
  1718. ::reportError(context, content->GetOriginalExpression(),
  1719. "Expression syntax not recognized.");
  1720. return std::string();
  1721. }
  1722. cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
  1723. if (!target) {
  1724. ::reportError(context, content->GetOriginalExpression(),
  1725. "No target \"" + name + "\"");
  1726. return std::string();
  1727. }
  1728. if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
  1729. target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
  1730. ::reportError(context, content->GetOriginalExpression(),
  1731. "Target \"" + name +
  1732. "\" is not an executable or library.");
  1733. return std::string();
  1734. }
  1735. if (dagChecker &&
  1736. (dagChecker->EvaluatingLinkLibraries(target) ||
  1737. (dagChecker->EvaluatingSources() &&
  1738. target == dagChecker->TopTarget()))) {
  1739. ::reportError(context, content->GetOriginalExpression(),
  1740. "Expressions which require the linker language may not "
  1741. "be used while evaluating link libraries");
  1742. return std::string();
  1743. }
  1744. context->DependTargets.insert(target);
  1745. context->AllTargets.insert(target);
  1746. std::string result =
  1747. TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,
  1748. content);
  1749. if (context->HadError) {
  1750. return std::string();
  1751. }
  1752. return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
  1753. }
  1754. };
  1755. template <typename ArtifactT>
  1756. struct TargetFilesystemArtifactNodeGroup
  1757. {
  1758. TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
  1759. {
  1760. }
  1761. TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
  1762. TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
  1763. TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
  1764. };
  1765. static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag>
  1766. targetNodeGroup;
  1767. static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>
  1768. targetLinkerNodeGroup;
  1769. static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
  1770. targetSoNameNodeGroup;
  1771. static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
  1772. targetPdbNodeGroup;
  1773. static const TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>
  1774. targetBundleDirNode;
  1775. static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
  1776. ArtifactPathTag>
  1777. targetBundleContentDirNode;
  1778. static const struct ShellPathNode : public cmGeneratorExpressionNode
  1779. {
  1780. ShellPathNode() {} // NOLINT(modernize-use-equals-default)
  1781. std::string Evaluate(
  1782. const std::vector<std::string>& parameters,
  1783. cmGeneratorExpressionContext* context,
  1784. const GeneratorExpressionContent* content,
  1785. cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
  1786. {
  1787. if (!cmSystemTools::FileIsFullPath(parameters.front())) {
  1788. reportError(context, content->GetOriginalExpression(),
  1789. "\"" + parameters.front() + "\" is not an absolute path.");
  1790. return std::string();
  1791. }
  1792. cmOutputConverter converter(context->LG->GetStateSnapshot());
  1793. return converter.ConvertDirectorySeparatorsForShell(parameters.front());
  1794. }
  1795. } shellPathNode;
  1796. const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
  1797. const std::string& identifier)
  1798. {
  1799. typedef std::map<std::string, const cmGeneratorExpressionNode*> NodeMap;
  1800. static NodeMap nodeMap;
  1801. if (nodeMap.empty()) {
  1802. nodeMap["0"] = &zeroNode;
  1803. nodeMap["1"] = &oneNode;
  1804. nodeMap["AND"] = &andNode;
  1805. nodeMap["OR"] = &orNode;
  1806. nodeMap["NOT"] = &notNode;
  1807. nodeMap["C_COMPILER_ID"] = &cCompilerIdNode;
  1808. nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode;
  1809. nodeMap["Fortran_COMPILER_ID"] = &fortranCompilerIdNode;
  1810. nodeMap["VERSION_GREATER"] = &versionGreaterNode;
  1811. nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode;
  1812. nodeMap["VERSION_LESS"] = &versionLessNode;
  1813. nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode;
  1814. nodeMap["VERSION_EQUAL"] = &versionEqualNode;
  1815. nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
  1816. nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
  1817. nodeMap["Fortran_COMPILER_VERSION"] = &fortranCompilerVersionNode;
  1818. nodeMap["PLATFORM_ID"] = &platformIdNode;
  1819. nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode;
  1820. nodeMap["CONFIGURATION"] = &configurationNode;
  1821. nodeMap["CONFIG"] = &configurationTestNode;
  1822. nodeMap["TARGET_FILE"] = &targetNodeGroup.File;
  1823. nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File;
  1824. nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File;
  1825. nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File;
  1826. nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName;
  1827. nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName;
  1828. nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName;
  1829. nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName;
  1830. nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir;
  1831. nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir;
  1832. nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir;
  1833. nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir;
  1834. nodeMap["TARGET_BUNDLE_DIR"] = &targetBundleDirNode;
  1835. nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode;
  1836. nodeMap["STREQUAL"] = &strEqualNode;
  1837. nodeMap["EQUAL"] = &equalNode;
  1838. nodeMap["IN_LIST"] = &inListNode;
  1839. nodeMap["LOWER_CASE"] = &lowerCaseNode;
  1840. nodeMap["UPPER_CASE"] = &upperCaseNode;
  1841. nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
  1842. nodeMap["BOOL"] = &boolNode;
  1843. nodeMap["IF"] = &ifNode;
  1844. nodeMap["ANGLE-R"] = &angle_rNode;
  1845. nodeMap["COMMA"] = &commaNode;
  1846. nodeMap["SEMICOLON"] = &semicolonNode;
  1847. nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
  1848. nodeMap["TARGET_NAME"] = &targetNameNode;
  1849. nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
  1850. nodeMap["TARGET_POLICY"] = &targetPolicyNode;
  1851. nodeMap["TARGET_EXISTS"] = &targetExistsNode;
  1852. nodeMap["TARGET_NAME_IF_EXISTS"] = &targetNameIfExistsNode;
  1853. nodeMap["TARGET_GENEX_EVAL"] = &targetGenexEvalNode;
  1854. nodeMap["GENEX_EVAL"] = &genexEvalNode;
  1855. nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
  1856. nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
  1857. nodeMap["INSTALL_PREFIX"] = &installPrefixNode;
  1858. nodeMap["JOIN"] = &joinNode;
  1859. nodeMap["LINK_ONLY"] = &linkOnlyNode;
  1860. nodeMap["COMPILE_LANGUAGE"] = &languageNode;
  1861. nodeMap["SHELL_PATH"] = &shellPathNode;
  1862. }
  1863. NodeMap::const_iterator i = nodeMap.find(identifier);
  1864. if (i == nodeMap.end()) {
  1865. return nullptr;
  1866. }
  1867. return i->second;
  1868. }
  1869. void reportError(cmGeneratorExpressionContext* context,
  1870. const std::string& expr, const std::string& result)
  1871. {
  1872. context->HadError = true;
  1873. if (context->Quiet) {
  1874. return;
  1875. }
  1876. std::ostringstream e;
  1877. /* clang-format off */
  1878. e << "Error evaluating generator expression:\n"
  1879. << " " << expr << "\n"
  1880. << result;
  1881. /* clang-format on */
  1882. context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
  1883. e.str(), context->Backtrace);
  1884. }