diff options
Diffstat (limited to 'Source/cmGeneratorExpressionNode.cxx')
-rw-r--r-- | Source/cmGeneratorExpressionNode.cxx | 343 |
1 files changed, 154 insertions, 189 deletions
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index a60c75cd9..66f1c71f4 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -2,6 +2,24 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGeneratorExpressionNode.h" +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstdlib> +#include <cstring> +#include <map> +#include <memory> +#include <set> +#include <sstream> +#include <utility> + +#include <cm/iterator> + +#include "cmsys/RegularExpression.hxx" +#include "cmsys/String.h" + +#include "cm_static_string_view.hxx" + #include "cmAlgorithms.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionContext.h" @@ -19,39 +37,25 @@ #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" +#include "cmString.hxx" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cm_static_string_view.hxx" -#include "cm_string_view.hxx" #include "cmake.h" -#include "cmsys/RegularExpression.hxx" -#include "cmsys/String.h" - -#include <algorithm> -#include <assert.h> -#include <errno.h> -#include <iterator> -#include <map> -#include <memory> // IWYU pragma: keep -#include <set> -#include <sstream> -#include <stdlib.h> -#include <string.h> -#include <utility> - std::string cmGeneratorExpressionNode::EvaluateDependentExpression( std::string const& prop, cmLocalGenerator* lg, cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget, - cmGeneratorTarget const* currentTarget, - cmGeneratorExpressionDAGChecker* dagChecker) + cmGeneratorExpressionDAGChecker* dagChecker, + cmGeneratorTarget const* currentTarget) { cmGeneratorExpression ge(context->Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem); + cge->SetQuiet(context->Quiet); std::string result = - cge->Evaluate(lg, context->Config, context->Quiet, headTarget, - currentTarget, dagChecker, context->Language); + cge->Evaluate(lg, context->Config, headTarget, dagChecker, currentTarget, + context->Language); if (cge->GetHadContextSensitiveCondition()) { context->HadContextSensitiveCondition = true; } @@ -168,7 +172,7 @@ static const struct BoolNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - return !cmSystemTools::IsOff(parameters.front()) ? "1" : "0"; + return !cmIsOff(parameters.front()) ? "1" : "0"; } } boolNode; @@ -274,17 +278,18 @@ static const struct InListNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - std::vector<std::string> values, checkValues; + std::vector<std::string> values; + std::vector<std::string> checkValues; bool check = false; switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) { case cmPolicies::WARN: if (parameters.front().empty()) { check = true; - cmSystemTools::ExpandListArgument(parameters[1], checkValues, true); + cmExpandList(parameters[1], checkValues, true); } CM_FALLTHROUGH; case cmPolicies::OLD: - cmSystemTools::ExpandListArgument(parameters[1], values); + cmExpandList(parameters[1], values); if (check && values != checkValues) { std::ostringstream e; e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085) @@ -301,14 +306,11 @@ static const struct InListNode : public cmGeneratorExpressionNode case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::NEW: - cmSystemTools::ExpandListArgument(parameters[1], values, true); + cmExpandList(parameters[1], values, true); break; } - return std::find(values.cbegin(), values.cend(), parameters.front()) == - values.cend() - ? "0" - : "1"; + return cmContains(values, parameters.front()) ? "1" : "0"; } } inListNode; @@ -346,8 +348,9 @@ static const struct FilterNode : public cmGeneratorExpressionNode return {}; } - std::vector<std::string> values, result; - cmSystemTools::ExpandListArgument(parameters.front(), values, true); + std::vector<std::string> values; + std::vector<std::string> result; + cmExpandList(parameters.front(), values, true); std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result), [&re, exclude](std::string const& input) { @@ -375,8 +378,7 @@ static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode "$<REMOVE_DUPLICATES:...> expression requires one parameter"); } - std::vector<std::string> values; - cmSystemTools::ExpandListArgument(parameters.front(), values, true); + std::vector<std::string> values = cmExpandedList(parameters.front(), true); auto valuesEnd = cmRemoveDuplicates(values); auto valuesBegin = values.cbegin(); @@ -477,13 +479,13 @@ protected: } return this->EvaluateDependentExpression( - expression, context->LG, context, context->HeadTarget, - context->CurrentTarget, &dagChecker); + expression, context->LG, context, context->HeadTarget, &dagChecker, + context->CurrentTarget); } return this->EvaluateDependentExpression( - expression, context->LG, context, context->HeadTarget, - context->CurrentTarget, dagCheckerParent); + expression, context->LG, context, context->HeadTarget, dagCheckerParent, + context->CurrentTarget); } }; @@ -684,10 +686,10 @@ struct CompilerIdNode : public cmGeneratorExpressionNode if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) { switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) { case cmPolicies::WARN: { - std::ostringstream e; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044); context->LG->GetCMakeInstance()->IssueMessage( - MessageType::AUTHOR_WARNING, e.str(), context->Backtrace); + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0044), + context->Backtrace); CM_FALLTHROUGH; } case cmPolicies::OLD: @@ -706,7 +708,8 @@ struct CompilerIdNode : public cmGeneratorExpressionNode }; static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"), - cudaCompilerIdNode("CUDA"), fortranCompilerIdNode("Fortran"); + cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"), + objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"); struct CompilerVersionNode : public cmGeneratorExpressionNode { @@ -770,6 +773,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode static const CompilerVersionNode cCompilerVersionNode("C"), cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"), + objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"), fortranCompilerVersionNode("Fortran"); struct PlatformIdNode : public cmGeneratorExpressionNode @@ -909,15 +913,13 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode // 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); + std::string mapProp = cmStrCat( + "MAP_IMPORTED_CONFIG_", 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() + cmExpandList(cmSystemTools::UpperCase(mapValue), mappedConfigs); + return cmContains(mappedConfigs, + cmSystemTools::UpperCase(parameters.front())) ? "1" : "0"; } @@ -941,8 +943,7 @@ static const struct JoinNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - std::vector<std::string> list; - cmSystemTools::ExpandListArgument(parameters.front(), list); + std::vector<std::string> list = cmExpandedList(parameters.front()); return cmJoin(list, parameters[1]); } } joinNode; @@ -1038,45 +1039,38 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode } } languageAndIdNode; -#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY - -static const char* targetPropertyTransitiveWhitelist[] = { - nullptr CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME) -}; - -#undef TRANSITIVE_PROPERTY_NAME - -template <typename T> std::string getLinkedTargetsContent( - std::vector<T> const& libraries, cmGeneratorTarget const* target, - cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext* context, - cmGeneratorExpressionDAGChecker* dagChecker, - const std::string& interfacePropertyName) -{ - std::string linkedTargetsContent; - std::string sep; - std::string depString; - for (T const& l : libraries) { - // 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 (l.Target && l.Target != target) { - std::string uniqueName = - target->GetGlobalGenerator()->IndexGeneratorTargetUniquely(l.Target); - depString += sep + "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + - interfacePropertyName + ">"; - sep = ";"; - } - } - if (!depString.empty()) { - linkedTargetsContent = - cmGeneratorExpressionNode::EvaluateDependentExpression( - depString, target->GetLocalGenerator(), context, headTarget, target, - dagChecker); - } - linkedTargetsContent = - cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent); - return linkedTargetsContent; + cmGeneratorTarget const* target, std::string const& prop, + cmGeneratorExpressionContext* context, + cmGeneratorExpressionDAGChecker* dagChecker) +{ + std::string result; + if (cmLinkImplementationLibraries const* impl = + target->GetLinkImplementationLibraries(context->Config)) { + for (cmLinkImplItem const& lib : impl->Libraries) { + if (lib.Target) { + // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our + // caller's property and hand-evaluate it as if it were compiled. + // Create a context as cmCompiledGeneratorExpression::Evaluate does. + cmGeneratorExpressionContext libContext( + target->GetLocalGenerator(), context->Config, context->Quiet, target, + target, context->EvaluateForBuildsystem, lib.Backtrace, + context->Language); + std::string libResult = + lib.Target->EvaluateInterfaceProperty(prop, &libContext, dagChecker); + if (!libResult.empty()) { + if (result.empty()) { + result = std::move(libResult); + } else { + result.reserve(result.size() + 1 + libResult.size()); + result += ";"; + result += libResult; + } + } + } + } + } + return result; } static const struct TargetPropertyNode : public cmGeneratorExpressionNode @@ -1116,7 +1110,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$"); cmGeneratorTarget const* target = nullptr; - std::string targetName, propertyName; + std::string targetName; + std::string propertyName; if (parameters.size() == 2) { targetName = parameters[0]; @@ -1205,44 +1200,37 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return target->GetLinkerLanguage(context->Config); } - cmGeneratorExpressionDAGChecker dagChecker( - context->Backtrace, target, propertyName, content, dagCheckerParent); + std::string interfacePropertyName; + bool isInterfaceProperty = false; - 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 < cm::size(targetPropertyTransitiveWhitelist); - ++i) { - if (targetPropertyTransitiveWhitelist[i] == propertyName) { - // No error. We're not going to find anything new here. - return std::string(); - } - } - case cmGeneratorExpressionDAGChecker::DAG: - break; - } +#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ + if (propertyName == #prop) { \ + interfacePropertyName = "INTERFACE_" #prop; \ + } else if (propertyName == "INTERFACE_" #prop) { \ + interfacePropertyName = "INTERFACE_" #prop; \ + isInterfaceProperty = true; \ + } else - std::string prop; - bool haveProp = false; - if (const char* p = target->GetProperty(propertyName)) { - prop = p; - haveProp = true; + CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) + // Note that the above macro terminates with an else + /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { + cmPolicies::PolicyStatus polSt = + context->LG->GetPolicyStatus(cmPolicies::CMP0043); + if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { + interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; + } } +#undef POPULATE_INTERFACE_PROPERTY_NAME + + bool evaluatingLinkLibraries = false; if (dagCheckerParent) { if (dagCheckerParent->EvaluatingGenexExpression() || dagCheckerParent->EvaluatingPICExpression()) { // No check required. } else if (dagCheckerParent->EvaluatingLinkLibraries()) { -#define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \ - (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) || - if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME( - TRANSITIVE_PROPERTY_COMPARE) false) { // NOLINT(*) + evaluatingLinkLibraries = true; + if (!interfacePropertyName.empty()) { reportError( context, content->GetOriginalExpression(), "$<TARGET_PROPERTY:...> expression in link libraries " @@ -1250,69 +1238,47 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode "over the link libraries, creating a recursion."); return std::string(); } -#undef TRANSITIVE_PROPERTY_COMPARE - - if (!haveProp) { - return std::string(); - } } else { #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() || - assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy) #undef ASSERT_TRANSITIVE_PROPERTY_METHOD } } - std::string linkedTargetsContent; - - std::string interfacePropertyName; - bool isInterfaceProperty = false; + if (isInterfaceProperty) { + return target->EvaluateInterfaceProperty(propertyName, context, + dagCheckerParent); + } -#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ - if (propertyName == #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - } else if (propertyName == "INTERFACE_" #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - isInterfaceProperty = true; \ - } else + cmGeneratorExpressionDAGChecker dagChecker( + context->Backtrace, target, propertyName, content, dagCheckerParent); - CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) - // Note that the above macro terminates with an else - /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { - cmPolicies::PolicyStatus polSt = - context->LG->GetPolicyStatus(cmPolicies::CMP0043); - if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; - } + 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: + // We handle transitive properties above. For non-transitive + // properties we accept repeats anyway. + case cmGeneratorExpressionDAGChecker::DAG: + break; } -#undef POPULATE_INTERFACE_PROPERTY_NAME - cmGeneratorTarget const* headTarget = - context->HeadTarget && isInterfaceProperty ? context->HeadTarget - : target; - if (isInterfaceProperty) { - if (cmLinkInterfaceLibraries const* iface = - target->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); - } + std::string result; + bool haveProp = false; + if (const char* p = target->GetProperty(propertyName)) { + result = p; + haveProp = true; + } else if (evaluatingLinkLibraries) { + return std::string(); } - if (!haveProp) { - if (target->IsImported() || - target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - return linkedTargetsContent; - } + if (!haveProp && !target->IsImported() && + target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { if (target->IsLinkInterfaceDependentBoolProperty(propertyName, context->Config)) { context->HadContextSensitiveCondition = true; @@ -1345,8 +1311,6 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode context->Config); return propContent ? propContent : ""; } - - return linkedTargetsContent; } if (!target->IsImported() && dagCheckerParent && @@ -1368,15 +1332,17 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return propContent ? propContent : ""; } } + if (!interfacePropertyName.empty()) { - std::string result = this->EvaluateDependentExpression( - prop, context->LG, context, headTarget, target, &dagChecker); + result = this->EvaluateDependentExpression(result, context->LG, context, + target, &dagChecker, target); + std::string linkedTargetsContent = getLinkedTargetsContent( + target, interfacePropertyName, context, &dagChecker); if (!linkedTargetsContent.empty()) { result += (result.empty() ? "" : ";") + linkedTargetsContent; } - return result; } - return prop; + return result; } } targetPropertyNode; @@ -1456,7 +1422,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode const char* imp = nullptr; std::string suffix; if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) { - cmSystemTools::ExpandListArgument(loc, objects); + cmExpandList(loc, objects); } context->HadContextSensitiveCondition = true; } else { @@ -1476,7 +1442,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode } for (std::string& o : objects) { - o = obj_dir + o; + o = cmStrCat(obj_dir, o); } } @@ -1512,7 +1478,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode } context->HadHeadSensitiveCondition = true; - typedef std::map<std::string, std::vector<std::string>> LangMap; + using LangMap = std::map<std::string, std::vector<std::string>>; static LangMap availableFeatures; LangMap testedFeatures; @@ -1534,8 +1500,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode reportError(context, content->GetOriginalExpression(), error); return std::string(); } - cmSystemTools::ExpandListArgument(featuresKnown, - availableFeatures[lang]); + cmExpandList(featuresKnown, availableFeatures[lang]); } } @@ -1547,8 +1512,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode const char* standardDefault = context->LG->GetMakefile()->GetDefinition( "CMAKE_" + lit.first + "_STANDARD_DEFAULT"); for (std::string const& it : lit.second) { - if (std::find(langAvailable.begin(), langAvailable.end(), it) == - langAvailable.end()) { + if (!cmContains(langAvailable, it)) { return "0"; } if (standardDefault && !*standardDefault) { @@ -1734,9 +1698,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag> "SHARED libraries."); return std::string(); } - std::string result = target->GetDirectory(context->Config); - result += "/"; - result += target->GetSOName(context->Config); + std::string result = cmStrCat(target->GetDirectory(context->Config), '/', + target->GetSOName(context->Config)); return result; } }; @@ -1775,9 +1738,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag> return std::string(); } - std::string result = target->GetPDBDirectory(context->Config); - result += "/"; - result += target->GetPDBName(context->Config); + std::string result = cmStrCat(target->GetPDBDirectory(context->Config), + '/', target->GetPDBName(context->Config)); return result; } }; @@ -2250,8 +2212,7 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - std::vector<std::string> listIn; - cmSystemTools::ExpandListArgument(parameters.front(), listIn); + std::vector<std::string> listIn = cmExpandedList(parameters.front()); if (listIn.empty()) { reportError(context, content->GetOriginalExpression(), "\"\" is not an absolute path."); @@ -2285,6 +2246,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "NOT", ¬Node }, { "C_COMPILER_ID", &cCompilerIdNode }, { "CXX_COMPILER_ID", &cxxCompilerIdNode }, + { "OBJC_COMPILER_ID", &objcCompilerIdNode }, + { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode }, { "CUDA_COMPILER_ID", &cudaCompilerIdNode }, { "Fortran_COMPILER_ID", &fortranCompilerIdNode }, { "VERSION_GREATER", &versionGreaterNode }, @@ -2295,6 +2258,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "C_COMPILER_VERSION", &cCompilerVersionNode }, { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode }, { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode }, + { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode }, + { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode }, { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode }, { "PLATFORM_ID", &platformIdNode }, { "COMPILE_FEATURES", &compileFeaturesNode }, |