summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@qt.io>2021-08-06 12:59:29 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-10-12 00:28:12 +0000
commit58136c0c706cc44e5f7f016b4297dbc9b38ef2ac (patch)
tree23827d2efa3826aceb9ab63a4cff55f8059422c3
parent7fcae4e1b51d8a9d1ba65fb1ade240ae8b204980 (diff)
Fix missing QT.<module>.run_depends entries in module .pri files
The .pri files for public Qt modules were missing run_depends entries. Those entries are used by qmake when linking plugins of a static Qt build. In shared builds, run_depends entries are used to decide whether to add the -rpath-link argument to the linker. In that matter, run_depends entries serve a similar purpose as CMake's IMPORTED_LINK_DEPENDENT_LIBRARIES. In Qt5, run_depends entries consist of the qmake values QT_PRIVATE and QT_FOR_PRIVATE. QT_PRIVATE contains the Qt modules that are privately linked to the public module, and QT_FOR_PRIVATE are the dependencies of the private module. That loosely translates to LINK_LIBRARIES of the public module and INTERFACE_LINK_LIBRARIES of the private module. Private modules whose public counterparts are already public dependencies don't have to be added to run_depends. Fixes: QTBUG-84310 Change-Id: If7025c98ea462a2d5a143202df3d98d88e4fee08 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> (cherry picked from commit 326b91ea788b013512ae911c51cc19497d88916d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--cmake/QtPriHelpers.cmake135
1 files changed, 118 insertions, 17 deletions
diff --git a/cmake/QtPriHelpers.cmake b/cmake/QtPriHelpers.cmake
index ad4625e542..6dd962b575 100644
--- a/cmake/QtPriHelpers.cmake
+++ b/cmake/QtPriHelpers.cmake
@@ -90,9 +90,37 @@ set(QMAKE_DEPENDS_${uclib}_LD, ${deps})
endfunction()
# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module.
+# The returned dependencies are "config module names", not target names.
+#
+# PRIVATE (OPTIONAL):
+# Retrieve private dependencies only. Dependencies that appear in both, LINK_LIBRARIES and
+# INTERFACE_LINK_LIBRARIES are discarded.
+#
function(qt_get_direct_module_dependencies target out_var)
+ cmake_parse_arguments(arg "PRIVATE" "" "" ${ARGN})
set(dependencies "")
- get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES)
+ if(arg_PRIVATE)
+ get_target_property(libs ${target} LINK_LIBRARIES)
+ get_target_property(public_libs ${target} INTERFACE_LINK_LIBRARIES)
+ list(REMOVE_DUPLICATES libs)
+ list(REMOVE_DUPLICATES public_libs)
+
+ # Remove all Qt::Foo and Qt6::Foo from libs that also appear in public_libs.
+ set(libs_to_remove "")
+ foreach(lib IN LISTS public_libs)
+ list(APPEND libs_to_remove "${lib}")
+ if(lib MATCHES "^Qt::(.*)")
+ list(APPEND libs_to_remove "${QT_CMAKE_EXPORT_NAMESPACE}::${CMAKE_MATCH_1}")
+ elseif(lib MATCHES "^{QT_CMAKE_EXPORT_NAMESPACE}::(.*)")
+ list(APPEND libs_to_remove "Qt::${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ list(REMOVE_DUPLICATES libs_to_remove)
+ list(REMOVE_ITEM libs ${libs_to_remove})
+ else()
+ get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES)
+ endif()
if(NOT libs)
set(libs "")
endif()
@@ -166,6 +194,60 @@ function(qt_internal_map_targets_to_qmake_libs out_var)
set(${out_var} "${result}" PARENT_SCOPE)
endfunction()
+# Retrieve the runtime dependencies of module ${target}.
+# The runtime dependencies are what in CMake is called IMPORTED_LINK_DEPENDENT_LIBRARIES.
+# This function returns the dependencies in out_var, separated by space.
+#
+# PUBLIC_DEPENDENCIES:
+# List of the module's public dependencies.
+# The dependencies are expected to be config module names.
+#
+# PUBLIC (OPTIONAL):
+# Specifies that target is a public module.
+# If not specified, a private module is assumed.
+#
+function(qt_internal_get_module_run_dependencies out_var target)
+ cmake_parse_arguments(arg "PUBLIC" "" "PUBLIC_DEPENDENCIES" ${ARGN})
+
+ # Private dependencies of the module are runtime dependencies.
+ qt_get_direct_module_dependencies(${target} run_dependencies PRIVATE)
+
+ # If ${target} is a public module then public dependencies
+ # of the private module are also runtime dependencies.
+ if(arg_PUBLIC AND TARGET ${target}Private)
+ qt_get_direct_module_dependencies(${target}Private qt_for_private)
+
+ # FooPrivate depends on Foo, but we must not record this dependency in run_depends.
+ get_target_property(config_module_name ${target} _qt_config_module_name)
+ list(REMOVE_ITEM qt_for_private ${config_module_name})
+
+ list(APPEND run_dependencies ${qt_for_private})
+ endif()
+
+ list(REMOVE_DUPLICATES run_dependencies)
+
+ # If foo-private is a private dependency and foo is a public dependency,
+ # we don't have to add foo-private as runtime dependency.
+ set(deps_to_remove "")
+ foreach(dep IN LISTS run_dependencies)
+ if(NOT dep MATCHES "(.*)_private$")
+ continue()
+ endif()
+
+ # Is foo a public dependency?
+ list(FIND arg_PUBLIC_DEPENDENCIES "${CMAKE_MATCH_1}" idx)
+ if(idx GREATER -1)
+ list(APPEND deps_to_remove "${dep}")
+ endif()
+ endforeach()
+ if(NOT "${deps_to_remove}" STREQUAL "")
+ list(REMOVE_ITEM run_dependencies ${deps_to_remove})
+ endif()
+
+ list(JOIN run_dependencies " " run_dependencies)
+ set("${out_var}" "${run_dependencies}" PARENT_SCOPE)
+endfunction()
+
# Generates module .pri files for consumption by qmake
function(qt_generate_module_pri_file target)
set(flags INTERNAL_MODULE HEADER_MODULE NO_PRIVATE_MODULE)
@@ -298,8 +380,8 @@ ${framework_base_path}/${fw_private_module_header_dir}")
"\nQT.${config_module_name}.plugin_types = ${module_plugin_types}")
endif()
- qt_get_direct_module_dependencies(${target} public_module_dependencies)
- list(JOIN public_module_dependencies " " public_module_dependencies)
+ qt_get_direct_module_dependencies(${target} public_module_dependencies_list)
+ list(JOIN public_module_dependencies_list " " public_module_dependencies)
set(public_module_dependencies "${module_depends} ${public_module_dependencies}")
qt_path_join(pri_file_name "${target_path}" "qt_lib_${config_module_name}.pri")
@@ -326,10 +408,12 @@ ${framework_base_path}/${fw_private_module_header_dir}")
qt_internal_map_targets_to_qmake_libs(module_uses ${dep_targets})
list(JOIN module_uses " " joined_module_uses)
- file(GENERATE
- OUTPUT "${pri_file_name}"
- CONTENT
- "QT.${config_module_name}.VERSION = ${PROJECT_VERSION}
+ # Retrieve the public module's runtime dependencies.
+ qt_internal_get_module_run_dependencies(public_module_run_dependencies ${target}
+ PUBLIC
+ PUBLIC_DEPENDENCIES "${public_module_dependencies_list}")
+
+ set(content "QT.${config_module_name}.VERSION = ${PROJECT_VERSION}
QT.${config_module_name}.name = ${module}
QT.${config_module_name}.module = ${module_name_in_pri}
QT.${config_module_name}.libs = $$QT_MODULE_LIB_BASE
@@ -338,7 +422,13 @@ QT.${config_module_name}.includes = ${public_module_includes}
QT.${config_module_name}.frameworks = ${public_module_frameworks}
QT.${config_module_name}.bins = $$QT_MODULE_BIN_BASE${module_plugin_types_assignment}
QT.${config_module_name}.depends = ${public_module_dependencies}
-QT.${config_module_name}.uses = ${joined_module_uses}
+")
+ if(NOT "${public_module_run_dependencies}" STREQUAL "")
+ string(APPEND content
+ "QT.${config_module_name}.run_depends = ${public_module_run_dependencies}\n")
+ endif()
+ string(APPEND content
+ "QT.${config_module_name}.uses = ${joined_module_uses}
QT.${config_module_name}.module_config = ${joined_module_internal_config}${module_build_config}
QT.${config_module_name}.DEFINES = ${joined_target_defines}
QT.${config_module_name}.enabled_features = ${enabled_features}
@@ -346,8 +436,8 @@ QT.${config_module_name}.disabled_features = ${disabled_features}${extra_assignm
QT_CONFIG += ${enabled_features}
QT_MODULES += ${config_module_name_base}
${module_pri_extra_content}
-"
- )
+")
+ file(GENERATE OUTPUT "${pri_file_name}" CONTENT "${content}")
if (NOT arg_NO_PRIVATE_MODULE AND NOT arg_INTERNAL_MODULE)
set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake")
@@ -371,22 +461,33 @@ ${module_pri_extra_content}
qt_internal_map_targets_to_qmake_libs(private_module_uses ${dep_targets})
list(JOIN private_module_uses " " joined_private_module_uses)
+ # Retrieve the private module's runtime dependencies.
+ qt_internal_get_module_run_dependencies(private_module_run_dependencies ${target}Private
+ PUBLIC_DEPENDENCIES "${dep_targets}")
+
# Generate a preliminary qt_lib_XXX_private.pri file
- file(GENERATE
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}"
- CONTENT
- "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION}
+ set(content
+ "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION}
QT.${config_module_name}_private.name = ${module}
QT.${config_module_name}_private.module =
QT.${config_module_name}_private.libs = $$QT_MODULE_LIB_BASE
QT.${config_module_name}_private.includes = ${private_module_includes}
QT.${config_module_name}_private.frameworks = ${private_module_frameworks}
QT.${config_module_name}_private.depends = ${private_module_dependencies}
-QT.${config_module_name}_private.uses = ${joined_private_module_uses}
+")
+ if(NOT "${private_module_run_dependencies}" STREQUAL "")
+ string(APPEND content
+ "QT.${config_module_name}_private.run_depends = ${private_module_run_dependencies}
+")
+ endif()
+ string(APPEND content
+ "QT.${config_module_name}_private.uses = ${joined_private_module_uses}
QT.${config_module_name}_private.module_config = ${joined_module_internal_config}
QT.${config_module_name}_private.enabled_features = ${enabled_private_features}
-QT.${config_module_name}_private.disabled_features = ${disabled_private_features}"
- )
+QT.${config_module_name}_private.disabled_features = ${disabled_private_features}")
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}"
+ CONTENT "${content}")
if(QT_GENERATOR_IS_MULTI_CONFIG)
set(configs ${CMAKE_CONFIGURATION_TYPES})