diff options
author | Joerg Bornemann <joerg.bornemann@qt.io> | 2023-09-21 08:48:53 +0200 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@qt.io> | 2023-09-21 21:46:46 +0200 |
commit | 814de4c2ce8a4a9198672c68d64a2eb9c8e30e8b (patch) | |
tree | 168719819de98b868145547d9d30d5df9279d523 | |
parent | 49ff83fcef270c2a4317b5c95524c08a26120074 (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.cmake | 49 | ||||
-rw-r--r-- | tests/auto/cmake/test_config_expressions/CMakeLists.txt | 6 |
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") |