diff --git a/cmake/QtPublicPluginHelpers.cmake b/cmake/QtPublicPluginHelpers.cmake index 5023498b73..913dede6bf 100644 --- a/cmake/QtPublicPluginHelpers.cmake +++ b/cmake/QtPublicPluginHelpers.cmake @@ -131,7 +131,7 @@ endfunction() # Wraps the genex condition to evaluate to true only when using the regular plugin importing mode # (not finalizer mode). function(__qt_internal_get_plugin_condition_regular_mode plugin_condition out_var) - set(not_finalizer_mode "$>>") + set(not_finalizer_mode "$>>") set(full_plugin_condition "$") set(${out_var} "${full_plugin_condition}" PARENT_SCOPE) endfunction() @@ -368,17 +368,6 @@ function(__qt_internal_collect_plugin_targets_from_dependencies_of_plugins targe set("${out_var}" "${plugin_targets}" PARENT_SCOPE) endfunction() -# Helper to check if the finalizer mode of plugin importing should be used. -# If true or unset, use finalizer mode. -# If false, use regular mode (usage requirement propagation via associated Qt module) -function(__qt_internal_get_plugin_imports_finalizer_mode target out_var) - get_target_property(value ${target} _qt_static_plugins_use_finalizer_mode) - if("${value}" STREQUAL "value-NOTFOUND") - set(value "") - endif() - set(${out_var} "${value}" PARENT_SCOPE) -endfunction() - # Main logic of finalizer mode. function(__qt_internal_apply_plugin_imports_finalizer_mode target) # Nothing to do in a shared build. @@ -392,17 +381,15 @@ function(__qt_internal_apply_plugin_imports_finalizer_mode target) return() endif() - __qt_internal_get_plugin_imports_finalizer_mode(${target} use_finalizer_mode) - # By default if the project hasn't explicitly opted in or out, use finalizer mode. # The precondition for this is that qt_finalize_target was called (either explicitly by the user # or auto-deferred by CMake 3.19+). - if("${use_finalizer_mode}" STREQUAL "") - qt_enable_import_plugins_finalizer_mode(${target} TRUE) - endif() + __qt_internal_check_finalizer_mode("${target}" + use_finalizer_mode + static_plugins + DEFAULT_VALUE "TRUE" + ) - # Check if the project chose a mode explicitly. - __qt_internal_get_plugin_imports_finalizer_mode(${target} use_finalizer_mode) if(NOT use_finalizer_mode) return() endif() diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 4c85873f6b..fe750f8585 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -881,48 +881,52 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) endfunction() endif() -# This function allows enabling or disabling the finalizer mode of plugin importing in static Qt -# builds. +# This function is currently in Technical Preview. It's signature may change or be removed entirely. + +# This function allows enabling or disabling finalizer modes for a specific target. +# Currently, the only supported finalizer mode is for plugin importing in static Qt builds which +# is called 'static_plugins'. You can enable / disable it by calling # -# When finalizer mode is enabled, all plugins initializer object libraries are directly linked to -# the given '${target}' (executable or shared library). -# This prevents cycles between Qt provided static libraries and reduces link time, due to the -# libraries not being repeated because they are not part of a cycle anymore. +# qt6_set_finalizer_mode(${target} ENABLE MODES "static_plugins") +# qt6_set_finalizer_mode(${target} DISABLE MODES "static_plugins") # -# When finalizer mode is disabled, each plugin initializer is propagated via usage requirements -# of its associated module. +# When the "static_plugins" finalizer mode is enabled, all plugins initializer object libraries are +# directly linked to the given ${target} (executable or shared library). +# This prevents cycles between Qt provided static libraries and reduces link time, thanks to the +# libraries not being repeated on the link line because they are not part of a cycle anymore. # -# Finalizer mode is enabled by default if: +# When the finalizer mode is disabled, each plugin initializer is propagated via usage requirements +# of its associated module, which may cause cycles in the current build system implementation. +# +# The "static_plugins" finalizer mode is enabled by default if: # - the project calls qt_finalize_target explicitly at the end of the project file or # - the project uses qt_add_executable and a CMake version greater than or equal to 3.19 # (which will DEFER CALL qt_finalize_target) -function(qt6_enable_import_plugins_finalizer_mode target enabled) - if(enabled) - set(enabled "TRUE") - else() - set(enabled "FALSE") +function(qt6_set_finalizer_mode target) + cmake_parse_arguments(arg "ENABLE;DISABLE" "" "MODES" ${ARGN}) + if(NOT arg_ENABLE AND NOT arg_DISABLE) + message(FATAL_ERROR "No option was specified whether to enable or disable the modes.") + elseif(arg_ENABLE AND arg_DISABLE) + message(FATAL_ERROR "Both ENABLE and DISABLE options were specified.") endif() - set_property(TARGET "${target}" PROPERTY _qt_static_plugins_use_finalizer_mode "${enabled}") + if(NOT arg_MODES) + message(FATAL_ERROR "No modes were specified in qt6_set_finalizer_mode() call.") + endif() + + if(arg_ENABLE) + set(value "TRUE") + elseif(arg_DISABLE) + set(value "FALSE") + endif() + + foreach(mode ${arg_MODES}) + __qt_internal_enable_finalizer_mode("${target}" "${mode}" "${value}") + endforeach() endfunction() if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) - function(qt_enable_import_plugins_finalizer_mode) - qt6_enable_import_plugins_finalizer_mode(${ARGV}) - endfunction() -endif() - -# This function allows enabling or disabling the finalizer mode of resource objects linking in -# static Qt builds. -# It makes sense to manually disable the finalizer of the resource object if you are using -# linkers other than ld, since the dependencies between resource objects and static libraries -# are resolved correctly by them. -function(qt6_enable_object_libraries_finalizer_mode target enabled) - __qt_internal_enable_finalizer_mode(${target} object_libraries ${enabled}) -endfunction() - -if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) - function(qt_enable_object_libraries_finalizer_mode) - qt6_enable_object_libraries_finalizer_mode(${ARGV}) + function(qt_set_finalizer_mode) + qt6_set_finalizer_mode(${ARGV}) endfunction() endif() diff --git a/tests/auto/cmake/test_import_plugins/CMakeLists.txt b/tests/auto/cmake/test_import_plugins/CMakeLists.txt index ecfa7a0777..044805a85a 100644 --- a/tests/auto/cmake/test_import_plugins/CMakeLists.txt +++ b/tests/auto/cmake/test_import_plugins/CMakeLists.txt @@ -38,12 +38,12 @@ function(create_test_executable target) add_test(test_${target_name_adjusted} ${target_name_adjusted}) if(arg_FINALIZER_MODE) - set(finalizer_mode "TRUE") + set(finalizer_mode_state "ENABLE") else() - set(finalizer_mode "FALSE") + set(finalizer_mode_state "DISABLE") endif() - qt_enable_import_plugins_finalizer_mode(${target_name_adjusted} ${finalizer_mode}) + qt_set_finalizer_mode(${target_name_adjusted} ${finalizer_mode_state} MODES static_plugins) set(target ${target_name_adjusted} PARENT_SCOPE) endfunction() @@ -73,7 +73,7 @@ target_link_libraries(${target} PRIVATE Qt6::MockPlugins2) # Check that both regular and finalizer mode plugin importing pulls in the same set of plugins. # In regular mode, qt_finalize_target won't execute the finalizer plugin importing, because -# we opt out via qt_enable_import_plugins_finalizer_mode(target FALSE). +# we opt out via qt_set_finalizer_mode(target DISABLE MODES static_plugins). foreach(import_mode "" "FINALIZER_MODE") create_test_executable(manual QMock1Plugin QMock2Plugin QMock3Plugin QMock4Plugin ${import_mode}) diff --git a/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt b/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt index a219d6938d..44d4839084 100644 --- a/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt +++ b/tests/auto/cmake/test_static_resources/test_static_resources_propagation/CMakeLists.txt @@ -1,3 +1,10 @@ +# TODO: Revisit which of these tests makes sense to keep now that we depend on CMake 3.21 to +# properly place object libraries object files on the link line. +# See QTBUG-95601 +# +# +# +# # Add a dummy library that links the static "Qt" module containing resources file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp" CONTENT "void dummy() { }") add_library(dummy STATIC "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp") @@ -77,24 +84,26 @@ if(NOT link_order_matters) COMMAND test_static_resources_propagation_non_ld ) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) - qt_add_executable(test_static_resources_propagation_not_finalize main.cpp) - qt6_enable_object_libraries_finalizer_mode( - test_static_resources_propagation_not_finalize FALSE - ) - set_target_properties(test_static_resources_propagation_not_finalize PROPERTIES - AUTOMOC TRUE - ) - target_link_libraries(test_static_resources_propagation_not_finalize - PRIVATE - dummy - Qt::Core - Qt::Test - ) - add_test(NAME test_static_resources_propagation_not_finalize - COMMAND test_static_resources_propagation_not_finalize - ) - endif() +# FIXME: qt6_enable_object_libraries_finalizer_mode is not available anymore. See QTBUG-95601 +# +# if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) +# qt_add_executable(test_static_resources_propagation_not_finalize main.cpp) +# qt6_enable_object_libraries_finalizer_mode( +# test_static_resources_propagation_not_finalize FALSE +# ) +# set_target_properties(test_static_resources_propagation_not_finalize PROPERTIES +# AUTOMOC TRUE +# ) +# target_link_libraries(test_static_resources_propagation_not_finalize +# PRIVATE +# dummy +# Qt::Core +# Qt::Test +# ) +# add_test(NAME test_static_resources_propagation_not_finalize +# COMMAND test_static_resources_propagation_not_finalize +# ) +# endif() endif() # Add the executable using add_executable, expecting resources are propagated using