From dc742fe4be83669a96aec4a47e70218c7ca70814 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 25 Apr 2013 13:54:18 +0200 Subject: [PATCH 1/4] Extract the ProcessArbitraryContent method. --- Source/cmGeneratorExpressionEvaluator.cxx | 95 +++++++++++++---------- Source/cmGeneratorExpressionEvaluator.h | 8 ++ 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 5d0619936..3aceb7143 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -992,6 +992,57 @@ std::string GeneratorExpressionContent::GetOriginalExpression() const return std::string(this->StartContent, this->ContentLength); } +//---------------------------------------------------------------------------- +std::string GeneratorExpressionContent::ProcessArbitraryContent( + const cmGeneratorExpressionNode *node, + const std::string &identifier, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + std::vector >::const_iterator + pit) const +{ + std::string result; + + const + std::vector >::const_iterator + pend = this->ParamChildren.end(); + for ( ; pit != pend; ++pit) + { + std::vector::const_iterator it + = pit->begin(); + const std::vector::const_iterator end + = pit->end(); + for ( ; it != end; ++it) + { + if (node->RequiresLiteralInput()) + { + if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) + { + reportError(context, this->GetOriginalExpression(), + "$<" + identifier + "> expression requires literal input."); + return std::string(); + } + } + result += (*it)->Evaluate(context, dagChecker); + if (context->HadError) + { + return std::string(); + } + } + if ((pit + 1) != pend) + { + result += ","; + } + } + if (node->RequiresLiteralInput()) + { + std::vector parameters; + parameters.push_back(result); + return node->Evaluate(parameters, context, this, dagChecker); + } + return result; +} + //---------------------------------------------------------------------------- std::string GeneratorExpressionContent::Evaluate( cmGeneratorExpressionContext *context, @@ -1043,47 +1094,9 @@ std::string GeneratorExpressionContent::Evaluate( if (node->AcceptsSingleArbitraryContentParameter()) { - std::string result; - std::vector >::const_iterator - pit = this->ParamChildren.begin(); - const - std::vector >::const_iterator - pend = this->ParamChildren.end(); - for ( ; pit != pend; ++pit) - { - std::vector::const_iterator it - = pit->begin(); - const std::vector::const_iterator end - = pit->end(); - for ( ; it != end; ++it) - { - if (node->RequiresLiteralInput()) - { - if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) - { - reportError(context, this->GetOriginalExpression(), - "$<" + identifier + "> expression requires literal input."); - return std::string(); - } - } - result += (*it)->Evaluate(context, dagChecker); - if (context->HadError) - { - return std::string(); - } - } - if ((pit + 1) != pend) - { - result += ","; - } - } - if (node->RequiresLiteralInput()) - { - std::vector parameters; - parameters.push_back(result); - return node->Evaluate(parameters, context, this, dagChecker); - } - return result; + return this->ProcessArbitraryContent(node, identifier, context, + dagChecker, + this->ParamChildren.begin()); } std::vector parameters; diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index ce7ad69bb..218abf160 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -129,6 +129,14 @@ private: cmGeneratorExpressionDAGChecker *dagChecker, std::vector ¶meters) const; + std::string ProcessArbitraryContent( + const cmGeneratorExpressionNode *node, + const std::string &identifier, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + std::vector >::const_iterator + pit) const; + private: std::vector IdentifierChildren; std::vector > ParamChildren; From bd638ee20f54e9fd7fb701fcf20ded1956c06bb0 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 25 Apr 2013 13:28:57 +0200 Subject: [PATCH 2/4] Rename the method determining if a genex accepts arbitrary content. The meaning of this will be expanded to generator expressions with more than a single parameter. --- Source/cmGeneratorExpressionEvaluator.cxx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 3aceb7143..60e1b0581 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -51,7 +51,7 @@ struct cmGeneratorExpressionNode virtual bool RequiresLiteralInput() const { return false; } - virtual bool AcceptsSingleArbitraryContentParameter() const + virtual bool AcceptsArbitraryContentParameter() const { return false; } virtual int NumExpectedParameters() const { return 1; } @@ -70,7 +70,7 @@ static const struct ZeroNode : public cmGeneratorExpressionNode virtual bool GeneratesContent() const { return false; } - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } std::string Evaluate(const std::vector &, cmGeneratorExpressionContext *, @@ -87,7 +87,7 @@ static const struct OneNode : public cmGeneratorExpressionNode { OneNode() {} - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } std::string Evaluate(const std::vector &, cmGeneratorExpressionContext *, @@ -600,7 +600,7 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode virtual bool GeneratesContent() const { return true; } - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } virtual bool RequiresLiteralInput() const { return true; } std::string Evaluate(const std::vector ¶meters, @@ -1075,7 +1075,8 @@ std::string GeneratorExpressionContent::Evaluate( if (!node->GeneratesContent()) { - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { if (this->ParamChildren.empty()) { @@ -1092,7 +1093,8 @@ std::string GeneratorExpressionContent::Evaluate( return std::string(); } - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { return this->ProcessArbitraryContent(node, identifier, context, dagChecker, From 96ec3147bbafd52b18bcf532b0da8727cd3c8104 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 25 Apr 2013 13:54:57 +0200 Subject: [PATCH 3/4] Make it possible for any genex to have arbitrary content at the end. --- Source/cmGeneratorExpressionEvaluator.cxx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 60e1b0581..efb8117d6 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -1119,12 +1119,15 @@ std::string GeneratorExpressionContent::EvaluateParameters( cmGeneratorExpressionDAGChecker *dagChecker, std::vector ¶meters) const { + const int numExpected = node->NumExpectedParameters(); { std::vector >::const_iterator pit = this->ParamChildren.begin(); const std::vector >::const_iterator pend = this->ParamChildren.end(); + const bool acceptsArbitraryContent + = node->AcceptsArbitraryContentParameter(); for ( ; pit != pend; ++pit) { std::string parameter; @@ -1141,10 +1144,20 @@ std::string GeneratorExpressionContent::EvaluateParameters( } } parameters.push_back(parameter); + if (acceptsArbitraryContent + && parameters.size() == (unsigned int)numExpected - 1) + { + assert(pit != pend); + std::string lastParam = this->ProcessArbitraryContent(node, identifier, + context, + dagChecker, + pit + 1); + parameters.push_back(lastParam); + return std::string(); + } } } - int numExpected = node->NumExpectedParameters(); if ((numExpected != -1 && (unsigned int)numExpected != parameters.size())) { if (numExpected == 0) From a7ba4520c7b15dc9f56d2c4718748b79b12c0c89 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 26 Feb 2013 00:50:49 +0100 Subject: [PATCH 4/4] Add the JOIN generator expression. This generator expression joins a list with a separator. The separator may contain arbitrary content, such as commas, which is ordinarily a delimiter in the generator expression syntax. --- Source/cmDocumentGeneratorExpressions.h | 2 ++ Source/cmGeneratorExpressionEvaluator.cxx | 30 +++++++++++++++++++ Tests/CompileDefinitions/compiletest.cpp | 20 +++++++++++-- .../target_prop/CMakeLists.txt | 6 ++++ .../TargetIncludeDirectories/CMakeLists.txt | 5 ++++ .../TargetIncludeDirectories/main.cpp | 1 + 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 6cc3f25ae..ac52db0c1 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -28,6 +28,8 @@ "strings which contain a ',' for example.\n" \ " $ = A literal ';'. Used to prevent " \ "list expansion on an argument with ';'.\n" \ + " $ = joins the list with the content of " \ + "\"...\"\n" \ " $ = Marks ... as being the name of a " \ "target. This is required if exporting targets to multiple " \ "dependent export sets. The '...' must be a literal name of a " \ diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index efb8117d6..6092aa2a8 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -307,6 +307,34 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode } 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 ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + std::string result; + + std::vector list; + cmSystemTools::ExpandListArgument(parameters.front(), list); + std::string sep; + for(std::vector::const_iterator li = list.begin(); + li != list.end(); ++li) + { + result += sep + *li; + sep = parameters[1]; + } + return result; + } +} joinNode; + //---------------------------------------------------------------------------- static const char* targetPropertyTransitiveWhitelist[] = { "INTERFACE_INCLUDE_DIRECTORIES" @@ -973,6 +1001,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &installInterfaceNode; else if (identifier == "INSTALL_PREFIX") return &installPrefixNode; + else if (identifier == "JOIN") + return &joinNode; return 0; } diff --git a/Tests/CompileDefinitions/compiletest.cpp b/Tests/CompileDefinitions/compiletest.cpp index 14b8eab4a..7379380de 100644 --- a/Tests/CompileDefinitions/compiletest.cpp +++ b/Tests/CompileDefinitions/compiletest.cpp @@ -20,10 +20,16 @@ static const char very_fun_string[] = CMAKE_IS_REALLY; #endif enum { - StringLiteralTest1 = sizeof(CMakeStaticAssert) + StringLiteralTest1 = sizeof(CMakeStaticAssert), #ifndef NO_SPACES_IN_DEFINE_VALUES - , - StringLiteralTest2 = sizeof(CMakeStaticAssert) + StringLiteralTest2 = sizeof(CMakeStaticAssert), +#endif +#ifdef TEST_GENERATOR_EXPRESSIONS + StringLiteralTest3 = sizeof(CMakeStaticAssert), + StringLiteralTest4 = sizeof(CMakeStaticAssert), + StringLiteralTest5 = sizeof(CMakeStaticAssert), + StringLiteralTest6 = sizeof(CMakeStaticAssert), + StringLiteralTest7 = sizeof(CMakeStaticAssert) #endif }; @@ -42,6 +48,14 @@ enum { #error Expected define expanded from list #endif +#ifndef PREFIX_DEF1 +#error Expect PREFIX_DEF1 +#endif + +#ifndef PREFIX_DEF2 +#error Expect PREFIX_DEF2 +#endif + // TEST_GENERATOR_EXPRESSIONS #endif diff --git a/Tests/CompileDefinitions/target_prop/CMakeLists.txt b/Tests/CompileDefinitions/target_prop/CMakeLists.txt index 1ef2d6d6e..34be91779 100644 --- a/Tests/CompileDefinitions/target_prop/CMakeLists.txt +++ b/Tests/CompileDefinitions/target_prop/CMakeLists.txt @@ -13,6 +13,12 @@ set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS "$<1:CMAKE_IS_DECLARATIVE>" "$<0:GE_NOT_DEFINED>" "$<1:ARGUMENT;LIST>" + PREFIX_$ + LETTER_LIST1=\"$\" + LETTER_LIST2=\"$\" + LETTER_LIST3=\"$\" + LETTER_LIST4=\"$\" + LETTER_LIST5=\"$\" ) set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt index ad6671feb..60d4c6a22 100644 --- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt @@ -123,3 +123,8 @@ target_link_libraries(lib5 libbad libgood) target_include_directories(lib5 BEFORE PRIVATE $ ) + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat/prefix_foo_bar_bat.h" "// prefix_foo_bar_bat.h\n") + +target_include_directories(TargetIncludeDirectories PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/prefix_$") diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp index 90909d334..5bb34aac6 100644 --- a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp @@ -10,6 +10,7 @@ #include "arguments.h" #include "list.h" #include "target.h" +#include "prefix_foo_bar_bat.h" int main(int, char**) {