summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@qt.io>2023-09-21 08:48:53 +0200
committerJoerg Bornemann <joerg.bornemann@qt.io>2023-09-21 21:46:46 +0200
commit814de4c2ce8a4a9198672c68d64a2eb9c8e30e8b (patch)
tree168719819de98b868145547d9d30d5df9279d523
parent49ff83fcef270c2a4317b5c95524c08a26120074 (diff)
CMake: Fix config condition evaluator
Use recursive descent to handle parentheses in config condition expressions. This fixes cases like 'NOT (A AND B)'. Fixes: QTBUG-117053 Change-Id: Iab1b6173abe00d763808bb972a9a5443ffa0938d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> Reviewed-by: Amir Masoud Abdol <amir.abdol@qt.io>
-rw-r--r--cmake/QtFeature.cmake49
-rw-r--r--tests/auto/cmake/test_config_expressions/CMakeLists.txt6
2 files changed, 34 insertions, 21 deletions
diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake
index 2c6fa94c25..ee7e0ab824 100644
--- a/cmake/QtFeature.cmake
+++ b/cmake/QtFeature.cmake
@@ -81,35 +81,23 @@ function(qt_evaluate_to_boolean expressionVar)
endif()
endfunction()
-function(qt_evaluate_config_expression resultVar)
+function(qt_internal_evaluate_config_expression resultVar outIdx startIdx)
set(result "")
- set(nestingLevel 0)
set(expression "${ARGN}")
list(LENGTH expression length)
- set(memberIdx -1)
+ math(EXPR memberIdx "${startIdx} - 1")
math(EXPR length "${length}-1")
while(memberIdx LESS ${length})
math(EXPR memberIdx "${memberIdx} + 1")
list(GET expression ${memberIdx} member)
if("${member}" STREQUAL "(")
- if(${nestingLevel} GREATER 0)
- list(APPEND result ${member})
- endif()
- math(EXPR nestingLevel "${nestingLevel} + 1")
+ math(EXPR memberIdx "${memberIdx} + 1")
+ qt_internal_evaluate_config_expression(sub_result memberIdx ${memberIdx} ${expression})
+ list(APPEND result ${sub_result})
elseif("${member}" STREQUAL ")")
- math(EXPR nestingLevel "${nestingLevel} - 1")
- if(nestingLevel LESS 0)
- break()
- endif()
- if(${nestingLevel} EQUAL 0)
- qt_evaluate_config_expression(result ${result})
- else()
- list(APPEND result ${member})
- endif()
- elseif(${nestingLevel} GREATER 0)
- list(APPEND result ${member})
+ break()
elseif("${member}" STREQUAL "NOT")
list(APPEND result ${member})
elseif("${member}" STREQUAL "AND")
@@ -166,9 +154,34 @@ function(qt_evaluate_config_expression resultVar)
qt_evaluate_to_boolean(result)
endif()
+ # When in recursion, we must skip to the next closing parenthesis on nesting level 0. The outIdx
+ # must point to the matching closing parenthesis, and that's not the case if we're early exiting
+ # in AND/OR.
+ if(startIdx GREATER 0)
+ set(nestingLevel 1)
+ while(TRUE)
+ list(GET expression ${memberIdx} member)
+ if("${member}" STREQUAL ")")
+ math(EXPR nestingLevel "${nestingLevel} - 1")
+ if(nestingLevel EQUAL 0)
+ break()
+ endif()
+ elseif("${member}" STREQUAL "(")
+ math(EXPR nestingLevel "${nestingLevel} + 1")
+ endif()
+ math(EXPR memberIdx "${memberIdx} + 1")
+ endwhile()
+ endif()
+
+ set(${outIdx} ${memberIdx} PARENT_SCOPE)
set(${resultVar} ${result} PARENT_SCOPE)
endfunction()
+function(qt_evaluate_config_expression resultVar)
+ qt_internal_evaluate_config_expression(result unused 0 ${ARGN})
+ set("${resultVar}" "${result}" PARENT_SCOPE)
+endfunction()
+
function(_qt_internal_get_feature_condition_keywords out_var)
set(keywords "EQUAL" "LESS" "LESS_EQUAL" "GREATER" "GREATER_EQUAL" "STREQUAL" "STRLESS"
"STRLESS_EQUAL" "STRGREATER" "STRGREATER_EQUAL" "VERSION_EQUAL" "VERSION_LESS"
diff --git a/tests/auto/cmake/test_config_expressions/CMakeLists.txt b/tests/auto/cmake/test_config_expressions/CMakeLists.txt
index 4061728113..e3863b738a 100644
--- a/tests/auto/cmake/test_config_expressions/CMakeLists.txt
+++ b/tests/auto/cmake/test_config_expressions/CMakeLists.txt
@@ -88,9 +88,9 @@ assert_F(A AND B)
assert_T(A AND (B OR C))
assert_T((A AND B) OR C)
assert_T((A AND B) OR (NOT B AND C))
-expect_failure_F(NOT (B OR C)) # QTBUG-117053
-expect_failure_T(NOT (A AND B)) # QTBUG-117053
-expect_failure_F(NOT (B OR C)) # QTBUG-117053
+assert_F(NOT (B OR C))
+assert_T(NOT (A AND B))
+assert_F(NOT (B OR C))
# target check
set(lib1_cpp "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp")