summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2022-05-10 15:02:43 +0200
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2022-11-03 15:02:36 +0100
commitf0a7d74e1dd2c1d802aa09d7b8c144599f4a54ce (patch)
tree31a684f2f8f63eaef4f07fee98ebe0bc4a6bd87d /cmake
parent1c6bf3e09ea9722717caedcfcceaaf3d607615cf (diff)
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>
Diffstat (limited to 'cmake')
-rw-r--r--cmake/QtFrameworkHelpers.cmake4
-rw-r--r--cmake/QtModuleConfig.cmake.in4
-rw-r--r--cmake/QtPluginHelpers.cmake78
3 files changed, 84 insertions, 2 deletions
diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake
index 3b4cb01223..e4e2a1373f 100644
--- a/cmake/QtFrameworkHelpers.cmake
+++ b/cmake/QtFrameworkHelpers.cmake
@@ -31,6 +31,10 @@ macro(qt_find_apple_system_frameworks)
qt_internal_find_apple_system_framework(FWWatchKit WatchKit)
qt_internal_find_apple_system_framework(FWGameController GameController)
qt_internal_find_apple_system_framework(FWCoreBluetooth CoreBluetooth)
+ qt_internal_find_apple_system_framework(FWAVFoundation AVFoundation)
+ qt_internal_find_apple_system_framework(FWContacts Contacts)
+ qt_internal_find_apple_system_framework(FWEventKit EventKit)
+ qt_internal_find_apple_system_framework(FWHealthKit HealthKit)
endif()
endmacro()
diff --git a/cmake/QtModuleConfig.cmake.in b/cmake/QtModuleConfig.cmake.in
index 8ea763d86e..55402f50ca 100644
--- a/cmake/QtModuleConfig.cmake.in
+++ b/cmake/QtModuleConfig.cmake.in
@@ -89,12 +89,12 @@ if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
endif()
if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::@target@)
+ qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@)
+
foreach(extra_cmake_include @extra_cmake_includes@)
include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}")
endforeach()
- qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@)
-
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake")
endif()
diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake
index aca5421221..20bde6f310 100644
--- a/cmake/QtPluginHelpers.cmake
+++ b/cmake/QtPluginHelpers.cmake
@@ -507,3 +507,81 @@ function(qt_internal_get_module_for_plugin target target_type out_var)
endforeach()
message(FATAL_ERROR "The plug-in '${target}' does not belong to any Qt module.")
endfunction()
+
+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
+ )
+
+ # 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}"
+ )
+ 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()