diff options
20 files changed, 110 insertions, 4 deletions
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 8c3f2d7..022ffcc 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -195,6 +195,12 @@ Two forms of conditional generator expressions are supported: if ``condition`` is ``0``. Any other value for ``condition`` results in an error. + .. versionadded:: 3.28 + + This generator expression short-circuits such that generator expressions in + ``false_string`` will not evaluate when ``condition`` is ``1``, and generator + expressions in ``true_string`` will not evaluate when condition is ``0``. + Typically, the ``condition`` is itself a generator expression. For instance, the following expression expands to ``DEBUG_MODE`` when the ``Debug`` configuration is used, and the empty string for all other configurations: @@ -252,6 +258,11 @@ The common boolean logic operators are supported: ``condition`` must be ``0`` or ``1``. The result of the expression is ``0`` if ``condition`` is ``1``, else ``1``. + .. versionadded:: 3.28 + + Logical operators short-circuit such that generator expressions in the + arguments list will not be evaluated once a return value can be determined. + .. _`Comparison Expressions`: Primary Comparison Expressions diff --git a/Help/release/dev/genexp-no-eval.rst b/Help/release/dev/genexp-no-eval.rst new file mode 100644 index 0000000..42ff1aa --- /dev/null +++ b/Help/release/dev/genexp-no-eval.rst @@ -0,0 +1,5 @@ +genexp-no-eval +-------------- + +* :manual:`generator expressions <cmake-generator-expressions(7)>` + short-circuit to avoid unnecessary evaluation of parameters. diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index b239408..50334ef 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -153,10 +153,12 @@ std::string GeneratorExpressionContent::EvaluateParameters( return std::string(); } std::string parameter; - for (const auto& pExprEval : *pit) { - parameter += pExprEval->Evaluate(context, dagChecker); - if (context->HadError) { - return std::string(); + if (node->ShouldEvaluateNextParameter(parameters, parameter)) { + for (const auto& pExprEval : *pit) { + parameter += pExprEval->Evaluate(context, dagChecker); + if (context->HadError) { + return std::string(); + } } } parameters.push_back(std::move(parameter)); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 30798a3..811d53b 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -128,6 +128,16 @@ struct BooleanOpNode : public cmGeneratorExpressionNode int NumExpectedParameters() const override { return OneOrMoreParameters; } + bool ShouldEvaluateNextParameter(const std::vector<std::string>& parameters, + std::string& def_value) const override + { + if (!parameters.empty() && parameters[0] == failureVal) { + def_value = failureVal; + return false; + } + return true; + } + std::string Evaluate(const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, @@ -195,6 +205,13 @@ static const struct IfNode : public cmGeneratorExpressionNode int NumExpectedParameters() const override { return 3; } + bool ShouldEvaluateNextParameter(const std::vector<std::string>& parameters, + std::string&) const override + { + return (parameters.empty() || + parameters[0] != cmStrCat(parameters.size() - 1, "")); + } + std::string Evaluate(const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, diff --git a/Source/cmGeneratorExpressionNode.h b/Source/cmGeneratorExpressionNode.h index f068b02..7a76289 100644 --- a/Source/cmGeneratorExpressionNode.h +++ b/Source/cmGeneratorExpressionNode.h @@ -33,6 +33,12 @@ struct cmGeneratorExpressionNode virtual int NumExpectedParameters() const { return 1; } + virtual bool ShouldEvaluateNextParameter(const std::vector<std::string>&, + std::string&) const + { + return true; + } + virtual std::string Evaluate( const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 280b81e..6a53d6e 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -393,6 +393,7 @@ add_RunCMake_test(GenEx-PATH) add_RunCMake_test(GenEx-PATH_EQUAL) add_RunCMake_test(GenEx-LIST) add_RunCMake_test(GeneratorExpression) +add_RunCMake_test(GeneratorExpressionShortCircuit) add_RunCMake_test(GeneratorInstance) add_RunCMake_test(GeneratorPlatform) if(XCODE_VERSION) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-result.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-stderr.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-stderr.txt new file mode 100644 index 0000000..1267cb3 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at BadAND.cmake:2 \(add_custom_target\): + Error evaluating generator expression: + + \$<0> + + \$<0> expression requires a parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND.cmake new file mode 100644 index 0000000..91efaf4 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND.cmake @@ -0,0 +1,4 @@ +set(error $<0>) +add_custom_target(check ALL COMMAND check + $<AND:1,${error}> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-result.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-stderr.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-stderr.txt new file mode 100644 index 0000000..4e296a5 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at BadIF.cmake:2 \(add_custom_target\): + Error evaluating generator expression: + + \$<0> + + \$<0> expression requires a parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF.cmake new file mode 100644 index 0000000..797cc69 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF.cmake @@ -0,0 +1,4 @@ +set(error $<0>) +add_custom_target(check ALL COMMAND check + $<IF:0,1,${error}> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-result.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-stderr.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-stderr.txt new file mode 100644 index 0000000..7876d7d --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at BadOR.cmake:2 \(add_custom_target\): + Error evaluating generator expression: + + \$<0> + + \$<0> expression requires a parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR.cmake new file mode 100644 index 0000000..7477b8f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR.cmake @@ -0,0 +1,4 @@ +set(error $<0>) +add_custom_target(check ALL COMMAND check + $<OR:0,${error}> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/CMakeLists.txt b/Tests/RunCMake/GeneratorExpressionShortCircuit/CMakeLists.txt new file mode 100644 index 0000000..54a4d62 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.26) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodAND.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodAND.cmake new file mode 100644 index 0000000..26bcaba --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodAND.cmake @@ -0,0 +1,4 @@ +set(error $<0>) +add_custom_target(check ALL COMMAND check + $<AND:0,${error}> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodIF.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodIF.cmake new file mode 100644 index 0000000..1f9fbe6 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodIF.cmake @@ -0,0 +1,5 @@ +set(error $<0>) +add_custom_target(check ALL + COMMAND check $<IF:1,1,${error}> + COMMAND Check $<IF:0,${error},1> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodOR.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodOR.cmake new file mode 100644 index 0000000..b574937 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/GoodOR.cmake @@ -0,0 +1,4 @@ +set(error $<0>) +add_custom_target(check ALL COMMAND check + $<OR:1,${error}> +) diff --git a/Tests/RunCMake/GeneratorExpressionShortCircuit/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpressionShortCircuit/RunCMakeTest.cmake new file mode 100644 index 0000000..b0ad679 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpressionShortCircuit/RunCMakeTest.cmake @@ -0,0 +1,9 @@ +include(RunCMake) + +run_cmake(GoodIF) +run_cmake(GoodAND) +run_cmake(GoodOR) + +run_cmake(BadIF) +run_cmake(BadAND) +run_cmake(BadOR) |