diff options
Diffstat (limited to 'Source/cmGeneratorExpressionNode.cxx')
-rw-r--r-- | Source/cmGeneratorExpressionNode.cxx | 358 |
1 files changed, 348 insertions, 10 deletions
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 50413c8..8b3d9d6 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -15,6 +15,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmRange.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -27,6 +28,7 @@ #include <algorithm> #include <assert.h> #include <errno.h> +#include <iterator> #include <map> #include <memory> // IWYU pragma: keep #include <set> @@ -326,6 +328,79 @@ static const struct InListNode : public cmGeneratorExpressionNode } } inListNode; +static const struct FilterNode : public cmGeneratorExpressionNode +{ + FilterNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 3; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 3) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> expression requires three parameters"); + return {}; + } + + if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") { + reportError( + context, content->GetOriginalExpression(), + "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE"); + return {}; + } + + const bool exclude = parameters[1] == "EXCLUDE"; + + cmsys::RegularExpression re; + if (!re.compile(parameters[2])) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> failed to compile regex"); + return {}; + } + + std::vector<std::string> values, result; + cmSystemTools::ExpandListArgument(parameters.front(), values, true); + + std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result), + [&re, exclude](std::string const& input) { + return exclude ^ re.find(input); + }); + return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";"); + } +} filterNode; + +static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode +{ + RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 1) { + reportError( + context, content->GetOriginalExpression(), + "$<REMOVE_DUPLICATES:...> expression requires one parameter"); + } + + std::vector<std::string> values; + cmSystemTools::ExpandListArgument(parameters.front(), values, true); + + auto valuesEnd = cmRemoveDuplicates(values); + auto valuesBegin = values.cbegin(); + return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";"); + } + +} removeDuplicatesNode; + static const struct TargetExistsNode : public cmGeneratorExpressionNode { TargetExistsNode() {} // NOLINT(modernize-use-equals-default) @@ -1994,18 +2069,16 @@ struct TargetFilesystemArtifactResultGetter<ArtifactPathTag> static std::string Get(const std::string& result) { return result; } }; -template <typename ArtifactT, typename ComponentT> -struct TargetFilesystemArtifact : public cmGeneratorExpressionNode +struct TargetArtifactBase : public cmGeneratorExpressionNode { - TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default) + TargetArtifactBase() {} // NOLINT(modernize-use-equals-default) - int NumExpectedParameters() const override { return 1; } - - std::string Evaluate( +protected: + cmGeneratorTarget* GetTarget( const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override + cmGeneratorExpressionDAGChecker* dagChecker) const { // Lookup the referenced target. std::string name = parameters.front(); @@ -2013,20 +2086,20 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode if (!cmGeneratorExpression::IsValidTargetName(name)) { ::reportError(context, content->GetOriginalExpression(), "Expression syntax not recognized."); - return std::string(); + return nullptr; } cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name); if (!target) { ::reportError(context, content->GetOriginalExpression(), "No target \"" + name + "\""); - return std::string(); + return nullptr; } if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY && target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) { ::reportError(context, content->GetOriginalExpression(), "Target \"" + name + "\" is not an executable or library."); - return std::string(); + return nullptr; } if (dagChecker && (dagChecker->EvaluatingLinkLibraries(target) || @@ -2035,6 +2108,29 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode ::reportError(context, content->GetOriginalExpression(), "Expressions which require the linker language may not " "be used while evaluating link libraries"); + return nullptr; + } + + return target; + } +}; + +template <typename ArtifactT, typename ComponentT> +struct TargetFilesystemArtifact : public TargetArtifactBase +{ + TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + cmGeneratorTarget* target = + this->GetTarget(parameters, context, content, dagChecker); + if (!target) { return std::string(); } context->DependTargets.insert(target); @@ -2081,6 +2177,239 @@ static const TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag> targetBundleContentDirNode; +// +// To retrieve base name for various artifacts +// +template <typename ArtifactT> +struct TargetOutputNameArtifactResultGetter +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content); +}; + +template <> +struct TargetOutputNameArtifactResultGetter<ArtifactNameTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* /*unused*/) + { + return target->GetOutputName(context->Config, + cmStateEnums::RuntimeBinaryArtifact); + } +}; + +template <> +struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + // The file used to link to the target (.so, .lib, .a). + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_FILE_BASE_NAME is allowed only for " + "libraries and executables with ENABLE_EXPORTS."); + return std::string(); + } + cmStateEnums::ArtifactType artifact = + target->HasImportLibrary(context->Config) + ? cmStateEnums::ImportLibraryArtifact + : cmStateEnums::RuntimeBinaryArtifact; + return target->GetOutputName(context->Config, artifact); + } +}; + +template <> +struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (target->IsImported()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_PDB_FILE_BASE_NAME 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->LG->GetMakefile()->IsOn(pdbSupportVar)) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker."); + return std::string(); + } + + cmStateEnums::TargetType targetType = target->GetType(); + + if (targetType != cmStateEnums::SHARED_LIBRARY && + targetType != cmStateEnums::MODULE_LIBRARY && + targetType != cmStateEnums::EXECUTABLE) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_PDB_FILE_BASE_NAME is allowed only for " + "targets with linker created artifacts."); + return std::string(); + } + + return target->GetPDBOutputName(context->Config); + } +}; + +template <typename ArtifactT> +struct TargetFileBaseNameArtifact : public TargetArtifactBase +{ + TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + cmGeneratorTarget* target = + this->GetTarget(parameters, context, content, dagChecker); + if (!target) { + return std::string(); + } + + std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get( + target, context, content); + if (context->HadError) { + return std::string(); + } + return result; + } +}; + +static const TargetFileBaseNameArtifact<ArtifactNameTag> + targetFileBaseNameNode; +static const TargetFileBaseNameArtifact<ArtifactLinkerTag> + targetLinkerFileBaseNameNode; +static const TargetFileBaseNameArtifact<ArtifactPdbTag> + targetPdbFileBaseNameNode; + +class ArtifactFilePrefixTag; +class ArtifactLinkerFilePrefixTag; +class ArtifactFileSuffixTag; +class ArtifactLinkerFileSuffixTag; + +template <typename ArtifactT> +struct TargetFileArtifactResultGetter +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content); +}; + +template <> +struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + return target->GetFilePrefix(context->Config); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_PREFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + cmStateEnums::ArtifactType artifact = + target->HasImportLibrary(context->Config) + ? cmStateEnums::ImportLibraryArtifact + : cmStateEnums::RuntimeBinaryArtifact; + + return target->GetFilePrefix(context->Config, artifact); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + return target->GetFileSuffix(context->Config); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_SUFFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + cmStateEnums::ArtifactType artifact = + target->HasImportLibrary(context->Config) + ? cmStateEnums::ImportLibraryArtifact + : cmStateEnums::RuntimeBinaryArtifact; + + return target->GetFileSuffix(context->Config, artifact); + } +}; + +template <typename ArtifactT> +struct TargetFileArtifact : public TargetArtifactBase +{ + TargetFileArtifact() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + cmGeneratorTarget* target = + this->GetTarget(parameters, context, content, dagChecker); + if (!target) { + return std::string(); + } + + std::string result = + TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content); + if (context->HadError) { + return std::string(); + } + return result; + } +}; + +static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode; +static const TargetFileArtifact<ArtifactLinkerFilePrefixTag> + targetLinkerFilePrefixNode; +static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode; +static const TargetFileArtifact<ArtifactLinkerFileSuffixTag> + targetLinkerFileSuffixNode; + static const struct ShellPathNode : public cmGeneratorExpressionNode { ShellPathNode() {} // NOLINT(modernize-use-equals-default) @@ -2145,6 +2474,13 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File }, { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File }, { "TARGET_PDB_FILE", &targetPdbNodeGroup.File }, + { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode }, + { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode }, + { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode }, + { "TARGET_FILE_PREFIX", &targetFilePrefixNode }, + { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode }, + { "TARGET_FILE_SUFFIX", &targetFileSuffixNode }, + { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode }, { "TARGET_FILE_NAME", &targetNodeGroup.FileName }, { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName }, { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName }, @@ -2158,6 +2494,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "STREQUAL", &strEqualNode }, { "EQUAL", &equalNode }, { "IN_LIST", &inListNode }, + { "FILTER", &filterNode }, + { "REMOVE_DUPLICATES", &removeDuplicatesNode }, { "LOWER_CASE", &lowerCaseNode }, { "UPPER_CASE", &upperCaseNode }, { "MAKE_C_IDENTIFIER", &makeCIdentifierNode }, |