1
0

cmGeneratorExpressionNode.cxx 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149
  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,
  352. genexOperator + ":" + expression, content, 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. static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
  1800. { "0", &zeroNode },
  1801. { "1", &oneNode },
  1802. { "AND", &andNode },
  1803. { "OR", &orNode },
  1804. { "NOT", &notNode },
  1805. { "C_COMPILER_ID", &cCompilerIdNode },
  1806. { "CXX_COMPILER_ID", &cxxCompilerIdNode },
  1807. { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
  1808. { "VERSION_GREATER", &versionGreaterNode },
  1809. { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
  1810. { "VERSION_LESS", &versionLessNode },
  1811. { "VERSION_LESS_EQUAL", &versionLessEqNode },
  1812. { "VERSION_EQUAL", &versionEqualNode },
  1813. { "C_COMPILER_VERSION", &cCompilerVersionNode },
  1814. { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
  1815. { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
  1816. { "PLATFORM_ID", &platformIdNode },
  1817. { "COMPILE_FEATURES", &compileFeaturesNode },
  1818. { "CONFIGURATION", &configurationNode },
  1819. { "CONFIG", &configurationTestNode },
  1820. { "TARGET_FILE", &targetNodeGroup.File },
  1821. { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
  1822. { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
  1823. { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
  1824. { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
  1825. { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
  1826. { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
  1827. { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
  1828. { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
  1829. { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
  1830. { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
  1831. { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
  1832. { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
  1833. { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
  1834. { "STREQUAL", &strEqualNode },
  1835. { "EQUAL", &equalNode },
  1836. { "IN_LIST", &inListNode },
  1837. { "LOWER_CASE", &lowerCaseNode },
  1838. { "UPPER_CASE", &upperCaseNode },
  1839. { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
  1840. { "BOOL", &boolNode },
  1841. { "IF", &ifNode },
  1842. { "ANGLE-R", &angle_rNode },
  1843. { "COMMA", &commaNode },
  1844. { "SEMICOLON", &semicolonNode },
  1845. { "TARGET_PROPERTY", &targetPropertyNode },
  1846. { "TARGET_NAME", &targetNameNode },
  1847. { "TARGET_OBJECTS", &targetObjectsNode },
  1848. { "TARGET_POLICY", &targetPolicyNode },
  1849. { "TARGET_EXISTS", &targetExistsNode },
  1850. { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
  1851. { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
  1852. { "GENEX_EVAL", &genexEvalNode },
  1853. { "BUILD_INTERFACE", &buildInterfaceNode },
  1854. { "INSTALL_INTERFACE", &installInterfaceNode },
  1855. { "INSTALL_PREFIX", &installPrefixNode },
  1856. { "JOIN", &joinNode },
  1857. { "LINK_ONLY", &linkOnlyNode },
  1858. { "COMPILE_LANGUAGE", &languageNode },
  1859. { "SHELL_PATH", &shellPathNode }
  1860. };
  1861. {
  1862. auto itr = nodeMap.find(identifier);
  1863. if (itr != nodeMap.end()) {
  1864. return itr->second;
  1865. }
  1866. }
  1867. return nullptr;
  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. }