You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1931 lines
67 KiB

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