CMake: Move Apple specific functions into a separate file
Pick-to: 6.4 Task-number: QTBUG-95838 Change-Id: Ib0ce53fe0e2068482b654921ecba3232efe656c8 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
parent
b0fef2849b
commit
51f8eaa328
@ -328,6 +328,7 @@ set(__public_cmake_helpers
|
||||
cmake/QtCopyFileIfDifferent.cmake
|
||||
cmake/QtFeature.cmake
|
||||
cmake/QtFeatureCommon.cmake
|
||||
cmake/QtPublicAppleHelpers.cmake
|
||||
cmake/QtPublicCMakeHelpers.cmake
|
||||
cmake/QtPublicCMakeVersionHelpers.cmake
|
||||
cmake/QtPublicFinalizerHelpers.cmake
|
||||
|
@ -551,6 +551,7 @@ if(WASM)
|
||||
endif()
|
||||
|
||||
# Helpers that are available in public projects and while building Qt itself.
|
||||
include(QtPublicAppleHelpers)
|
||||
include(QtPublicCMakeHelpers)
|
||||
include(QtPublicPluginHelpers)
|
||||
include(QtPublicTargetHelpers)
|
||||
|
@ -109,6 +109,7 @@ __qt_internal_prefix_paths_to_roots(_qt_additional_host_packages_root_paths
|
||||
|
||||
# Public helpers available to all Qt packages.
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtFeature.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicAppleHelpers.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicFinalizerHelpers.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicPluginHelpers.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtPublicTargetHelpers.cmake")
|
||||
|
628
cmake/QtPublicAppleHelpers.cmake
Normal file
628
cmake/QtPublicAppleHelpers.cmake
Normal file
@ -0,0 +1,628 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
function(_qt_internal_handle_ios_launch_screen target)
|
||||
# Check if user provided a launch screen path via a variable.
|
||||
set(launch_screen "")
|
||||
|
||||
# Check if the project provided a launch screen path via a variable.
|
||||
# This variable is currently in Technical Preview.
|
||||
if(QT_IOS_LAUNCH_SCREEN)
|
||||
set(launch_screen "${QT_IOS_LAUNCH_SCREEN}")
|
||||
endif()
|
||||
|
||||
# Check if the project provided a launch screen path via a target property, it takes precedence
|
||||
# over the variable.
|
||||
# This property is currently in Technical Preview.
|
||||
get_target_property(launch_screen_from_prop "${target}" QT_IOS_LAUNCH_SCREEN)
|
||||
if(launch_screen_from_prop)
|
||||
set(launch_screen "${launch_screen_from_prop}")
|
||||
endif()
|
||||
|
||||
# If the project hasn't provided a launch screen file path, use a copy of the template
|
||||
# that qmake uses.
|
||||
# It needs to be a copy because configure_file can't handle all the escaped double quotes
|
||||
# present in the qmake template file.
|
||||
set(is_default_launch_screen FALSE)
|
||||
if(NOT launch_screen AND NOT QT_NO_SET_DEFAULT_IOS_LAUNCH_SCREEN)
|
||||
set(is_default_launch_screen TRUE)
|
||||
set(launch_screen
|
||||
"${__qt_internal_cmake_ios_support_files_path}/LaunchScreen.storyboard")
|
||||
endif()
|
||||
|
||||
# Check that the launch screen exists.
|
||||
if(launch_screen)
|
||||
if(NOT IS_ABSOLUTE "${launch_screen}")
|
||||
message(FATAL_ERROR
|
||||
"Provided launch screen value should be an absolute path: '${launch_screen}'")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${launch_screen}")
|
||||
message(FATAL_ERROR
|
||||
"Provided launch screen file does not exist: '${launch_screen}'")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(launch_screen AND NOT QT_NO_ADD_IOS_LAUNCH_SCREEN_TO_BUNDLE)
|
||||
get_filename_component(launch_screen_name "${launch_screen}" NAME)
|
||||
|
||||
# Make a copy of the default launch screen template for this target and replace the
|
||||
# label inside the template with the target name.
|
||||
if(is_default_launch_screen)
|
||||
# Configure our default template and place it in the build dir.
|
||||
set(launch_screen_in_path "${launch_screen}")
|
||||
|
||||
string(MAKE_C_IDENTIFIER "${target}" target_identifier)
|
||||
set(launch_screen_out_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.qt/launch_screen_storyboards/${target_identifier}")
|
||||
|
||||
set(launch_screen_out_path
|
||||
"${launch_screen_out_dir}/${launch_screen_name}")
|
||||
|
||||
file(MAKE_DIRECTORY "${launch_screen_out_dir}")
|
||||
|
||||
# Replaces the value in the default template.
|
||||
set(QT_IOS_LAUNCH_SCREEN_TEXT "${target}")
|
||||
configure_file(
|
||||
"${launch_screen_in_path}"
|
||||
"${launch_screen_out_path}"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(final_launch_screen_path "${launch_screen_out_path}")
|
||||
else()
|
||||
set(final_launch_screen_path "${launch_screen}")
|
||||
endif()
|
||||
|
||||
# Add the launch screen storyboard file as a source file, otherwise CMake doesn't consider
|
||||
# it as a resource file and MACOSX_PACKAGE_LOCATION processing will be skipped.
|
||||
target_sources("${target}" PRIVATE "${final_launch_screen_path}")
|
||||
|
||||
# Ensure Xcode compiles the storyboard file and installs the compiled storyboard .nib files
|
||||
# into the app bundle.
|
||||
# We use target_sources and the MACOSX_PACKAGE_LOCATION source file property for that
|
||||
# instead of the RESOURCE target property, becaues the latter could potentially end up
|
||||
# needlessly installing the source storyboard file.
|
||||
#
|
||||
# We can't rely on policy CMP0118 since user project controls it.
|
||||
set(scope_args)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
|
||||
set(scope_args TARGET_DIRECTORY ${target})
|
||||
endif()
|
||||
set_source_files_properties("${final_launch_screen_path}" ${scope_args}
|
||||
PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
# Save the launch screen name, so its value is added as an UILaunchStoryboardName entry
|
||||
# in the Qt generated Info.plist file.
|
||||
# Xcode expects an Info.plist storyboard entry without an extension.
|
||||
get_filename_component(launch_screen_base_name "${launch_screen}" NAME_WE)
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
_qt_ios_launch_screen_name "${launch_screen_name}"
|
||||
_qt_ios_launch_screen_base_name "${launch_screen_base_name}"
|
||||
_qt_ios_launch_screen_path "${final_launch_screen_path}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_find_ios_development_team_id out_var)
|
||||
get_property(team_id GLOBAL PROPERTY _qt_internal_ios_development_team_id)
|
||||
get_property(team_id_computed GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed)
|
||||
if(team_id_computed)
|
||||
# Just in case if the value is non-empty but still booly FALSE.
|
||||
if(NOT team_id)
|
||||
set(team_id "")
|
||||
endif()
|
||||
set("${out_var}" "${team_id}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed "TRUE")
|
||||
|
||||
set(home_dir "$ENV{HOME}")
|
||||
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
||||
|
||||
# Extract the first account name (email) from the user's Xcode preferences
|
||||
message(DEBUG "Trying to extract an Xcode development team id from '${xcode_preferences_path}'")
|
||||
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
||||
-x -c "print IDEProvisioningTeams" "${xcode_preferences_path}"
|
||||
OUTPUT_VARIABLE teams_xml
|
||||
ERROR_VARIABLE plist_error)
|
||||
|
||||
# Parsing state.
|
||||
set(is_free "")
|
||||
set(current_team_id "")
|
||||
set(parsing_is_free FALSE)
|
||||
set(parsing_team_id FALSE)
|
||||
set(first_team_id "")
|
||||
|
||||
# Parse the xml output and return the first encountered non-free team id. If no non-free team id
|
||||
# is found, return the first encountered free team id.
|
||||
# If no team is found, return an empty string.
|
||||
#
|
||||
# Example input:
|
||||
#<plist version="1.0">
|
||||
#<dict>
|
||||
# <key>marty@planet.local</key>
|
||||
# <array>
|
||||
# <dict>
|
||||
# <key>isFreeProvisioningTeam</key>
|
||||
# <false/>
|
||||
# <key>teamID</key>
|
||||
# <string>AAA</string>
|
||||
# ...
|
||||
# </dict>
|
||||
# <dict>
|
||||
# <key>isFreeProvisioningTeam</key>
|
||||
# <true/>
|
||||
# <key>teamID</key>
|
||||
# <string>BBB</string>
|
||||
# ...
|
||||
# </dict>
|
||||
# </array>
|
||||
#</dict>
|
||||
#</plist>
|
||||
if(teams_xml AND NOT plist_error)
|
||||
string(REPLACE "\n" ";" teams_xml_lines "${teams_xml}")
|
||||
|
||||
foreach(xml_line ${teams_xml_lines})
|
||||
string(STRIP "${xml_line}" xml_line)
|
||||
if(xml_line STREQUAL "<dict>")
|
||||
# Clean any previously found values when a new team dict is matched.
|
||||
set(is_free "")
|
||||
set(current_team_id "")
|
||||
|
||||
elseif(xml_line STREQUAL "<key>isFreeProvisioningTeam</key>")
|
||||
set(parsing_is_free TRUE)
|
||||
|
||||
elseif(parsing_is_free)
|
||||
set(parsing_is_free FALSE)
|
||||
|
||||
if(xml_line MATCHES "true")
|
||||
set(is_free TRUE)
|
||||
else()
|
||||
set(is_free FALSE)
|
||||
endif()
|
||||
|
||||
elseif(xml_line STREQUAL "<key>teamID</key>")
|
||||
set(parsing_team_id TRUE)
|
||||
|
||||
elseif(parsing_team_id)
|
||||
set(parsing_team_id FALSE)
|
||||
if(xml_line MATCHES "<string>([^<]+)</string>")
|
||||
set(current_team_id "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
continue()
|
||||
endif()
|
||||
|
||||
string(STRIP "${current_team_id}" current_team_id)
|
||||
|
||||
# If this is the first team id we found so far, remember that, regardless if's free
|
||||
# or not.
|
||||
if(NOT first_team_id AND current_team_id)
|
||||
set(first_team_id "${current_team_id}")
|
||||
endif()
|
||||
|
||||
# Break early if we found a non-free team id and use it, because we prefer
|
||||
# a non-free team for signing, just like qmake.
|
||||
if(NOT is_free AND current_team_id)
|
||||
set(first_team_id "${current_team_id}")
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT first_team_id)
|
||||
message(DEBUG "Failed to extract an Xcode development team id.")
|
||||
set("${out_var}" "" PARENT_SCOPE)
|
||||
else()
|
||||
message(DEBUG "Successfully extracted the first encountered Xcode development team id.")
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id "${first_team_id}")
|
||||
set("${out_var}" "${first_team_id}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_get_ios_bundle_identifier_prefix out_var)
|
||||
get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix)
|
||||
get_property(prefix_computed GLOBAL PROPERTY
|
||||
_qt_internal_ios_bundle_identifier_prefix_computed)
|
||||
if(prefix_computed)
|
||||
# Just in case if the value is non-empty but still booly FALSE.
|
||||
if(NOT prefix)
|
||||
set(prefix "")
|
||||
endif()
|
||||
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix_computed "TRUE")
|
||||
|
||||
set(home_dir "$ENV{HOME}")
|
||||
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
||||
|
||||
message(DEBUG "Trying to extract the default bundle identifier prefix from Xcode preferences.")
|
||||
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
||||
-c "print IDETemplateOptions:bundleIdentifierPrefix"
|
||||
"${xcode_preferences_path}"
|
||||
OUTPUT_VARIABLE prefix
|
||||
ERROR_VARIABLE prefix_error)
|
||||
if(prefix AND NOT prefix_error)
|
||||
message(DEBUG "Successfully extracted the default bundle identifier prefix.")
|
||||
string(STRIP "${prefix}" prefix)
|
||||
else()
|
||||
message(DEBUG "Failed to extract the default bundle identifier prefix.")
|
||||
endif()
|
||||
|
||||
if(prefix AND NOT prefix_error)
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix "${prefix}")
|
||||
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
||||
else()
|
||||
set("${out_var}" "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_escape_rfc_1034_identifier value out_var)
|
||||
# According to https://datatracker.ietf.org/doc/html/rfc1034#section-3.5
|
||||
# we can only use letters, digits, dot (.) and hyphens (-).
|
||||
# Underscores are not allowed.
|
||||
string(REGEX REPLACE "[^A-Za-z0-9.]" "-" value "${value}")
|
||||
|
||||
set("${out_var}" "${value}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_get_default_ios_bundle_identifier out_var)
|
||||
_qt_internal_get_ios_bundle_identifier_prefix(prefix)
|
||||
if(NOT prefix)
|
||||
set(prefix "com.yourcompany")
|
||||
|
||||
# For a better out-of-the-box experience, try to create a unique prefix by appending
|
||||
# the sha1 of the team id, if one is found.
|
||||
_qt_internal_find_ios_development_team_id(team_id)
|
||||
if(team_id)
|
||||
string(SHA1 hash "${team_id}")
|
||||
string(SUBSTRING "${hash}" 0 8 infix)
|
||||
string(APPEND prefix ".${infix}")
|
||||
else()
|
||||
message(WARNING
|
||||
"No organization bundle identifier prefix could be retrieved from Xcode "
|
||||
"preferences. This can lead to code signing issues due to a non-unique bundle "
|
||||
"identifier. Please set up an organization prefix by creating a new project within "
|
||||
"Xcode, or consider providing a custom bundle identifier by specifying the "
|
||||
"XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER property."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Escape the prefix according to rfc 1034, it's important for code-signing. If an invalid
|
||||
# identifier is used, calling xcodebuild on the command line says that no provisioning profile
|
||||
# could be found, with no additional error message. If one opens the generated project with
|
||||
# Xcode and clicks on 'Try again' to get a new profile, it shows a semi-useful error message
|
||||
# that the identifier is invalid.
|
||||
_qt_internal_escape_rfc_1034_identifier("${prefix}" prefix)
|
||||
|
||||
set(identifier "${prefix}.\${PRODUCT_NAME:rfc1034identifier}")
|
||||
set("${out_var}" "${identifier}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_placeholder_apple_bundle_version target)
|
||||
# If user hasn't provided neither a bundle version nor a bundle short version string for the
|
||||
# app, set a placeholder value for both which will add them to the generated Info.plist file.
|
||||
# This is required so that the app launches in the simulator (but apparently not for running
|
||||
# on-device).
|
||||
get_target_property(bundle_version "${target}" MACOSX_BUNDLE_BUNDLE_VERSION)
|
||||
get_target_property(bundle_short_version "${target}" MACOSX_BUNDLE_SHORT_VERSION_STRING)
|
||||
|
||||
if(NOT MACOSX_BUNDLE_BUNDLE_VERSION AND
|
||||
NOT MACOSX_BUNDLE_SHORT_VERSION_STRING AND
|
||||
NOT bundle_version AND
|
||||
NOT bundle_short_version AND
|
||||
NOT QT_NO_SET_XCODE_BUNDLE_VERSION
|
||||
)
|
||||
get_target_property(version "${target}" VERSION)
|
||||
if(NOT version)
|
||||
set(version "${PROJECT_VERSION}")
|
||||
if(NOT version)
|
||||
set(version "1.0.0")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use x.y for short version and x.y.z for full version
|
||||
# Any versions longer than this will fail App Store
|
||||
# submission.
|
||||
string(REPLACE "." ";" version_list ${version})
|
||||
list(LENGTH version_list version_list_length)
|
||||
list(GET version_list 0 version_major)
|
||||
set(bundle_short_version "${version_major}")
|
||||
if(version_list_length GREATER 1)
|
||||
list(GET version_list 1 version_minor)
|
||||
string(APPEND bundle_short_version ".${version_minor}")
|
||||
endif()
|
||||
set(bundle_version "${bundle_short_version}")
|
||||
if(version_list_length GREATER 2)
|
||||
list(GET version_list 2 version_patch)
|
||||
string(APPEND bundle_version ".${version_patch}")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION
|
||||
AND NOT QT_NO_SET_XCODE_ATTRIBUTE_MARKETING_VERSION
|
||||
AND NOT CMAKE_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION
|
||||
AND NOT QT_NO_SET_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION)
|
||||
get_target_property(marketing_version "${target}"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION)
|
||||
get_target_property(current_project_version "${target}"
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION)
|
||||
if(NOT marketing_version AND NOT current_project_version)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${bundle_version}"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION "${bundle_short_version}"
|
||||
)
|
||||
set(bundle_version "$(CURRENT_PROJECT_VERSION)")
|
||||
set(bundle_short_version "$(MARKETING_VERSION)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${bundle_version}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${bundle_short_version}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_development_team_id target)
|
||||
# If user hasn't provided a development team id, try to find the first one specified
|
||||
# in the Xcode preferences.
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM AND NOT QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID)
|
||||
get_target_property(existing_team_id "${target}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM)
|
||||
if(NOT existing_team_id)
|
||||
_qt_internal_find_ios_development_team_id(team_id)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${team_id}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bundle_identifier target)
|
||||
# Skip all logic if requested.
|
||||
if(QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# There are two fields to consider: the CFBundleIdentifier key (CFBI) to be written to
|
||||
# Info.plist
|
||||
# and the PRODUCT_BUNDLE_IDENTIFIER (PBI) property to set in the Xcode project.
|
||||
# The following logic enables the best out-of-the-box experience combined with maximum
|
||||
# customization.
|
||||
# 1) If values for both fields are not provided, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI
|
||||
# (which is expanded by xcodebuild at build time and will use the value of PBI) and
|
||||
# auto-compute a default PBI from Xcode's ${PRODUCT_NAME}.
|
||||
# 2) If CFBI is set and PBI isn't, use given CFBI and keep PBI empty.
|
||||
# 3) If PBI is set and CFBI isn't, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI and use
|
||||
# the given PBI.
|
||||
# 4) If both are set, use both given values.
|
||||
# TLDR:
|
||||
# cfbi pbi -> result_cfbi result_pbi
|
||||
# unset unset computed computed
|
||||
# set unset given_val unset
|
||||
# unset set computed given_val
|
||||
# set set given_val given_val
|
||||
|
||||
get_target_property(existing_cfbi "${target}" MACOSX_BUNDLE_GUI_IDENTIFIER)
|
||||
if(NOT MACOSX_BUNDLE_GUI_IDENTIFIER AND NOT existing_cfbi)
|
||||
set(is_cfbi_given FALSE)
|
||||
else()
|
||||
set(is_cfbi_given TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT is_cfbi_given)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "\${PRODUCT_BUNDLE_IDENTIFIER}")
|
||||
endif()
|
||||
|
||||
get_target_property(existing_pbi "${target}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER AND NOT existing_pbi)
|
||||
set(is_pbi_given FALSE)
|
||||
else()
|
||||
set(is_pbi_given TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT is_pbi_given AND NOT is_cfbi_given)
|
||||
_qt_internal_get_default_ios_bundle_identifier(bundle_id)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${bundle_id}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_targeted_device_family target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
|
||||
AND NOT QT_NO_SET_XCODE_TARGETED_DEVICE_FAMILY)
|
||||
get_target_property(existing_device_family
|
||||
"${target}" XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY)
|
||||
if(NOT existing_device_family)
|
||||
set(device_family_iphone_and_ipad "1,2")
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
|
||||
"${device_family_iphone_and_ipad}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_code_sign_style target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_STYLE
|
||||
AND NOT QT_NO_SET_XCODE_CODE_SIGN_STYLE)
|
||||
get_target_property(existing_code_style
|
||||
"${target}" XCODE_ATTRIBUTE_CODE_SIGN_STYLE)
|
||||
if(NOT existing_code_style)
|
||||
set(existing_code_style "Automatic")
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_STYLE
|
||||
"${existing_code_style}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15183
|
||||
function(_qt_internal_set_xcode_install_path target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_INSTALL_PATH
|
||||
AND NOT QT_NO_SET_XCODE_INSTALL_PATH)
|
||||
get_target_property(existing_install_path
|
||||
"${target}" XCODE_ATTRIBUTE_INSTALL_PATH)
|
||||
if(NOT existing_install_path)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_INSTALL_PATH
|
||||
"$(inherited)")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bundle_display_name target)
|
||||
# We want the value of CFBundleDisplayName to be ${PRODUCT_NAME}, but we can't put that
|
||||
# into the Info.plist.in template file directly, because the implicit configure_file(Info.plist)
|
||||
# done by CMake is not using the @ONLY option, so CMake would treat the assignment as
|
||||
# variable expansion. Escaping using backslashes does not help.
|
||||
# Work around it by assigning the dollar char to a separate cache var, and expand it, so that
|
||||
# the final value in the file will be ${PRODUCT_NAME}, to be evaluated at build time by Xcode.
|
||||
set(QT_INTERNAL_DOLLAR_VAR "$" CACHE STRING "")
|
||||
endfunction()
|
||||
|
||||
# Adds ${PRODUCT_NAME} to the Info.plist file, which is then evaluated by Xcode itself.
|
||||
function(_qt_internal_set_xcode_bundle_name target)
|
||||
if(QT_NO_SET_XCODE_BUNDLE_NAME)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_bundle_name "${target}" MACOSX_BUNDLE_BUNDLE_NAME)
|
||||
if(NOT MACOSX_BUNDLE_BUNDLE_NAME AND NOT existing_bundle_name)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "\${PRODUCT_NAME}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bitcode_enablement target)
|
||||
if(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE
|
||||
OR QT_NO_SET_XCODE_ENABLE_BITCODE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_bitcode_enablement
|
||||
"${target}" XCODE_ATTRIBUTE_ENABLE_BITCODE)
|
||||
if(NOT existing_bitcode_enablement MATCHES "-NOTFOUND")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Disable bitcode to match Xcode 14's new default
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE
|
||||
"NO")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_generate_ios_info_plist target)
|
||||
# If the project already specifies a custom file, we don't override it.
|
||||
get_target_property(existing_plist "${target}" MACOSX_BUNDLE_INFO_PLIST)
|
||||
if(existing_plist)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(info_plist_in "${__qt_internal_cmake_ios_support_files_path}/Info.plist.app.in")
|
||||
|
||||
string(MAKE_C_IDENTIFIER "${target}" target_identifier)
|
||||
set(info_plist_out_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.qt/info_plist/${target_identifier}")
|
||||
set(info_plist_out "${info_plist_out_dir}/Info.plist")
|
||||
|
||||
# Check if we need to specify a custom launch screen storyboard entry.
|
||||
get_target_property(launch_screen_base_name "${target}" _qt_ios_launch_screen_base_name)
|
||||
if(launch_screen_base_name)
|
||||
set(qt_ios_launch_screen_plist_entry "${launch_screen_base_name}")
|
||||
endif()
|
||||
|
||||
# Call configure_file to substitute Qt-specific @FOO@ values, not ${FOO} values.
|
||||
#
|
||||
# The output file will be another template file to be fed to CMake via the
|
||||
# MACOSX_BUNDLE_INFO_PLIST property. CMake will then call configure_file on it to provide
|
||||
# content for regular entries like CFBundleName, etc.
|
||||
#
|
||||
# We require this extra configure_file call so we can create unique Info.plist files for each
|
||||
# target in a project, while also providing a way to add Qt specific entries that CMake
|
||||
# does not support out of the box (e.g. a launch screen name).
|
||||
configure_file(
|
||||
"${info_plist_in}"
|
||||
"${info_plist_out}"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set_target_properties("${target}" PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${info_plist_out}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_ios_simulator_arch target)
|
||||
if(CMAKE_XCODE_ATTRIBUTE_ARCHS
|
||||
OR QT_NO_SET_XCODE_ARCHS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_archs
|
||||
"${target}" XCODE_ATTRIBUTE_ARCHS)
|
||||
if(NOT existing_archs MATCHES "-NOTFOUND")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT x86_64 IN_LIST QT_OSX_ARCHITECTURES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_OSX_ARCHITECTURES AND NOT x86_64 IN_LIST CMAKE_OSX_ARCHITECTURES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
"XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*]"
|
||||
"x86_64")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_apple_app target)
|
||||
# Shared between macOS and iOS apps
|
||||
_qt_internal_set_xcode_development_team_id("${target}")
|
||||
_qt_internal_set_xcode_bundle_identifier("${target}")
|
||||
_qt_internal_set_xcode_code_sign_style("${target}")
|
||||
_qt_internal_set_xcode_bundle_name("${target}")
|
||||
_qt_internal_set_xcode_bundle_display_name("${target}")
|
||||
_qt_internal_set_xcode_install_path("${target}")
|
||||
_qt_internal_set_placeholder_apple_bundle_version("${target}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_ios_app target)
|
||||
_qt_internal_finalize_apple_app("${target}")
|
||||
|
||||
_qt_internal_set_xcode_targeted_device_family("${target}")
|
||||
_qt_internal_set_xcode_bitcode_enablement("${target}")
|
||||
_qt_internal_handle_ios_launch_screen("${target}")
|
||||
_qt_internal_generate_ios_info_plist("${target}")
|
||||
_qt_internal_set_ios_simulator_arch("${target}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_macos_app target)
|
||||
get_target_property(is_bundle ${target} MACOSX_BUNDLE)
|
||||
if(NOT is_bundle)
|
||||
return()
|
||||
endif()
|
||||
|
||||
_qt_internal_finalize_apple_app("${target}")
|
||||
|
||||
# Make sure the install rpath has at least the minimum needed if the app
|
||||
# has any non-static frameworks. We can't rigorously know if the app will
|
||||
# have any, even with a static Qt, so always add this. If there are no
|
||||
# frameworks, it won't do any harm.
|
||||
get_property(install_rpath TARGET ${target} PROPERTY INSTALL_RPATH)
|
||||
list(APPEND install_rpath "@executable_path/../Frameworks")
|
||||
list(REMOVE_DUPLICATES install_rpath)
|
||||
set_property(TARGET ${target} PROPERTY INSTALL_RPATH "${install_rpath}")
|
||||
endfunction()
|
@ -712,632 +712,6 @@ function(qt6_finalize_target target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_handle_ios_launch_screen target)
|
||||
# Check if user provided a launch screen path via a variable.
|
||||
set(launch_screen "")
|
||||
|
||||
# Check if the project provided a launch screen path via a variable.
|
||||
# This variable is currently in Technical Preview.
|
||||
if(QT_IOS_LAUNCH_SCREEN)
|
||||
set(launch_screen "${QT_IOS_LAUNCH_SCREEN}")
|
||||
endif()
|
||||
|
||||
# Check if the project provided a launch screen path via a target property, it takes precedence
|
||||
# over the variable.
|
||||
# This property is currently in Technical Preview.
|
||||
get_target_property(launch_screen_from_prop "${target}" QT_IOS_LAUNCH_SCREEN)
|
||||
if(launch_screen_from_prop)
|
||||
set(launch_screen "${launch_screen_from_prop}")
|
||||
endif()
|
||||
|
||||
# If the project hasn't provided a launch screen file path, use a copy of the template
|
||||
# that qmake uses.
|
||||
# It needs to be a copy because configure_file can't handle all the escaped double quotes
|
||||
# present in the qmake template file.
|
||||
set(is_default_launch_screen FALSE)
|
||||
if(NOT launch_screen AND NOT QT_NO_SET_DEFAULT_IOS_LAUNCH_SCREEN)
|
||||
set(is_default_launch_screen TRUE)
|
||||
set(launch_screen
|
||||
"${__qt_internal_cmake_ios_support_files_path}/LaunchScreen.storyboard")
|
||||
endif()
|
||||
|
||||
# Check that the launch screen exists.
|
||||
if(launch_screen)
|
||||
if(NOT IS_ABSOLUTE "${launch_screen}")
|
||||
message(FATAL_ERROR
|
||||
"Provided launch screen value should be an absolute path: '${launch_screen}'")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${launch_screen}")
|
||||
message(FATAL_ERROR
|
||||
"Provided launch screen file does not exist: '${launch_screen}'")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(launch_screen AND NOT QT_NO_ADD_IOS_LAUNCH_SCREEN_TO_BUNDLE)
|
||||
get_filename_component(launch_screen_name "${launch_screen}" NAME)
|
||||
|
||||
# Make a copy of the default launch screen template for this target and replace the
|
||||
# label inside the template with the target name.
|
||||
if(is_default_launch_screen)
|
||||
# Configure our default template and place it in the build dir.
|
||||
set(launch_screen_in_path "${launch_screen}")
|
||||
|
||||
string(MAKE_C_IDENTIFIER "${target}" target_identifier)
|
||||
set(launch_screen_out_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.qt/launch_screen_storyboards/${target_identifier}")
|
||||
|
||||
set(launch_screen_out_path
|
||||
"${launch_screen_out_dir}/${launch_screen_name}")
|
||||
|
||||
file(MAKE_DIRECTORY "${launch_screen_out_dir}")
|
||||
|
||||
# Replaces the value in the default template.
|
||||
set(QT_IOS_LAUNCH_SCREEN_TEXT "${target}")
|
||||
configure_file(
|
||||
"${launch_screen_in_path}"
|
||||
"${launch_screen_out_path}"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(final_launch_screen_path "${launch_screen_out_path}")
|
||||
else()
|
||||
set(final_launch_screen_path "${launch_screen}")
|
||||
endif()
|
||||
|
||||
# Add the launch screen storyboard file as a source file, otherwise CMake doesn't consider
|
||||
# it as a resource file and MACOSX_PACKAGE_LOCATION processing will be skipped.
|
||||
target_sources("${target}" PRIVATE "${final_launch_screen_path}")
|
||||
|
||||
# Ensure Xcode compiles the storyboard file and installs the compiled storyboard .nib files
|
||||
# into the app bundle.
|
||||
# We use target_sources and the MACOSX_PACKAGE_LOCATION source file property for that
|
||||
# instead of the RESOURCE target property, becaues the latter could potentially end up
|
||||
# needlessly installing the source storyboard file.
|
||||
#
|
||||
# We can't rely on policy CMP0118 since user project controls it.
|
||||
set(scope_args)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
|
||||
set(scope_args TARGET_DIRECTORY ${target})
|
||||
endif()
|
||||
set_source_files_properties("${final_launch_screen_path}" ${scope_args}
|
||||
PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
# Save the launch screen name, so its value is added as an UILaunchStoryboardName entry
|
||||
# in the Qt generated Info.plist file.
|
||||
# Xcode expects an Info.plist storyboard entry without an extension.
|
||||
get_filename_component(launch_screen_base_name "${launch_screen}" NAME_WE)
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
_qt_ios_launch_screen_name "${launch_screen_name}"
|
||||
_qt_ios_launch_screen_base_name "${launch_screen_base_name}"
|
||||
_qt_ios_launch_screen_path "${final_launch_screen_path}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_find_ios_development_team_id out_var)
|
||||
get_property(team_id GLOBAL PROPERTY _qt_internal_ios_development_team_id)
|
||||
get_property(team_id_computed GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed)
|
||||
if(team_id_computed)
|
||||
# Just in case if the value is non-empty but still booly FALSE.
|
||||
if(NOT team_id)
|
||||
set(team_id "")
|
||||
endif()
|
||||
set("${out_var}" "${team_id}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed "TRUE")
|
||||
|
||||
set(home_dir "$ENV{HOME}")
|
||||
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
||||
|
||||
# Extract the first account name (email) from the user's Xcode preferences
|
||||
message(DEBUG "Trying to extract an Xcode development team id from '${xcode_preferences_path}'")
|
||||
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
||||
-x -c "print IDEProvisioningTeams" "${xcode_preferences_path}"
|
||||
OUTPUT_VARIABLE teams_xml
|
||||
ERROR_VARIABLE plist_error)
|
||||
|
||||
# Parsing state.
|
||||
set(is_free "")
|
||||
set(current_team_id "")
|
||||
set(parsing_is_free FALSE)
|
||||
set(parsing_team_id FALSE)
|
||||
set(first_team_id "")
|
||||
|
||||
# Parse the xml output and return the first encountered non-free team id. If no non-free team id
|
||||
# is found, return the first encountered free team id.
|
||||
# If no team is found, return an empty string.
|
||||
#
|
||||
# Example input:
|
||||
#<plist version="1.0">
|
||||
#<dict>
|
||||
# <key>marty@planet.local</key>
|
||||
# <array>
|
||||
# <dict>
|
||||
# <key>isFreeProvisioningTeam</key>
|
||||
# <false/>
|
||||
# <key>teamID</key>
|
||||
# <string>AAA</string>
|
||||
# ...
|
||||
# </dict>
|
||||
# <dict>
|
||||
# <key>isFreeProvisioningTeam</key>
|
||||
# <true/>
|
||||
# <key>teamID</key>
|
||||
# <string>BBB</string>
|
||||
# ...
|
||||
# </dict>
|
||||
# </array>
|
||||
#</dict>
|
||||
#</plist>
|
||||
if(teams_xml AND NOT plist_error)
|
||||
string(REPLACE "\n" ";" teams_xml_lines "${teams_xml}")
|
||||
|
||||
foreach(xml_line ${teams_xml_lines})
|
||||
string(STRIP "${xml_line}" xml_line)
|
||||
if(xml_line STREQUAL "<dict>")
|
||||
# Clean any previously found values when a new team dict is matched.
|
||||
set(is_free "")
|
||||
set(current_team_id "")
|
||||
|
||||
elseif(xml_line STREQUAL "<key>isFreeProvisioningTeam</key>")
|
||||
set(parsing_is_free TRUE)
|
||||
|
||||
elseif(parsing_is_free)
|
||||
set(parsing_is_free FALSE)
|
||||
|
||||
if(xml_line MATCHES "true")
|
||||
set(is_free TRUE)
|
||||
else()
|
||||
set(is_free FALSE)
|
||||
endif()
|
||||
|
||||
elseif(xml_line STREQUAL "<key>teamID</key>")
|
||||
set(parsing_team_id TRUE)
|
||||
|
||||
elseif(parsing_team_id)
|
||||
set(parsing_team_id FALSE)
|
||||
if(xml_line MATCHES "<string>([^<]+)</string>")
|
||||
set(current_team_id "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
continue()
|
||||
endif()
|
||||
|
||||
string(STRIP "${current_team_id}" current_team_id)
|
||||
|
||||
# If this is the first team id we found so far, remember that, regardless if's free
|
||||
# or not.
|
||||
if(NOT first_team_id AND current_team_id)
|
||||
set(first_team_id "${current_team_id}")
|
||||
endif()
|
||||
|
||||
# Break early if we found a non-free team id and use it, because we prefer
|
||||
# a non-free team for signing, just like qmake.
|
||||
if(NOT is_free AND current_team_id)
|
||||
set(first_team_id "${current_team_id}")
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT first_team_id)
|
||||
message(DEBUG "Failed to extract an Xcode development team id.")
|
||||
set("${out_var}" "" PARENT_SCOPE)
|
||||
else()
|
||||
message(DEBUG "Successfully extracted the first encountered Xcode development team id.")
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id "${first_team_id}")
|
||||
set("${out_var}" "${first_team_id}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_get_ios_bundle_identifier_prefix out_var)
|
||||
get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix)
|
||||
get_property(prefix_computed GLOBAL PROPERTY
|
||||
_qt_internal_ios_bundle_identifier_prefix_computed)
|
||||
if(prefix_computed)
|
||||
# Just in case if the value is non-empty but still booly FALSE.
|
||||
if(NOT prefix)
|
||||
set(prefix "")
|
||||
endif()
|
||||
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix_computed "TRUE")
|
||||
|
||||
set(home_dir "$ENV{HOME}")
|
||||
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
||||
|
||||
message(DEBUG "Trying to extract the default bundle identifier prefix from Xcode preferences.")
|
||||
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
||||
-c "print IDETemplateOptions:bundleIdentifierPrefix"
|
||||
"${xcode_preferences_path}"
|
||||
OUTPUT_VARIABLE prefix
|
||||
ERROR_VARIABLE prefix_error)
|
||||
if(prefix AND NOT prefix_error)
|
||||
message(DEBUG "Successfully extracted the default bundle identifier prefix.")
|
||||
string(STRIP "${prefix}" prefix)
|
||||
else()
|
||||
message(DEBUG "Failed to extract the default bundle identifier prefix.")
|
||||
endif()
|
||||
|
||||
if(prefix AND NOT prefix_error)
|
||||
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix "${prefix}")
|
||||
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
||||
else()
|
||||
set("${out_var}" "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_escape_rfc_1034_identifier value out_var)
|
||||
# According to https://datatracker.ietf.org/doc/html/rfc1034#section-3.5
|
||||
# we can only use letters, digits, dot (.) and hyphens (-).
|
||||
# Underscores are not allowed.
|
||||
string(REGEX REPLACE "[^A-Za-z0-9.]" "-" value "${value}")
|
||||
|
||||
set("${out_var}" "${value}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_get_default_ios_bundle_identifier out_var)
|
||||
_qt_internal_get_ios_bundle_identifier_prefix(prefix)
|
||||
if(NOT prefix)
|
||||
set(prefix "com.yourcompany")
|
||||
|
||||
# For a better out-of-the-box experience, try to create a unique prefix by appending
|
||||
# the sha1 of the team id, if one is found.
|
||||
_qt_internal_find_ios_development_team_id(team_id)
|
||||
if(team_id)
|
||||
string(SHA1 hash "${team_id}")
|
||||
string(SUBSTRING "${hash}" 0 8 infix)
|
||||
string(APPEND prefix ".${infix}")
|
||||
else()
|
||||
message(WARNING
|
||||
"No organization bundle identifier prefix could be retrieved from Xcode "
|
||||
"preferences. This can lead to code signing issues due to a non-unique bundle "
|
||||
"identifier. Please set up an organization prefix by creating a new project within "
|
||||
"Xcode, or consider providing a custom bundle identifier by specifying the "
|
||||
"XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER property."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Escape the prefix according to rfc 1034, it's important for code-signing. If an invalid
|
||||
# identifier is used, calling xcodebuild on the command line says that no provisioning profile
|
||||
# could be found, with no additional error message. If one opens the generated project with
|
||||
# Xcode and clicks on 'Try again' to get a new profile, it shows a semi-useful error message
|
||||
# that the identifier is invalid.
|
||||
_qt_internal_escape_rfc_1034_identifier("${prefix}" prefix)
|
||||
|
||||
set(identifier "${prefix}.\${PRODUCT_NAME:rfc1034identifier}")
|
||||
set("${out_var}" "${identifier}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_placeholder_apple_bundle_version target)
|
||||
# If user hasn't provided neither a bundle version nor a bundle short version string for the
|
||||
# app, set a placeholder value for both which will add them to the generated Info.plist file.
|
||||
# This is required so that the app launches in the simulator (but apparently not for running
|
||||
# on-device).
|
||||
get_target_property(bundle_version "${target}" MACOSX_BUNDLE_BUNDLE_VERSION)
|
||||
get_target_property(bundle_short_version "${target}" MACOSX_BUNDLE_SHORT_VERSION_STRING)
|
||||
|
||||
if(NOT MACOSX_BUNDLE_BUNDLE_VERSION AND
|
||||
NOT MACOSX_BUNDLE_SHORT_VERSION_STRING AND
|
||||
NOT bundle_version AND
|
||||
NOT bundle_short_version AND
|
||||
NOT QT_NO_SET_XCODE_BUNDLE_VERSION
|
||||
)
|
||||
get_target_property(version "${target}" VERSION)
|
||||
if(NOT version)
|
||||
set(version "${PROJECT_VERSION}")
|
||||
if(NOT version)
|
||||
set(version "1.0.0")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use x.y for short version and x.y.z for full version
|
||||
# Any versions longer than this will fail App Store
|
||||
# submission.
|
||||
string(REPLACE "." ";" version_list ${version})
|
||||
list(LENGTH version_list version_list_length)
|
||||
list(GET version_list 0 version_major)
|
||||
set(bundle_short_version "${version_major}")
|
||||
if(version_list_length GREATER 1)
|
||||
list(GET version_list 1 version_minor)
|
||||
string(APPEND bundle_short_version ".${version_minor}")
|
||||
endif()
|
||||
set(bundle_version "${bundle_short_version}")
|
||||
if(version_list_length GREATER 2)
|
||||
list(GET version_list 2 version_patch)
|
||||
string(APPEND bundle_version ".${version_patch}")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION
|
||||
AND NOT QT_NO_SET_XCODE_ATTRIBUTE_MARKETING_VERSION
|
||||
AND NOT CMAKE_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION
|
||||
AND NOT QT_NO_SET_XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION)
|
||||
get_target_property(marketing_version "${target}"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION)
|
||||
get_target_property(current_project_version "${target}"
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION)
|
||||
if(NOT marketing_version AND NOT current_project_version)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${bundle_version}"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION "${bundle_short_version}"
|
||||
)
|
||||
set(bundle_version "$(CURRENT_PROJECT_VERSION)")
|
||||
set(bundle_short_version "$(MARKETING_VERSION)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${bundle_version}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${bundle_short_version}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_development_team_id target)
|
||||
# If user hasn't provided a development team id, try to find the first one specified
|
||||
# in the Xcode preferences.
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM AND NOT QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID)
|
||||
get_target_property(existing_team_id "${target}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM)
|
||||
if(NOT existing_team_id)
|
||||
_qt_internal_find_ios_development_team_id(team_id)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${team_id}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bundle_identifier target)
|
||||
# Skip all logic if requested.
|
||||
if(QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# There are two fields to consider: the CFBundleIdentifier key (CFBI) to be written to
|
||||
# Info.plist
|
||||
# and the PRODUCT_BUNDLE_IDENTIFIER (PBI) property to set in the Xcode project.
|
||||
# The following logic enables the best out-of-the-box experience combined with maximum
|
||||
# customization.
|
||||
# 1) If values for both fields are not provided, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI
|
||||
# (which is expanded by xcodebuild at build time and will use the value of PBI) and
|
||||
# auto-compute a default PBI from Xcode's ${PRODUCT_NAME}.
|
||||
# 2) If CFBI is set and PBI isn't, use given CFBI and keep PBI empty.
|
||||
# 3) If PBI is set and CFBI isn't, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI and use
|
||||
# the given PBI.
|
||||
# 4) If both are set, use both given values.
|
||||
# TLDR:
|
||||
# cfbi pbi -> result_cfbi result_pbi
|
||||
# unset unset computed computed
|
||||
# set unset given_val unset
|
||||
# unset set computed given_val
|
||||
# set set given_val given_val
|
||||
|
||||
get_target_property(existing_cfbi "${target}" MACOSX_BUNDLE_GUI_IDENTIFIER)
|
||||
if(NOT MACOSX_BUNDLE_GUI_IDENTIFIER AND NOT existing_cfbi)
|
||||
set(is_cfbi_given FALSE)
|
||||
else()
|
||||
set(is_cfbi_given TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT is_cfbi_given)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "\${PRODUCT_BUNDLE_IDENTIFIER}")
|
||||
endif()
|
||||
|
||||
get_target_property(existing_pbi "${target}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER AND NOT existing_pbi)
|
||||
set(is_pbi_given FALSE)
|
||||
else()
|
||||
set(is_pbi_given TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT is_pbi_given AND NOT is_cfbi_given)
|
||||
_qt_internal_get_default_ios_bundle_identifier(bundle_id)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${bundle_id}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_targeted_device_family target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
|
||||
AND NOT QT_NO_SET_XCODE_TARGETED_DEVICE_FAMILY)
|
||||
get_target_property(existing_device_family
|
||||
"${target}" XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY)
|
||||
if(NOT existing_device_family)
|
||||
set(device_family_iphone_and_ipad "1,2")
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY
|
||||
"${device_family_iphone_and_ipad}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_code_sign_style target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_STYLE
|
||||
AND NOT QT_NO_SET_XCODE_CODE_SIGN_STYLE)
|
||||
get_target_property(existing_code_style
|
||||
"${target}" XCODE_ATTRIBUTE_CODE_SIGN_STYLE)
|
||||
if(NOT existing_code_style)
|
||||
set(existing_code_style "Automatic")
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_STYLE
|
||||
"${existing_code_style}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15183
|
||||
function(_qt_internal_set_xcode_install_path target)
|
||||
if(NOT CMAKE_XCODE_ATTRIBUTE_INSTALL_PATH
|
||||
AND NOT QT_NO_SET_XCODE_INSTALL_PATH)
|
||||
get_target_property(existing_install_path
|
||||
"${target}" XCODE_ATTRIBUTE_INSTALL_PATH)
|
||||
if(NOT existing_install_path)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_INSTALL_PATH
|
||||
"$(inherited)")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bundle_display_name target)
|
||||
# We want the value of CFBundleDisplayName to be ${PRODUCT_NAME}, but we can't put that
|
||||
# into the Info.plist.in template file directly, because the implicit configure_file(Info.plist)
|
||||
# done by CMake is not using the @ONLY option, so CMake would treat the assignment as
|
||||
# variable expansion. Escaping using backslashes does not help.
|
||||
# Work around it by assigning the dollar char to a separate cache var, and expand it, so that
|
||||
# the final value in the file will be ${PRODUCT_NAME}, to be evaluated at build time by Xcode.
|
||||
set(QT_INTERNAL_DOLLAR_VAR "$" CACHE STRING "")
|
||||
endfunction()
|
||||
|
||||
# Adds ${PRODUCT_NAME} to the Info.plist file, which is then evaluated by Xcode itself.
|
||||
function(_qt_internal_set_xcode_bundle_name target)
|
||||
if(QT_NO_SET_XCODE_BUNDLE_NAME)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_bundle_name "${target}" MACOSX_BUNDLE_BUNDLE_NAME)
|
||||
if(NOT MACOSX_BUNDLE_BUNDLE_NAME AND NOT existing_bundle_name)
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "\${PRODUCT_NAME}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_xcode_bitcode_enablement target)
|
||||
if(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE
|
||||
OR QT_NO_SET_XCODE_ENABLE_BITCODE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_bitcode_enablement
|
||||
"${target}" XCODE_ATTRIBUTE_ENABLE_BITCODE)
|
||||
if(NOT existing_bitcode_enablement MATCHES "-NOTFOUND")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Disable bitcode to match Xcode 14's new default
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE
|
||||
"NO")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_generate_ios_info_plist target)
|
||||
# If the project already specifies a custom file, we don't override it.
|
||||
get_target_property(existing_plist "${target}" MACOSX_BUNDLE_INFO_PLIST)
|
||||
if(existing_plist)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(info_plist_in "${__qt_internal_cmake_ios_support_files_path}/Info.plist.app.in")
|
||||
|
||||
string(MAKE_C_IDENTIFIER "${target}" target_identifier)
|
||||
set(info_plist_out_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.qt/info_plist/${target_identifier}")
|
||||
set(info_plist_out "${info_plist_out_dir}/Info.plist")
|
||||
|
||||
# Check if we need to specify a custom launch screen storyboard entry.
|
||||
get_target_property(launch_screen_base_name "${target}" _qt_ios_launch_screen_base_name)
|
||||
if(launch_screen_base_name)
|
||||
set(qt_ios_launch_screen_plist_entry "${launch_screen_base_name}")
|
||||
endif()
|
||||
|
||||
# Call configure_file to substitute Qt-specific @FOO@ values, not ${FOO} values.
|
||||
#
|
||||
# The output file will be another template file to be fed to CMake via the
|
||||
# MACOSX_BUNDLE_INFO_PLIST property. CMake will then call configure_file on it to provide
|
||||
# content for regular entries like CFBundleName, etc.
|
||||
#
|
||||
# We require this extra configure_file call so we can create unique Info.plist files for each
|
||||
# target in a project, while also providing a way to add Qt specific entries that CMake
|
||||
# does not support out of the box (e.g. a launch screen name).
|
||||
configure_file(
|
||||
"${info_plist_in}"
|
||||
"${info_plist_out}"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set_target_properties("${target}" PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${info_plist_out}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_set_ios_simulator_arch target)
|
||||
if(CMAKE_XCODE_ATTRIBUTE_ARCHS
|
||||
OR QT_NO_SET_XCODE_ARCHS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(existing_archs
|
||||
"${target}" XCODE_ATTRIBUTE_ARCHS)
|
||||
if(NOT existing_archs MATCHES "-NOTFOUND")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT x86_64 IN_LIST QT_OSX_ARCHITECTURES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_OSX_ARCHITECTURES AND NOT x86_64 IN_LIST CMAKE_OSX_ARCHITECTURES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_target_properties("${target}"
|
||||
PROPERTIES
|
||||
"XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*]"
|
||||
"x86_64")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_apple_app target)
|
||||
# Shared between macOS and iOS apps
|
||||
_qt_internal_set_xcode_development_team_id("${target}")
|
||||
_qt_internal_set_xcode_bundle_identifier("${target}")
|
||||
_qt_internal_set_xcode_code_sign_style("${target}")
|
||||
_qt_internal_set_xcode_bundle_name("${target}")
|
||||
_qt_internal_set_xcode_bundle_display_name("${target}")
|
||||
_qt_internal_set_xcode_install_path("${target}")
|
||||
_qt_internal_set_placeholder_apple_bundle_version("${target}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_ios_app target)
|
||||
_qt_internal_finalize_apple_app("${target}")
|
||||
|
||||
_qt_internal_set_xcode_targeted_device_family("${target}")
|
||||
_qt_internal_set_xcode_bitcode_enablement("${target}")
|
||||
_qt_internal_handle_ios_launch_screen("${target}")
|
||||
_qt_internal_generate_ios_info_plist("${target}")
|
||||
_qt_internal_set_ios_simulator_arch("${target}")
|
||||
endfunction()
|
||||
|
||||
function(_qt_internal_finalize_macos_app target)
|
||||
get_target_property(is_bundle ${target} MACOSX_BUNDLE)
|
||||
if(NOT is_bundle)
|
||||
return()
|
||||
endif()
|
||||
|
||||
_qt_internal_finalize_apple_app("${target}")
|
||||
|
||||
# Make sure the install rpath has at least the minimum needed if the app
|
||||
# has any non-static frameworks. We can't rigorously know if the app will
|
||||
# have any, even with a static Qt, so always add this. If there are no
|
||||
# frameworks, it won't do any harm.
|
||||
get_property(install_rpath TARGET ${target} PROPERTY INSTALL_RPATH)
|
||||
list(APPEND install_rpath "@executable_path/../Frameworks")
|
||||
list(REMOVE_DUPLICATES install_rpath)
|
||||
set_property(TARGET ${target} PROPERTY INSTALL_RPATH "${install_rpath}")
|
||||
endfunction()
|
||||
|
||||
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
||||
function(qt_add_executable)
|
||||
qt6_add_executable(${ARGV})
|
||||
|
Loading…
Reference in New Issue
Block a user