cmGeneratorExpressionNode.cxx 79 KB

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