CMake: Generate better Xcode iOS projects

Add an iOS specific plist file like we do for macOS.

If the user hasn't specified a bundle identifier or a development
team id, do what qmake does and query the Xcode preferences file to
pre-populate those if possible.

This allows running

 cmake -GXcode ./foo

on a Qt example project and building it with xcodebuild on the
command line without having to go through the IDE to set a development
team id or modifying the example project to add a product
bundle identifier.

Note that the change assumes that the development team id has been
previously set / configured via Xcode. If no such id is found, then
the value will not be set and the user will still have to specify it
either in the project file or via the Xcode UI after the project
has been generated.

Amends 3a2fa3fec5

Pick-to: 6.1
Change-Id: Iaab4e57de72c9877fb9035d28f9a879b2c91a33c
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Alexandru Croitor 2021-04-14 18:16:44 +02:00
parent b25eb6e0bd
commit 4d838dae5a
5 changed files with 195 additions and 0 deletions

View File

@ -50,6 +50,9 @@ if(NOT QT_BUILD_STANDALONE_TESTS)
if(MACOS)
# Add module directory to pick up custom Info.plist template
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos")
elseif(IOS)
# Add module directory to pick up custom Info.plist template
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios")
endif()
## Find the build internals package.

View File

@ -253,6 +253,11 @@ if(MACOS)
cmake/macos/MacOSXBundleInfo.plist.in
DESTINATION "${__GlobalConfig_install_dir}/macos"
)
elseif(IOS)
qt_copy_or_install(FILES
cmake/ios/MacOSXBundleInfo.plist.in
DESTINATION "${__GlobalConfig_install_dir}/ios"
)
endif()
# Install CI support files to libexec.

View File

@ -44,6 +44,9 @@ list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/3rdparty/kwin")
if(APPLE AND (NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
# Add module directory to pick up custom Info.plist template for macOS
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/macos")
elseif(APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
# Add module directory to pick up custom Info.plist template for iOS
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/ios")
endif()
set(QT_ADDITIONAL_PACKAGES_PREFIX_PATH "" CACHE STRING "Additional directories where find(Qt6 ...) components are searched")

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -562,6 +562,144 @@ function(qt6_finalize_executable target)
if(EMSCRIPTEN)
qt_wasm_add_target_helpers("${target}")
endif()
if(IOS)
qt6_finalize_ios_app("${target}")
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)
if(teams_xml AND NOT plist_error)
string(REPLACE "\n" ";" teams_xml_lines "${teams_xml}")
foreach(xml_line ${teams_xml_lines})
if(xml_line MATCHES "<key>(.+)</key>")
set(first_account "${CMAKE_MATCH_1}")
string(STRIP "${first_account}" first_account)
break()
endif()
endforeach()
endif()
if(NOT first_account)
message(DEBUG "Failed to extract an Xcode development team id.")
return()
endif()
# Extract the first team ID
execute_process(COMMAND "/usr/libexec/PlistBuddy"
-c "print IDEProvisioningTeams:${first_account}:0:teamID"
"${xcode_preferences_path}"
OUTPUT_VARIABLE team_id
ERROR_VARIABLE team_id_error)
if(team_id AND NOT team_id_error)
message(DEBUG "Successfully extracted the first encountered Xcode development team id.")
string(STRIP "${team_id}" team_id)
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id "${team_id}")
set("${out_var}" "${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 indentifier prefix.")
string(STRIP "${prefix}" prefix)
else()
message(DEBUG "Failed to extract the default bundle indentifier prefix.")
endif()
if(prefix)
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix "${prefix}")
set("${out_var}" "${prefix}" PARENT_SCOPE)
endif()
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")
endif()
set("${out_var}" "${prefix}.\${PRODUCT_NAME:rfc1034identifier}" PARENT_SCOPE)
endfunction()
function(qt6_finalize_ios_app 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()
# If user hasn't provided a bundle identifier for the app, get a default identifier
# using the default bundle prefix from Xcode preferences and add it to the generated
# Info.plist file.
if(NOT MACOSX_BUNDLE_GUI_IDENTIFIER AND NOT QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
get_target_property(existing_id "${target}" MACOSX_BUNDLE_GUI_IDENTIFIER)
if(NOT existing_id)
_qt_internal_get_default_ios_bundle_identifier(bundle_id)
set_target_properties("${target}"
PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "${bundle_id}")
endif()
endif()
# Reuse the same bundle identifier for the Xcode property.
if(NOT CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
AND NOT QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
get_target_property(existing_id "${target}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
if(NOT existing_id)
set_target_properties("${target}"
PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
"${bundle_id}")
endif()
endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)