qt5base-lts/cmake/QtPluginHelpers.cmake

610 lines
26 KiB
CMake
Raw Normal View History

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Note that these are only the keywords that are unique to qt_internal_add_plugin().
# That function also supports the keywords defined by _qt_internal_get_add_plugin_keywords().
macro(qt_internal_get_internal_add_plugin_keywords option_args single_args multi_args)
set(${option_args}
EXCEPTIONS
ALLOW_UNDEFINED_SYMBOLS
SKIP_INSTALL
NO_UNITY_BUILD
)
set(${single_args}
OUTPUT_DIRECTORY
INSTALL_DIRECTORY
ARCHIVE_INSTALL_DIRECTORY
${__default_target_info_args}
)
set(${multi_args}
${__default_private_args}
${__default_public_args}
DEFAULT_IF
)
endmacro()
# This is the main entry point for defining Qt plugins.
# A CMake target is created with the given target.
# The target name should end with "Plugin" so static plugins are linked automatically.
# The PLUGIN_TYPE parameter is needed to place the plugin into the correct plugins/ sub-directory.
function(qt_internal_add_plugin target)
qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}")
_qt_internal_get_add_plugin_keywords(
public_option_args
public_single_args
public_multi_args
)
qt_internal_get_internal_add_plugin_keywords(
internal_option_args
internal_single_args
internal_multi_args
)
set(option_args ${public_option_args} ${internal_option_args})
set(single_args ${public_single_args} ${internal_single_args})
set(multi_args ${public_multi_args} ${internal_multi_args})
cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
"${single_args}"
"${multi_args}"
)
_qt_internal_validate_all_args_are_parsed(arg)
# Put this behind a cache option for now. It's too noisy for general use
# until most repos are updated.
option(QT_WARN_PLUGIN_PUBLIC_KEYWORDS "Warn if a plugin specifies a PUBLIC keyword" ON)
if(QT_WARN_PLUGIN_PUBLIC_KEYWORDS)
foreach(publicKeyword IN LISTS __default_public_args)
if(NOT "${arg_${publicKeyword}}" STREQUAL "")
string(REPLACE "PUBLIC_" "" privateKeyword "${publicKeyword}")
message(AUTHOR_WARNING
"Plugins are not intended to be linked to. "
"They should not have any public properties, but ${target} "
"sets ${publicKeyword} to the following value:\n"
" ${arg_${publicKeyword}}\n"
"Update your project to use ${privateKeyword} instead.\n")
endif()
endforeach()
endif()
qt_remove_args(plugin_args
ARGS_TO_REMOVE
${internal_option_args}
${internal_single_args}
${internal_multi_args}
ALL_ARGS
${option_args}
${single_args}
${multi_args}
ARGS
${ARGN}
)
CMake: Create plugin initializers for static user plugins Previously we only created object library static plugin initializers for Qt plugins only, not user-project plugins. The reason was that if a user tried to install the plugin target via an export set, CMake would error out saying that the _init library is not part of the same export set. Introduce an OUTPUT_TARGETS option that would allow projects to get the name of the generated _init target, so they can install it if needed. This was already done for qt6_add_qml_module, so we just introduce the same option for qt6_add_plugin. Now user static plugins will have an _init target created, which will be propagated to consumers whenever the consumers link against the plugin itself. We also need an internal option to disable this propagation, because it's handled a bit differently for Qt plugins which can be linked either via finalizers or via usage requirements. Amends 91c65dd80cdd2de666448c14202c0c63718152b6 As a result of the implementation change, cleanup example projects to ensure that they build successfully (the important part is specifying the CLASS_NAME). Only plugandpaint works properly with both shared and static Qt builds. echoplugin works with a shared Qt build, but not a static one due to some assumptions in the C++ code about shared plugins. styleplugin doesn't seem to work properly neither with shared Qt builds nor static Qt builds, at least on macOS. But it builds fine. For some reason even if the plugin is found, the style is not applied. Amends 4caac1feea025b0ad496141e8f16ab88c04c2caa Pick-to: 6.2 Task-number: QTBUG-80863 Task-number: QTBUG-92933 Change-Id: I6f631cda9566229b7a63992b23d7d7fa50303eeb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
2021-08-19 09:42:12 +00:00
# When creating a static plugin, retrieve the plugin initializer target name, but don't
# automatically propagate the plugin initializer.
list(APPEND plugin_args
__QT_INTERNAL_NO_PROPAGATE_PLUGIN_INITIALIZER
OUTPUT_TARGETS plugin_init_target
)
qt6_add_plugin(${target} ${plugin_args})
qt_internal_mark_as_internal_library(${target})
set(plugin_type "")
# TODO: Transitional: Remove the TYPE option handling after all repos have been converted to use
# PLUGIN_TYPE.
if(arg_TYPE)
set(plugin_type "${arg_TYPE}")
elseif(arg_PLUGIN_TYPE)
set(plugin_type "${arg_PLUGIN_TYPE}")
endif()
if((NOT plugin_type STREQUAL "qml_plugin") AND (NOT target MATCHES "(.*)Plugin$"))
message(AUTHOR_WARNING "The internal plugin target name '${target}' should end with the 'Plugin' suffix.")
endif()
qt_get_sanitized_plugin_type("${plugin_type}" plugin_type_escaped)
set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${plugin_type}")
set(install_directory_default "${INSTALL_PLUGINSDIR}/${plugin_type}")
qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${plugin_type}"
"${output_directory_default}" output_directory)
if (NOT arg_SKIP_INSTALL)
qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}"
"${plugin_type}"
"${install_directory_default}" install_directory)
set(archive_install_directory ${arg_ARCHIVE_INSTALL_DIRECTORY})
if (NOT archive_install_directory AND install_directory)
set(archive_install_directory "${install_directory}")
endif()
endif()
qt_set_target_info_properties(${target} ${ARGN})
CMake: Record used package version for each target dependency When recording which package version to look for in QtFooModuleDependencies.cmake and other files like it, instead of using PROJECT_VERSION, use the version of the package that contains the dependency. For example if we're hypothetically building the qtdeclarative repo from the 6.4 branch, against an installed 6.2 qtbase, then the Qt6QmlModuleDependencies.cmake file will have a find_package(Qt6Core 6.2) call because qtdeclarative's find_package(Qt6Core) call found a 6.2 Core when it was configured. This allows switching the versioning scheme of specific Qt modules that might not want to follow the general Qt versioning scheme. The first candidate would be QtWebEngine which might want to follow the Chromium versioning scheme, something like Qt 6.94.0 where 94 is the Chromium major version. Implementation notes. We now record the package version of a target in a property called _qt_package_version. We do it for qt modules, plugins, 3rd party libraries, tools and the Platform target. When we try to look up which version to write into the QtFooModuleDependencies.cmake file (or the equivalent Plugins and Tools file), we try to find the version from a few sources: the property mentioned above, then the Qt6{target}_VERSION variable, and finally PROJECT_VERSION. In the latter case, we issue a warning because technically that should never have to happen, and it's a bug or an unforeseen case if it does. A few more places also need adjustments: - package versions to look for when configuring standalone tests and generating standalone tests Config files - handling of tools packages - The main Qt6 package lookup in each Dependencies.cmake files Note that there are some requirements and consequences in case a module wants to use a different versioning scheme like 6.94.0. Requirements. - The root CMakeLists.txt file needs to call find_package with a version different from the usual PROJECT_VERSION. Ideally it should look for a few different Qt versions which are known to be compatible, for example the last stable and LTS versions, or just the lowest supported Qt version, e.g. 6.2.6 or whenever this change would land in the 6.2 branch. - If the repository has multiple modules, some of which need to follow the Qt versioning scheme and some not, project(VERSION x.y.z) calls need to be carefully placed in subdirectory scopes with appropriate version numbers, so that qt_internal_add_module / _tool / _plugin pick up the correct version. Consequences. - The .so / .dylib names will contain the new version, e.g. .so.6.94 - Linux ELF symbols will contain the new versions - syncqt private headers will now exist under a include/QtFoo/6.94.0/QtFoo/private folder - pri and prl files will also contain the new version numbers - pkg-config .pc files contain the new version numbers - It won't be possible to write find_package(Qt6 6.94 COMPONENTS WebEngineWidgets) in user code. One would have to write find_package(Qt6WebEngineWidgets 6.94) otherwise CMake will try to look for Qt6Config 6.94 which won't exist. - Similarly, a find_package(Qt6 6.4 COMPONENTS Widgets WebEngineWidgets) call would always find any kind of WebEngine package that is higher than 6.4, which might be 6.94, 6.95, etc. - In the future, if we fix Qt6Config to pass EXACT to its subcomponent find_package calls, a find_package(Qt6 6.5.0 EXACT COMPONENTS Widgets WebEngineWidgets) would fail to find WebEngineWidgets, because its 6.94.0 version will not be equal to 6.5.0. Currently we don't pass through EXACT, so it's not an issue. Augments 5ffc744b791a114a3180a425dd26e298f7399955 Task-number: QTBUG-103500 Change-Id: I8bdb56bfcbc7f7f6484d1e56651ffc993fd30bab Reviewed-by: Michal Klocek <michal.klocek@qt.io> Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
2022-05-17 06:44:43 +00:00
set_target_properties(${target} PROPERTIES
_qt_package_version "${PROJECT_VERSION}"
)
set_property(TARGET ${target}
APPEND PROPERTY
EXPORT_PROPERTIES "_qt_package_version")
# Override the OUTPUT_NAME that qt6_add_plugin() set, we need to account for
# QT_LIBINFIX, which is specific to building Qt.
# Make sure the Qt6 plugin library names are like they were in Qt5 qmake land.
# Whereas the Qt6 CMake target names are like the Qt5 CMake target names.
get_target_property(output_name ${target} OUTPUT_NAME)
set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}${QT_LIBINFIX}")
# Add a custom target with the Qt5 qmake name for a more user friendly ninja experience.
if(arg_OUTPUT_NAME AND NOT TARGET "${output_name}")
# But don't create such a target if it would just differ in case from "${target}"
# and we're not using Ninja. See https://gitlab.kitware.com/cmake/cmake/-/issues/21915
string(TOUPPER "${output_name}" uc_output_name)
string(TOUPPER "${target}" uc_target)
if(NOT uc_output_name STREQUAL uc_target OR CMAKE_GENERATOR MATCHES "^Ninja")
add_custom_target("${output_name}")
add_dependencies("${output_name}" "${target}")
endif()
endif()
qt_set_common_target_properties("${target}")
qt_internal_add_target_aliases("${target}")
qt_skip_warnings_are_errors_when_repo_unclean("${target}")
_qt_internal_apply_strict_cpp("${target}")
set_target_properties("${target}" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${output_directory}"
RUNTIME_OUTPUT_DIRECTORY "${output_directory}"
ARCHIVE_OUTPUT_DIRECTORY "${output_directory}"
QT_PLUGIN_TYPE "${plugin_type_escaped}"
# Save the non-sanitized plugin type values for qmake consumption via .pri files.
QT_QMAKE_PLUGIN_TYPE "${plugin_type}"
)
qt_handle_multi_config_output_dirs("${target}")
qt_internal_library_deprecation_level(deprecation_define)
qt_autogen_tools_initial_setup(${target})
unset(plugin_install_package_suffix)
# The generic plugins should be enabled by default.
# But platform plugins should always be disabled by default, and only one is enabled
# based on the platform (condition specified in arg_DEFAULT_IF).
if(plugin_type_escaped STREQUAL "platforms")
set(_default_plugin 0)
else()
set(_default_plugin 1)
endif()
if(DEFINED arg_DEFAULT_IF)
if(${arg_DEFAULT_IF})
set(_default_plugin 1)
else()
set(_default_plugin 0)
endif()
endif()
# Save the Qt module in the plug-in's properties and vice versa
if(NOT plugin_type_escaped STREQUAL "qml_plugin")
qt_internal_get_module_for_plugin("${target}" "${plugin_type_escaped}" qt_module)
set(qt_module_target "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}")
if(NOT TARGET "${qt_module_target}")
message(FATAL_ERROR "Failed to associate Qt plugin with Qt module. ${qt_module_target} is not a known CMake target")
endif()
set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}")
set(plugin_install_package_suffix "${qt_module}")
get_target_property(aliased_target ${qt_module_target} ALIASED_TARGET)
if(aliased_target)
set(qt_module_target ${aliased_target})
endif()
get_target_property(is_imported_qt_module ${qt_module_target} IMPORTED)
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.
set_property(TARGET "${qt_module_target}" APPEND PROPERTY QT_PLUGINS "${target}")
endif()
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()
Replace the syncqt.pl script with syncqt tool syncqt.pl adds an extra dependency on perl when building Qt. Modern C++ provides the convenient cross-platform way to access a filesystem and to use regular expressions, so we may replace the perl script with C++ application. The syncqt executable is built at configure time and installed as QtCore tool. It's running at configure time to deliver the required header files for IDE to build a consistent code model and at the build time to keep tracking changes in header files and generate the missing aliases without reconfiguring. 'syncqt' only parses header files from a CMake build tree, so the resulting Qt installation only contains interfacing headers that belong to the platform that Qt is built for. 'sync.profile' files are not used as the 'source of truth' for sync qt procedure anymore, all the necessary information is taken from either CMake files at configure time or from the module header files while parsing them. syncqt.pl is still in place since it's required as fallback solution for a smooth transition to the new syncqt implementation for all qt repositories. This patchset only enables the C++ based syncqt for 'qtbase' repository. From the performance perspective C++ version works faster then perl script, also the configure time is reduced significally on subsequent reconfigurations - up x2 times faster when re-configuring repository, but it also takes time to compile the tool itself the first time. Numbers for qtbase: syncqt.pl syncqt.cpp initial: 0m16,035s 0m20,413s reconfig: 0m6,819s 0m3,725s The syncing procedure can be run separately for each module using <ModuleName>_sync_headers targets. The 'sync_headers' target can be used to sync all the modules at once. Task-number: QTBUG-87480 Task-number: QTBUG-103196 Change-Id: I8c938bcaf88a8713b39bbfd66d9e7ef12b2c3523 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
2022-08-15 16:29:41 +00:00
qt_internal_add_autogen_sync_header_dependencies(${target} ${qt_module_target})
endif()
# Change the configuration file install location for qml plugins into the Qml package location.
if(plugin_type_escaped STREQUAL "qml_plugin" AND TARGET "${INSTALL_CMAKE_NAMESPACE}::Qml")
set(plugin_install_package_suffix "Qml/QmlPlugins")
endif()
# Save the install package suffix as a property, so that the Dependencies file is placed
# in the correct location.
if(plugin_install_package_suffix)
set_target_properties("${target}" PROPERTIES
_qt_plugin_install_package_suffix "${plugin_install_package_suffix}")
endif()
if(TARGET qt_plugins)
add_dependencies(qt_plugins "${target}")
endif()
# Record plugin for current repo.
if(qt_repo_plugins AND TARGET ${qt_repo_plugins})
add_dependencies(${qt_repo_plugins} "${target}")
endif()
if(plugin_type STREQUAL "platforms")
if(TARGET qpa_plugins)
add_dependencies(qpa_plugins "${target}")
endif()
if(_default_plugin AND TARGET qpa_default_plugins)
add_dependencies(qpa_default_plugins "${target}")
endif()
endif()
set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}")
set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN")
set(private_includes
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
# For the syncqt headers
"$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>"
${arg_INCLUDE_DIRECTORIES}
)
set(public_includes
${arg_PUBLIC_INCLUDE_DIRECTORIES}
)
if(arg_NO_UNITY_BUILD)
set(arg_NO_UNITY_BUILD "NO_UNITY_BUILD")
else()
set(arg_NO_UNITY_BUILD "")
endif()
qt_internal_extend_target("${target}"
${arg_NO_UNITY_BUILD}
SOURCES ${arg_SOURCES}
NO_UNITY_BUILD_SOURCES
${arg_NO_UNITY_BUILD_SOURCES}
INCLUDE_DIRECTORIES
${private_includes}
SYSTEM_INCLUDE_DIRECTORIES
${arg_SYSTEM_INCLUDE_DIRECTORIES}
PUBLIC_INCLUDE_DIRECTORIES
${public_includes}
LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
DEFINES
${arg_DEFINES}
${deprecation_define}
PUBLIC_DEFINES
${arg_PUBLIC_DEFINES}
FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES}
DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES}
DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS}
DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES}
DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS}
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS}
LINK_OPTIONS ${arg_LINK_OPTIONS}
PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS}
MOC_OPTIONS ${arg_MOC_OPTIONS}
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
)
qt_internal_add_repo_local_defines("${target}")
qt_internal_set_exceptions_flags("${target}" ${arg_EXCEPTIONS})
set(qt_libs_private "")
qt_internal_get_qt_all_known_modules(known_modules)
foreach(it ${known_modules})
list(FIND arg_LIBRARIES "Qt::${it}Private" pos)
if(pos GREATER -1)
list(APPEND qt_libs_private "Qt::${it}Private")
endif()
endforeach()
qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}")
get_target_property(target_type "${target}" TYPE)
if(target_type STREQUAL STATIC_LIBRARY)
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>
2021-05-11 09:19:19 +00:00
if(qt_module_target)
qt_internal_link_internal_platform_for_object_library("${plugin_init_target}")
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>
2021-05-11 09:19:19 +00:00
endif()
endif()
if (NOT arg_SKIP_INSTALL)
# Handle creation of cmake files for consumers of find_package().
# If we are part of a Qt module, the plugin cmake files are installed as part of that
# module.
# For qml plugins, they are all installed into the QtQml package location for automatic
# discovery.
if(plugin_install_package_suffix)
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${plugin_install_package_suffix}")
else()
set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}")
endif()
qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix})
qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix})
qt_internal_export_additional_targets_file(
CMake: Allow promoting the Qt libraries to be global targets User projects can set the QT_PROMOTE_TO_GLOBAL_TARGETS variable to true so that the various imported targets created by find_package(Qt6) are promoted to global targets. This would allow a project to find Qt packages in a subdirectory scope while using those Qt targets from a different scope. E.g. it fixes errors like CMake Error at CMakeLists.txt:5 (target_link_libraries): Error evaluating generator expression: $<TARGET_OBJECTS:Qt6::Widgets_resources_1> Objects of target "Qt6::Widgets_resources_1" referenced but no such target exists. when trying to use a static Qt from a sibling scope. Various 3rd party dependency targets (like Atomic or ZLIB) are not made global due to limitations in CMake, but as long as those targets are not mentioned directly, it shouldn't cause issues. The targets are made global in the generated QtFooAdditionalTargetInfo.cmake file. To ensure that resource object libraries promoted, the generation of the file has to be done at the end of the defining scope where qt_internal_export_additional_targets_file is called, which is achieved with a deferred finalizer. Replaced all occurrences of target promotion with a helper function which allows tracing of all promoted targets by specifying --log-level=debug to CMake. Pick-to: 6.2 Fixes: QTBUG-92878 Change-Id: Ic4ec03b0bc383d7e591a58c520c3974fbea746d2 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
2021-05-20 11:38:30 +00:00
TARGETS ${target} ${plugin_init_target}
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
CONFIG_INSTALL_DIR "${config_install_dir}")
CMake: Enable NEW policies by CMake version with a global default When a CMake release introduces a new policy that affects most Qt modules, it may be appropriate to make each module aware of that newer CMake version and use the NEW policy without raising the minimum CMake version requirement. To reduce the churn associated with making that change across all Qt modules individually, this change allows it to be updated in a central place (qtbase), but in a way that allows a Qt module to override it in its own .cmake.conf file if required (e.g. to address the issues identified by policy warnings at a later time). The policies are modified at the start of the call to qt_build_repo_begin(). For commands defined by the qtbase module, qtbase needs to be in control of the policy settings at the point where those commands are defined. The above mechanism should not affect the policy settings for these commands, so the various *Config.cmake.in files must not specify policy ranges in a way that a Qt module's .cmake.conf file could influence. Starting with CMake 3.12, policies can be specified as a version range with the cmake_minimum_required() and cmake_policy() commands. All policies introduced in CMake versions up to the upper limit of that range will be set to NEW. The actual version of CMake being used only has to be at least the lower limit of the specified version range. This change uses cmake_minimum_required() rather than cmake_policy() due to the latter not halting further processing upon failure. See the following: https://gitlab.kitware.com/cmake/cmake/-/issues/21557 Task-number: QTBUG-88700 Pick-to: 6.0 Change-Id: I0a1f2611dd629f847a18186394f500d7f52753bc Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
2020-11-30 07:46:49 +00:00
qt_internal_get_min_new_policy_cmake_version(min_new_policy_version)
qt_internal_get_max_new_policy_cmake_version(max_new_policy_version)
configure_package_config_file(
"${QT_CMAKE_DIR}/QtPluginConfig.cmake.in"
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
INSTALL_DESTINATION "${config_install_dir}"
)
write_basic_package_version_file(
CMake: Allow disabling package version check When building Qt repos, all find_package(Qt6) calls request a PROJECT_VERSION version which is set in .cmake.conf via QT_REPO_MODULE_VERSION. This means trying to configure qtsvg from a 6.3 branch using a 6.2 qtbase won't work, because qtsvg will call find_package(Qt6 6.3) and no such Qt6 package version exists. There are certain scenarios where it might be useful to try to do that though. One of them is doing Qt development while locally mixing branches. Another is building a 6.4 QtWebEngine against a 6.2 Qt. Allow to opt out of the version check by configuring each Qt repo with -DQT_NO_PACKAGE_VERSION_CHECK=TRUE. This setting is not recorded and will have to be set again when configuring another repo. The version check will also be disabled by default when configuring with the -developer-build feature. This will be recorded and embedded into each ConfigVersion file. If the version check is disabled, a warning will be shown mentioning the incompatible version of a package that was found but that package will still be accepted. The warning will show both when building Qt or using Qt in a user project. The warnings can be disabled by passing -DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE Furthermore when building a Qt repo, another warning will show when an incompatible package version is detected, to suggest to the Qt builder whether they want to use the incompatible version by disabling the version check. Note that there are no compatibility promises when using mixed non-matching versions. Things might not work. These options are only provided for convenience and their users know what they are doing. Pick-to: 6.2 Fixes: QTBUG-96458 Change-Id: I1a42e0b2a00b73513d776d89a76102ffd9136422 Reviewed-by: Craig Scott <craig.scott@qt.io>
2021-10-22 11:38:00 +00:00
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
CMake: Allow disabling package version check When building Qt repos, all find_package(Qt6) calls request a PROJECT_VERSION version which is set in .cmake.conf via QT_REPO_MODULE_VERSION. This means trying to configure qtsvg from a 6.3 branch using a 6.2 qtbase won't work, because qtsvg will call find_package(Qt6 6.3) and no such Qt6 package version exists. There are certain scenarios where it might be useful to try to do that though. One of them is doing Qt development while locally mixing branches. Another is building a 6.4 QtWebEngine against a 6.2 Qt. Allow to opt out of the version check by configuring each Qt repo with -DQT_NO_PACKAGE_VERSION_CHECK=TRUE. This setting is not recorded and will have to be set again when configuring another repo. The version check will also be disabled by default when configuring with the -developer-build feature. This will be recorded and embedded into each ConfigVersion file. If the version check is disabled, a warning will be shown mentioning the incompatible version of a package that was found but that package will still be accepted. The warning will show both when building Qt or using Qt in a user project. The warnings can be disabled by passing -DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE Furthermore when building a Qt repo, another warning will show when an incompatible package version is detected, to suggest to the Qt builder whether they want to use the incompatible version by disabling the version check. Note that there are no compatibility promises when using mixed non-matching versions. Things might not work. These options are only provided for convenience and their users know what they are doing. Pick-to: 6.2 Fixes: QTBUG-96458 Change-Id: I1a42e0b2a00b73513d776d89a76102ffd9136422 Reviewed-by: Craig Scott <craig.scott@qt.io>
2021-10-22 11:38:00 +00:00
qt_internal_write_qt_package_version_file(
"${INSTALL_CMAKE_NAMESPACE}${target}"
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
)
qt_install(FILES
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake"
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake"
CMake: Allow disabling package version check When building Qt repos, all find_package(Qt6) calls request a PROJECT_VERSION version which is set in .cmake.conf via QT_REPO_MODULE_VERSION. This means trying to configure qtsvg from a 6.3 branch using a 6.2 qtbase won't work, because qtsvg will call find_package(Qt6 6.3) and no such Qt6 package version exists. There are certain scenarios where it might be useful to try to do that though. One of them is doing Qt development while locally mixing branches. Another is building a 6.4 QtWebEngine against a 6.2 Qt. Allow to opt out of the version check by configuring each Qt repo with -DQT_NO_PACKAGE_VERSION_CHECK=TRUE. This setting is not recorded and will have to be set again when configuring another repo. The version check will also be disabled by default when configuring with the -developer-build feature. This will be recorded and embedded into each ConfigVersion file. If the version check is disabled, a warning will be shown mentioning the incompatible version of a package that was found but that package will still be accepted. The warning will show both when building Qt or using Qt in a user project. The warnings can be disabled by passing -DQT_NO_PACKAGE_VERSION_INCOMPATIBLE_WARNING=TRUE Furthermore when building a Qt repo, another warning will show when an incompatible package version is detected, to suggest to the Qt builder whether they want to use the incompatible version by disabling the version check. Note that there are no compatibility promises when using mixed non-matching versions. Things might not work. These options are only provided for convenience and their users know what they are doing. Pick-to: 6.2 Fixes: QTBUG-96458 Change-Id: I1a42e0b2a00b73513d776d89a76102ffd9136422 Reviewed-by: Craig Scott <craig.scott@qt.io>
2021-10-22 11:38:00 +00:00
"${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersionImpl.cmake"
DESTINATION "${config_install_dir}"
COMPONENT Devel
)
# 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")
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>
2021-05-11 09:19:19 +00:00
qt_install(TARGETS
"${target}"
${plugin_init_target}
EXPORT ${export_name}
RUNTIME DESTINATION "${install_directory}"
LIBRARY DESTINATION "${install_directory}"
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>
2021-05-11 09:19:19 +00:00
OBJECTS DESTINATION "${install_directory}"
ARCHIVE DESTINATION "${archive_install_directory}"
)
qt_install(EXPORT ${export_name}
NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
DESTINATION "${config_install_dir}"
)
if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
CMake: Work around build rpath issue when CMAKE_STAGING_PREFIX is set CMake has logic to rewrite build rpaths that contain CMAKE_STAGING_PREFIX to instead point to CMAKE_INSTALL_PREFIX. This breaks running executables from the build directory, because their build rpath will point to a location where the libraries might not exist yet (we didn't install Qt yet). Work around this by setting CMAKE_STAGING_PREFIX to a fake path, so that CMake does not do the rewriting anymore. CMAKE_STAGING_PREFIX needs to be set at subdirectory scope, not function scope, which is why qt_internal_apply_staging_prefix_build_rpath_workaround() is a macro that is called from within each Qt internal function that creates a target. The workaround can be disabled by configuring with -DQT_NO_STAGING_PREFIX_BUILD_RPATH_WORKAROUND=ON The downside of this workaround is that it breaks per-subdirectory install rules like 'ninja src/gui/install'. Regular global installation like 'ninja install' works fine. This is similar to what we do for tests in qt_set_up_fake_standalone_tests_install_prefix() introduced by 20292250d44e08437306096e9096fc655cc9fb8b The reason it's not as good for other target types is because in contrast to tests, we do want to install them. In case if someone does call `ninja src/gui/install' they will most likely get a permission error, telling them it's not possible to install into /qt_fake_staging_prefix/ check_qt_internal_apply_staging_prefix_build_rpath_workaround Fixes: QTBUG-102592 Change-Id: I6ce78dde1924a8d830ef5c62808ff674c9639d65 Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
2022-04-14 16:04:41 +00:00
qt_internal_apply_staging_prefix_build_rpath_workaround()
endif()
endif()
if (NOT arg_ALLOW_UNDEFINED_SYMBOLS)
### fixme: cmake is missing a built-in variable for this. We want to apply it only to
# modules and plugins that belong to Qt.
qt_internal_add_link_flags_no_undefined("${target}")
endif()
qt_internal_add_linker_version_script(${target})
set(finalizer_extra_args "")
if(NOT arg_SKIP_INSTALL)
list(APPEND finalizer_extra_args INSTALL_PATH "${install_directory}")
endif()
qt_add_list_file_finalizer(qt_finalize_plugin ${target} ${finalizer_extra_args})
if(NOT arg_SKIP_INSTALL)
qt_enable_separate_debug_info(${target} "${install_directory}")
qt_internal_install_pdb_files(${target} "${install_directory}")
endif()
endfunction()
function(qt_finalize_plugin target)
cmake_parse_arguments(arg "" "INSTALL_PATH" "" ${ARGN})
if(WIN32 AND BUILD_SHARED_LIBS)
_qt_internal_generate_win32_rc_file("${target}")
endif()
# Generate .prl and .pri files for static plugins.
get_target_property(target_type "${target}" TYPE)
if(target_type STREQUAL STATIC_LIBRARY)
if(arg_INSTALL_PATH)
qt_generate_prl_file(${target} "${arg_INSTALL_PATH}")
endif()
# There's no point in generating pri files for qml plugins.
# We didn't do it in Qt5 times.
get_target_property(plugin_type "${target}" QT_PLUGIN_TYPE)
if(NOT plugin_type STREQUAL "qml_plugin")
qt_generate_plugin_pri_file("${target}")
endif()
endif()
endfunction()
function(qt_get_sanitized_plugin_type plugin_type out_var)
# Used to handle some edge cases such as platforms/darwin
string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}")
set("${out_var}" "${plugin_type}" PARENT_SCOPE)
endfunction()
# Utility function to find the module to which a plug-in belongs.
function(qt_internal_get_module_for_plugin target target_type out_var)
qt_internal_get_qt_all_known_modules(known_modules)
qt_get_sanitized_plugin_type("${target_type}" target_type)
foreach(qt_module ${known_modules})
get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE)
# Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property
# name, because the current one would be invalid for interface libraries.
if(module_type STREQUAL "INTERFACE_LIBRARY")
continue()
endif()
get_target_property(plugin_types
"${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}"
MODULE_PLUGIN_TYPES)
if(plugin_types AND target_type IN_LIST plugin_types)
set("${out_var}" "${qt_module}" PARENT_SCOPE)
return()
endif()
endforeach()
message(FATAL_ERROR "The plug-in '${target}' does not belong to any Qt module.")
endfunction()
Add permission API backend for macOS and iOS When submitting applications to the iOS and macOS AppStore the application goes through static analysis, which will trigger on uses of various privacy protected APIs, unless the application has a corresponding usage description for the permission in the Info.plist file. This applies even if the application never requests the given permission, but just links to a Qt library that has the offending symbols or library dependencies. To ensure that the application does not have to add usage descriptions to their Info.plist for permissions they never plan to use we split up the various permission implementations into small static libraries that register with the Qt plugin mechanism as permission backends. We can then inspect the application's Info.plist at configure time and only add the relevant static permission libraries. Furthermore, since some permissions can be checked without any usage description, we allow the implementation to be split up into two separate translation units. By putting the request in its own translation unit we can selectively include it during linking by telling the linker to look for a special symbol. This is useful for libraries such as Qt Multimedia who would like to check the current permission status, but without needing to request any permission of its own. Done-with: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Change-Id: Ic2a43e1a0c45a91df6101020639f473ffd9454cc Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-05-10 13:02:43 +00:00
function(qt_internal_add_darwin_permission_plugin permission)
string(TOLOWER "${permission}" permission_lower)
string(TOUPPER "${permission}" permission_upper)
set(permission_source_file "platform/darwin/qdarwinpermissionplugin_${permission_lower}.mm")
set(plugin_target "QDarwin${permission}PermissionPlugin")
set(plugin_name "qdarwin${permission_lower}permission")
qt_internal_add_plugin(${plugin_target}
STATIC # Force static, even in shared builds
OUTPUT_NAME ${plugin_name}
PLUGIN_TYPE permissions
DEFAULT_IF FALSE
SOURCES
${permission_source_file}
DEFINES
QT_DARWIN_PERMISSION_PLUGIN=${permission}
LIBRARIES
Qt::Core
Qt::CorePrivate
${FWFoundation}
Add permission API backend for macOS and iOS When submitting applications to the iOS and macOS AppStore the application goes through static analysis, which will trigger on uses of various privacy protected APIs, unless the application has a corresponding usage description for the permission in the Info.plist file. This applies even if the application never requests the given permission, but just links to a Qt library that has the offending symbols or library dependencies. To ensure that the application does not have to add usage descriptions to their Info.plist for permissions they never plan to use we split up the various permission implementations into small static libraries that register with the Qt plugin mechanism as permission backends. We can then inspect the application's Info.plist at configure time and only add the relevant static permission libraries. Furthermore, since some permissions can be checked without any usage description, we allow the implementation to be split up into two separate translation units. By putting the request in its own translation unit we can selectively include it during linking by telling the linker to look for a special symbol. This is useful for libraries such as Qt Multimedia who would like to check the current permission status, but without needing to request any permission of its own. Done-with: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Change-Id: Ic2a43e1a0c45a91df6101020639f473ffd9454cc Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-05-10 13:02:43 +00:00
)
# Disable PCH since CMake falls over on single .mm source targets
set_target_properties(${plugin_target} PROPERTIES
DISABLE_PRECOMPILE_HEADERS ON
)
# Generate plugin JSON file
set(content "{ \"Permissions\": [ \"Q${permission}Permission\" ] }")
get_target_property(plugin_build_dir "${plugin_target}" BINARY_DIR)
set(output_file "${plugin_build_dir}/${plugin_target}.json")
qt_configure_file(OUTPUT "${output_file}" CONTENT "${content}")
# Associate required usage descriptions
set(usage_descriptions_property "_qt_info_plist_usage_descriptions")
set_target_properties(${plugin_target} PROPERTIES
${usage_descriptions_property} "NS${permission}UsageDescription"
)
set_property(TARGET ${plugin_target} APPEND PROPERTY
EXPORT_PROPERTIES ${usage_descriptions_property}
)
set(usage_descriptions_genex "$<JOIN:$<TARGET_PROPERTY:${plugin_target},${usage_descriptions_property}>, >")
set(extra_plugin_pri_content
"QT_PLUGIN.${plugin_name}.usage_descriptions = ${usage_descriptions_genex}"
)
# Support granular check and request implementations
set(separate_request_source_file
"${plugin_build_dir}/qdarwinpermissionplugin_${permission_lower}_request.mm")
set(separate_request_genex
"$<BOOL:$<TARGET_PROPERTY:${plugin_target},_qt_darwin_permissison_separate_request>>")
file(GENERATE OUTPUT "${separate_request_source_file}" CONTENT
"
#define BUILDING_PERMISSION_REQUEST 1
#include \"${CMAKE_CURRENT_SOURCE_DIR}/${permission_source_file}\"
"
CONDITION "${separate_request_genex}"
)
if(CMAKE_VERSION VERSION_LESS "3.18")
set_property(SOURCE "${separate_request_source_file}" PROPERTY GENERATED TRUE)
endif()
Add permission API backend for macOS and iOS When submitting applications to the iOS and macOS AppStore the application goes through static analysis, which will trigger on uses of various privacy protected APIs, unless the application has a corresponding usage description for the permission in the Info.plist file. This applies even if the application never requests the given permission, but just links to a Qt library that has the offending symbols or library dependencies. To ensure that the application does not have to add usage descriptions to their Info.plist for permissions they never plan to use we split up the various permission implementations into small static libraries that register with the Qt plugin mechanism as permission backends. We can then inspect the application's Info.plist at configure time and only add the relevant static permission libraries. Furthermore, since some permissions can be checked without any usage description, we allow the implementation to be split up into two separate translation units. By putting the request in its own translation unit we can selectively include it during linking by telling the linker to look for a special symbol. This is useful for libraries such as Qt Multimedia who would like to check the current permission status, but without needing to request any permission of its own. Done-with: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Change-Id: Ic2a43e1a0c45a91df6101020639f473ffd9454cc Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-05-10 13:02:43 +00:00
target_sources(${plugin_target} PRIVATE
"$<${separate_request_genex}:${separate_request_source_file}>"
)
set_property(TARGET ${plugin_target} APPEND PROPERTY
EXPORT_PROPERTIES _qt_darwin_permissison_separate_request
)
set(permission_request_symbol "_QDarwin${permission}PermissionRequest")
set(permission_request_flag "-Wl,-u,${permission_request_symbol}")
set(has_usage_description_property "_qt_has_${plugin_target}_usage_description")
set(has_usage_description_genex "$<BOOL:$<TARGET_PROPERTY:${has_usage_description_property}>>")
target_link_options(${plugin_target} INTERFACE
"$<$<AND:${separate_request_genex},${has_usage_description_genex}>:${permission_request_flag}>")
list(APPEND extra_plugin_pri_content
"QT_PLUGIN.${plugin_name}.request_flag = $<${separate_request_genex}:${permission_request_flag}>"
)
# Expose properties to qmake
set_property(TARGET ${plugin_target} PROPERTY
QT_PLUGIN_PRI_EXTRA_CONTENT ${extra_plugin_pri_content}
)
endfunction()