1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-19 19:43:23 +08:00

cmGeneratorExpressionEvaluator: Short-circuit boolean operators

This commit is contained in:
Martin Duffy
2023-09-11 09:36:12 -04:00
parent 49e2a4a0a7
commit 634079b86d
20 changed files with 110 additions and 4 deletions

View File

@@ -195,6 +195,12 @@ Two forms of conditional generator expressions are supported:
if ``condition`` is ``0``. Any other value for ``condition`` results in an if ``condition`` is ``0``. Any other value for ``condition`` results in an
error. 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, Typically, the ``condition`` is itself a generator expression. For instance,
the following expression expands to ``DEBUG_MODE`` when the ``Debug`` the following expression expands to ``DEBUG_MODE`` when the ``Debug``
configuration is used, and the empty string for all other configurations: 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 ``condition`` must be ``0`` or ``1``. The result of the expression is
``0`` if ``condition`` is ``1``, else ``1``. ``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`: .. _`Comparison Expressions`:
Primary Comparison Expressions Primary Comparison Expressions

View File

@@ -0,0 +1,5 @@
genexp-no-eval
--------------
* :manual:`generator expressions <cmake-generator-expressions(7)>`
short-circuit to avoid unnecessary evaluation of parameters.

View File

@@ -153,10 +153,12 @@ std::string GeneratorExpressionContent::EvaluateParameters(
return std::string(); return std::string();
} }
std::string parameter; std::string parameter;
for (const auto& pExprEval : *pit) { if (node->ShouldEvaluateNextParameter(parameters, parameter)) {
parameter += pExprEval->Evaluate(context, dagChecker); for (const auto& pExprEval : *pit) {
if (context->HadError) { parameter += pExprEval->Evaluate(context, dagChecker);
return std::string(); if (context->HadError) {
return std::string();
}
} }
} }
parameters.push_back(std::move(parameter)); parameters.push_back(std::move(parameter));

View File

@@ -128,6 +128,16 @@ struct BooleanOpNode : public cmGeneratorExpressionNode
int NumExpectedParameters() const override { return OneOrMoreParameters; } 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, std::string Evaluate(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context, cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content, const GeneratorExpressionContent* content,
@@ -195,6 +205,13 @@ static const struct IfNode : public cmGeneratorExpressionNode
int NumExpectedParameters() const override { return 3; } 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, std::string Evaluate(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context, cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content, const GeneratorExpressionContent* content,

View File

@@ -33,6 +33,12 @@ struct cmGeneratorExpressionNode
virtual int NumExpectedParameters() const { return 1; } virtual int NumExpectedParameters() const { return 1; }
virtual bool ShouldEvaluateNextParameter(const std::vector<std::string>&,
std::string&) const
{
return true;
}
virtual std::string Evaluate( virtual std::string Evaluate(
const std::vector<std::string>& parameters, const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context, cmGeneratorExpressionContext* context,

View File

@@ -393,6 +393,7 @@ add_RunCMake_test(GenEx-PATH)
add_RunCMake_test(GenEx-PATH_EQUAL) add_RunCMake_test(GenEx-PATH_EQUAL)
add_RunCMake_test(GenEx-LIST) add_RunCMake_test(GenEx-LIST)
add_RunCMake_test(GeneratorExpression) add_RunCMake_test(GeneratorExpression)
add_RunCMake_test(GeneratorExpressionShortCircuit)
add_RunCMake_test(GeneratorInstance) add_RunCMake_test(GeneratorInstance)
add_RunCMake_test(GeneratorPlatform) add_RunCMake_test(GeneratorPlatform)
if(XCODE_VERSION) if(XCODE_VERSION)

View File

@@ -0,0 +1 @@
1

View File

@@ -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\)

View File

@@ -0,0 +1,4 @@
set(error $<0>)
add_custom_target(check ALL COMMAND check
$<AND:1,${error}>
)

View File

@@ -0,0 +1 @@
1

View File

@@ -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\)

View File

@@ -0,0 +1,4 @@
set(error $<0>)
add_custom_target(check ALL COMMAND check
$<IF:0,1,${error}>
)

View File

@@ -0,0 +1 @@
1

View File

@@ -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\)

View File

@@ -0,0 +1,4 @@
set(error $<0>)
add_custom_target(check ALL COMMAND check
$<OR:0,${error}>
)

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.26)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,4 @@
set(error $<0>)
add_custom_target(check ALL COMMAND check
$<AND:0,${error}>
)

View File

@@ -0,0 +1,5 @@
set(error $<0>)
add_custom_target(check ALL
COMMAND check $<IF:1,1,${error}>
COMMAND Check $<IF:0,${error},1>
)

View File

@@ -0,0 +1,4 @@
set(error $<0>)
add_custom_target(check ALL COMMAND check
$<OR:1,${error}>
)

View File

@@ -0,0 +1,9 @@
include(RunCMake)
run_cmake(GoodIF)
run_cmake(GoodAND)
run_cmake(GoodOR)
run_cmake(BadIF)
run_cmake(BadAND)
run_cmake(BadOR)