From 61943aefd68b7d88c5eb395c4e44d08a94a70ad0 Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Fri, 11 Dec 2020 16:11:35 +0100 Subject: [PATCH] CMake: Add detection of FEATURE_foo change by user Unset all QT_FEATURE_foo values for every build. If any of FEATURE_foo is different of QT_FEATURE_foo, mark whole Qt build as dirty. Reset FEATURE_foo for dirty builds to the calculated value if it doesn't meet its condition. Set Qt module as NOT FOUND if its target was not created during configuration. Main issue with this approach are generated files, that became trash once the related features are disabled. This especially affects features that enable/disable Qt modules. FooConfig.cmake files are created and generate lots of warnings if feature was disabled. We may introduce a module cleanup procedure at some point. Fixes: QTBUG-85962 Pick-to: 6.0 Change-Id: Id71c1edb4027b24c6793063e40cc9d612c24ebce Reviewed-by: Joerg Bornemann --- cmake/QtFeature.cmake | 33 ++++++++++++++++----------- cmake/QtModuleConfig.cmake.in | 42 +++++++++++++++++++---------------- cmake/QtSetup.cmake | 24 ++++++++++++++++++++ 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake index be749eedaf5..72b4001d57b 100644 --- a/cmake/QtFeature.cmake +++ b/cmake/QtFeature.cmake @@ -227,7 +227,7 @@ function(_qt_internal_dump_expression_values expression_dump expression) set(${expression_dump} "${${expression_dump}}" PARENT_SCOPE) endfunction() -function(qt_feature_set_cache_value resultVar feature emit_if calculated label) +function(qt_feature_set_cache_value resultVar feature emit_if condition calculated label) if (DEFINED "FEATURE_${feature}") # Must set up the cache if (NOT (emit_if)) @@ -236,14 +236,25 @@ function(qt_feature_set_cache_value resultVar feature emit_if calculated label) # Revisit value: set(cache "${FEATURE_${feature}}") + + # If the build is marked as dirty and the cache value doesn't meet the new condition, + # reset it to the calculated one. + get_property(dirty_build GLOBAL PROPERTY _qt_dirty_build) + if(NOT condition AND cache AND dirty_build) + set(cache "${calculated}") + message(WARNING "Reset FEATURE_${feature} value to ${calculated}, because it doesn't \ +meet its condition after reconfiguration.") + endif() + set(bool_values OFF NO FALSE N ON YES TRUE Y) if ((cache IN_LIST bool_values) OR (cache GREATER_EQUAL 0)) set(result "${cache}") else() message(FATAL_ERROR "Sanity check failed: FEATURE_${feature} has invalid value \"${cache}\"!") endif() + # Fix-up user-provided values - set("FEATURE_${feature}" "${cache}" CACHE BOOL "${label}") + set("FEATURE_${feature}" "${cache}" CACHE BOOL "${label}" FORCE) else() # Initial setup: if (emit_if) @@ -271,11 +282,14 @@ macro(qt_feature_set_value feature cache condition label conditionExpression) message(FATAL_ERROR "Feature ${feature} is already defined when evaluating configure.cmake features for ${target}.") endif() set(QT_FEATURE_${feature} "${result}" CACHE INTERNAL "Qt feature: ${feature}") + + # Add feature to build feature collection + list(APPEND QT_KNOWN_FEATURES "${feature}") + set(QT_KNOWN_FEATURES "${QT_KNOWN_FEATURES}" CACHE INTERNAL "" FORCE) endmacro() function(qt_evaluate_feature feature) - # If the feature was set explicitly by the user to be on or off, in the cache, then - # there's nothing for us to do. + # If the feature was already evaluated as dependency nothing to do here. if(DEFINED "QT_FEATURE_${feature}") return() endif() @@ -289,10 +303,6 @@ function(qt_evaluate_feature feature) "PRIVATE;PUBLIC" "LABEL;PURPOSE;SECTION;" "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF" ${_QT_FEATURE_DEFINITION_${feature}}) - if(DEFINED QT_FEATURE_${feature}) - return() - endif() - if("${arg_ENABLE}" STREQUAL "") set(arg_ENABLE OFF) endif() @@ -329,10 +339,6 @@ function(qt_evaluate_feature feature) qt_evaluate_config_expression(emit_if ${arg_EMIT_IF}) endif() - if (NOT (condition) AND (calculated)) - message(FATAL_ERROR "Sanity check failed: Feature ${feature} is enabled but condition does not hold true.") - endif() - # If FEATURE_ is not defined trying to use INPUT_ variable to enable/disable feature. if ((NOT DEFINED "FEATURE_${feature}") AND (DEFINED "INPUT_${feature}") AND (NOT "${INPUT_${feature}}" STREQUAL "undefined") @@ -344,7 +350,8 @@ function(qt_evaluate_feature feature) endif() endif() - qt_feature_set_cache_value(cache "${feature}" "${emit_if}" "${result}" "${arg_LABEL}") + qt_feature_set_cache_value(cache "${feature}" "${emit_if}" "${condition}" "${result}" + "${arg_LABEL}") qt_feature_set_value("${feature}" "${cache}" "${condition}" "${arg_LABEL}" "${arg_CONDITION}") diff --git a/cmake/QtModuleConfig.cmake.in b/cmake/QtModuleConfig.cmake.in index ecd5e04e634..05732569827 100644 --- a/cmake/QtModuleConfig.cmake.in +++ b/cmake/QtModuleConfig.cmake.in @@ -86,32 +86,36 @@ if (NOT QT_NO_CREATE_TARGETS) list(REMOVE_DUPLICATES @QT_CMAKE_EXPORT_NAMESPACE@@target@_COMPILE_DEFINITIONS) endif() -foreach(extra_cmake_include @extra_cmake_includes@) - include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}") -endforeach() +if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::@target@) + foreach(extra_cmake_include @extra_cmake_includes@) + include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}") + endforeach() -include(${_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir}/QtFeature.cmake) + include(${_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir}/QtFeature.cmake) -qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@) + qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@) -if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") -endif() + if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") + endif() -list(APPEND QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "@target@") + list(APPEND QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "@target@") -get_target_property(_qt_module_target_type "@INSTALL_CMAKE_NAMESPACE@::@target@" TYPE) -if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY") - get_target_property(_qt_module_plugin_types - @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES) - if(_qt_module_plugin_types) - list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}") + get_target_property(_qt_module_target_type "@INSTALL_CMAKE_NAMESPACE@::@target@" TYPE) + if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(_qt_module_plugin_types + @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES) + if(_qt_module_plugin_types) + list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}") + endif() endif() -endif() -# Load Module's BuildInternals should any exist -if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND + # Load Module's BuildInternals should any exist + if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake") + endif() +else() + set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" FALSE) endif() diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake index ec8be5e269f..13daf40381f 100644 --- a/cmake/QtSetup.cmake +++ b/cmake/QtSetup.cmake @@ -222,3 +222,27 @@ if(QT_USE_CCACHE) message(WARNING "Ccache use was requested, but the program was not found.") endif() endif() + +# We need to clean up QT_FEATURE_*, but only once per configuration cycle +get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean) +if(NOT qt_feature_clean) + message(STATUS "Check for feature set changes") + set_property(GLOBAL PROPERTY _qt_feature_clean TRUE) + foreach(feature ${QT_KNOWN_FEATURES}) + if(DEFINED "FEATURE_${feature}" AND + NOT "${QT_FEATURE_${feature}}" STREQUAL "${FEATURE_${feature}}") + message(" '${feature}' is changed from ${QT_FEATURE_${feature}} \ +to ${FEATURE_${feature}}") + set(dirty_build TRUE) + endif() + unset("QT_FEATURE_${feature}" CACHE) + endforeach() + + set(QT_KNOWN_FEATURES "" CACHE INTERNAL "" FORCE) + + if(dirty_build) + set_property(GLOBAL PROPERTY _qt_dirty_build TRUE) + message(WARNING "Re-configuring in existing build folder. \ +Some features will be re-evaluated automatically.") + endif() +endif()