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>
This commit is contained in:
Joerg Bornemann 2023-09-21 08:48:53 +02:00
parent 49ff83fcef
commit 814de4c2ce
2 changed files with 34 additions and 21 deletions

View File

@ -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"

View File

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