1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2012 Stephen Kelly <steveire@gmail.com>
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmMakefile.h"
14 #include "cmGeneratorExpressionEvaluator.h"
15 #include "cmGeneratorExpressionParser.h"
16 #include "cmGeneratorExpressionDAGChecker.h"
17 #include "cmGeneratorExpression.h"
19 #include <cmsys/String.h>
23 //----------------------------------------------------------------------------
24 #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
27 void reportError(cmGeneratorExpressionContext *context,
28 const std::string &expr, const std::string &result)
30 context->HadError = true;
37 e << "Error evaluating generator expression:\n"
38 << " " << expr << "\n"
40 context->Makefile->GetCMakeInstance()
41 ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
45 //----------------------------------------------------------------------------
46 struct cmGeneratorExpressionNode
49 DynamicParameters = 0,
50 OneOrMoreParameters = -1,
51 ZeroOrMoreParameters = -2
53 virtual ~cmGeneratorExpressionNode() {}
55 virtual bool GeneratesContent() const { return true; }
57 virtual bool RequiresLiteralInput() const { return false; }
59 virtual bool AcceptsArbitraryContentParameter() const
62 virtual int NumExpectedParameters() const { return 1; }
64 virtual std::string Evaluate(const std::vector<std::string> ¶meters,
65 cmGeneratorExpressionContext *context,
66 const GeneratorExpressionContent *content,
67 cmGeneratorExpressionDAGChecker *dagChecker
71 //----------------------------------------------------------------------------
72 static const struct ZeroNode : public cmGeneratorExpressionNode
76 virtual bool GeneratesContent() const { return false; }
78 virtual bool AcceptsArbitraryContentParameter() const { return true; }
80 std::string Evaluate(const std::vector<std::string> &,
81 cmGeneratorExpressionContext *,
82 const GeneratorExpressionContent *,
83 cmGeneratorExpressionDAGChecker *) const
90 //----------------------------------------------------------------------------
91 static const struct OneNode : public cmGeneratorExpressionNode
95 virtual bool AcceptsArbitraryContentParameter() const { return true; }
97 std::string Evaluate(const std::vector<std::string> &,
98 cmGeneratorExpressionContext *,
99 const GeneratorExpressionContent *,
100 cmGeneratorExpressionDAGChecker *) const
103 return std::string();
107 //----------------------------------------------------------------------------
108 static const struct OneNode buildInterfaceNode;
110 //----------------------------------------------------------------------------
111 static const struct ZeroNode installInterfaceNode;
113 //----------------------------------------------------------------------------
114 #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
115 static const struct OP ## Node : public cmGeneratorExpressionNode \
118 virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
120 std::string Evaluate(const std::vector<std::string> ¶meters, \
121 cmGeneratorExpressionContext *context, \
122 const GeneratorExpressionContent *content, \
123 cmGeneratorExpressionDAGChecker *) const \
125 std::vector<std::string>::const_iterator it = parameters.begin(); \
126 const std::vector<std::string>::const_iterator end = parameters.end(); \
127 for ( ; it != end; ++it) \
129 if (*it == #FAILURE_VALUE) \
131 return #FAILURE_VALUE; \
133 else if (*it != #SUCCESS_VALUE) \
135 reportError(context, content->GetOriginalExpression(), \
136 "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
137 return std::string(); \
140 return #SUCCESS_VALUE; \
144 BOOLEAN_OP_NODE(andNode, AND, 1, 0)
145 BOOLEAN_OP_NODE(orNode, OR, 0, 1)
147 #undef BOOLEAN_OP_NODE
149 //----------------------------------------------------------------------------
150 static const struct NotNode : public cmGeneratorExpressionNode
154 std::string Evaluate(const std::vector<std::string> ¶meters,
155 cmGeneratorExpressionContext *context,
156 const GeneratorExpressionContent *content,
157 cmGeneratorExpressionDAGChecker *) const
159 if (*parameters.begin() != "0" && *parameters.begin() != "1")
161 reportError(context, content->GetOriginalExpression(),
162 "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
163 return std::string();
165 return *parameters.begin() == "0" ? "1" : "0";
169 //----------------------------------------------------------------------------
170 static const struct BoolNode : public cmGeneratorExpressionNode
174 virtual int NumExpectedParameters() const { return 1; }
176 std::string Evaluate(const std::vector<std::string> ¶meters,
177 cmGeneratorExpressionContext *,
178 const GeneratorExpressionContent *,
179 cmGeneratorExpressionDAGChecker *) const
181 return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
185 //----------------------------------------------------------------------------
186 static const struct StrEqualNode : public cmGeneratorExpressionNode
190 virtual int NumExpectedParameters() const { return 2; }
192 std::string Evaluate(const std::vector<std::string> ¶meters,
193 cmGeneratorExpressionContext *,
194 const GeneratorExpressionContent *,
195 cmGeneratorExpressionDAGChecker *) const
197 return *parameters.begin() == parameters[1] ? "1" : "0";
201 //----------------------------------------------------------------------------
202 static const struct Angle_RNode : public cmGeneratorExpressionNode
206 virtual int NumExpectedParameters() const { return 0; }
208 std::string Evaluate(const std::vector<std::string> &,
209 cmGeneratorExpressionContext *,
210 const GeneratorExpressionContent *,
211 cmGeneratorExpressionDAGChecker *) const
217 //----------------------------------------------------------------------------
218 static const struct CommaNode : public cmGeneratorExpressionNode
222 virtual int NumExpectedParameters() const { return 0; }
224 std::string Evaluate(const std::vector<std::string> &,
225 cmGeneratorExpressionContext *,
226 const GeneratorExpressionContent *,
227 cmGeneratorExpressionDAGChecker *) const
233 //----------------------------------------------------------------------------
234 static const struct SemicolonNode : public cmGeneratorExpressionNode
238 virtual int NumExpectedParameters() const { return 0; }
240 std::string Evaluate(const std::vector<std::string> &,
241 cmGeneratorExpressionContext *,
242 const GeneratorExpressionContent *,
243 cmGeneratorExpressionDAGChecker *) const
249 //----------------------------------------------------------------------------
250 struct CompilerIdNode : public cmGeneratorExpressionNode
254 virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
256 std::string EvaluateWithLanguage(const std::vector<std::string> ¶meters,
257 cmGeneratorExpressionContext *context,
258 const GeneratorExpressionContent *content,
259 cmGeneratorExpressionDAGChecker *,
260 const std::string &lang) const
262 const char *compilerId = context->Makefile ?
263 context->Makefile->GetSafeDefinition((
264 "CMAKE_" + lang + "_COMPILER_ID").c_str()) : "";
265 if (parameters.size() == 0)
267 return compilerId ? compilerId : "";
269 cmsys::RegularExpression compilerIdValidator;
270 compilerIdValidator.compile("^[A-Za-z0-9_]*$");
271 if (!compilerIdValidator.find(parameters.begin()->c_str()))
273 reportError(context, content->GetOriginalExpression(),
274 "Expression syntax not recognized.");
275 return std::string();
279 return parameters.front().empty() ? "1" : "0";
282 if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0)
290 //----------------------------------------------------------------------------
291 static const struct CCompilerIdNode : public CompilerIdNode
295 std::string Evaluate(const std::vector<std::string> ¶meters,
296 cmGeneratorExpressionContext *context,
297 const GeneratorExpressionContent *content,
298 cmGeneratorExpressionDAGChecker *dagChecker) const
300 if (parameters.size() != 0 && parameters.size() != 1)
302 reportError(context, content->GetOriginalExpression(),
303 "$<C_COMPILER_ID> expression requires one or two parameters");
304 return std::string();
306 if (!context->HeadTarget)
308 reportError(context, content->GetOriginalExpression(),
309 "$<C_COMPILER_ID> may only be used with targets. It may not "
310 "be used with add_custom_command.");
312 return this->EvaluateWithLanguage(parameters, context, content,
317 //----------------------------------------------------------------------------
318 static const struct CXXCompilerIdNode : public CompilerIdNode
320 CXXCompilerIdNode() {}
322 std::string Evaluate(const std::vector<std::string> ¶meters,
323 cmGeneratorExpressionContext *context,
324 const GeneratorExpressionContent *content,
325 cmGeneratorExpressionDAGChecker *dagChecker) const
327 if (parameters.size() != 0 && parameters.size() != 1)
329 reportError(context, content->GetOriginalExpression(),
330 "$<CXX_COMPILER_ID> expression requires one or two parameters");
331 return std::string();
333 if (!context->HeadTarget)
335 reportError(context, content->GetOriginalExpression(),
336 "$<CXX_COMPILER_ID> may only be used with targets. It may not "
337 "be used with add_custom_command.");
339 return this->EvaluateWithLanguage(parameters, context, content,
344 //----------------------------------------------------------------------------
345 struct CompilerVersionNode : public cmGeneratorExpressionNode
347 CompilerVersionNode() {}
349 virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
351 std::string EvaluateWithLanguage(const std::vector<std::string> ¶meters,
352 cmGeneratorExpressionContext *context,
353 const GeneratorExpressionContent *content,
354 cmGeneratorExpressionDAGChecker *,
355 const std::string &lang) const
357 const char *compilerVersion = context->Makefile ?
358 context->Makefile->GetSafeDefinition((
359 "CMAKE_" + lang + "_COMPILER_VERSION").c_str()) : "";
360 if (parameters.size() == 0)
362 return compilerVersion ? compilerVersion : "";
365 cmsys::RegularExpression compilerIdValidator;
366 compilerIdValidator.compile("^[0-9\\.]*$");
367 if (!compilerIdValidator.find(parameters.begin()->c_str()))
369 reportError(context, content->GetOriginalExpression(),
370 "Expression syntax not recognized.");
371 return std::string();
373 if (!compilerVersion)
375 return parameters.front().empty() ? "1" : "0";
378 return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
379 parameters.begin()->c_str(),
380 compilerVersion) ? "1" : "0";
384 //----------------------------------------------------------------------------
385 static const struct CCompilerVersionNode : public CompilerVersionNode
387 CCompilerVersionNode() {}
389 std::string Evaluate(const std::vector<std::string> ¶meters,
390 cmGeneratorExpressionContext *context,
391 const GeneratorExpressionContent *content,
392 cmGeneratorExpressionDAGChecker *dagChecker) const
394 if (parameters.size() != 0 && parameters.size() != 1)
396 reportError(context, content->GetOriginalExpression(),
397 "$<C_COMPILER_VERSION> expression requires one or two parameters");
398 return std::string();
400 if (!context->HeadTarget)
402 reportError(context, content->GetOriginalExpression(),
403 "$<C_COMPILER_VERSION> may only be used with targets. It may not "
404 "be used with add_custom_command.");
406 return this->EvaluateWithLanguage(parameters, context, content,
409 } cCompilerVersionNode;
411 //----------------------------------------------------------------------------
412 static const struct CxxCompilerVersionNode : public CompilerVersionNode
414 CxxCompilerVersionNode() {}
416 std::string Evaluate(const std::vector<std::string> ¶meters,
417 cmGeneratorExpressionContext *context,
418 const GeneratorExpressionContent *content,
419 cmGeneratorExpressionDAGChecker *dagChecker) const
421 if (parameters.size() != 0 && parameters.size() != 1)
423 reportError(context, content->GetOriginalExpression(),
424 "$<CXX_COMPILER_VERSION> expression requires one or two "
426 return std::string();
428 if (!context->HeadTarget)
430 reportError(context, content->GetOriginalExpression(),
431 "$<CXX_COMPILER_VERSION> may only be used with targets. It may "
432 "not be used with add_custom_command.");
434 return this->EvaluateWithLanguage(parameters, context, content,
437 } cxxCompilerVersionNode;
440 //----------------------------------------------------------------------------
441 static const struct VersionGreaterNode : public cmGeneratorExpressionNode
443 VersionGreaterNode() {}
445 virtual int NumExpectedParameters() const { return 2; }
447 std::string Evaluate(const std::vector<std::string> ¶meters,
448 cmGeneratorExpressionContext *,
449 const GeneratorExpressionContent *,
450 cmGeneratorExpressionDAGChecker *) const
452 return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
453 parameters.front().c_str(),
454 parameters[1].c_str()) ? "1" : "0";
456 } versionGreaterNode;
458 //----------------------------------------------------------------------------
459 static const struct VersionLessNode : public cmGeneratorExpressionNode
463 virtual int NumExpectedParameters() const { return 2; }
465 std::string Evaluate(const std::vector<std::string> ¶meters,
466 cmGeneratorExpressionContext *,
467 const GeneratorExpressionContent *,
468 cmGeneratorExpressionDAGChecker *) const
470 return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
471 parameters.front().c_str(),
472 parameters[1].c_str()) ? "1" : "0";
476 //----------------------------------------------------------------------------
477 static const struct VersionEqualNode : public cmGeneratorExpressionNode
479 VersionEqualNode() {}
481 virtual int NumExpectedParameters() const { return 2; }
483 std::string Evaluate(const std::vector<std::string> ¶meters,
484 cmGeneratorExpressionContext *,
485 const GeneratorExpressionContent *,
486 cmGeneratorExpressionDAGChecker *) const
488 return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
489 parameters.front().c_str(),
490 parameters[1].c_str()) ? "1" : "0";
494 //----------------------------------------------------------------------------
495 static const struct LinkOnlyNode : public cmGeneratorExpressionNode
499 std::string Evaluate(const std::vector<std::string> ¶meters,
500 cmGeneratorExpressionContext *,
501 const GeneratorExpressionContent *,
502 cmGeneratorExpressionDAGChecker *dagChecker) const
504 if(!dagChecker->GetTransitivePropertiesOnly())
506 return parameters.front();
512 //----------------------------------------------------------------------------
513 static const struct ConfigurationNode : public cmGeneratorExpressionNode
515 ConfigurationNode() {}
517 virtual int NumExpectedParameters() const { return 0; }
519 std::string Evaluate(const std::vector<std::string> &,
520 cmGeneratorExpressionContext *context,
521 const GeneratorExpressionContent *,
522 cmGeneratorExpressionDAGChecker *) const
524 context->HadContextSensitiveCondition = true;
525 return context->Config ? context->Config : "";
529 //----------------------------------------------------------------------------
530 static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
532 ConfigurationTestNode() {}
534 virtual int NumExpectedParameters() const { return 1; }
536 std::string Evaluate(const std::vector<std::string> ¶meters,
537 cmGeneratorExpressionContext *context,
538 const GeneratorExpressionContent *content,
539 cmGeneratorExpressionDAGChecker *) const
541 cmsys::RegularExpression configValidator;
542 configValidator.compile("^[A-Za-z0-9_]*$");
543 if (!configValidator.find(parameters.begin()->c_str()))
545 reportError(context, content->GetOriginalExpression(),
546 "Expression syntax not recognized.");
547 return std::string();
549 context->HadContextSensitiveCondition = true;
550 if (!context->Config)
552 return parameters.front().empty() ? "1" : "0";
555 if (cmsysString_strcasecmp(parameters.begin()->c_str(),
556 context->Config) == 0)
561 if (context->CurrentTarget
562 && context->CurrentTarget->IsImported())
567 if (context->CurrentTarget->GetMappedConfig(context->Config,
572 // This imported target has an appropriate location
573 // for this (possibly mapped) config.
574 // Check if there is a proper config mapping for the tested config.
575 std::vector<std::string> mappedConfigs;
576 std::string mapProp = "MAP_IMPORTED_CONFIG_";
577 mapProp += cmSystemTools::UpperCase(context->Config);
578 if(const char* mapValue =
579 context->CurrentTarget->GetProperty(mapProp.c_str()))
581 cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue),
583 return std::find(mappedConfigs.begin(), mappedConfigs.end(),
584 cmSystemTools::UpperCase(parameters.front()))
585 != mappedConfigs.end() ? "1" : "0";
591 } configurationTestNode;
593 static const struct JoinNode : public cmGeneratorExpressionNode
597 virtual int NumExpectedParameters() const { return 2; }
599 virtual bool AcceptsArbitraryContentParameter() const { return true; }
601 std::string Evaluate(const std::vector<std::string> ¶meters,
602 cmGeneratorExpressionContext *,
603 const GeneratorExpressionContent *,
604 cmGeneratorExpressionDAGChecker *) const
608 std::vector<std::string> list;
609 cmSystemTools::ExpandListArgument(parameters.front(), list);
611 for(std::vector<std::string>::const_iterator li = list.begin();
612 li != list.end(); ++li)
621 #define TRANSITIVE_PROPERTY_NAME(PROPERTY) \
624 //----------------------------------------------------------------------------
625 static const char* targetPropertyTransitiveWhitelist[] = {
627 CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
630 std::string getLinkedTargetsContent(const std::vector<std::string> &libraries,
632 cmTarget *headTarget,
633 cmGeneratorExpressionContext *context,
634 cmGeneratorExpressionDAGChecker *dagChecker,
635 const std::string &interfacePropertyName)
637 cmGeneratorExpression ge(context->Backtrace);
640 std::string depString;
641 for (std::vector<std::string>::const_iterator
642 it = libraries.begin();
643 it != libraries.end(); ++it)
645 if (*it == target->GetName())
647 // Broken code can have a target in its own link interface.
648 // Don't follow such link interface entries so as not to create a
649 // self-referencing loop.
652 if (context->Makefile->FindTargetToUse(it->c_str()))
655 sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">";
659 cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString);
660 std::string linkedTargetsContent = cge->Evaluate(context->Makefile,
666 if (cge->GetHadContextSensitiveCondition())
668 context->HadContextSensitiveCondition = true;
670 return linkedTargetsContent;
673 //----------------------------------------------------------------------------
674 struct TransitiveWhitelistCompare
676 explicit TransitiveWhitelistCompare(const std::string &needle)
678 bool operator() (const char *item)
679 { return strcmp(item, this->Needle.c_str()) == 0; }
684 //----------------------------------------------------------------------------
685 static const struct TargetPropertyNode : public cmGeneratorExpressionNode
687 TargetPropertyNode() {}
689 // This node handles errors on parameter count itself.
690 virtual int NumExpectedParameters() const { return OneOrMoreParameters; }
692 std::string Evaluate(const std::vector<std::string> ¶meters,
693 cmGeneratorExpressionContext *context,
694 const GeneratorExpressionContent *content,
695 cmGeneratorExpressionDAGChecker *dagCheckerParent
698 if (parameters.size() != 1 && parameters.size() != 2)
700 reportError(context, content->GetOriginalExpression(),
701 "$<TARGET_PROPERTY:...> expression requires one or two parameters");
702 return std::string();
704 cmsys::RegularExpression propertyNameValidator;
705 propertyNameValidator.compile("^[A-Za-z0-9_]+$");
707 cmTarget* target = context->HeadTarget;
708 std::string propertyName = *parameters.begin();
710 if (!target && parameters.size() == 1)
712 reportError(context, content->GetOriginalExpression(),
713 "$<TARGET_PROPERTY:prop> may only be used with targets. It may not "
714 "be used with add_custom_command. Specify the target to read a "
715 "property from using the $<TARGET_PROPERTY:tgt,prop> signature "
717 return std::string();
720 if (parameters.size() == 2)
722 if (parameters.begin()->empty() && parameters[1].empty())
724 reportError(context, content->GetOriginalExpression(),
725 "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
726 "target name and property name.");
727 return std::string();
729 if (parameters.begin()->empty())
731 reportError(context, content->GetOriginalExpression(),
732 "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
734 return std::string();
737 std::string targetName = parameters.front();
738 propertyName = parameters[1];
739 if (!cmGeneratorExpression::IsValidTargetName(targetName))
741 if (!propertyNameValidator.find(propertyName.c_str()))
743 ::reportError(context, content->GetOriginalExpression(),
744 "Target name and property name not supported.");
745 return std::string();
747 ::reportError(context, content->GetOriginalExpression(),
748 "Target name not supported.");
749 return std::string();
751 if(propertyName == "ALIASED_TARGET")
753 if(context->Makefile->IsAlias(targetName.c_str()))
756 context->Makefile->FindTargetToUse(targetName.c_str()))
758 return tgt->GetName();
763 target = context->Makefile->FindTargetToUse(
772 reportError(context, content->GetOriginalExpression(), e.str());
773 return std::string();
775 context->AllTargets.insert(target);
778 if (target == context->HeadTarget)
780 // Keep track of the properties seen while processing.
781 // The evaluation of the LINK_LIBRARIES generator expressions
782 // will check this to ensure that properties have one consistent
783 // value for all evaluations.
784 context->SeenTargetProperties.insert(propertyName);
787 if (propertyName.empty())
789 reportError(context, content->GetOriginalExpression(),
790 "$<TARGET_PROPERTY:...> expression requires a non-empty property "
792 return std::string();
795 if (!propertyNameValidator.find(propertyName.c_str()))
797 ::reportError(context, content->GetOriginalExpression(),
798 "Property name not supported.");
799 return std::string();
804 if (propertyName == "LINKER_LANGUAGE")
806 if (target->LinkLanguagePropagatesToDependents() &&
807 dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries())
809 reportError(context, content->GetOriginalExpression(),
810 "LINKER_LANGUAGE target property can not be used while evaluating "
811 "link libraries for a static library");
812 return std::string();
814 const char *lang = target->GetLinkerLanguage(context->Config);
815 return lang ? lang : "";
818 cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
824 switch (dagChecker.check())
826 case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
827 dagChecker.reportError(context, content->GetOriginalExpression());
828 return std::string();
829 case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
830 // No error. We just skip cyclic references.
831 return std::string();
832 case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
834 i < (sizeof(targetPropertyTransitiveWhitelist) /
835 sizeof(*targetPropertyTransitiveWhitelist));
838 if (targetPropertyTransitiveWhitelist[i] == propertyName)
840 // No error. We're not going to find anything new here.
841 return std::string();
844 case cmGeneratorExpressionDAGChecker::DAG:
848 const char *prop = target->GetProperty(propertyName.c_str());
850 if (dagCheckerParent)
852 if (dagCheckerParent->EvaluatingLinkLibraries())
856 return std::string();
861 #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) \
862 dagCheckerParent->METHOD () ||
865 CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
866 ASSERT_TRANSITIVE_PROPERTY_METHOD)
871 std::string linkedTargetsContent;
873 std::string interfacePropertyName;
875 if (propertyName == "INTERFACE_INCLUDE_DIRECTORIES"
876 || propertyName == "INCLUDE_DIRECTORIES")
878 interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES";
880 else if (propertyName == "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")
882 interfacePropertyName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES";
884 else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS"
885 || propertyName == "COMPILE_DEFINITIONS"
886 || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0)
888 interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
890 else if (propertyName == "INTERFACE_COMPILE_OPTIONS"
891 || propertyName == "COMPILE_OPTIONS")
893 interfacePropertyName = "INTERFACE_COMPILE_OPTIONS";
896 cmTarget *headTarget = context->HeadTarget ? context->HeadTarget : target;
898 const char **transBegin = targetPropertyTransitiveWhitelist + 1;
899 const char **transEnd = targetPropertyTransitiveWhitelist
900 + (sizeof(targetPropertyTransitiveWhitelist) /
901 sizeof(*targetPropertyTransitiveWhitelist));
902 if (std::find_if(transBegin, transEnd,
903 TransitiveWhitelistCompare(propertyName)) != transEnd)
906 std::vector<std::string> libs;
907 target->GetTransitivePropertyLinkLibraries(context->Config,
911 linkedTargetsContent =
912 getLinkedTargetsContent(libs, target,
914 context, &dagChecker,
915 interfacePropertyName);
918 else if (std::find_if(transBegin, transEnd,
919 TransitiveWhitelistCompare(interfacePropertyName)) != transEnd)
921 const cmTarget::LinkImplementation *impl = target->GetLinkImplementation(
926 linkedTargetsContent =
927 getLinkedTargetsContent(impl->Libraries, target,
929 context, &dagChecker,
930 interfacePropertyName);
934 linkedTargetsContent =
935 cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
939 if (target->IsImported())
941 return linkedTargetsContent;
943 if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
946 context->HadContextSensitiveCondition = true;
947 return target->GetLinkInterfaceDependentBoolProperty(
949 context->Config) ? "1" : "0";
951 if (target->IsLinkInterfaceDependentStringProperty(propertyName,
954 context->HadContextSensitiveCondition = true;
955 const char *propContent =
956 target->GetLinkInterfaceDependentStringProperty(
959 return propContent ? propContent : "";
962 return linkedTargetsContent;
966 i < (sizeof(targetPropertyTransitiveWhitelist) /
967 sizeof(*targetPropertyTransitiveWhitelist));
970 if (targetPropertyTransitiveWhitelist[i] == interfacePropertyName)
972 cmGeneratorExpression ge(context->Backtrace);
973 cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
974 std::string result = cge->Evaluate(context->Makefile,
981 if (cge->GetHadContextSensitiveCondition())
983 context->HadContextSensitiveCondition = true;
985 if (!linkedTargetsContent.empty())
987 result += (result.empty() ? "" : ";") + linkedTargetsContent;
994 } targetPropertyNode;
996 //----------------------------------------------------------------------------
997 static const struct TargetNameNode : public cmGeneratorExpressionNode
1001 virtual bool GeneratesContent() const { return true; }
1003 virtual bool AcceptsArbitraryContentParameter() const { return true; }
1004 virtual bool RequiresLiteralInput() const { return true; }
1006 std::string Evaluate(const std::vector<std::string> ¶meters,
1007 cmGeneratorExpressionContext *,
1008 const GeneratorExpressionContent *,
1009 cmGeneratorExpressionDAGChecker *) const
1011 return parameters.front();
1014 virtual int NumExpectedParameters() const { return 1; }
1018 //----------------------------------------------------------------------------
1019 static const char* targetPolicyWhitelist[] = {
1021 #define TARGET_POLICY_STRING(POLICY) \
1024 CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
1026 #undef TARGET_POLICY_STRING
1029 cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
1031 #define RETURN_POLICY(POLICY) \
1032 if (strcmp(policy, #POLICY) == 0) \
1034 return tgt->GetPolicyStatus ## POLICY (); \
1037 CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
1039 #undef RETURN_POLICY
1041 assert("!Unreachable code. Not a valid policy");
1042 return cmPolicies::WARN;
1045 cmPolicies::PolicyID policyForString(const char *policy_id)
1047 #define RETURN_POLICY_ID(POLICY_ID) \
1048 if (strcmp(policy_id, #POLICY_ID) == 0) \
1050 return cmPolicies:: POLICY_ID; \
1053 CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
1055 #undef RETURN_POLICY_ID
1057 assert("!Unreachable code. Not a valid policy");
1058 return cmPolicies::CMP0002;
1061 //----------------------------------------------------------------------------
1062 static const struct TargetPolicyNode : public cmGeneratorExpressionNode
1064 TargetPolicyNode() {}
1066 virtual int NumExpectedParameters() const { return 1; }
1068 std::string Evaluate(const std::vector<std::string> ¶meters,
1069 cmGeneratorExpressionContext *context ,
1070 const GeneratorExpressionContent *content,
1071 cmGeneratorExpressionDAGChecker *) const
1073 if (!context->HeadTarget)
1075 reportError(context, content->GetOriginalExpression(),
1076 "$<TARGET_POLICY:prop> may only be used with targets. It may not "
1077 "be used with add_custom_command.");
1078 return std::string();
1081 context->HadContextSensitiveCondition = true;
1084 i < (sizeof(targetPolicyWhitelist) /
1085 sizeof(*targetPolicyWhitelist));
1088 const char *policy = targetPolicyWhitelist[i];
1089 if (parameters.front() == policy)
1091 cmMakefile *mf = context->HeadTarget->GetMakefile();
1092 switch(statusForTarget(context->HeadTarget, policy))
1094 case cmPolicies::WARN:
1095 mf->IssueMessage(cmake::AUTHOR_WARNING,
1097 GetPolicyWarning(policyForString(policy)));
1098 case cmPolicies::REQUIRED_IF_USED:
1099 case cmPolicies::REQUIRED_ALWAYS:
1100 case cmPolicies::OLD:
1102 case cmPolicies::NEW:
1107 reportError(context, content->GetOriginalExpression(),
1108 "$<TARGET_POLICY:prop> may only be used with a limited number of "
1109 "policies. Currently it may be used with the following policies:\n"
1111 #define STRINGIFY_HELPER(X) #X
1112 #define STRINGIFY(X) STRINGIFY_HELPER(X)
1114 #define TARGET_POLICY_LIST_ITEM(POLICY) \
1115 " * " STRINGIFY(POLICY) "\n"
1117 CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
1119 #undef TARGET_POLICY_LIST_ITEM
1121 return std::string();
1126 //----------------------------------------------------------------------------
1127 static const struct InstallPrefixNode : public cmGeneratorExpressionNode
1129 InstallPrefixNode() {}
1131 virtual bool GeneratesContent() const { return true; }
1132 virtual int NumExpectedParameters() const { return 0; }
1134 std::string Evaluate(const std::vector<std::string> &,
1135 cmGeneratorExpressionContext *context,
1136 const GeneratorExpressionContent *content,
1137 cmGeneratorExpressionDAGChecker *) const
1139 reportError(context, content->GetOriginalExpression(),
1140 "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
1141 "should never be evaluated.");
1142 return std::string();
1145 } installPrefixNode;
1147 //----------------------------------------------------------------------------
1148 template<bool linker, bool soname>
1149 struct TargetFilesystemArtifactResultCreator
1151 static std::string Create(cmTarget* target,
1152 cmGeneratorExpressionContext *context,
1153 const GeneratorExpressionContent *content);
1156 //----------------------------------------------------------------------------
1158 struct TargetFilesystemArtifactResultCreator<false, true>
1160 static std::string Create(cmTarget* target,
1161 cmGeneratorExpressionContext *context,
1162 const GeneratorExpressionContent *content)
1164 // The target soname file (.so.1).
1165 if(target->IsDLLPlatform())
1167 ::reportError(context, content->GetOriginalExpression(),
1168 "TARGET_SONAME_FILE is not allowed "
1169 "for DLL target platforms.");
1170 return std::string();
1172 if(target->GetType() != cmTarget::SHARED_LIBRARY)
1174 ::reportError(context, content->GetOriginalExpression(),
1175 "TARGET_SONAME_FILE is allowed only for "
1176 "SHARED libraries.");
1177 return std::string();
1179 std::string result = target->GetDirectory(context->Config);
1181 result += target->GetSOName(context->Config);
1186 //----------------------------------------------------------------------------
1188 struct TargetFilesystemArtifactResultCreator<true, false>
1190 static std::string Create(cmTarget* target,
1191 cmGeneratorExpressionContext *context,
1192 const GeneratorExpressionContent *content)
1194 // The file used to link to the target (.so, .lib, .a).
1195 if(!target->IsLinkable())
1197 ::reportError(context, content->GetOriginalExpression(),
1198 "TARGET_LINKER_FILE is allowed only for libraries and "
1199 "executables with ENABLE_EXPORTS.");
1200 return std::string();
1202 return target->GetFullPath(context->Config,
1203 target->HasImportLibrary());
1207 //----------------------------------------------------------------------------
1209 struct TargetFilesystemArtifactResultCreator<false, false>
1211 static std::string Create(cmTarget* target,
1212 cmGeneratorExpressionContext *context,
1213 const GeneratorExpressionContent *)
1215 return target->GetFullPath(context->Config, false, true);
1220 //----------------------------------------------------------------------------
1221 template<bool dirQual, bool nameQual>
1222 struct TargetFilesystemArtifactResultGetter
1224 static std::string Get(const std::string &result);
1227 //----------------------------------------------------------------------------
1229 struct TargetFilesystemArtifactResultGetter<false, true>
1231 static std::string Get(const std::string &result)
1232 { return cmSystemTools::GetFilenameName(result); }
1235 //----------------------------------------------------------------------------
1237 struct TargetFilesystemArtifactResultGetter<true, false>
1239 static std::string Get(const std::string &result)
1240 { return cmSystemTools::GetFilenamePath(result); }
1243 //----------------------------------------------------------------------------
1245 struct TargetFilesystemArtifactResultGetter<false, false>
1247 static std::string Get(const std::string &result)
1251 //----------------------------------------------------------------------------
1252 template<bool linker, bool soname, bool dirQual, bool nameQual>
1253 struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
1255 TargetFilesystemArtifact() {}
1257 virtual int NumExpectedParameters() const { return 1; }
1259 std::string Evaluate(const std::vector<std::string> ¶meters,
1260 cmGeneratorExpressionContext *context,
1261 const GeneratorExpressionContent *content,
1262 cmGeneratorExpressionDAGChecker *dagChecker) const
1264 // Lookup the referenced target.
1265 std::string name = *parameters.begin();
1267 if (!cmGeneratorExpression::IsValidTargetName(name))
1269 ::reportError(context, content->GetOriginalExpression(),
1270 "Expression syntax not recognized.");
1271 return std::string();
1273 cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
1276 ::reportError(context, content->GetOriginalExpression(),
1277 "No target \"" + name + "\"");
1278 return std::string();
1280 if(target->GetType() >= cmTarget::OBJECT_LIBRARY &&
1281 target->GetType() != cmTarget::UNKNOWN_LIBRARY)
1283 ::reportError(context, content->GetOriginalExpression(),
1284 "Target \"" + name + "\" is not an executable or library.");
1285 return std::string();
1287 if (dagChecker && dagChecker->EvaluatingLinkLibraries(name.c_str()))
1289 ::reportError(context, content->GetOriginalExpression(),
1290 "Expressions which require the linker language may not "
1291 "be used while evaluating link libraries");
1292 return std::string();
1294 context->DependTargets.insert(target);
1295 context->AllTargets.insert(target);
1297 std::string result =
1298 TargetFilesystemArtifactResultCreator<linker, soname>::Create(
1302 if (context->HadError)
1304 return std::string();
1307 TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
1311 //----------------------------------------------------------------------------
1313 TargetFilesystemArtifact<false, false, false, false> targetFileNode;
1315 TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
1317 TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
1319 TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
1321 TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
1323 TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
1325 TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
1327 TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
1329 TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
1331 //----------------------------------------------------------------------------
1333 cmGeneratorExpressionNode* GetNode(const std::string &identifier)
1335 if (identifier == "0")
1337 else if (identifier == "1")
1339 else if (identifier == "AND")
1341 else if (identifier == "OR")
1343 else if (identifier == "NOT")
1345 else if (identifier == "C_COMPILER_ID")
1346 return &cCompilerIdNode;
1347 else if (identifier == "CXX_COMPILER_ID")
1348 return &cxxCompilerIdNode;
1349 else if (identifier == "VERSION_GREATER")
1350 return &versionGreaterNode;
1351 else if (identifier == "VERSION_LESS")
1352 return &versionLessNode;
1353 else if (identifier == "VERSION_EQUAL")
1354 return &versionEqualNode;
1355 else if (identifier == "C_COMPILER_VERSION")
1356 return &cCompilerVersionNode;
1357 else if (identifier == "CXX_COMPILER_VERSION")
1358 return &cxxCompilerVersionNode;
1359 else if (identifier == "CONFIGURATION")
1360 return &configurationNode;
1361 else if (identifier == "CONFIG")
1362 return &configurationTestNode;
1363 else if (identifier == "TARGET_FILE")
1364 return &targetFileNode;
1365 else if (identifier == "TARGET_LINKER_FILE")
1366 return &targetLinkerFileNode;
1367 else if (identifier == "TARGET_SONAME_FILE")
1368 return &targetSoNameFileNode;
1369 else if (identifier == "TARGET_FILE_NAME")
1370 return &targetFileNameNode;
1371 else if (identifier == "TARGET_LINKER_FILE_NAME")
1372 return &targetLinkerFileNameNode;
1373 else if (identifier == "TARGET_SONAME_FILE_NAME")
1374 return &targetSoNameFileNameNode;
1375 else if (identifier == "TARGET_FILE_DIR")
1376 return &targetFileDirNode;
1377 else if (identifier == "TARGET_LINKER_FILE_DIR")
1378 return &targetLinkerFileDirNode;
1379 else if (identifier == "TARGET_SONAME_FILE_DIR")
1380 return &targetSoNameFileDirNode;
1381 else if (identifier == "STREQUAL")
1382 return &strEqualNode;
1383 else if (identifier == "BOOL")
1385 else if (identifier == "ANGLE-R")
1386 return &angle_rNode;
1387 else if (identifier == "COMMA")
1389 else if (identifier == "SEMICOLON")
1390 return &semicolonNode;
1391 else if (identifier == "TARGET_PROPERTY")
1392 return &targetPropertyNode;
1393 else if (identifier == "TARGET_NAME")
1394 return &targetNameNode;
1395 else if (identifier == "TARGET_POLICY")
1396 return &targetPolicyNode;
1397 else if (identifier == "BUILD_INTERFACE")
1398 return &buildInterfaceNode;
1399 else if (identifier == "INSTALL_INTERFACE")
1400 return &installInterfaceNode;
1401 else if (identifier == "INSTALL_PREFIX")
1402 return &installPrefixNode;
1403 else if (identifier == "JOIN")
1405 else if (identifier == "LINK_ONLY")
1406 return &linkOnlyNode;
1411 //----------------------------------------------------------------------------
1412 GeneratorExpressionContent::GeneratorExpressionContent(
1413 const char *startContent,
1414 unsigned int length)
1415 : StartContent(startContent), ContentLength(length)
1420 //----------------------------------------------------------------------------
1421 std::string GeneratorExpressionContent::GetOriginalExpression() const
1423 return std::string(this->StartContent, this->ContentLength);
1426 //----------------------------------------------------------------------------
1427 std::string GeneratorExpressionContent::ProcessArbitraryContent(
1428 const cmGeneratorExpressionNode *node,
1429 const std::string &identifier,
1430 cmGeneratorExpressionContext *context,
1431 cmGeneratorExpressionDAGChecker *dagChecker,
1432 std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1438 std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1439 pend = this->ParamChildren.end();
1440 for ( ; pit != pend; ++pit)
1442 std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1444 const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1446 for ( ; it != end; ++it)
1448 if (node->RequiresLiteralInput())
1450 if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
1452 reportError(context, this->GetOriginalExpression(),
1453 "$<" + identifier + "> expression requires literal input.");
1454 return std::string();
1457 result += (*it)->Evaluate(context, dagChecker);
1458 if (context->HadError)
1460 return std::string();
1463 if ((pit + 1) != pend)
1468 if (node->RequiresLiteralInput())
1470 std::vector<std::string> parameters;
1471 parameters.push_back(result);
1472 return node->Evaluate(parameters, context, this, dagChecker);
1477 //----------------------------------------------------------------------------
1478 std::string GeneratorExpressionContent::Evaluate(
1479 cmGeneratorExpressionContext *context,
1480 cmGeneratorExpressionDAGChecker *dagChecker) const
1482 std::string identifier;
1484 std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1485 = this->IdentifierChildren.begin();
1486 const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1487 = this->IdentifierChildren.end();
1488 for ( ; it != end; ++it)
1490 identifier += (*it)->Evaluate(context, dagChecker);
1491 if (context->HadError)
1493 return std::string();
1498 const cmGeneratorExpressionNode *node = GetNode(identifier);
1502 reportError(context, this->GetOriginalExpression(),
1503 "Expression did not evaluate to a known generator expression");
1504 return std::string();
1507 if (!node->GeneratesContent())
1509 if (node->NumExpectedParameters() == 1
1510 && node->AcceptsArbitraryContentParameter())
1512 if (this->ParamChildren.empty())
1514 reportError(context, this->GetOriginalExpression(),
1515 "$<" + identifier + "> expression requires a parameter.");
1520 std::vector<std::string> parameters;
1521 this->EvaluateParameters(node, identifier, context, dagChecker,
1524 return std::string();
1527 if (node->NumExpectedParameters() == 1
1528 && node->AcceptsArbitraryContentParameter())
1530 return this->ProcessArbitraryContent(node, identifier, context,
1532 this->ParamChildren.begin());
1535 std::vector<std::string> parameters;
1536 this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
1537 if (context->HadError)
1539 return std::string();
1542 return node->Evaluate(parameters, context, this, dagChecker);
1545 //----------------------------------------------------------------------------
1546 std::string GeneratorExpressionContent::EvaluateParameters(
1547 const cmGeneratorExpressionNode *node,
1548 const std::string &identifier,
1549 cmGeneratorExpressionContext *context,
1550 cmGeneratorExpressionDAGChecker *dagChecker,
1551 std::vector<std::string> ¶meters) const
1553 const int numExpected = node->NumExpectedParameters();
1555 std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1556 pit = this->ParamChildren.begin();
1558 std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1559 pend = this->ParamChildren.end();
1560 const bool acceptsArbitraryContent
1561 = node->AcceptsArbitraryContentParameter();
1562 for ( ; pit != pend; ++pit)
1564 std::string parameter;
1565 std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
1567 const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
1569 for ( ; it != end; ++it)
1571 parameter += (*it)->Evaluate(context, dagChecker);
1572 if (context->HadError)
1574 return std::string();
1577 parameters.push_back(parameter);
1578 if (acceptsArbitraryContent
1579 && parameters.size() == (unsigned int)numExpected - 1)
1581 assert(pit != pend);
1582 std::string lastParam = this->ProcessArbitraryContent(node, identifier,
1586 parameters.push_back(lastParam);
1587 return std::string();
1592 if ((numExpected > cmGeneratorExpressionNode::DynamicParameters
1593 && (unsigned int)numExpected != parameters.size()))
1595 if (numExpected == 0)
1597 reportError(context, this->GetOriginalExpression(),
1598 "$<" + identifier + "> expression requires no parameters.");
1600 else if (numExpected == 1)
1602 reportError(context, this->GetOriginalExpression(),
1603 "$<" + identifier + "> expression requires "
1604 "exactly one parameter.");
1609 e << "$<" + identifier + "> expression requires "
1611 << " comma separated parameters, but got "
1612 << parameters.size() << " instead.";
1613 reportError(context, this->GetOriginalExpression(), e.str());
1615 return std::string();
1618 if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
1619 && parameters.empty())
1621 reportError(context, this->GetOriginalExpression(), "$<" + identifier
1622 + "> expression requires at least one parameter.");
1624 return std::string();
1627 //----------------------------------------------------------------------------
1628 static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
1630 std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1632 const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1634 for ( ; it != end; ++it)
1640 //----------------------------------------------------------------------------
1641 GeneratorExpressionContent::~GeneratorExpressionContent()
1643 deleteAll(this->IdentifierChildren);
1645 typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
1646 std::vector<EvaluatorVector>::const_iterator pit =
1647 this->ParamChildren.begin();
1648 const std::vector<EvaluatorVector>::const_iterator pend =
1649 this->ParamChildren.end();
1650 for ( ; pit != pend; ++pit)