CMake: Fix auto-linking of static plugins for non-QML in-tree tests
Certain repositories like qtsvg, qtimageformats and qtvirtualkyboard build plugins associated with Qt modules from other repositories (qtsvg's QSvgPlugin associated to qtbase's QtGui). When configuring in-tree tests in the same build folder as the repository, the test executables would not automatically link to these plugins. Fix this by recording the existence of such plugins in a separate property of the associated Qt module and only link them when both the test executable and plugin are from the same project (their PROJECT_NAME coincides). This is in addition to linking the plugins associated with the module where both are built in the same repository. The logic is a bit tricky and ensures that plugins are not accidentally initialized twice, so that in-tree tests work for both top-level and per-repo builds. As a drive-by, added a TODO explaining why in-tree tests that need to link to static QML plugins won't work (somewhat unrelated to this change). Amends 734d2cdbc4ff6db6b3df8fffbb23dbbb565c076b Amends b1fcdad9c9b9ad2bddd00f7301c8dd1159d523c2 Task-number: QTBUG-87580 Change-Id: I3e1ff8166864f92dea931ec2ea34b6f56b4eec60 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> (cherry picked from commit 6969496e0078f9f9df9bef817caad71cf5213e3a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
09e9fd4f77
commit
e3314328f3
@ -190,14 +190,56 @@ function(qt_internal_add_executable name)
|
|||||||
${extra_libraries}
|
${extra_libraries}
|
||||||
Qt::PlatformCommonInternal
|
Qt::PlatformCommonInternal
|
||||||
)
|
)
|
||||||
list(REMOVE_DUPLICATES libs)
|
|
||||||
|
set(deduped_libs "")
|
||||||
foreach(lib IN LISTS libs)
|
foreach(lib IN LISTS libs)
|
||||||
if(NOT TARGET "${lib}")
|
if(NOT TARGET "${lib}")
|
||||||
continue()
|
continue()
|
||||||
endif()
|
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(MAKE_C_IDENTIFIER "${name}_plugin_imports_${lib}" out_file)
|
||||||
string(APPEND out_file .cpp)
|
string(APPEND out_file .cpp)
|
||||||
set(class_names "$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},_qt_repo_plugin_class_names>>")
|
|
||||||
|
# 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}")
|
||||||
|
|
||||||
file(GENERATE OUTPUT ${out_file} CONTENT
|
file(GENERATE OUTPUT ${out_file} CONTENT
|
||||||
"// This file is auto-generated. Do not edit.
|
"// This file is auto-generated. Do not edit.
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
@ -209,7 +251,9 @@ Q_IMPORT_PLUGIN($<JOIN:${class_names},)\nQ_IMPORT_PLUGIN(>)
|
|||||||
target_sources(${name} PRIVATE
|
target_sources(${name} PRIVATE
|
||||||
"$<$<NOT:$<STREQUAL:${class_names},>>:${out_file}>"
|
"$<$<NOT:$<STREQUAL:${class_names},>>:${out_file}>"
|
||||||
)
|
)
|
||||||
target_link_libraries(${name} PRIVATE "$<TARGET_PROPERTY:${lib},_qt_repo_plugins>")
|
target_link_libraries(${name} PRIVATE
|
||||||
|
"$<TARGET_PROPERTY:${lib},_qt_initial_repo_plugins>"
|
||||||
|
"$<TARGET_PROPERTY:${lib},${prop_prefix}_plugins>")
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -178,30 +178,69 @@ function(qt_internal_add_plugin target)
|
|||||||
endif()
|
endif()
|
||||||
get_target_property(is_imported_qt_module ${qt_module_target} IMPORTED)
|
get_target_property(is_imported_qt_module ${qt_module_target} IMPORTED)
|
||||||
|
|
||||||
|
# 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)
|
if(NOT is_imported_qt_module)
|
||||||
|
# This QT_PLUGINS assignment is only used by QtPostProcessHelpers to decide if a
|
||||||
|
# QtModulePlugins.cmake file should be generated (which only happens in static builds).
|
||||||
set_property(TARGET "${qt_module_target}" APPEND PROPERTY QT_PLUGINS "${target}")
|
set_property(TARGET "${qt_module_target}" APPEND PROPERTY QT_PLUGINS "${target}")
|
||||||
|
|
||||||
get_target_property(module_source_dir ${qt_module_target} SOURCE_DIR)
|
get_target_property(module_source_dir ${qt_module_target} SOURCE_DIR)
|
||||||
get_directory_property(module_project_name
|
get_directory_property(module_project_name
|
||||||
DIRECTORY ${module_source_dir}
|
DIRECTORY ${module_source_dir}
|
||||||
DEFINITION PROJECT_NAME
|
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,
|
# When linking static plugins with the special logic in qt_internal_add_executable,
|
||||||
# make sure to skip non-default plugins.
|
# make sure to skip non-default plugins.
|
||||||
if(module_project_name STREQUAL PROJECT_NAME AND _default_plugin)
|
if(is_plugin_and_module_in_same_project AND _default_plugin)
|
||||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY _qt_repo_plugins "${target}")
|
set_property(TARGET ${qt_module_target} APPEND PROPERTY
|
||||||
set_property(TARGET ${qt_module_target} APPEND PROPERTY _qt_repo_plugin_class_names
|
_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>"
|
"$<TARGET_PROPERTY:${target},QT_PLUGIN_CLASS_NAME>"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
endif()
|
||||||
# TODO: If a repo A provides an internal executable E and a plugin P, with the plugin
|
|
||||||
# type belonging to a Qt module defined in a different repo, and executable E needs to
|
# Associate plugin with its Qt module when the plugin is built in the current repository
|
||||||
# link to plugin P in a static build, currently that won't happen. The executable E
|
# but the module is built in a different repository (qtsvg's QSvgPlugin associated with
|
||||||
# will link to plugins mentioned in the Qt module's _qt_repo_plugins property, but that
|
# qtbase's QtGui).
|
||||||
# property will not list P because the Qt module will be an imported target and won't
|
# The association is done in a separate property, to ensure that reconfiguring in-tree tests
|
||||||
# have a SOURCE_DIR or PROJECT NAME, so the checks above will not be met.
|
# in qtbase doesn't accidentally cause linking to a plugin from a previously built qtsvg.
|
||||||
# Figure out how to handle such a scenario.
|
# 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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user