diff options
Diffstat (limited to 'cmake/QtPublicPluginHelpers.cmake')
-rw-r--r-- | cmake/QtPublicPluginHelpers.cmake | 224 |
1 files changed, 184 insertions, 40 deletions
diff --git a/cmake/QtPublicPluginHelpers.cmake b/cmake/QtPublicPluginHelpers.cmake index a765157f5f..7087c31234 100644 --- a/cmake/QtPublicPluginHelpers.cmake +++ b/cmake/QtPublicPluginHelpers.cmake @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # Gets the qt plugin type of the given plugin into out_var_plugin_type. # Also sets out_var_has_plugin_type to TRUE or FALSE depending on whether the plugin type was found. function(__qt_internal_plugin_get_plugin_type @@ -36,22 +39,32 @@ endfunction() # # The conditions are based on the various properties set in qt_import_plugins. -# All the TARGET_PROPERTY genexes are evaluated in the context of the currently linked target. +# All the TARGET_PROPERTY genexes are evaluated in the context of the currently linked target, +# unless the TARGET argument is given. # # The genex is saved into out_var. function(__qt_internal_get_static_plugin_condition_genex plugin_target_unprefixed out_var) + set(options) + set(oneValueArgs TARGET) + set(multiValueArgs) + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target_unprefixed}") set(plugin_target_versionless "Qt::${plugin_target_unprefixed}") get_target_property(_plugin_type "${plugin_target}" QT_PLUGIN_TYPE) + set(target_infix "") + if(arg_TARGET) + set(target_infix "${arg_TARGET},") + endif() + set(_default_plugins_are_enabled - "$<NOT:$<STREQUAL:$<GENEX_EVAL:$<TARGET_PROPERTY:QT_DEFAULT_PLUGINS>>,0>>") - set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS>>") - set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_NO_PLUGINS>>") + "$<NOT:$<STREQUAL:$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_DEFAULT_PLUGINS>>,0>>") + set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_PLUGINS>>") + set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_NO_PLUGINS>>") # Plugin genex marker for prl processing. set(_is_plugin_marker_genex "$<BOOL:QT_IS_PLUGIN_GENEX>") @@ -78,7 +91,7 @@ function(__qt_internal_get_static_plugin_condition_genex ">," # Excludes both plugins targeted by EXCLUDE_BY_TYPE and not included in # INCLUDE_BY_TYPE. - "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>>>" + "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>>>" ">" ) @@ -87,7 +100,7 @@ function(__qt_internal_get_static_plugin_condition_genex "$<IN_LIST:" "${plugin_target}," "$<GENEX_EVAL:" - "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>" + "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>" ">" ">" ) @@ -95,7 +108,7 @@ function(__qt_internal_get_static_plugin_condition_genex "$<IN_LIST:" "${plugin_target_versionless}," "$<GENEX_EVAL:" - "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>" + "$<TARGET_PROPERTY:${target_infix}QT_PLUGINS_${_plugin_type}>" ">" ">" ) @@ -103,7 +116,7 @@ function(__qt_internal_get_static_plugin_condition_genex # No point in linking the plugin initialization source file into static libraries. The # initialization symbol will be discarded by the linker when the static lib is linked into an # executable or shared library, because nothing is referencing the global static symbol. - set(type_genex "$<TARGET_PROPERTY:TYPE>") + set(type_genex "$<TARGET_PROPERTY:${target_infix}TYPE>") set(no_static_genex "$<NOT:$<STREQUAL:${type_genex},STATIC_LIBRARY>>") # Complete condition that defines whether a static plugin is linked @@ -131,7 +144,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 "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_static_plugins_use_finalizer_mode>>>") + set(not_finalizer_mode "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_static_plugins_finalizer_mode>>>") set(full_plugin_condition "$<AND:${plugin_condition},${not_finalizer_mode}>") set(${out_var} "${full_plugin_condition}" PARENT_SCOPE) endfunction() @@ -174,7 +187,7 @@ function(__qt_internal_get_plugin_import_macro plugin_target out_var) set(class_name "${class_name_prefixed}") endif() - set(${out_var} "Q_IMPORT_PLUGIN(${class_name})" PARENT_SCOPE) + set(${out_var} "Q_IMPORT_PLUGIN(${class_name})\n" PARENT_SCOPE) endfunction() function(__qt_internal_get_plugin_include_prelude out_var) @@ -193,13 +206,14 @@ function(__qt_internal_add_static_plugin_import_macro qt_module_unprefixed) __qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target) - set(objs_genex "$<TARGET_OBJECTS:${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_init_target}>") + set(plugin_init_target_namespaced "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_init_target}") - # TODO: Replace the target_sources call here with the more generalized approach that will be - # added to __qt_propagate_generated_resource (the one that determines whether to use - # target_sources or target_link_libraries depending on the CMake version). - target_sources(${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target} INTERFACE - "${objs_genex}") + __qt_internal_propagate_object_library( + "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}" + "${plugin_init_target_namespaced}" + EXTRA_CONDITIONS + "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_static_plugins_finalizer_mode>>>" + ) endfunction() # Get target name of object library which is used to initialize a qt plugin. @@ -234,16 +248,20 @@ function(__qt_internal_add_static_plugin_init_object_library CONTENT "${import_content}" ) + # CMake versions earlier than 3.18.0 can't find the generated file for some reason, + # failing at generation phase. + # Explicitly marking the file as GENERATED fixes the issue. + set_source_files_properties("${generated_qt_plugin_file_name}" PROPERTIES GENERATED TRUE) + __qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target) - add_library("${plugin_init_target}" OBJECT "${generated_qt_plugin_file_name}") + qt6_add_library("${plugin_init_target}" OBJECT "${generated_qt_plugin_file_name}") target_link_libraries(${plugin_init_target} PRIVATE # Core provides the symbols needed by Q_IMPORT_PLUGIN. ${QT_CMAKE_EXPORT_NAMESPACE}::Core ) - _qt_internal_set_up_static_runtime_library("${plugin_init_target}") set_property(TARGET ${plugin_init_target} PROPERTY _is_qt_plugin_init_target TRUE) set_property(TARGET ${plugin_init_target} APPEND PROPERTY @@ -258,12 +276,16 @@ function(__qt_internal_collect_plugin_libraries plugin_targets out_var) set(plugins_to_link "") foreach(plugin_target ${plugin_targets}) + set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}") + get_target_property(type "${plugin_target_versioned}" TYPE) + if(NOT type STREQUAL STATIC_LIBRARY) + continue() + endif() + __qt_internal_get_static_plugin_condition_genex( "${plugin_target}" plugin_condition) - set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}") - list(APPEND plugins_to_link "$<${plugin_condition}:${plugin_target_versioned}>") endforeach() @@ -277,6 +299,12 @@ function(__qt_internal_collect_plugin_init_libraries plugin_targets out_var) set(plugin_inits_to_link "") foreach(plugin_target ${plugin_targets}) + set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}") + get_target_property(type "${plugin_target_versioned}" TYPE) + if(NOT type STREQUAL STATIC_LIBRARY) + continue() + endif() + __qt_internal_get_static_plugin_condition_genex( "${plugin_target}" plugin_condition) @@ -290,6 +318,25 @@ function(__qt_internal_collect_plugin_init_libraries plugin_targets out_var) set("${out_var}" "${plugin_inits_to_link}" PARENT_SCOPE) endfunction() +# Collect a list of genexes to deploy plugin libraries. +function(__qt_internal_collect_plugin_library_files target plugin_targets out_var) + set(library_files "") + + foreach(plugin_target ${plugin_targets}) + set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}") + __qt_internal_get_static_plugin_condition_genex( + "${plugin_target}" + plugin_condition + TARGET ${target} + ) + + set(target_genex "$<${plugin_condition}:${plugin_target_versioned}>") + list(APPEND library_files "$<$<BOOL:${target_genex}>:$<TARGET_FILE:${target_genex}>>") + endforeach() + + set("${out_var}" "${library_files}" PARENT_SCOPE) +endfunction() + # Collects all plugin targets discovered by walking the dependencies of ${target}. # # Walks immediate dependencies and their transitive dependencies. @@ -369,46 +416,70 @@ 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 "") +# Generate plugin information files for deployment +# +# Arguments: +# OUT_PLUGIN_TARGETS - Variable name to store the plugin targets that were collected with +# __qt_internal_collect_plugin_targets_from_dependencies. +function(__qt_internal_generate_plugin_deployment_info target) + set(no_value_options "") + set(single_value_options "OUT_PLUGIN_TARGETS") + set(multi_value_options "") + cmake_parse_arguments(PARSE_ARGV 0 arg + "${no_value_options}" "${single_value_options}" "${multi_value_options}" + ) + + __qt_internal_collect_plugin_targets_from_dependencies("${target}" plugin_targets) + if(NOT "${arg_OUT_PLUGIN_TARGETS}" STREQUAL "") + set("${arg_OUT_PLUGIN_TARGETS}" "${plugin_targets}" PARENT_SCOPE) 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. - if(QT6_IS_SHARED_LIBS_BUILD) + get_target_property(marked_for_deployment ${target} _qt_marked_for_deployment) + if(NOT marked_for_deployment) return() endif() + __qt_internal_collect_plugin_library_files(${target} "${plugin_targets}" plugins_files) + set(plugins_files "$<FILTER:${plugins_files},EXCLUDE,^$>") + + _qt_internal_get_deploy_impl_dir(deploy_impl_dir) + set(file_path "${deploy_impl_dir}/${target}-plugins") + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + string(APPEND file_path "-$<CONFIG>") + endif() + string(APPEND file_path ".cmake") + + file(GENERATE + OUTPUT ${file_path} + CONTENT "set(__QT_DEPLOY_PLUGINS ${plugins_files})" + ) +endfunction() + +# Main logic of finalizer mode. +function(__qt_internal_apply_plugin_imports_finalizer_mode target) # Process a target only once. get_target_property(processed ${target} _qt_plugin_finalizer_imports_processed) if(processed) return() endif() - __qt_internal_get_plugin_imports_finalizer_mode(${target} use_finalizer_mode) + __qt_internal_generate_plugin_deployment_info(${target} + OUT_PLUGIN_TARGETS plugin_targets) # 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() - __qt_internal_collect_plugin_targets_from_dependencies("${target}" plugin_targets) __qt_internal_collect_plugin_init_libraries("${plugin_targets}" init_libraries) __qt_internal_collect_plugin_libraries("${plugin_targets}" plugin_libraries) @@ -416,3 +487,76 @@ function(__qt_internal_apply_plugin_imports_finalizer_mode target) set_target_properties(${target} PROPERTIES _qt_plugin_finalizer_imports_processed TRUE) endfunction() + +# Include CMake plugin packages that belong to the Qt module ${target} and initialize automatic +# linkage of the plugins in static builds. +# The variables inside the macro have to be named unique to the module because an included Plugin +# file might look up another module dependency that calls the same macro before the first one +# has finished processing, which can silently override the values if the variables are not unique. +macro(__qt_internal_include_plugin_packages target) + set(__qt_${target}_plugin_module_target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}") + set(__qt_${target}_plugins "") + + # Properties can't be set on aliased targets, so make sure to unalias the target. This is needed + # when Qt examples are built as part of the Qt build itself. + get_target_property(_aliased_target ${__qt_${target}_plugin_module_target} ALIASED_TARGET) + if(_aliased_target) + set(__qt_${target}_plugin_module_target ${_aliased_target}) + endif() + + # Include all PluginConfig.cmake files and update the _qt_plugins and QT_PLUGINS property of + # the module. The underscored version is the one we will use going forward to have compatibility + # with INTERFACE libraries. QT_PLUGINS is now deprecated and only kept so that we don't break + # existing projects using it (like CMake itself). + file(GLOB __qt_${target}_plugin_config_files + "${CMAKE_CURRENT_LIST_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}*PluginConfig.cmake") + foreach(__qt_${target}_plugin_config_file ${__qt_${target}_plugin_config_files}) + string(REGEX REPLACE + "^.*/${QT_CMAKE_EXPORT_NAMESPACE}(.*Plugin)Config.cmake$" + "\\1" + __qt_${target}_qt_plugin "${__qt_${target}_plugin_config_file}") + include("${__qt_${target}_plugin_config_file}") + if(TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${__qt_${target}_qt_plugin}") + list(APPEND __qt_${target}_plugins ${__qt_${target}_qt_plugin}) + endif() + endforeach() + set_property(TARGET ${__qt_${target}_plugin_module_target} + PROPERTY _qt_plugins ${__qt_${target}_plugins}) + + # TODO: Deprecated. Remove in Qt 7. + set_property(TARGET ${__qt_${target}_plugin_module_target} + PROPERTY QT_PLUGINS ${__qt_${target}_plugins}) + + get_target_property(__qt_${target}_have_added_plugins_already + ${__qt_${target}_plugin_module_target} __qt_internal_plugins_added) + if(__qt_${target}_have_added_plugins_already) + return() + endif() + + foreach(plugin_target ${__qt_${target}_plugins}) + __qt_internal_plugin_get_plugin_type("${plugin_target}" __has_plugin_type __plugin_type) + if(NOT __has_plugin_type) + continue() + endif() + + __qt_internal_plugin_has_class_name("${plugin_target}" __has_class_name) + if(NOT __has_class_name) + continue() + endif() + + list(APPEND "QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_${__plugin_type}" "${plugin_target}") + + # Auto-linkage should be set up only for static plugins. + set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}") + get_target_property(type "${plugin_target_versioned}" TYPE) + if(type STREQUAL STATIC_LIBRARY) + __qt_internal_add_static_plugin_linkage( + "${plugin_target}" "${__qt_${target}_plugin_module_target}") + __qt_internal_add_static_plugin_import_macro( + "${plugin_target}" ${__qt_${target}_plugin_module_target} "${target}") + endif() + endforeach() + + set_target_properties( + ${__qt_${target}_plugin_module_target} PROPERTIES __qt_internal_plugins_added TRUE) +endmacro() |