| /*============================================================================ |
| CMake - Cross Platform Makefile Generator |
| Copyright 2012 Stephen Kelly <steveire@gmail.com> |
| |
| Distributed under the OSI-approved BSD License (the "License"); |
| see accompanying file Copyright.txt for details. |
| |
| This software is distributed WITHOUT ANY WARRANTY; without even the |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the License for more information. |
| ============================================================================*/ |
| |
| #include "cmGeneratorExpressionNode.h" |
| #include "cmGlobalGenerator.h" |
| #include "cmAlgorithms.h" |
| #include "cmOutputConverter.h" |
| |
| //---------------------------------------------------------------------------- |
| std::string cmGeneratorExpressionNode::EvaluateDependentExpression( |
| std::string const& prop, cmMakefile *makefile, |
| cmGeneratorExpressionContext *context, |
| cmTarget const* headTarget, cmTarget const* currentTarget, |
| cmGeneratorExpressionDAGChecker *dagChecker) |
| { |
| cmGeneratorExpression ge(context->Backtrace); |
| cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); |
| cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem); |
| std::string result = cge->Evaluate(makefile, |
| context->Config, |
| context->Quiet, |
| headTarget, |
| currentTarget, |
| dagChecker, |
| context->Language); |
| if (cge->GetHadContextSensitiveCondition()) |
| { |
| context->HadContextSensitiveCondition = true; |
| } |
| if (cge->GetHadHeadSensitiveCondition()) |
| { |
| context->HadHeadSensitiveCondition = true; |
| } |
| return result; |
| } |
| |
| //---------------------------------------------------------------------------- |
| static const struct ZeroNode : public cmGeneratorExpressionNode |
| { |
| ZeroNode() {} |
| |
| virtual bool GeneratesContent() const { return false; } |
| |
| virtual bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return std::string(); |
| } |
| } zeroNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct OneNode : public cmGeneratorExpressionNode |
| { |
| OneNode() {} |
| |
| virtual bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return parameters.front(); |
| } |
| } oneNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct OneNode buildInterfaceNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct ZeroNode installInterfaceNode; |
| |
| //---------------------------------------------------------------------------- |
| #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \ |
| static const struct OP ## Node : public cmGeneratorExpressionNode \ |
| { \ |
| OP ## Node () {} \ |
| virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \ |
| \ |
| std::string Evaluate(const std::vector<std::string> ¶meters, \ |
| cmGeneratorExpressionContext *context, \ |
| const GeneratorExpressionContent *content, \ |
| cmGeneratorExpressionDAGChecker *) const \ |
| { \ |
| std::vector<std::string>::const_iterator it = parameters.begin(); \ |
| const std::vector<std::string>::const_iterator end = parameters.end(); \ |
| for ( ; it != end; ++it) \ |
| { \ |
| if (*it == #FAILURE_VALUE) \ |
| { \ |
| return #FAILURE_VALUE; \ |
| } \ |
| else if (*it != #SUCCESS_VALUE) \ |
| { \ |
| reportError(context, content->GetOriginalExpression(), \ |
| "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \ |
| return std::string(); \ |
| } \ |
| } \ |
| return #SUCCESS_VALUE; \ |
| } \ |
| } OPNAME; |
| |
| BOOLEAN_OP_NODE(andNode, AND, 1, 0) |
| BOOLEAN_OP_NODE(orNode, OR, 0, 1) |
| |
| #undef BOOLEAN_OP_NODE |
| |
| //---------------------------------------------------------------------------- |
| static const struct NotNode : public cmGeneratorExpressionNode |
| { |
| NotNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| if (*parameters.begin() != "0" && *parameters.begin() != "1") |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<NOT> parameter must resolve to exactly one '0' or '1' value."); |
| return std::string(); |
| } |
| return *parameters.begin() == "0" ? "1" : "0"; |
| } |
| } notNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct BoolNode : public cmGeneratorExpressionNode |
| { |
| BoolNode() {} |
| |
| virtual int NumExpectedParameters() const { return 1; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0"; |
| } |
| } boolNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct StrEqualNode : public cmGeneratorExpressionNode |
| { |
| StrEqualNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return *parameters.begin() == parameters[1] ? "1" : "0"; |
| } |
| } strEqualNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct EqualNode : public cmGeneratorExpressionNode |
| { |
| EqualNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| char *pEnd; |
| |
| int base = 0; |
| bool flipSign = false; |
| |
| const char *lhs = parameters[0].c_str(); |
| if (cmHasLiteralPrefix(lhs, "0b") || cmHasLiteralPrefix(lhs, "0B")) |
| { |
| base = 2; |
| lhs += 2; |
| } |
| if (cmHasLiteralPrefix(lhs, "-0b") || cmHasLiteralPrefix(lhs, "-0B")) |
| { |
| base = 2; |
| lhs += 3; |
| flipSign = true; |
| } |
| if (cmHasLiteralPrefix(lhs, "+0b") || cmHasLiteralPrefix(lhs, "+0B")) |
| { |
| base = 2; |
| lhs += 3; |
| } |
| |
| long lnum = strtol(lhs, &pEnd, base); |
| if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<EQUAL> parameter " + parameters[0] + " is not a valid integer."); |
| return std::string(); |
| } |
| |
| if (flipSign) |
| { |
| lnum = -lnum; |
| } |
| |
| base = 0; |
| flipSign = false; |
| |
| const char *rhs = parameters[1].c_str(); |
| if (cmHasLiteralPrefix(rhs, "0b") || cmHasLiteralPrefix(rhs, "0B")) |
| { |
| base = 2; |
| rhs += 2; |
| } |
| if (cmHasLiteralPrefix(rhs, "-0b") || cmHasLiteralPrefix(rhs, "-0B")) |
| { |
| base = 2; |
| rhs += 3; |
| flipSign = true; |
| } |
| if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) |
| { |
| base = 2; |
| rhs += 3; |
| } |
| |
| long rnum = strtol(rhs, &pEnd, base); |
| if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<EQUAL> parameter " + parameters[1] + " is not a valid integer."); |
| return std::string(); |
| } |
| |
| if (flipSign) |
| { |
| rnum = -rnum; |
| } |
| |
| return lnum == rnum ? "1" : "0"; |
| } |
| } equalNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct LowerCaseNode : public cmGeneratorExpressionNode |
| { |
| LowerCaseNode() {} |
| |
| bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::LowerCase(parameters.front()); |
| } |
| } lowerCaseNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct UpperCaseNode : public cmGeneratorExpressionNode |
| { |
| UpperCaseNode() {} |
| |
| bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::UpperCase(parameters.front()); |
| } |
| } upperCaseNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode |
| { |
| MakeCIdentifierNode() {} |
| |
| bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::MakeCidentifier(parameters.front()); |
| } |
| } makeCIdentifierNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct Angle_RNode : public cmGeneratorExpressionNode |
| { |
| Angle_RNode() {} |
| |
| virtual int NumExpectedParameters() const { return 0; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return ">"; |
| } |
| } angle_rNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CommaNode : public cmGeneratorExpressionNode |
| { |
| CommaNode() {} |
| |
| virtual int NumExpectedParameters() const { return 0; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return ","; |
| } |
| } commaNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct SemicolonNode : public cmGeneratorExpressionNode |
| { |
| SemicolonNode() {} |
| |
| virtual int NumExpectedParameters() const { return 0; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return ";"; |
| } |
| } semicolonNode; |
| |
| //---------------------------------------------------------------------------- |
| struct CompilerIdNode : public cmGeneratorExpressionNode |
| { |
| CompilerIdNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrZeroParameters; } |
| |
| std::string EvaluateWithLanguage(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *, |
| const std::string &lang) const |
| { |
| const char *compilerId = |
| context->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID"); |
| if (parameters.empty()) |
| { |
| return compilerId ? compilerId : ""; |
| } |
| static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$"); |
| if (!compilerIdValidator.find(*parameters.begin())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "Expression syntax not recognized."); |
| return std::string(); |
| } |
| if (!compilerId) |
| { |
| return parameters.front().empty() ? "1" : "0"; |
| } |
| |
| if (strcmp(parameters.begin()->c_str(), compilerId) == 0) |
| { |
| return "1"; |
| } |
| |
| if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0) |
| { |
| switch(context->Makefile->GetPolicyStatus(cmPolicies::CMP0044)) |
| { |
| case cmPolicies::WARN: |
| { |
| std::ostringstream e; |
| e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044); |
| context->Makefile->GetCMakeInstance() |
| ->IssueMessage(cmake::AUTHOR_WARNING, |
| e.str(), context->Backtrace); |
| } |
| case cmPolicies::OLD: |
| return "1"; |
| case cmPolicies::NEW: |
| case cmPolicies::REQUIRED_ALWAYS: |
| case cmPolicies::REQUIRED_IF_USED: |
| break; |
| } |
| } |
| return "0"; |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CCompilerIdNode : public CompilerIdNode |
| { |
| CCompilerIdNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if (!context->HeadTarget) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<C_COMPILER_ID> may only be used with binary targets. It may " |
| "not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| return this->EvaluateWithLanguage(parameters, context, content, |
| dagChecker, "C"); |
| } |
| } cCompilerIdNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CXXCompilerIdNode : public CompilerIdNode |
| { |
| CXXCompilerIdNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if (!context->HeadTarget) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<CXX_COMPILER_ID> may only be used with binary targets. It may " |
| "not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| return this->EvaluateWithLanguage(parameters, context, content, |
| dagChecker, "CXX"); |
| } |
| } cxxCompilerIdNode; |
| |
| //---------------------------------------------------------------------------- |
| struct CompilerVersionNode : public cmGeneratorExpressionNode |
| { |
| CompilerVersionNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrZeroParameters; } |
| |
| std::string EvaluateWithLanguage(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *, |
| const std::string &lang) const |
| { |
| const char *compilerVersion = context->Makefile->GetSafeDefinition( |
| "CMAKE_" + lang + "_COMPILER_VERSION"); |
| if (parameters.empty()) |
| { |
| return compilerVersion ? compilerVersion : ""; |
| } |
| |
| static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$"); |
| if (!compilerIdValidator.find(*parameters.begin())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "Expression syntax not recognized."); |
| return std::string(); |
| } |
| if (!compilerVersion) |
| { |
| return parameters.front().empty() ? "1" : "0"; |
| } |
| |
| return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, |
| parameters.begin()->c_str(), |
| compilerVersion) ? "1" : "0"; |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CCompilerVersionNode : public CompilerVersionNode |
| { |
| CCompilerVersionNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if (!context->HeadTarget) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<C_COMPILER_VERSION> may only be used with binary targets. It " |
| "may not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| return this->EvaluateWithLanguage(parameters, context, content, |
| dagChecker, "C"); |
| } |
| } cCompilerVersionNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CxxCompilerVersionNode : public CompilerVersionNode |
| { |
| CxxCompilerVersionNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if (!context->HeadTarget) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<CXX_COMPILER_VERSION> may only be used with binary targets. It " |
| "may not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| return this->EvaluateWithLanguage(parameters, context, content, |
| dagChecker, "CXX"); |
| } |
| } cxxCompilerVersionNode; |
| |
| |
| //---------------------------------------------------------------------------- |
| struct PlatformIdNode : public cmGeneratorExpressionNode |
| { |
| PlatformIdNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrZeroParameters; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| const char *platformId = |
| context->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"); |
| if (parameters.empty()) |
| { |
| return platformId ? platformId : ""; |
| } |
| |
| if (!platformId) |
| { |
| return parameters.front().empty() ? "1" : "0"; |
| } |
| |
| if (strcmp(parameters.begin()->c_str(), platformId) == 0) |
| { |
| return "1"; |
| } |
| return "0"; |
| } |
| } platformIdNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct VersionGreaterNode : public cmGeneratorExpressionNode |
| { |
| VersionGreaterNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, |
| parameters.front().c_str(), |
| parameters[1].c_str()) ? "1" : "0"; |
| } |
| } versionGreaterNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct VersionLessNode : public cmGeneratorExpressionNode |
| { |
| VersionLessNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, |
| parameters.front().c_str(), |
| parameters[1].c_str()) ? "1" : "0"; |
| } |
| } versionLessNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct VersionEqualNode : public cmGeneratorExpressionNode |
| { |
| VersionEqualNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, |
| parameters.front().c_str(), |
| parameters[1].c_str()) ? "1" : "0"; |
| } |
| } versionEqualNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct LinkOnlyNode : public cmGeneratorExpressionNode |
| { |
| LinkOnlyNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if(!dagChecker->GetTransitivePropertiesOnly()) |
| { |
| return parameters.front(); |
| } |
| return ""; |
| } |
| } linkOnlyNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct ConfigurationNode : public cmGeneratorExpressionNode |
| { |
| ConfigurationNode() {} |
| |
| virtual int NumExpectedParameters() const { return 0; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| context->HadContextSensitiveCondition = true; |
| return context->Config; |
| } |
| } configurationNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct ConfigurationTestNode : public cmGeneratorExpressionNode |
| { |
| ConfigurationTestNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrZeroParameters; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| if (parameters.empty()) |
| { |
| return configurationNode.Evaluate(parameters, context, content, 0); |
| } |
| static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$"); |
| if (!configValidator.find(*parameters.begin())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "Expression syntax not recognized."); |
| return std::string(); |
| } |
| context->HadContextSensitiveCondition = true; |
| if (context->Config.empty()) |
| { |
| return parameters.front().empty() ? "1" : "0"; |
| } |
| |
| if (cmsysString_strcasecmp(parameters.begin()->c_str(), |
| context->Config.c_str()) == 0) |
| { |
| return "1"; |
| } |
| |
| if (context->CurrentTarget |
| && context->CurrentTarget->IsImported()) |
| { |
| const char* loc = 0; |
| const char* imp = 0; |
| std::string suffix; |
| if (context->CurrentTarget->GetMappedConfig(context->Config, |
| &loc, |
| &imp, |
| suffix)) |
| { |
| // This imported target has an appropriate location |
| // for this (possibly mapped) config. |
| // Check if there is a proper config mapping for the tested config. |
| std::vector<std::string> mappedConfigs; |
| std::string mapProp = "MAP_IMPORTED_CONFIG_"; |
| mapProp += cmSystemTools::UpperCase(context->Config); |
| if(const char* mapValue = |
| context->CurrentTarget->GetProperty(mapProp)) |
| { |
| cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue), |
| mappedConfigs); |
| return std::find(mappedConfigs.begin(), mappedConfigs.end(), |
| cmSystemTools::UpperCase(parameters.front())) |
| != mappedConfigs.end() ? "1" : "0"; |
| } |
| } |
| } |
| return "0"; |
| } |
| } configurationTestNode; |
| |
| static const struct JoinNode : public cmGeneratorExpressionNode |
| { |
| JoinNode() {} |
| |
| virtual int NumExpectedParameters() const { return 2; } |
| |
| virtual bool AcceptsArbitraryContentParameter() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| std::vector<std::string> list; |
| cmSystemTools::ExpandListArgument(parameters.front(), list); |
| return cmJoin(list, parameters[1]); |
| } |
| } joinNode; |
| |
| static const struct CompileLanguageNode : public cmGeneratorExpressionNode |
| { |
| CompileLanguageNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrZeroParameters; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| if(context->Language.empty()) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_LANGUAGE:...> may only be used to specify include " |
| "directories compile definitions, compile options and to evaluate " |
| "components of the file(GENERATE) command."); |
| return std::string(); |
| } |
| |
| std::vector<std::string> enabledLanguages; |
| cmGlobalGenerator* gg = context->Makefile->GetGlobalGenerator(); |
| gg->GetEnabledLanguages(enabledLanguages); |
| if (!parameters.empty() && |
| std::find(enabledLanguages.begin(), enabledLanguages.end(), |
| parameters.front()) == enabledLanguages.end()) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_LANGUAGE:...> Unknown language."); |
| return std::string(); |
| } |
| std::string genName = gg->GetName(); |
| if (genName.find("Visual Studio") != std::string::npos) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_LANGUAGE:...> may not be used with Visual Studio " |
| "generators."); |
| return std::string(); |
| } |
| else if (genName.find("Xcode") != std::string::npos) |
| { |
| if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() |
| || dagChecker->EvaluatingIncludeDirectories())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_LANGUAGE:...> may only be used with COMPILE_OPTIONS " |
| "with the Xcode generator."); |
| return std::string(); |
| } |
| } |
| else |
| { |
| if(genName.find("Makefiles") == std::string::npos && |
| genName.find("Ninja") == std::string::npos && |
| genName.find("Watcom WMake") == std::string::npos) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_LANGUAGE:...> not supported for this generator."); |
| return std::string(); |
| } |
| } |
| if (parameters.empty()) |
| { |
| return context->Language; |
| } |
| return context->Language == parameters.front() ? "1" : "0"; |
| } |
| } languageNode; |
| |
| #define TRANSITIVE_PROPERTY_NAME(PROPERTY) \ |
| , "INTERFACE_" #PROPERTY |
| |
| //---------------------------------------------------------------------------- |
| static const char* targetPropertyTransitiveWhitelist[] = { |
| 0 |
| CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME) |
| }; |
| |
| #undef TRANSITIVE_PROPERTY_NAME |
| |
| template <typename T> |
| std::string |
| getLinkedTargetsContent( |
| std::vector<T> const &libraries, |
| cmTarget const* target, |
| cmTarget const* headTarget, |
| cmGeneratorExpressionContext *context, |
| cmGeneratorExpressionDAGChecker *dagChecker, |
| const std::string &interfacePropertyName) |
| { |
| std::string linkedTargetsContent; |
| std::string sep; |
| std::string depString; |
| for (typename std::vector<T>::const_iterator it = libraries.begin(); |
| it != libraries.end(); ++it) |
| { |
| // Broken code can have a target in its own link interface. |
| // Don't follow such link interface entries so as not to create a |
| // self-referencing loop. |
| if (it->Target && it->Target != target) |
| { |
| depString += |
| sep + "$<TARGET_PROPERTY:" + |
| it->Target->GetName() + "," + interfacePropertyName + ">"; |
| sep = ";"; |
| } |
| } |
| if(!depString.empty()) |
| { |
| linkedTargetsContent = |
| cmGeneratorExpressionNode::EvaluateDependentExpression(depString, |
| target->GetMakefile(), context, |
| headTarget, target, dagChecker); |
| } |
| linkedTargetsContent = |
| cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent); |
| return linkedTargetsContent; |
| } |
| |
| //---------------------------------------------------------------------------- |
| static const struct TargetPropertyNode : public cmGeneratorExpressionNode |
| { |
| TargetPropertyNode() {} |
| |
| // This node handles errors on parameter count itself. |
| virtual int NumExpectedParameters() const { return OneOrMoreParameters; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagCheckerParent |
| ) const |
| { |
| if (parameters.size() != 1 && parameters.size() != 2) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:...> expression requires one or two parameters"); |
| return std::string(); |
| } |
| static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$"); |
| |
| cmTarget const* target = context->HeadTarget; |
| std::string propertyName = *parameters.begin(); |
| |
| if (parameters.size() == 1) |
| { |
| context->HadHeadSensitiveCondition = true; |
| } |
| if (!target && parameters.size() == 1) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:prop> may only be used with binary targets. " |
| "It may not be used with add_custom_command or add_custom_target. " |
| "Specify the target to read a property from using the " |
| "$<TARGET_PROPERTY:tgt,prop> signature instead."); |
| return std::string(); |
| } |
| |
| if (parameters.size() == 2) |
| { |
| if (parameters.begin()->empty() && parameters[1].empty()) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " |
| "target name and property name."); |
| return std::string(); |
| } |
| if (parameters.begin()->empty()) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " |
| "target name."); |
| return std::string(); |
| } |
| |
| std::string targetName = parameters.front(); |
| propertyName = parameters[1]; |
| if (!cmGeneratorExpression::IsValidTargetName(targetName)) |
| { |
| if (!propertyNameValidator.find(propertyName.c_str())) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "Target name and property name not supported."); |
| return std::string(); |
| } |
| ::reportError(context, content->GetOriginalExpression(), |
| "Target name not supported."); |
| return std::string(); |
| } |
| if(propertyName == "ALIASED_TARGET") |
| { |
| if(context->Makefile->IsAlias(targetName)) |
| { |
| if(cmTarget* tgt = context->Makefile->FindTargetToUse(targetName)) |
| { |
| return tgt->GetName(); |
| } |
| } |
| return ""; |
| } |
| target = context->Makefile->FindTargetToUse(targetName); |
| |
| if (!target) |
| { |
| std::ostringstream e; |
| e << "Target \"" |
| << targetName |
| << "\" not found."; |
| reportError(context, content->GetOriginalExpression(), e.str()); |
| return std::string(); |
| } |
| context->AllTargets.insert(target); |
| } |
| |
| if (target == context->HeadTarget) |
| { |
| // Keep track of the properties seen while processing. |
| // The evaluation of the LINK_LIBRARIES generator expressions |
| // will check this to ensure that properties have one consistent |
| // value for all evaluations. |
| context->SeenTargetProperties.insert(propertyName); |
| } |
| if (propertyName == "SOURCES") |
| { |
| context->SourceSensitiveTargets.insert(target); |
| } |
| |
| if (propertyName.empty()) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:...> expression requires a non-empty property " |
| "name."); |
| return std::string(); |
| } |
| |
| if (!propertyNameValidator.find(propertyName)) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "Property name not supported."); |
| return std::string(); |
| } |
| |
| assert(target); |
| |
| cmGeneratorTarget* gtgt = |
| context->Makefile->GetGlobalGenerator()->GetGeneratorTarget(target); |
| |
| if (propertyName == "LINKER_LANGUAGE") |
| { |
| if (target->LinkLanguagePropagatesToDependents() && |
| dagCheckerParent && (dagCheckerParent->EvaluatingLinkLibraries() |
| || dagCheckerParent->EvaluatingSources())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "LINKER_LANGUAGE target property can not be used while evaluating " |
| "link libraries for a static library"); |
| return std::string(); |
| } |
| return gtgt->GetLinkerLanguage(context->Config); |
| } |
| |
| cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, |
| target->GetName(), |
| propertyName, |
| content, |
| dagCheckerParent); |
| |
| switch (dagChecker.Check()) |
| { |
| case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: |
| dagChecker.ReportError(context, content->GetOriginalExpression()); |
| return std::string(); |
| case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: |
| // No error. We just skip cyclic references. |
| return std::string(); |
| case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: |
| for (size_t i = 1; |
| i < cmArraySize(targetPropertyTransitiveWhitelist); |
| ++i) |
| { |
| if (targetPropertyTransitiveWhitelist[i] == propertyName) |
| { |
| // No error. We're not going to find anything new here. |
| return std::string(); |
| } |
| } |
| case cmGeneratorExpressionDAGChecker::DAG: |
| break; |
| } |
| |
| const char *prop = target->GetProperty(propertyName); |
| |
| if (dagCheckerParent) |
| { |
| if (dagCheckerParent->EvaluatingLinkLibraries()) |
| { |
| #define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \ |
| (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) || |
| if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_COMPARE) |
| false) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_PROPERTY:...> expression in link libraries " |
| "evaluation depends on target property which is transitive " |
| "over the link libraries, creating a recursion."); |
| return std::string(); |
| } |
| #undef TRANSITIVE_PROPERTY_COMPARE |
| |
| if(!prop) |
| { |
| return std::string(); |
| } |
| } |
| else |
| { |
| #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) \ |
| dagCheckerParent->METHOD () || |
| |
| assert( |
| CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( |
| ASSERT_TRANSITIVE_PROPERTY_METHOD) |
| false); |
| #undef ASSERT_TRANSITIVE_PROPERTY_METHOD |
| } |
| } |
| |
| std::string linkedTargetsContent; |
| |
| std::string interfacePropertyName; |
| bool isInterfaceProperty = false; |
| |
| #define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ |
| if (propertyName == #prop) \ |
| { \ |
| interfacePropertyName = "INTERFACE_" #prop; \ |
| } \ |
| else if (propertyName == "INTERFACE_" #prop) \ |
| { \ |
| interfacePropertyName = "INTERFACE_" #prop; \ |
| isInterfaceProperty = true; \ |
| } \ |
| else |
| |
| CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) |
| // Note that the above macro terminates with an else |
| /* else */ if (cmHasLiteralPrefix(propertyName.c_str(), |
| "COMPILE_DEFINITIONS_")) |
| { |
| cmPolicies::PolicyStatus polSt = |
| context->Makefile->GetPolicyStatus(cmPolicies::CMP0043); |
| if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) |
| { |
| interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; |
| } |
| } |
| #undef POPULATE_INTERFACE_PROPERTY_NAME |
| cmTarget const* headTarget = context->HeadTarget && isInterfaceProperty |
| ? context->HeadTarget : target; |
| |
| if(isInterfaceProperty) |
| { |
| if(cmLinkInterfaceLibraries const* iface = |
| gtgt->GetLinkInterfaceLibraries(context->Config, headTarget, true)) |
| { |
| linkedTargetsContent = |
| getLinkedTargetsContent(iface->Libraries, target, |
| headTarget, |
| context, &dagChecker, |
| interfacePropertyName); |
| } |
| } |
| else if(!interfacePropertyName.empty()) |
| { |
| if(cmLinkImplementationLibraries const* impl = |
| target->GetLinkImplementationLibraries(context->Config)) |
| { |
| linkedTargetsContent = |
| getLinkedTargetsContent(impl->Libraries, target, |
| target, |
| context, &dagChecker, |
| interfacePropertyName); |
| } |
| } |
| |
| if (!prop) |
| { |
| if (target->IsImported() |
| || target->GetType() == cmTarget::INTERFACE_LIBRARY) |
| { |
| return linkedTargetsContent; |
| } |
| if (gtgt->IsLinkInterfaceDependentBoolProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| return gtgt->GetLinkInterfaceDependentBoolProperty( |
| propertyName, |
| context->Config) ? "1" : "0"; |
| } |
| if (gtgt->IsLinkInterfaceDependentStringProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| const char *propContent = |
| gtgt->GetLinkInterfaceDependentStringProperty( |
| propertyName, |
| context->Config); |
| return propContent ? propContent : ""; |
| } |
| if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| const char *propContent = |
| gtgt->GetLinkInterfaceDependentNumberMinProperty( |
| propertyName, |
| context->Config); |
| return propContent ? propContent : ""; |
| } |
| if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| const char *propContent = |
| gtgt->GetLinkInterfaceDependentNumberMaxProperty( |
| propertyName, |
| context->Config); |
| return propContent ? propContent : ""; |
| } |
| |
| return linkedTargetsContent; |
| } |
| |
| if (!target->IsImported() |
| && dagCheckerParent && !dagCheckerParent->EvaluatingLinkLibraries()) |
| { |
| if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| const char *propContent = |
| gtgt->GetLinkInterfaceDependentNumberMinProperty( |
| propertyName, |
| context->Config); |
| return propContent ? propContent : ""; |
| } |
| if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName, |
| context->Config)) |
| { |
| context->HadContextSensitiveCondition = true; |
| const char *propContent = |
| gtgt->GetLinkInterfaceDependentNumberMaxProperty( |
| propertyName, |
| context->Config); |
| return propContent ? propContent : ""; |
| } |
| } |
| if(!interfacePropertyName.empty()) |
| { |
| std::string result = this->EvaluateDependentExpression(prop, |
| context->Makefile, context, |
| headTarget, target, &dagChecker); |
| if (!linkedTargetsContent.empty()) |
| { |
| result += (result.empty() ? "" : ";") + linkedTargetsContent; |
| } |
| return result; |
| } |
| return prop; |
| } |
| } targetPropertyNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct TargetNameNode : public cmGeneratorExpressionNode |
| { |
| TargetNameNode() {} |
| |
| virtual bool GeneratesContent() const { return true; } |
| |
| virtual bool AcceptsArbitraryContentParameter() const { return true; } |
| virtual bool RequiresLiteralInput() const { return true; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *, |
| const GeneratorExpressionContent *, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| return parameters.front(); |
| } |
| |
| virtual int NumExpectedParameters() const { return 1; } |
| |
| } targetNameNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct TargetObjectsNode : public cmGeneratorExpressionNode |
| { |
| TargetObjectsNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| if (!context->EvaluateForBuildsystem) |
| { |
| std::ostringstream e; |
| e << "The evaluation of the TARGET_OBJECTS generator expression " |
| "is only suitable for consumption by CMake. It is not suitable " |
| "for writing out elsewhere."; |
| reportError(context, content->GetOriginalExpression(), e.str()); |
| return std::string(); |
| } |
| |
| std::string tgtName = parameters.front(); |
| cmGeneratorTarget* gt = |
| context->Makefile->FindGeneratorTargetToUse(tgtName); |
| if (!gt) |
| { |
| std::ostringstream e; |
| e << "Objects of target \"" << tgtName |
| << "\" referenced but no such target exists."; |
| reportError(context, content->GetOriginalExpression(), e.str()); |
| return std::string(); |
| } |
| if (gt->GetType() != cmTarget::OBJECT_LIBRARY) |
| { |
| std::ostringstream e; |
| e << "Objects of target \"" << tgtName |
| << "\" referenced but is not an OBJECT library."; |
| reportError(context, content->GetOriginalExpression(), e.str()); |
| return std::string(); |
| } |
| |
| std::vector<cmSourceFile const*> objectSources; |
| gt->GetObjectSources(objectSources, context->Config); |
| std::map<cmSourceFile const*, std::string> mapping; |
| |
| for(std::vector<cmSourceFile const*>::const_iterator it |
| = objectSources.begin(); it != objectSources.end(); ++it) |
| { |
| mapping[*it]; |
| } |
| |
| gt->LocalGenerator->ComputeObjectFilenames(mapping, gt); |
| |
| std::string obj_dir = gt->ObjectDirectory; |
| std::string result; |
| const char* sep = ""; |
| for(std::vector<cmSourceFile const*>::const_iterator it |
| = objectSources.begin(); it != objectSources.end(); ++it) |
| { |
| // Find the object file name corresponding to this source file. |
| std::map<cmSourceFile const*, std::string>::const_iterator |
| map_it = mapping.find(*it); |
| // It must exist because we populated the mapping just above. |
| assert(!map_it->second.empty()); |
| result += sep; |
| std::string objFile = obj_dir + map_it->second; |
| cmSourceFile* sf = context->Makefile->GetOrCreateSource(objFile, true); |
| sf->SetObjectLibrary(tgtName); |
| sf->SetProperty("EXTERNAL_OBJECT", "1"); |
| result += objFile; |
| sep = ";"; |
| } |
| return result; |
| } |
| } targetObjectsNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct CompileFeaturesNode : public cmGeneratorExpressionNode |
| { |
| CompileFeaturesNode() {} |
| |
| virtual int NumExpectedParameters() const { return OneOrMoreParameters; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| cmTarget const* target = context->HeadTarget; |
| if (!target) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<COMPILE_FEATURE> may only be used with binary targets. It may " |
| "not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| context->HadHeadSensitiveCondition = true; |
| |
| typedef std::map<std::string, std::vector<std::string> > LangMap; |
| static LangMap availableFeatures; |
| |
| LangMap testedFeatures; |
| |
| for (std::vector<std::string>::const_iterator it = parameters.begin(); |
| it != parameters.end(); ++it) |
| { |
| std::string error; |
| std::string lang; |
| if (!context->Makefile->CompileFeatureKnown(context->HeadTarget, |
| *it, lang, &error)) |
| { |
| reportError(context, content->GetOriginalExpression(), error); |
| return std::string(); |
| } |
| testedFeatures[lang].push_back(*it); |
| |
| if (availableFeatures.find(lang) == availableFeatures.end()) |
| { |
| const char* featuresKnown |
| = context->Makefile->CompileFeaturesAvailable(lang, &error); |
| if (!featuresKnown) |
| { |
| reportError(context, content->GetOriginalExpression(), error); |
| return std::string(); |
| } |
| cmSystemTools::ExpandListArgument(featuresKnown, |
| availableFeatures[lang]); |
| } |
| } |
| |
| bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries(); |
| |
| for (LangMap::const_iterator lit = testedFeatures.begin(); |
| lit != testedFeatures.end(); ++lit) |
| { |
| std::vector<std::string> const& langAvailable |
| = availableFeatures[lit->first]; |
| const char* standardDefault = context->Makefile |
| ->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT"); |
| for (std::vector<std::string>::const_iterator it = lit->second.begin(); |
| it != lit->second.end(); ++it) |
| { |
| if (std::find(langAvailable.begin(), langAvailable.end(), *it) |
| == langAvailable.end()) |
| { |
| return "0"; |
| } |
| if (standardDefault && !*standardDefault) |
| { |
| // This compiler has no notion of language standard levels. |
| // All features known for the language are always available. |
| continue; |
| } |
| if (!context->Makefile->HaveStandardAvailable(target, |
| lit->first, *it)) |
| { |
| if (evalLL) |
| { |
| const char* l = target->GetProperty(lit->first + "_STANDARD"); |
| if (!l) |
| { |
| l = standardDefault; |
| } |
| assert(l); |
| context->MaxLanguageStandard[target][lit->first] = l; |
| } |
| else |
| { |
| return "0"; |
| } |
| } |
| } |
| } |
| return "1"; |
| } |
| } compileFeaturesNode; |
| |
| //---------------------------------------------------------------------------- |
| static const char* targetPolicyWhitelist[] = { |
| 0 |
| #define TARGET_POLICY_STRING(POLICY) \ |
| , #POLICY |
| |
| CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING) |
| |
| #undef TARGET_POLICY_STRING |
| }; |
| |
| cmPolicies::PolicyStatus statusForTarget(cmTarget const* tgt, |
| const char *policy) |
| { |
| #define RETURN_POLICY(POLICY) \ |
| if (strcmp(policy, #POLICY) == 0) \ |
| { \ |
| return tgt->GetPolicyStatus ## POLICY (); \ |
| } \ |
| |
| CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY) |
| |
| #undef RETURN_POLICY |
| |
| assert(0 && "Unreachable code. Not a valid policy"); |
| return cmPolicies::WARN; |
| } |
| |
| cmPolicies::PolicyID policyForString(const char *policy_id) |
| { |
| #define RETURN_POLICY_ID(POLICY_ID) \ |
| if (strcmp(policy_id, #POLICY_ID) == 0) \ |
| { \ |
| return cmPolicies:: POLICY_ID; \ |
| } \ |
| |
| CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID) |
| |
| #undef RETURN_POLICY_ID |
| |
| assert(0 && "Unreachable code. Not a valid policy"); |
| return cmPolicies::CMP0002; |
| } |
| |
| //---------------------------------------------------------------------------- |
| static const struct TargetPolicyNode : public cmGeneratorExpressionNode |
| { |
| TargetPolicyNode() {} |
| |
| virtual int NumExpectedParameters() const { return 1; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context , |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| if (!context->HeadTarget) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_POLICY:prop> may only be used with binary targets. It " |
| "may not be used with add_custom_command or add_custom_target."); |
| return std::string(); |
| } |
| |
| context->HadContextSensitiveCondition = true; |
| context->HadHeadSensitiveCondition = true; |
| |
| for (size_t i = 1; i < cmArraySize(targetPolicyWhitelist); ++i) |
| { |
| const char *policy = targetPolicyWhitelist[i]; |
| if (parameters.front() == policy) |
| { |
| cmMakefile *mf = context->HeadTarget->GetMakefile(); |
| switch(statusForTarget(context->HeadTarget, policy)) |
| { |
| case cmPolicies::WARN: |
| mf->IssueMessage(cmake::AUTHOR_WARNING, |
| cmPolicies::GetPolicyWarning(policyForString(policy))); |
| case cmPolicies::REQUIRED_IF_USED: |
| case cmPolicies::REQUIRED_ALWAYS: |
| case cmPolicies::OLD: |
| return "0"; |
| case cmPolicies::NEW: |
| return "1"; |
| } |
| } |
| } |
| reportError(context, content->GetOriginalExpression(), |
| "$<TARGET_POLICY:prop> may only be used with a limited number of " |
| "policies. Currently it may be used with the following policies:\n" |
| |
| #define STRINGIFY_HELPER(X) #X |
| #define STRINGIFY(X) STRINGIFY_HELPER(X) |
| |
| #define TARGET_POLICY_LIST_ITEM(POLICY) \ |
| " * " STRINGIFY(POLICY) "\n" |
| |
| CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM) |
| |
| #undef TARGET_POLICY_LIST_ITEM |
| ); |
| return std::string(); |
| } |
| |
| } targetPolicyNode; |
| |
| //---------------------------------------------------------------------------- |
| static const struct InstallPrefixNode : public cmGeneratorExpressionNode |
| { |
| InstallPrefixNode() {} |
| |
| virtual bool GeneratesContent() const { return true; } |
| virtual int NumExpectedParameters() const { return 0; } |
| |
| std::string Evaluate(const std::vector<std::string> &, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "INSTALL_PREFIX is a marker for install(EXPORT) only. It " |
| "should never be evaluated."); |
| return std::string(); |
| } |
| |
| } installPrefixNode; |
| |
| //---------------------------------------------------------------------------- |
| class ArtifactNameTag; |
| class ArtifactLinkerTag; |
| class ArtifactSonameTag; |
| class ArtifactPdbTag; |
| |
| class ArtifactPathTag; |
| class ArtifactDirTag; |
| |
| //---------------------------------------------------------------------------- |
| template<typename ArtifactT> |
| struct TargetFilesystemArtifactResultCreator |
| { |
| static std::string Create(cmGeneratorTarget* target, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content); |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag> |
| { |
| static std::string Create(cmGeneratorTarget* target, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content) |
| { |
| // The target soname file (.so.1). |
| if(target->Target->IsDLLPlatform()) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_SONAME_FILE is not allowed " |
| "for DLL target platforms."); |
| return std::string(); |
| } |
| if(target->GetType() != cmTarget::SHARED_LIBRARY) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_SONAME_FILE is allowed only for " |
| "SHARED libraries."); |
| return std::string(); |
| } |
| std::string result = target->Target->GetDirectory(context->Config); |
| result += "/"; |
| result += target->GetSOName(context->Config); |
| return result; |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag> |
| { |
| static std::string Create(cmGeneratorTarget* target, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content) |
| { |
| if (target->IsImported()) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_PDB_FILE not allowed for IMPORTED targets."); |
| return std::string(); |
| } |
| |
| std::string language = target->GetLinkerLanguage(context->Config); |
| |
| std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB"; |
| |
| if(!context->Makefile->IsOn(pdbSupportVar)) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_PDB_FILE is not supported by the target linker."); |
| return std::string(); |
| } |
| |
| cmTarget::TargetType targetType = target->Target->GetType(); |
| |
| if(targetType != cmTarget::SHARED_LIBRARY && |
| targetType != cmTarget::MODULE_LIBRARY && |
| targetType != cmTarget::EXECUTABLE) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_PDB_FILE is allowed only for " |
| "targets with linker created artifacts."); |
| return std::string(); |
| } |
| |
| std::string result = target->Target->GetPDBDirectory(context->Config); |
| result += "/"; |
| result += target->GetPDBName(context->Config); |
| return result; |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag> |
| { |
| static std::string Create(cmGeneratorTarget* target, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content) |
| { |
| // The file used to link to the target (.so, .lib, .a). |
| if(!target->Target->IsLinkable()) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "TARGET_LINKER_FILE is allowed only for libraries and " |
| "executables with ENABLE_EXPORTS."); |
| return std::string(); |
| } |
| return target->GetFullPath(context->Config, |
| target->Target->HasImportLibrary()); |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultCreator<ArtifactNameTag> |
| { |
| static std::string Create(cmGeneratorTarget* target, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *) |
| { |
| return target->GetFullPath(context->Config, false, true); |
| } |
| }; |
| |
| |
| //---------------------------------------------------------------------------- |
| template<typename ArtifactT> |
| struct TargetFilesystemArtifactResultGetter |
| { |
| static std::string Get(const std::string &result); |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultGetter<ArtifactNameTag> |
| { |
| static std::string Get(const std::string &result) |
| { return cmSystemTools::GetFilenameName(result); } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultGetter<ArtifactDirTag> |
| { |
| static std::string Get(const std::string &result) |
| { return cmSystemTools::GetFilenamePath(result); } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<> |
| struct TargetFilesystemArtifactResultGetter<ArtifactPathTag> |
| { |
| static std::string Get(const std::string &result) |
| { return result; } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<typename ArtifactT, typename ComponentT> |
| struct TargetFilesystemArtifact : public cmGeneratorExpressionNode |
| { |
| TargetFilesystemArtifact() {} |
| |
| virtual int NumExpectedParameters() const { return 1; } |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *dagChecker) const |
| { |
| // Lookup the referenced target. |
| std::string name = *parameters.begin(); |
| |
| if (!cmGeneratorExpression::IsValidTargetName(name)) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "Expression syntax not recognized."); |
| return std::string(); |
| } |
| cmGeneratorTarget* target = |
| context->Makefile->FindGeneratorTargetToUse(name); |
| if(!target) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "No target \"" + name + "\""); |
| return std::string(); |
| } |
| if(target->GetType() >= cmTarget::OBJECT_LIBRARY && |
| target->GetType() != cmTarget::UNKNOWN_LIBRARY) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "Target \"" + name + "\" is not an executable or library."); |
| return std::string(); |
| } |
| if (dagChecker && (dagChecker->EvaluatingLinkLibraries(name.c_str()) |
| || (dagChecker->EvaluatingSources() |
| && name == dagChecker->TopTarget()))) |
| { |
| ::reportError(context, content->GetOriginalExpression(), |
| "Expressions which require the linker language may not " |
| "be used while evaluating link libraries"); |
| return std::string(); |
| } |
| context->DependTargets.insert(target->Target); |
| context->AllTargets.insert(target->Target); |
| |
| std::string result = |
| TargetFilesystemArtifactResultCreator<ArtifactT>::Create( |
| target, |
| context, |
| content); |
| if (context->HadError) |
| { |
| return std::string(); |
| } |
| return |
| TargetFilesystemArtifactResultGetter<ComponentT>::Get(result); |
| } |
| }; |
| |
| //---------------------------------------------------------------------------- |
| template<typename ArtifactT> |
| struct TargetFilesystemArtifactNodeGroup |
| { |
| TargetFilesystemArtifactNodeGroup() |
| { |
| } |
| |
| TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File; |
| TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName; |
| TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir; |
| }; |
| |
| //---------------------------------------------------------------------------- |
| static const |
| TargetFilesystemArtifactNodeGroup<ArtifactNameTag> targetNodeGroup; |
| |
| static const |
| TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag> targetLinkerNodeGroup; |
| |
| static const |
| TargetFilesystemArtifactNodeGroup<ArtifactSonameTag> targetSoNameNodeGroup; |
| |
| static const |
| TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> targetPdbNodeGroup; |
| |
| //---------------------------------------------------------------------------- |
| static const struct ShellPathNode : public cmGeneratorExpressionNode |
| { |
| ShellPathNode() {} |
| |
| std::string Evaluate(const std::vector<std::string> ¶meters, |
| cmGeneratorExpressionContext *context, |
| const GeneratorExpressionContent *content, |
| cmGeneratorExpressionDAGChecker *) const |
| { |
| if (!cmSystemTools::FileIsFullPath(parameters.front())) |
| { |
| reportError(context, content->GetOriginalExpression(), |
| "\"" + parameters.front() + "\" is not an absolute path."); |
| return std::string(); |
| } |
| cmOutputConverter converter(context->Makefile->GetStateSnapshot()); |
| return converter.ConvertDirectorySeparatorsForShell(parameters.front()); |
| } |
| } shellPathNode; |
| |
| //---------------------------------------------------------------------------- |
| const cmGeneratorExpressionNode* |
| cmGeneratorExpressionNode::GetNode(const std::string &identifier) |
| { |
| typedef std::map<std::string, const cmGeneratorExpressionNode*> NodeMap; |
| static NodeMap nodeMap; |
| if (nodeMap.empty()) |
| { |
| nodeMap["0"] = &zeroNode; |
| nodeMap["1"] = &oneNode; |
| nodeMap["AND"] = &andNode; |
| nodeMap["OR"] = &orNode; |
| nodeMap["NOT"] = ¬Node; |
| nodeMap["C_COMPILER_ID"] = &cCompilerIdNode; |
| nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode; |
| nodeMap["VERSION_GREATER"] = &versionGreaterNode; |
| nodeMap["VERSION_LESS"] = &versionLessNode; |
| nodeMap["VERSION_EQUAL"] = &versionEqualNode; |
| nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; |
| nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; |
| nodeMap["PLATFORM_ID"] = &platformIdNode; |
| nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode; |
| nodeMap["CONFIGURATION"] = &configurationNode; |
| nodeMap["CONFIG"] = &configurationTestNode; |
| nodeMap["TARGET_FILE"] = &targetNodeGroup.File; |
| nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File; |
| nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File; |
| nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File; |
| nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName; |
| nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName; |
| nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName; |
| nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName; |
| nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir; |
| nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir; |
| nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir; |
| nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir; |
| nodeMap["STREQUAL"] = &strEqualNode; |
| nodeMap["EQUAL"] = &equalNode; |
| nodeMap["LOWER_CASE"] = &lowerCaseNode; |
| nodeMap["UPPER_CASE"] = &upperCaseNode; |
| nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode; |
| nodeMap["BOOL"] = &boolNode; |
| nodeMap["ANGLE-R"] = &angle_rNode; |
| nodeMap["COMMA"] = &commaNode; |
| nodeMap["SEMICOLON"] = &semicolonNode; |
| nodeMap["TARGET_PROPERTY"] = &targetPropertyNode; |
| nodeMap["TARGET_NAME"] = &targetNameNode; |
| nodeMap["TARGET_OBJECTS"] = &targetObjectsNode; |
| nodeMap["TARGET_POLICY"] = &targetPolicyNode; |
| nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode; |
| nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode; |
| nodeMap["INSTALL_PREFIX"] = &installPrefixNode; |
| nodeMap["JOIN"] = &joinNode; |
| nodeMap["LINK_ONLY"] = &linkOnlyNode; |
| nodeMap["COMPILE_LANGUAGE"] = &languageNode; |
| nodeMap["SHELL_PATH"] = &shellPathNode; |
| } |
| NodeMap::const_iterator i = nodeMap.find(identifier); |
| if (i == nodeMap.end()) |
| { |
| return 0; |
| } |
| return i->second; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void reportError(cmGeneratorExpressionContext *context, |
| const std::string &expr, const std::string &result) |
| { |
| context->HadError = true; |
| if (context->Quiet) |
| { |
| return; |
| } |
| |
| std::ostringstream e; |
| e << "Error evaluating generator expression:\n" |
| << " " << expr << "\n" |
| << result; |
| context->Makefile->GetCMakeInstance() |
| ->IssueMessage(cmake::FATAL_ERROR, e.str(), |
| context->Backtrace); |
| } |