From 55a15a1c1b93d36d705fc69e44b5c806b807dd55 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 8 Apr 2019 17:23:57 +0200 Subject: Add initial support for cross-building to iOS Tested locally with the following configurations: - iOS device builds (arm64) - iOS simulator builds (x86_64) - iOS simulator_and_device builds (fat arm64 and x86_64 archives) All iOS builds currently require a custom vcpkg fork which contains fixes for building the required 3rd party libraries. qtsvg, qtdeclarative, qtgraphicaleffects and qtquickcontrols2 have also been tested to build successfully. simulator_and_device builds are also supported, but require an umerged patch in upstream CMake as well as further patches to vcpkg. Task-number: QTBUG-75576 Change-Id: Icd29913fbbd52a60e07ea5253fd9c7af7f8ce44c Reviewed-by: Cristian Adam Reviewed-by: Qt CMake Build Bot Reviewed-by: Leander Beernaert --- cmake/FindGLESv2.cmake | 27 +++++- cmake/QtAutoDetect.cmake | 97 ++++++++++++++++++++++ cmake/QtBaseConfigureTests.cmake | 43 +++++++--- cmake/QtBaseGlobalTargets.cmake | 31 ++++++- cmake/QtBuild.cmake | 8 +- cmake/QtCompilerOptimization.cmake | 4 +- cmake/QtFeature.cmake | 61 +++++++++++++- cmake/QtInternalTargets.cmake | 12 +++ cmake/QtPlatformSupport.cmake | 10 +-- cmake/QtSetup.cmake | 15 +++- cmake/README.md | 53 +++++++++++- config.tests/arch/CMakeLists.txt | 6 ++ configure.cmake | 2 +- src/gui/CMakeLists.txt | 10 +++ src/plugins/platforms/CMakeLists.txt | 2 +- src/plugins/platforms/ios/.prev_CMakeLists.txt | 81 ++++++++++++++++++ src/plugins/platforms/ios/CMakeLists.txt | 72 ++++++++++++++++ src/plugins/platforms/ios/optional/CMakeLists.txt | 6 ++ .../optional/nsphotolibrarysupport/CMakeLists.txt | 30 +++++++ tests/auto/CMakeLists.txt | 15 +++- tests/manual/CMakeLists.txt | 7 ++ util/cmake/configurejson2cmake.py | 1 + 22 files changed, 558 insertions(+), 35 deletions(-) create mode 100644 config.tests/arch/CMakeLists.txt create mode 100644 src/plugins/platforms/ios/.prev_CMakeLists.txt create mode 100644 src/plugins/platforms/ios/CMakeLists.txt create mode 100644 src/plugins/platforms/ios/optional/CMakeLists.txt create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt diff --git a/cmake/FindGLESv2.cmake b/cmake/FindGLESv2.cmake index 02df910285..49e757ef55 100644 --- a/cmake/FindGLESv2.cmake +++ b/cmake/FindGLESv2.cmake @@ -5,8 +5,8 @@ include(CheckCXXSourceCompiles) if(EMSCRIPTEN) set(HAVE_GLESv2 ON) else() - find_library(GLESv2_LIBRARY NAMES GLESv2) - find_path(GLESv2_INCLUDE_DIR NAMES "GLES2/gl2.h" DOC "The OpenGLES 2 include path") + find_library(GLESv2_LIBRARY NAMES GLESv2 OpenGLES) + find_path(GLESv2_INCLUDE_DIR NAMES "GLES2/gl2.h" "OpenGLES/ES2/gl.h" DOC "The OpenGLES 2 include path") set(_libraries "${CMAKE_REQUIRED_LIBRARIES}") list(APPEND CMAKE_REQUIRED_LIBRARIES "${GLESv2_LIBRARY}") set(_includes "${CMAKE_REQUIRED_INCLUDES}") @@ -32,6 +32,20 @@ int main(int argc, char *argv[]) { set(package_args GLESv2_INCLUDE_DIR GLESv2_LIBRARY HAVE_GLESv2) endif() +# Framework handling partially inspired by FindGLUT.cmake. +if(GLESv2_LIBRARY MATCHES "/([^/]+)\\.framework$") + # TODO: Might need to handle non .tbd suffixes, but didn't find an + # example like that. + # TODO: Might need to handle INTERFACE_INCLUDE_DIRECTORIES differently. + set(_library_imported_location "${GLESv2_LIBRARY}/${CMAKE_MATCH_1}.tbd") + if(NOT EXISTS "${_library_imported_location}") + set(_library_imported_location "") + endif() +else() + set(_library_imported_location "${GLESv2_LIBRARY}") +endif() +set(GLESv2_LIBRARY "${_library_imported_location}") + list(APPEND package_args HAVE_GLESv2) include(FindPackageHandleStandardArgs) @@ -40,8 +54,15 @@ find_package_handle_standard_args(GLESv2 DEFAULT_MSG ${package_args}) mark_as_advanced(${package_args}) if(GLESv2_FOUND AND NOT TARGET GLESv2::GLESv2) - if(EMSCRIPTEN) + if(EMSCRIPTEN OR APPLE_UIKIT) add_library(GLESv2::GLESv2 INTERFACE IMPORTED) + if(APPLE_UIKIT) + # For simulator_and_device builds we can't specify the full library path, because + # it's specific to either the device or the simulator. Resort to passing a link + # flag instead. + set_target_properties(GLESv2::GLESv2 PROPERTIES + INTERFACE_LINK_LIBRARIES "-framework OpenGLES") + endif() else() add_library(GLESv2::GLESv2 UNKNOWN IMPORTED) set_target_properties(GLESv2::GLESv2 PROPERTIES diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake index 7864d40501..1823d1e572 100644 --- a/cmake/QtAutoDetect.cmake +++ b/cmake/QtAutoDetect.cmake @@ -59,6 +59,103 @@ function(qt_auto_detect_vpckg) endif() endfunction() +function(qt_auto_detect_ios) + if(CMAKE_SYSTEM_NAME STREQUAL iOS + OR CMAKE_SYSTEM_NAME STREQUAL watchOS + OR CMAKE_SYSTEM_NAME STREQUAL tvOS) + message(STATUS "Using internal CMake ${CMAKE_SYSTEM_NAME} toolchain file.") + # The QT_UIKIT_SDK check simulates the input.sdk condition for simulator_and_device in + # configure.json. + # If the variable is explicitly provided, assume simulator_and_device to be off. + if(QT_UIKIT_SDK) + set(simulator_and_device OFF) + elseif(QT_FORCE_SIMULATOR_AND_DEVICE) + # TODO: Once we get simulator_and_device support in upstream CMake, only then allow + # usage of simulator_and_device without forcing. + set(simulator_and_device ON) + else() + # If QT_UIKIT_SDK is not provided, default to simulator. + set(simulator_and_device OFF) + set(QT_UIKIT_SDK "iphonesimulator" CACHE "STRING" "Chosen uikit SDK.") + endif() + + message(STATUS "simulator_and_device set to: \"${simulator_and_device}\".") + + # Choose relevant architectures. + # Using a non xcode generator requires explicit setting of the + # architectures, otherwise compilation fails with unknown defines. + if(CMAKE_SYSTEM_NAME STREQUAL iOS) + if(simulator_and_device) + set(osx_architectures "arm64;x86_64") + elseif(QT_UIKIT_SDK STREQUAL "iphoneos") + set(osx_architectures "arm64") + elseif(QT_UIKIT_SDK STREQUAL "iphonesimulator") + set(osx_architectures "x86_64") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: iphoneos, iphonesimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS) + if(simulator_and_device) + set(osx_architectures "arm64;x86_64") + elseif(QT_UIKIT_SDK STREQUAL "appletvos") + set(osx_architectures "arm64") + elseif(QT_UIKIT_SDK STREQUAL "appletvsimulator") + set(osx_architectures "x86_64") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: appletvos, appletvsimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS) + if(simulator_and_device) + set(osx_architectures "armv7k;i386") + elseif(QT_UIKIT_SDK STREQUAL "watchos") + set(osx_architectures "armv7k") + elseif(QT_UIKIT_SDK STREQUAL "watchsimulator") + set(osx_architectures "i386") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: watchos, watchsimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + endif() + + # For non simulator_and_device builds, we need to explicitly set the SYSROOT aka the sdk + # value. + if(QT_UIKIT_SDK) + set(CMAKE_OSX_SYSROOT "${QT_UIKIT_SDK}" CACHE STRING "") + endif() + message(STATUS "CMAKE_OSX_SYSROOT set to: \"${CMAKE_OSX_SYSROOT}\".") + + message(STATUS "CMAKE_OSX_ARCHITECTURES set to: \"${osx_architectures}\".") + set(CMAKE_OSX_ARCHITECTURES "${osx_architectures}" CACHE STRING "") + + if(NOT DEFINED BUILD_SHARED_LIBS) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE) + endif() + + if(BUILD_SHARED_LIBS) + message(FATAL_ERROR + "Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.") + endif() + endif() +endfunction() + +qt_auto_detect_ios() qt_auto_detect_android() qt_auto_detect_vpckg() diff --git a/cmake/QtBaseConfigureTests.cmake b/cmake/QtBaseConfigureTests.cmake index 6b46ed26b2..777adb7b5f 100644 --- a/cmake/QtBaseConfigureTests.cmake +++ b/cmake/QtBaseConfigureTests.cmake @@ -1,27 +1,41 @@ include(CheckCXXSourceCompiles) + function(qt_run_config_test_architecture) set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT "" CACHE INTERNAL "Test variables that should be exported" FORCE) - # Test architecture - set(_arch_file "${CMAKE_CURRENT_BINARY_DIR}/architecture_test") - set(saved_executable_suffix "${CMAKE_EXECUTABLE_SUFFIX}") - # With emscripten the application entry point is a .js file (to be run with node for example), but the - # real "data" is in the .wasm file, so that's where we need to look for the ABI, etc. information. - if (EMSCRIPTEN) - set(CMAKE_EXECUTABLE_SUFFIX ".wasm") - endif() + # Compile test to find the target architecture and sub-architectures. + set(flags "") + qt_get_platform_try_compile_vars(platform_try_compile_vars) + list(APPEND flags ${platform_try_compile_vars}) - try_compile(_arch_result "${CMAKE_CURRENT_BINARY_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/arch/arch.cpp" - COPY_FILE "${_arch_file}") - - set(CMAKE_EXECUTABLE_SUFFIX "${saved_executable_suffix}") + try_compile( + _arch_result + "${CMAKE_CURRENT_BINARY_DIR}/config.tests/arch" + "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/arch" + arch + CMAKE_FLAGS ${flags} + ) if (NOT _arch_result) message(FATAL_ERROR "Failed to compile architecture detection file.") endif() + set(_arch_file_suffix "${CMAKE_EXECUTABLE_SUFFIX}") + # With emscripten the application entry point is a .js file (to be run with node for example), + # but the real "data" is in the .wasm file, so that's where we need to look for the ABI, etc. + # information. + if (EMSCRIPTEN) + set(_arch_file_suffix ".wasm") + endif() + set(_arch_file + "${CMAKE_CURRENT_BINARY_DIR}/config.tests/arch/architecture_test${_arch_file_suffix}") + if (NOT EXISTS "${_arch_file}") + message(FATAL_ERROR + "Failed to find compiled architecture detection executable at ${_arch_file}.") + endif() + message(STATUS "Extracting architecture info from ${_arch_file}.") + file(STRINGS "${_arch_file}" _arch_lines LENGTH_MINIMUM 16 LENGTH_MAXIMUM 1024 ENCODING UTF-8) foreach (_line ${_arch_lines}) @@ -60,6 +74,9 @@ function(qt_run_config_test_architecture) set(TEST_buildAbi "${_build_abi}" CACHE INTERNAL "Target machine buildAbi") list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_buildAbi) set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT ${QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT} CACHE INTERNAL "Test variables that should be exported") + + list(JOIN _sub_architecture " " subarch_summary) + message(STATUS "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${TEST_architecture_arch}, CPU features: ${subarch_summary})") endfunction() diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index 66ec2c73e4..ad15207005 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -91,11 +91,27 @@ list(APPEND init_platform "set(CMAKE_CXX_COMPILER \"${CMAKE_CXX_COMPILER}\" CACH list(APPEND init_platform "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\" CACHE STRING \"\")") if(APPLE) - if(CMAKE_OSX_SYSROOT) + # For simulator_and_device build, we should not explicitly set the sysroot. + list(LENGTH CMAKE_OSX_ARCHITECTURES _qt_osx_architectures_count) + if(CMAKE_OSX_SYSROOT AND NOT _qt_osx_architectures_count GREATER 1 AND APPLE_UIKIT) list(APPEND init_platform "set(CMAKE_OSX_SYSROOT \"${CMAKE_OSX_SYSROOT}\" CACHE PATH \"\")") endif() + unset(_qt_osx_architectures_count) + if(CMAKE_OSX_DEPLOYMENT_TARGET) - list(APPEND init_platform "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")") + list(APPEND init_platform + "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")") + endif() + + if(APPLE_UIKIT) + list(APPEND init_platform + "set(CMAKE_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\" CACHE STRING \"\")") + set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}") + string(REPLACE ";" "LITERAL_SEMICOLON" + _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}") + list(APPEND init_platform + "set(CMAKE_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"\")") + unset(_qt_osx_architectures_escaped) endif() elseif(ANDROID) list(APPEND init_platform "set(ANDROID_NATIVE_API_LEVEL \"${ANDROID_NATIVE_API_LEVEL}\" CACHE STRING \"\")") @@ -108,6 +124,7 @@ endif() string(REPLACE ";" "\n" init_vcpkg "${init_vcpkg}") string(REPLACE ";" "\n" init_platform "${init_platform}") +string(REPLACE "LITERAL_SEMICOLON" ";" init_platform "${init_platform}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt.toolchain.cmake.in" "${__GlobalConfig_build_dir}/qt.toolchain.cmake" @ONLY) qt_install(FILES "${__GlobalConfig_build_dir}/qt.toolchain.cmake" DESTINATION "${__GlobalConfig_install_dir}" COMPONENT Devel) @@ -135,6 +152,16 @@ qt_feature_module_begin(NO_MODULE PRIVATE_FILE src/corelib/global/qconfig_p.h ) include("${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") + +# Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for +# simulator_and_device_builds. +if(APPLE_UIKIT AND NOT QT_UIKIT_SDK) + set(__QtFeature_custom_enabled_cache_variables + TEST_subarch_sse2 + FEATURE_sse2 + QT_FEATURE_sse2) +endif() + qt_feature_module_end(GlobalConfig OUT_VAR_PREFIX "__GlobalConfig_") qt_generate_global_config_pri_file() diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 13e954cd57..a1b044b97d 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -1895,6 +1895,8 @@ function(qt_add_plugin target) "${ARGN}" ) + qt_get_sanitized_plugin_type("${arg_TYPE}" arg_TYPE) + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}") set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}") set(archive_install_directory_default "${INSTALL_LIBDIR}/${arg_TYPE}") @@ -2760,7 +2762,7 @@ function(qt_add_cmake_library target) ### Define Targets: if(${arg_INTERFACE}) add_library("${target}" INTERFACE) - elseif(${arg_STATIC}) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) add_library("${target}" STATIC) elseif(${arg_SHARED}) add_library("${target}" SHARED) @@ -3376,10 +3378,14 @@ endfunction() macro(qt_find_apple_system_frameworks) if(APPLE) find_library(FWAppKit AppKit) + find_library(FWAssetsLibrary AssetsLibrary) + find_library(FWAudioToolbox AudioToolbox) find_library(FWApplicationServices ApplicationServices) find_library(FWCarbon Carbon) find_library(FWCoreFoundation CoreFoundation) find_library(FWCoreServices CoreServices) + find_library(FWCoreGraphics CoreGraphics) + find_library(FWCoreText CoreText) find_library(FWCoreVideo CoreVideo) find_library(FWcups cups) find_library(FWDiskArbitration DiskArbitration) diff --git a/cmake/QtCompilerOptimization.cmake b/cmake/QtCompilerOptimization.cmake index 5ca28c4de4..f1ebafc009 100644 --- a/cmake/QtCompilerOptimization.cmake +++ b/cmake/QtCompilerOptimization.cmake @@ -62,7 +62,9 @@ if(GCC OR CLANG) set(QT_CFLAGS_AVX512VBMI "-mavx512vbmi") set(QT_CFLAGS_AESNI "-maes") set(QT_CFLAGS_SHANI "-msha") - set(QT_CFLAGS_NEON "-mfpu=neon") + if(NOT APPLE_UIKIT) + set(QT_CFLAGS_NEON "-mfpu=neon") + endif() set(QT_CFLAGS_MIPS_DSP "-mdsp") set(QT_CFLAGS_MIPS_DSPR2 "-mdspr2") endif() diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake index 9849390922..b3e5eb9b8a 100644 --- a/cmake/QtFeature.cmake +++ b/cmake/QtFeature.cmake @@ -360,6 +360,14 @@ function(qt_feature_module_end) qt_evaluate_feature(${feature}) endforeach() + # Evaluate custom cache assignments. + foreach(cache_var_name ${__QtFeature_custom_enabled_cache_variables}) + set(${cache_var_name} ON CACHE BOOL "Force enabled by platform." FORCE) + endforeach() + foreach(cache_var_name ${__QtFeature_custom_disabled_cache_variables}) + set(${cache_var_name} OFF CACHE BOOL "Force disabled by platform." FORCE) + endforeach() + set(enabled_public_features "") set(disabled_public_features "") set(enabled_private_features "") @@ -445,6 +453,8 @@ function(qt_feature_module_end) unset(__QtFeature_public_extra PARENT_SCOPE) unset(__QtFeature_define_definitions PARENT_SCOPE) + unset(__QtFeature_custom_enabled_features PARENT_SCOPE) + unset(__QtFeature_custom_disabled_features PARENT_SCOPE) endfunction() function(qt_feature_copy_global_config_features_to_core target) @@ -527,18 +537,65 @@ function(qt_config_compile_test name) set(TEST_${name} "${HAVE_${name}}" CACHE INTERNAL "${arg_LABEL}") endfunction() +# This function should be used for passing required try compile platform variables to the +# project-based try_compile() call. +# out_var will be a list of -Dfoo=bar strings, suitable to pass to CMAKE_FLAGS. +function(qt_get_platform_try_compile_vars out_var) + # Use the regular variables that are used for source-based try_compile() calls. + set(flags "${CMAKE_TRY_COMPILE_PLATFORM_VARIABLES}") + + # Pass toolchain files. + if(CMAKE_TOOLCHAIN_FILE) + list(APPEND flags "CMAKE_TOOLCHAIN_FILE") + endif() + if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE) + list(APPEND flags "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") + endif() + + # Assemble the list with regular options. + set(flags_cmd_line "") + foreach(flag ${flags}) + if(${flag}) + list(APPEND flags_cmd_line "-D${flag}=${${flag}}") + endif() + endforeach() + + # Pass darwin specific options. + if(APPLE_UIKIT) + if(CMAKE_OSX_ARCHITECTURES) + list(GET CMAKE_OSX_ARCHITECTURES 0 osx_first_arch) + + # Do what qmake does, aka when doing a simulator_and_device build, build the + # target architecture test only with the first given architecture, which should be the + # device architecture, aka some variation of "arm" (armv7, arm64). + list(APPEND flags_cmd_line "-DCMAKE_OSX_ARCHITECTURES:STRING=${osx_first_arch}") + endif() + # Also specify the sysroot, but only if not doing a simulator_and_device build. + # So keep the sysroot empty for simulator_and_device builds. + if(QT_UIKIT_SDK) + list(APPEND flags_cmd_line "-DCMAKE_OSX_SYSROOT:STRING=${QT_UIKIT_SDK}") + endif() + endif() + + set("${out_var}" "${flags_cmd_line}" PARENT_SCOPE) +endfunction() + function(qt_config_compile_test_x86simd extension label) if (DEFINED TEST_X86SIMD_${extension}) return() endif() + set(flags "-DSIMD:string=${extension}") + + qt_get_platform_try_compile_vars(platform_try_compile_vars) + list(APPEND flags ${platform_try_compile_vars}) + message(STATUS "Performing SIMD Test ${label}") try_compile("TEST_X86SIMD_${extension}" "${CMAKE_CURRENT_BINARY_DIR}/config.tests/x86_simd_${extension}" "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/x86_simd" x86_simd - CMAKE_FLAGS "-DSIMD:string=${extension}") - + CMAKE_FLAGS ${flags}) if(${TEST_X86SIMD_${extension}}) set(status_label "Success") else() diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake index 2db065fbf5..54e7f4f50e 100644 --- a/cmake/QtInternalTargets.cmake +++ b/cmake/QtInternalTargets.cmake @@ -100,3 +100,15 @@ endif() if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) target_compile_definitions(PlatformCommonInternal INTERFACE QT_NO_DEBUG) endif() + +if(APPLE_UIKIT) + # Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for + # simulator_and_device_builds. + if(FEATURE_simulator_and_device) + # Setting the definition on PlatformCommonInternal behaves slightly differently from what + # is done in qmake land. This way the define is not propagated to tests, examples, or + # user projects built with qmake, but only modules, plugins and tools. + # TODO: Figure out if this ok or not (sounds ok to me). + target_compile_definitions(PlatformCommonInternal INTERFACE QT_COMPILER_SUPPORTS_SSE2) + endif() +endif() diff --git a/cmake/QtPlatformSupport.cmake b/cmake/QtPlatformSupport.cmake index ac8e8f6ad2..b54d52eba4 100644 --- a/cmake/QtPlatformSupport.cmake +++ b/cmake/QtPlatformSupport.cmake @@ -22,11 +22,11 @@ qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD) qt_set01(WINRT WIN32 AND CMAKE_VS_PLATFORM_TOOSLET STREQUAL "winrt") # FIXME: How to identify this? -qt_set01(APPLE_OSX APPLE) # FIXME: How to identify this? For now assume that always building for macOS. -qt_set01(APPLE_UIKIT APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "uikit") # FIXME: How to identify this? -qt_set01(APPLE_IOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "ios") # FIXME: How to identify this? -qt_set01(APPLE_TVOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "tvos") # FIXME: How to identify this? -qt_set01(APPLE_WATCHOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "watchos") # FIXME: How to identify this? +qt_set01(APPLE_IOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS") +qt_set01(APPLE_TVOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "tvOS") +qt_set01(APPLE_WATCHOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "watchOS") +qt_set01(APPLE_UIKIT APPLE AND (APPLE_IOS OR APPLE_TVOS OR APPLE_WATCHOS)) +qt_set01(APPLE_OSX APPLE AND NOT APPLE_UIKIT) qt_set01(GCC CMAKE_CXX_COMPILER_ID STREQUAL "GNU") qt_set01(CLANG CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake index 1f209e8076..65bd5b9a21 100644 --- a/cmake/QtSetup.cmake +++ b/cmake/QtSetup.cmake @@ -75,6 +75,12 @@ if(FEATURE_developer_build) set(QT_BUILD_TESTING ON) set(__build_benchmarks ON) + # Tests are not built by default with qmake for iOS and friends, and thus the overall build + # tends to fail. Disable them by default when targeting uikit. + if(APPLE_UIKIT) + set(QT_BUILD_TESTING OFF) + endif() + # Disable benchmarks for single configuration generators which do not build # with release configuration. if (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL Release) @@ -104,7 +110,14 @@ include(CTest) enable_testing() # Set up building of examples. -option(BUILD_EXAMPLES "Build Qt examples" ON) +set(QT_BUILD_EXAMPLES ON) +# Examples are not built by default with qmake for iOS and friends, and thus the overall build +# tends to fail. Disable them by default when targeting uikit. +if(APPLE_UIKIT) + set(QT_BUILD_EXAMPLES OFF) +endif() + +option(BUILD_EXAMPLES "Build Qt examples" ${QT_BUILD_EXAMPLES}) option(QT_NO_MAKE_EXAMPLES "Should examples be built as part of the default 'all' target." OFF) # Build Benchmarks diff --git a/cmake/README.md b/cmake/README.md index 5739b900f7..6c27bc9300 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -201,7 +201,7 @@ When running cmake in qtbase, pass ``-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DQT_HOST_PATH=/path/to/your/host/build -DANDROID_SDK_ROOT=$ANDROID_SDK_HOME -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH`` If you don't supply the configuration argument ``-DANDROID_ABI=...``, it will default to -``armeabi-v7a``. To target other architectures, use on of the following values: +``armeabi-v7a``. To target other architectures, use one of the following values: * arm64: ``-DANDROID_ABI=arm64-v8`` * x86: ``-DANDROID_ABI=x86`` * x86_64: ``-DANDROID_ABI=x86_64`` @@ -209,6 +209,57 @@ If you don't supply the configuration argument ``-DANDROID_ABI=...``, it will de By default we set the android API level to 21. Should you need to change this supply the following configuration argument to the above CMake call: ``-DANDROID_NATIVE_API_LEVEL=${API_LEVEL}`` +### Cross compiling for iOS + +In order to cross-compile Qt to iOS, you need a host macOS build. +In addition, it is necessary to install a custom version of vcpkg. Vcpkg is +needed to supply third-party libraries that Qt requires, but that are not part of the iOS SDK. + +Vcpkg for iOS can be set up using the following steps: + + * ```git clone -b qt https://github.com/alcroito/vcpkg``` + * Run ```bootstrap-vcpkg.sh``` + * Set the ``VCPKG_DEFAULT_TRIPLET`` environment variable to one of the following values: + * ``x64-ios`` (simulator x86_64) + * ``x86-ios`` (simulator i386) + * ``arm64-ios`` (device arm64) + * ``arm-ios`` (device armv7) + * ``fat-ios`` (simulator_and_device x86_64 and arm64* - special considedrations) + * Set the ``VCPKG_ROOT`` environment variable to the path where you cloned vcpkg + * Build Qt dependencies: ``vcpkg install @qt-packages-ios.txt`` + +When running cmake in qtbase, pass +``-DCMAKE_SYSTEM_NAME=iOS -DQT_HOST_PATH=/path/to/your/host/build -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH`` + +If you don't supply the configuration argument ``-DQT_UIKIT_SDK=...``, it will default to +``iphonesimulator``. To target another SDK / device type, use one of the following values: + * iphonesimulator: ``-DQT_UIKIT_SDK=iphonesimulator`` + * iphoneos: ``-DQT_UIKIT_SDK=iphoneos`` + * simulator_and_device: ``-DQT_FORCE_SIMULATOR_AND_DEVICE=ON -DQT_UIKIT_SDK=`` + +Depending on what value you pass to ``-DQT_UIKIT_SDK=`` a list of target architectures is chosen +by default: + * iphonesimulator: ``x86_64`` + * iphoneos: ``arm64`` + * simulator_and_device: ``arm64;x86_64`` + +You can try choosing a different list of architectures by passing +``-DCMAKE_OSX_ARCHITECTURES=x86_64;i386``. +Note that if you choose different architectures compared to the default ones, the build might fail. +Only do it if you know what you are doing. + +#### simulator_and_device special considerations +To do a simulator_and_device build, a custom version of CMake is required in addition to the vcpkg +fork. The merge request can be found here: +https://gitlab.kitware.com/cmake/cmake/merge_requests/3617 + +After you build your own copy of CMake using this merge request, you need to use it for both +vcpkg and Qt. + +Note that vcpkg prefers its own version of CMake when building packages. +Make sure to put your custom built CMake in PATH, and force vcpkg to use this CMake by running +``export VCPKG_FORCE_SYSTEM_BINARIES=1`` in your shell. + # Debugging CMake files CMake allows specifying the ``--trace`` and ``--trace-expand`` options, which work like diff --git a/config.tests/arch/CMakeLists.txt b/config.tests/arch/CMakeLists.txt new file mode 100644 index 0000000000..c0873a984f --- /dev/null +++ b/config.tests/arch/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.15.0) +project(arch LANGUAGES CXX) + +add_executable(architecture_test) +set_property(TARGET architecture_test PROPERTY MACOSX_BUNDLE FALSE) +target_sources(architecture_test PRIVATE arch.cpp) diff --git a/configure.cmake b/configure.cmake index 8ac9749663..4118f57f22 100644 --- a/configure.cmake +++ b/configure.cmake @@ -333,7 +333,7 @@ qt_feature("appstore_compliant" PUBLIC ) qt_feature("simulator_and_device" PUBLIC LABEL "Build for both simulator and device" - CONDITION APPLE_UIKIT AND INPUT_sdk STREQUAL '' + CONDITION APPLE_UIKIT AND NOT QT_UIKIT_SDK ) qt_feature("force_asserts" PUBLIC LABEL "Force assertions" diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index f081979aff..9f146721c0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -594,6 +594,16 @@ qt_extend_target(Gui CONDITION QT_FEATURE_harfbuzz WrapHarfbuzz::WrapHarfbuzz ) +# special case begin +# Replicate what src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro does, which is link CoreText +# when targeting uikit. + +qt_extend_target(Gui CONDITION QT_FEATURE_harfbuzz AND APPLE_UIKIT + LIBRARIES + ${FWCoreText} +) +# special case end + qt_extend_target(Gui CONDITION QT_FEATURE_textodfwriter SOURCES text/qtextodfwriter.cpp text/qtextodfwriter_p.h diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt index aba67bd59b..57c3952e4c 100644 --- a/src/plugins/platforms/CMakeLists.txt +++ b/src/plugins/platforms/CMakeLists.txt @@ -13,7 +13,7 @@ if(QT_FEATURE_xcb) add_subdirectory(xcb) endif() if(APPLE_UIKIT AND NOT APPLE_WATCHOS) - # add_subdirectory(ios) special case TODO + add_subdirectory(ios) endif() if(APPLE_OSX) add_subdirectory(cocoa) diff --git a/src/plugins/platforms/ios/.prev_CMakeLists.txt b/src/plugins/platforms/ios/.prev_CMakeLists.txt new file mode 100644 index 0000000000..f23cf8c300 --- /dev/null +++ b/src/plugins/platforms/ios/.prev_CMakeLists.txt @@ -0,0 +1,81 @@ +# Generated from ios.pro. + +##################################################################### +## qios Plugin: +##################################################################### + +add_qt_plugin(qios + TYPE platforms + CLASS_NAME QIOSIntegrationPlugin + SOURCES + plugin.mm + qiosapplicationdelegate.h qiosapplicationdelegate.mm + qiosapplicationstate.h qiosapplicationstate.mm + qiosbackingstore.h qiosbackingstore.mm + qioscontext.h qioscontext.mm + qioseventdispatcher.h qioseventdispatcher.mm + qiosglobal.h qiosglobal.mm + qiosinputcontext.h qiosinputcontext.mm + qiosintegration.h qiosintegration.mm + qiosplatformaccessibility.h qiosplatformaccessibility.mm + qiosscreen.h qiosscreen.mm + qiosservices.h qiosservices.mm + qiostextresponder.h qiostextresponder.mm + qiostheme.h qiostheme.mm + qiosviewcontroller.h qiosviewcontroller.mm + qioswindow.h qioswindow.mm + quiaccessibilityelement.h quiaccessibilityelement.mm + quiview.h quiview.mm + LIBRARIES + Qt::ClipboardSupportPrivate + Qt::CorePrivate + Qt::FontDatabaseSupportPrivate + Qt::GraphicsSupportPrivate + Qt::GuiPrivate + PUBLIC_LIBRARIES + ${FWAudioToolbox} + ${FWFoundation} + ${FWQuartzCore} + ${FWUIKit} + Qt::ClipboardSupport + Qt::Core + Qt::FontDatabaseSupport + Qt::GraphicsSupport + Qt::Gui +) + +#### Keys ignored in scope 2:.:.:kernel.pro:: +# OTHER_FILES = "quiview_textinput.mm" "quiview_accessibility.mm" +# PLUGIN_CLASS_NAME = "QIOSIntegrationPlugin" +# PLUGIN_TYPE = "platforms" +# _LOADED = "qt_plugin" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 3:.:.:kernel.pro:QT_FEATURE_shared: +# CONFIG = "static" + +extend_target(qios CONDITION NOT APPLE_TVOS + SOURCES + qiosclipboard.h qiosclipboard.mm + qiosfiledialog.h qiosfiledialog.mm + qiosmenu.h qiosmenu.mm + qiosmessagedialog.h qiosmessagedialog.mm + qiostextinputoverlay.h qiostextinputoverlay.mm + PUBLIC_LIBRARIES + ${FWAssetsLibrary} +) + +#### Keys ignored in scope 5:.:.:kernel.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN: +# PLUGIN_EXTENDS = "-" +add_subdirectory(optional) + + if(QT_FEATURE_shared) + endif() + + if(NOT APPLE_TVOS) + endif() + + if(NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN) + endif() diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt new file mode 100644 index 0000000000..4c9cac2bee --- /dev/null +++ b/src/plugins/platforms/ios/CMakeLists.txt @@ -0,0 +1,72 @@ +# Generated from ios.pro. + +##################################################################### +## qios Plugin: +##################################################################### + +add_qt_plugin(qios + TYPE platforms + CLASS_NAME QIOSIntegrationPlugin + SOURCES + plugin.mm + qiosapplicationdelegate.h qiosapplicationdelegate.mm + qiosapplicationstate.h qiosapplicationstate.mm + qiosbackingstore.h qiosbackingstore.mm + qioscontext.h qioscontext.mm + qioseventdispatcher.h qioseventdispatcher.mm + qiosglobal.h qiosglobal.mm + qiosinputcontext.h qiosinputcontext.mm + qiosintegration.h qiosintegration.mm + qiosplatformaccessibility.h qiosplatformaccessibility.mm + qiosscreen.h qiosscreen.mm + qiosservices.h qiosservices.mm + qiostextresponder.h qiostextresponder.mm + qiostheme.h qiostheme.mm + qiosviewcontroller.h qiosviewcontroller.mm + qioswindow.h qioswindow.mm + quiaccessibilityelement.h quiaccessibilityelement.mm + quiview.h quiview.mm + LIBRARIES + Qt::ClipboardSupportPrivate + Qt::CorePrivate + Qt::FontDatabaseSupportPrivate + Qt::GraphicsSupportPrivate + Qt::GuiPrivate + PUBLIC_LIBRARIES + ${FWAudioToolbox} + ${FWFoundation} + ${FWQuartzCore} + ${FWUIKit} + Qt::ClipboardSupport + Qt::Core + Qt::FontDatabaseSupport + Qt::GraphicsSupport + Qt::Gui +) + +#### Keys ignored in scope 2:.:.:kernel.pro:: +# OTHER_FILES = "quiview_textinput.mm" "quiview_accessibility.mm" +# PLUGIN_CLASS_NAME = "QIOSIntegrationPlugin" +# PLUGIN_TYPE = "platforms" +# _LOADED = "qt_plugin" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 3:.:.:kernel.pro:QT_FEATURE_shared: +# CONFIG = "static" + +extend_target(qios CONDITION NOT APPLE_TVOS + SOURCES + qiosclipboard.h qiosclipboard.mm + qiosfiledialog.h qiosfiledialog.mm + qiosmenu.h qiosmenu.mm + qiosmessagedialog.h qiosmessagedialog.mm + qiostextinputoverlay.h qiostextinputoverlay.mm + PUBLIC_LIBRARIES + ${FWAssetsLibrary} +) + +#### Keys ignored in scope 5:.:.:kernel.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN: +# PLUGIN_EXTENDS = "-" +add_subdirectory(optional) diff --git a/src/plugins/platforms/ios/optional/CMakeLists.txt b/src/plugins/platforms/ios/optional/CMakeLists.txt new file mode 100644 index 0000000000..a3807bee6c --- /dev/null +++ b/src/plugins/platforms/ios/optional/CMakeLists.txt @@ -0,0 +1,6 @@ +# Generated from optional.pro. + + +if(APPLE_IOS) + add_subdirectory(nsphotolibrarysupport) +endif() diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt new file mode 100644 index 0000000000..5adac3cabb --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated from nsphotolibrarysupport.pro. + +##################################################################### +## qiosnsphotolibrarysupport Plugin: +##################################################################### + +add_qt_plugin(qiosnsphotolibrarysupport + TYPE platforms/darwin + CLASS_NAME QIosOptionalPlugin_NSPhotoLibrary + SOURCES + plugin.mm + qiosfileengineassetslibrary.h qiosfileengineassetslibrary.mm + qiosfileenginefactory.h + qiosimagepickercontroller.h qiosimagepickercontroller.mm + LIBRARIES + Qt::GuiPrivate + PUBLIC_LIBRARIES + ${FWAssetsLibrary} + ${FWFoundation} + ${FWUIKit} + Qt::Core + Qt::Gui +) + +#### Keys ignored in scope 1:.:.:nsphotolibrarysupport.pro:: +# OTHER_FILES = "plugin.json" +# PLUGIN_EXTENDS = "-" + +## Scopes: +##################################################################### diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index 0bd3b47d92..c03838bee1 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -1,8 +1,6 @@ # Generated from auto.pro. -if (NOT APPLE_UIKIT) - add_subdirectory(corelib) -endif() +add_subdirectory(corelib) if (QT_FEATURE_dbus) set(run_dbus_tests ON) if(NOT CMAKE_CROSSCOMPILING AND TARGET Qt::DBus) @@ -22,9 +20,18 @@ if (QT_FEATURE_dbus) add_subdirectory(dbus) endif() endif() -if (NOT APPLE_UIKIT AND TARGET Qt::Gui) +if (TARGET Qt::Gui) add_subdirectory(gui) endif() + +# special case begin +# Build only corelib and gui tests when targeting uikit (iOS), +# because the script can't handle the SUBDIRS assignment well. +if (APPLE_UIKIT) + return() +endif() +# special case end + if (TARGET Qt::Network AND NOT WINRT) add_subdirectory(network) endif() diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt index 31547f6df7..9d5a3effaa 100644 --- a/tests/manual/CMakeLists.txt +++ b/tests/manual/CMakeLists.txt @@ -1,5 +1,12 @@ # Generated from manual.pro. +# special case begn +# Don't build manual tests when targeting iOS. +if(APPLE_UIKIT) + return() +endif() +# special case end + add_subdirectory(bearerex) add_subdirectory(filetest) add_subdirectory(embeddedintoforeignwindow) diff --git a/util/cmake/configurejson2cmake.py b/util/cmake/configurejson2cmake.py index 70d28c276b..481701eaed 100755 --- a/util/cmake/configurejson2cmake.py +++ b/util/cmake/configurejson2cmake.py @@ -708,6 +708,7 @@ def parseFeature(ctx, feature, data, cm_fh): "opengles2": { # special case to disable implicit feature on WIN32, until ANGLE is ported "condition": "NOT WIN32 AND ( NOT APPLE_WATCHOS AND NOT QT_FEATURE_opengl_desktop AND GLESv2_FOUND )" }, + "simulator_and_device": {"condition": "APPLE_UIKIT AND NOT QT_UIKIT_SDK"}, "pkg-config": None, "posix_fallocate": None, # Only needed for sqlite, which we do not want to build "posix-libiconv": { -- cgit v1.2.3