Fix the static linking of plugins to the Qt tools and internal executables
Qt tools and executables may required the static plugins from modules that are build as part of the Qt build tree. In this case we need to force plugin importing. This adds the qt_internal_import_plugins call when we extend the executable target. Replace the previos solution that considered libraries that were provided in the arguments of the qt_internal_add_executable call only. Pick-to: 6.7 6.6 6.5 Fixes: QTBUG-111988 Change-Id: Ifa2cf7f1f68d9f90cafc64f225aebe11d4cdb2ae Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
parent
669f7e3b97
commit
c7176f3142
@ -215,95 +215,6 @@ function(qt_internal_add_executable name)
|
||||
if("Qt::Gui" IN_LIST linked_libs AND TARGET qpa_default_plugins)
|
||||
add_dependencies("${name}" qpa_default_plugins)
|
||||
endif()
|
||||
|
||||
# For static plugins, we need to explicitly link to plugins we want to be
|
||||
# loaded with the executable. User projects get that automatically, but
|
||||
# for tools built as part of Qt, we can't use that mechanism because it
|
||||
# would pollute the targets we export as part of an install and lead to
|
||||
# circular dependencies. The logic here is a simpler equivalent of the
|
||||
# more dynamic logic in QtPlugins.cmake.in, but restricted to only
|
||||
# adding plugins that are provided by the same module as the module
|
||||
# libraries the executable links to.
|
||||
set(libs
|
||||
${arg_LIBRARIES}
|
||||
${arg_PUBLIC_LIBRARIES}
|
||||
${extra_libraries}
|
||||
Qt::PlatformCommonInternal
|
||||
)
|
||||
|
||||
set(deduped_libs "")
|
||||
foreach(lib IN LISTS libs)
|
||||
if(NOT TARGET "${lib}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Normalize module by stripping any leading "Qt::", because properties are set on the
|
||||
# versioned target (either Gui when building the module, or Qt6::Gui when it's
|
||||
# imported).
|
||||
if(lib MATCHES "Qt::([-_A-Za-z0-9]+)")
|
||||
set(new_lib "${QT_CMAKE_EXPORT_NAMESPACE}::${CMAKE_MATCH_1}")
|
||||
if(TARGET "${new_lib}")
|
||||
set(lib "${new_lib}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Unalias the target.
|
||||
get_target_property(aliased_target ${lib} ALIASED_TARGET)
|
||||
if(aliased_target)
|
||||
set(lib ${aliased_target})
|
||||
endif()
|
||||
|
||||
list(APPEND deduped_libs "${lib}")
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES deduped_libs)
|
||||
|
||||
foreach(lib IN LISTS deduped_libs)
|
||||
string(MAKE_C_IDENTIFIER "${name}_plugin_imports_${lib}" out_file)
|
||||
string(APPEND out_file .cpp)
|
||||
|
||||
# Initialize plugins that are built in the same repository as the Qt module 'lib'.
|
||||
set(class_names_regular
|
||||
"$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugin_class_names>>")
|
||||
|
||||
# Initialize plugins that are built in the current Qt repository, but are associated
|
||||
# with a Qt module from a different repository (qtsvg's QSvgPlugin associated with
|
||||
# qtbase's QtGui).
|
||||
string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
|
||||
set(prop_prefix "_qt_repo_${current_project_name}")
|
||||
set(class_names_current_project
|
||||
"$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},${prop_prefix}_plugin_class_names>>")
|
||||
|
||||
# Only add separator if first list is not empty, so we don't trigger the file generation
|
||||
# when all lists are empty.
|
||||
set(class_names_separator "$<$<NOT:$<STREQUAL:${class_names_regular},>>:;>" )
|
||||
set(class_names
|
||||
"${class_names_regular}${class_names_separator}${class_names_current_project}")
|
||||
|
||||
set(out_file_path "${CMAKE_CURRENT_BINARY_DIR}/${out_file}")
|
||||
|
||||
file(GENERATE OUTPUT "${out_file_path}" CONTENT
|
||||
"// This file is auto-generated. Do not edit.
|
||||
#include <QtPlugin>
|
||||
|
||||
Q_IMPORT_PLUGIN($<JOIN:${class_names},)\nQ_IMPORT_PLUGIN(>)
|
||||
"
|
||||
CONDITION "$<NOT:$<STREQUAL:${class_names},>>"
|
||||
)
|
||||
|
||||
# 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("${out_file_path}" PROPERTIES GENERATED TRUE)
|
||||
|
||||
target_sources(${name} PRIVATE
|
||||
"$<$<NOT:$<STREQUAL:${class_names},>>:${out_file_path}>"
|
||||
)
|
||||
target_link_libraries(${name} PRIVATE
|
||||
"$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugins>"
|
||||
"$<TARGET_PROPERTY:${lib},${prop_prefix}_plugins>")
|
||||
endforeach()
|
||||
|
||||
endfunction()
|
||||
|
||||
# This function compiles the target at configure time the very first time and creates the custom
|
||||
|
@ -227,69 +227,6 @@ function(qt_internal_add_plugin target)
|
||||
|
||||
set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
|
||||
get_target_property(type "${plugin_target_versioned}" TYPE)
|
||||
if(type STREQUAL STATIC_LIBRARY)
|
||||
# Associate plugin with its Qt module when both are both built in the same repository.
|
||||
# Check that by comparing the PROJECT_NAME of each.
|
||||
# This covers auto-linking of the majority of plugins to executables and in-tree tests.
|
||||
# Linking of plugins in standalone tests (when the Qt module will be an imported target)
|
||||
# is handled instead by the complicated genex logic in QtModulePlugins.cmake.in.
|
||||
set(is_plugin_and_module_in_same_project FALSE)
|
||||
if(NOT is_imported_qt_module)
|
||||
get_target_property(module_source_dir ${qt_module_target} SOURCE_DIR)
|
||||
get_directory_property(module_project_name
|
||||
DIRECTORY ${module_source_dir}
|
||||
DEFINITION PROJECT_NAME
|
||||
)
|
||||
if(module_project_name STREQUAL PROJECT_NAME)
|
||||
set(is_plugin_and_module_in_same_project TRUE)
|
||||
endif()
|
||||
|
||||
# When linking static plugins with the special logic in qt_internal_add_executable,
|
||||
# make sure to skip non-default plugins.
|
||||
if(is_plugin_and_module_in_same_project AND _default_plugin)
|
||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY
|
||||
_qt_initial_repo_plugins
|
||||
"${target}")
|
||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY
|
||||
_qt_initial_repo_plugin_class_names
|
||||
"$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Associate plugin with its Qt module when the plugin is built in the current repository
|
||||
# but the module is built in a different repository (qtsvg's QSvgPlugin associated with
|
||||
# qtbase's QtGui).
|
||||
# The association is done in a separate property, to ensure that reconfiguring in-tree tests
|
||||
# in qtbase doesn't accidentally cause linking to a plugin from a previously built qtsvg.
|
||||
# Needed for in-tree tests like in qtsvg, qtimageformats.
|
||||
# This is done for each Qt module regardless if it's an imported target or not, to handle
|
||||
# both per-repo and top-level builds (in per-repo build of qtsvg QtGui is imported, in a
|
||||
# top-level build Gui is not imported, but in both cases qtsvg tests need to link to
|
||||
# QSvgPlugin).
|
||||
#
|
||||
# TODO: Top-level in-tree tests and qdeclarative per-repo in-tree tests that depend on
|
||||
# static Qml plugins won't work due to the requirement of running qmlimportscanner
|
||||
# at configure time, but qmlimportscanner is not built at that point. Moving the
|
||||
# execution of qmlimportscanner to build time is non-trivial because qmlimportscanner
|
||||
# not only generates a cpp file to compile but also outputs a list of static plugins
|
||||
# that should be linked and there is no straightforward way to tell CMake to link
|
||||
# against a list of libraries that was discovered at build time (apart from
|
||||
# response files, which apparently might not work on all platforms).
|
||||
# qmake doesn't have this problem because each project is configured separately so
|
||||
# qmlimportscanner is always built by the time it needs to be run for a test.
|
||||
if(NOT is_plugin_and_module_in_same_project AND _default_plugin)
|
||||
string(MAKE_C_IDENTIFIER "${PROJECT_NAME}" current_project_name)
|
||||
set(prop_prefix "_qt_repo_${current_project_name}")
|
||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY
|
||||
${prop_prefix}_plugins "${target}")
|
||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY
|
||||
${prop_prefix}_plugin_class_names
|
||||
"$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
qt_internal_add_autogen_sync_header_dependencies(${target} ${qt_module_target})
|
||||
endif()
|
||||
|
||||
@ -623,3 +560,48 @@ function(qt_internal_add_darwin_permission_plugin permission)
|
||||
QT_PLUGIN_PRI_EXTRA_CONTENT ${extra_plugin_pri_content}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# The function looks and links the static plugins that the target depends on. The function behaves
|
||||
# similar to qt_import_plugins, but should be used when building Qt executable or shared libraries.
|
||||
# It's expected that all dependencies are valid targets at the time when the function is called.
|
||||
# If not their plugins will be not collected for linking.
|
||||
function(qt_internal_import_plugins target)
|
||||
set(plugin_targets "")
|
||||
foreach(dep_target IN LISTS ARGN)
|
||||
if(dep_target AND TARGET ${dep_target})
|
||||
get_target_property(plugins ${dep_target} _qt_plugins)
|
||||
if(plugins)
|
||||
list(APPEND plugin_targets ${plugins})
|
||||
else()
|
||||
# Fallback should be remove in Qt 7.
|
||||
get_target_property(target_type ${dep_target} TYPE)
|
||||
if(NOT "${target_type}" STREQUAL "INTERFACE_LIBRARY")
|
||||
get_target_property(plugins ${dep_target} QT_PLUGINS)
|
||||
if(plugins)
|
||||
list(APPEND plugin_targets ${plugins})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(non_imported_plugin_targets "")
|
||||
foreach(plugin_target IN LISTS plugin_targets)
|
||||
if(NOT TARGET ${plugin_target} OR "${plugin_target}" IN_LIST non_imported_plugin_targets)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
get_target_property(is_imported ${plugin_target} IMPORTED)
|
||||
if(NOT is_imported)
|
||||
list(APPEND non_imported_plugin_targets "${plugin_target}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(plugin_targets)
|
||||
__qt_internal_collect_plugin_init_libraries("${non_imported_plugin_targets}" init_libraries)
|
||||
__qt_internal_collect_plugin_libraries("${non_imported_plugin_targets}" plugin_libraries)
|
||||
if(plugin_libraries OR init_libraries)
|
||||
target_link_libraries(${target} PRIVATE ${plugin_libraries} ${init_libraries})
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
@ -99,10 +99,13 @@ function(qt_internal_extend_target target)
|
||||
get_target_property(target_type ${target} TYPE)
|
||||
set(is_library FALSE)
|
||||
set(is_interface_lib FALSE)
|
||||
set(is_executable FALSE)
|
||||
if(${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY")
|
||||
set(is_library TRUE)
|
||||
elseif(target_type STREQUAL "INTERFACE_LIBRARY")
|
||||
set(is_interface_lib TRUE)
|
||||
elseif(target_type STREQUAL "EXECUTABLE")
|
||||
set(is_executable TRUE)
|
||||
endif()
|
||||
|
||||
foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
|
||||
@ -273,6 +276,11 @@ function(qt_internal_extend_target target)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
_qt_extra_linker_script_exports "${arg_EXTRA_LINKER_SCRIPT_EXPORTS}")
|
||||
endif()
|
||||
|
||||
# For executables collect static plugins that these targets depend on.
|
||||
if(is_executable)
|
||||
qt_internal_import_plugins(${target} ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Given CMAKE_CONFIG and ALL_CMAKE_CONFIGS, determines if a directory suffix needs to be appended
|
||||
|
Loading…
x
Reference in New Issue
Block a user