CMake: Build plugin initializers as object libs
Instead of compiling the plugin initializers as part of a user
project, pre-compile them as object libraries while building Qt.
The installed object libraries can then be used with
target_sources(qt_module INTERFACE $<TARGET_OBJECTS:plugin_init>)
so that they are linked into the final executable or shared library
via qt module usage requirement propagation.
This reduces the build times of user projects.
The link line placement of the object files should be correct for all
linux-y linkers because the only dependency for the object files is
Core and the Gui -> plugin -> Gui -> Core cycle does not hamper that
from empirical observations.
As a consequence of the recent change not to link plugin initialization
object files into static libraries, as well not having to compile the
files in user projects, we can get rid of the
_qt_internal_disable_static_default_plugins calls in various places.
A side note.
Consider a user static library (L) that links to a Qt static library
(Gui) which provides plugins (platform plugins).
If there is an executable (E) that links to (L), with no direct
dependency to any other Qt module and the intention is that the
executable will automatically get the platform plugin linked,
then (L) needs to link PUBLIC-ly to (Gui) so that the plugin usage
requirements are propagated successfully.
This is a limitation of using
target_sources(qt_module INTERFACE $<TARGET_OBJECTS:plugin_init>)
which will propagate object files across static libraries only if
qt_module is linked publicly.
One could try to use
target_link_libraries(qt_module
INTERFACE $<TARGET_OBJECTS:plugin_init>)
which preserves the linker arguments across static libs even if
qt_module is linked privately, but unfortunately CMake will lose
dependency information on Core, which means the object files might be
placed in the wrong place on the link line.
As far as I know this is a limitation of CMake that can't be worked
around at the moment.
Note this behavior was present before this change as well.
Task-number: QTBUG-80863
Task-number: QTBUG-92933
Change-Id: Ia99e8aa3d32d6197cacd6162515ac808f2c6c53f
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
bb10
parent
208dbb4c18
commit
91c65dd80c
|
|
@ -49,11 +49,6 @@ function(qt_internal_add_cmake_library target)
|
|||
endif()
|
||||
qt_skip_warnings_are_errors_when_repo_unclean("${target}")
|
||||
|
||||
# No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
|
||||
if(is_static_lib)
|
||||
_qt_internal_disable_static_default_plugins("${target}")
|
||||
endif()
|
||||
|
||||
if (arg_INSTALL_DIRECTORY)
|
||||
set(install_arguments
|
||||
ARCHIVE_INSTALL_DIRECTORY ${arg_ARCHIVE_INSTALL_DIRECTORY}
|
||||
|
|
@ -145,11 +140,6 @@ function(qt_internal_add_3rdparty_library target)
|
|||
qt_internal_add_target_aliases(${target})
|
||||
_qt_internal_apply_strict_cpp(${target})
|
||||
|
||||
# No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
|
||||
if(is_static_lib)
|
||||
_qt_internal_disable_static_default_plugins("${target}")
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
qt_android_apply_arch_suffix("${target}")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -144,11 +144,6 @@ function(qt_internal_add_module target)
|
|||
qt_skip_warnings_are_errors_when_repo_unclean("${target}")
|
||||
_qt_internal_apply_strict_cpp("${target}")
|
||||
|
||||
# No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
|
||||
if(is_static_lib)
|
||||
_qt_internal_disable_static_default_plugins("${target}")
|
||||
endif()
|
||||
|
||||
# Add _private target to link against the private headers:
|
||||
if(NOT ${arg_NO_PRIVATE_MODULE})
|
||||
set(target_private "${target}Private")
|
||||
|
|
|
|||
|
|
@ -119,10 +119,6 @@ function(qt_internal_add_plugin target)
|
|||
qt_skip_warnings_are_errors_when_repo_unclean("${target}")
|
||||
_qt_internal_apply_strict_cpp("${target}")
|
||||
|
||||
# Disable linking of plugins against other plugins during static regular and
|
||||
# super builds. The latter causes cyclic dependencies otherwise.
|
||||
_qt_internal_disable_static_default_plugins("${target}")
|
||||
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${output_directory}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
|
||||
|
|
@ -322,8 +318,13 @@ function(qt_internal_add_plugin target)
|
|||
endforeach()
|
||||
|
||||
qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
|
||||
set(plugin_init_target "")
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
qt_generate_plugin_pri_file("${target}" pri_file)
|
||||
|
||||
if(qt_module_target)
|
||||
__qt_internal_add_static_plugin_init_object_library("${target}" plugin_init_target)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT arg_SKIP_INSTALL)
|
||||
|
|
@ -372,10 +373,13 @@ function(qt_internal_add_plugin target)
|
|||
# Make the export name of plugins be consistent with modules, so that
|
||||
# qt_add_resource adds its additional targets to the same export set in a static Qt build.
|
||||
set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets")
|
||||
qt_install(TARGETS "${target}"
|
||||
qt_install(TARGETS
|
||||
"${target}"
|
||||
${plugin_init_target}
|
||||
EXPORT ${export_name}
|
||||
RUNTIME DESTINATION "${install_directory}"
|
||||
LIBRARY DESTINATION "${install_directory}"
|
||||
OBJECTS DESTINATION "${install_directory}"
|
||||
ARCHIVE DESTINATION "${archive_install_directory}"
|
||||
)
|
||||
qt_install(EXPORT ${export_name}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# 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
|
||||
plugin_target
|
||||
out_var_has_plugin_type
|
||||
|
|
@ -17,8 +19,8 @@ function(__qt_internal_plugin_get_plugin_type
|
|||
set(${out_var_has_plugin_type} "${has_plugin_type}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Gets the qt plugin class name of the given target into out_var.
|
||||
function(__qt_internal_plugin_has_class_name plugin_target out_var)
|
||||
|
||||
set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
|
||||
|
||||
get_target_property(classname "${plugin_target_versioned}" QT_PLUGIN_CLASS_NAME)
|
||||
|
|
@ -118,6 +120,7 @@ function(__qt_internal_get_static_plugin_condition_genex
|
|||
set(${out_var} "${_plugin_condition}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Link plugin via usage requirements of associated Qt module.
|
||||
function(__qt_internal_add_static_plugin_linkage plugin_target qt_module_target)
|
||||
__qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition)
|
||||
|
||||
|
|
@ -128,36 +131,77 @@ function(__qt_internal_add_static_plugin_linkage plugin_target qt_module_target)
|
|||
target_link_libraries(${qt_module_target} INTERFACE "${plugin_genex}")
|
||||
endfunction()
|
||||
|
||||
# Generates C++ import macro source code for given plugin
|
||||
function(__qt_internal_get_plugin_import_macro plugin_target out_var)
|
||||
set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
|
||||
get_target_property(class_name "${plugin_target_versioned}" QT_PLUGIN_CLASS_NAME)
|
||||
set(${out_var} "Q_IMPORT_PLUGIN(${class_name})" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(__qt_internal_get_plugin_include_prelude out_var)
|
||||
set(${out_var} "#include <QtPlugin>\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Set up plugin initialization via usage requirements of associated Qt module.
|
||||
#
|
||||
# Adds the plugin init object library as an INTERFACE source of the plugin target.
|
||||
# This is similar to how it was done before, except instead of generating a C++ file and compiling
|
||||
# it as part of the user project, we just specify the pre-compiled object file as an INTERFACE
|
||||
# source so that user projects don't have to compile it. User project builds will thus be shorter.
|
||||
function(__qt_internal_add_static_plugin_import_macro
|
||||
plugin_target
|
||||
qt_module_target
|
||||
qt_module_unprefixed)
|
||||
set(_generated_qt_plugin_file_name
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.qt_plugins/qt_${qt_module_unprefixed}_${plugin_target}.cpp")
|
||||
|
||||
set(plugin_target_versioned "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
|
||||
get_target_property(class_name "${plugin_target_versioned}" QT_PLUGIN_CLASS_NAME)
|
||||
__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(_generated_qt_plugin_file_content "#include <QtPlugin>\nQ_IMPORT_PLUGIN(${class_name})")
|
||||
|
||||
# Generate a source file to import that plug-in. Be careful not to
|
||||
# update the timestamp of the generated file if we are not going to
|
||||
# change anything. Otherwise we will trigger CMake's autogen to re-run
|
||||
# and executables will then need to at least relink.
|
||||
set(need_write TRUE)
|
||||
if(EXISTS ${_generated_qt_plugin_file_name})
|
||||
file(READ ${_generated_qt_plugin_file_name} old_contents)
|
||||
if(old_contents STREQUAL "${_generated_qt_plugin_file_content}")
|
||||
set(need_write FALSE)
|
||||
endif()
|
||||
endif()
|
||||
if(need_write)
|
||||
file(WRITE "${_generated_qt_plugin_file_name}"
|
||||
"${_generated_qt_plugin_file_content}")
|
||||
endif()
|
||||
|
||||
__qt_internal_get_static_plugin_condition_genex("${plugin_target}" plugin_condition)
|
||||
|
||||
target_sources(${qt_module_target} INTERFACE
|
||||
"$<${plugin_condition}:${_generated_qt_plugin_file_name}>")
|
||||
target_sources(${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target} INTERFACE
|
||||
"${objs_genex}")
|
||||
endfunction()
|
||||
|
||||
# Get target name of object library which is used to initialize a qt plugin.
|
||||
function(__qt_internal_get_static_plugin_init_target_name plugin_target out_var)
|
||||
# Keep the target name short, so we don't hit long path issues on Windows.
|
||||
set(plugin_init_target "${plugin_target}_init")
|
||||
|
||||
set(${out_var} "${plugin_init_target}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Create an object library that initializes a static qt plugin.
|
||||
#
|
||||
# The object library contains a single generated C++ file that calls Q_IMPORT_PLUGIN(plugin_class).
|
||||
# The object library is exported as part of the Qt build and consumed by user applications
|
||||
# that link to qt plugins.
|
||||
#
|
||||
# The created target name is assigned to 'out_var_plugin_init_target'.
|
||||
function(__qt_internal_add_static_plugin_init_object_library
|
||||
plugin_target
|
||||
out_var_plugin_init_target)
|
||||
|
||||
__qt_internal_get_plugin_import_macro(${plugin_target} import_macro)
|
||||
__qt_internal_get_plugin_include_prelude(include_prelude)
|
||||
set(import_content "${include_prelude}${import_macro}")
|
||||
|
||||
string(MAKE_C_IDENTIFIER "${plugin_target}" plugin_target_identifier)
|
||||
set(generated_qt_plugin_file_name
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${plugin_target_identifier}_init.cpp")
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT "${generated_qt_plugin_file_name}"
|
||||
CONTENT "${import_content}"
|
||||
)
|
||||
|
||||
__qt_internal_get_static_plugin_init_target_name("${plugin_target}" plugin_init_target)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
set(${out_var_plugin_init_target} "${plugin_init_target}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
|
|
|||
|
|
@ -1373,9 +1373,6 @@ function(__qt_propagate_generated_resource target resource_name generated_source
|
|||
target_link_libraries(${target} INTERFACE ${resource_target})
|
||||
endif()
|
||||
set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
|
||||
|
||||
# No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
|
||||
_qt_internal_disable_static_default_plugins("${resource_target}")
|
||||
else()
|
||||
set(${output_generated_target} "" PARENT_SCOPE)
|
||||
target_sources(${target} PRIVATE ${generated_source_code})
|
||||
|
|
|
|||
Loading…
Reference in New Issue