summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst11
-rw-r--r--Help/release/dev/genexp-no-eval.rst5
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx10
-rw-r--r--Source/cmGeneratorExpressionNode.cxx17
-rw-r--r--Source/cmGeneratorExpressionNode.h6
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadAND.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadIF.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/BadOR.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/GoodAND.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/GoodIF.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/GoodOR.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpressionShortCircuit/RunCMakeTest.cmake9
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)