e379147f95
Before this change, we created a CMake toolchain file for iOS and macOS universal which propagated the initially configured CMAKE_OSX_ARCHITECTURES values to user projects. So if Qt was configured with 2 arches, configuring a CMake user project using the generated toolchain file would also build the user project targeting those 2 arches. The reason for this that the same toolchain file is used for configuring both Qt and users projects and we needed to ensure that other Qt repos are built with the same set of arches. That unfortunately led the multiple arches to carry over into user projects. This is different from qmake behavior which configured user projects with 1 arch only. Instead of the toolchain file explicitly setting CMAKE_OSX_ARCHITECTURES for all projects, save the initial list of arches into QT_OSX_ARCHITECTURES. Then if the toolchain file detects that we're building a Qt repo (by checking for the presence of QT_REPO_MODULE_VERSION) set CMAKE_OSX_ARCHITECTURES to QT_OSX_ARCHITECTURES to propagate the initial list of arches. For user projects we want to have some sensible defaults. For macOS projects, leave the decision of the architecture to build to CMake. For iOS Xcode projects, leave the decision to Xcode. For iOS Ninja projects, set the architecture to the first value of the architectures used when configuring Qt. As a side note this fixes an issue in our CI where we configured macOS Qt with 2 architectures and then tried to run CMake build tests for both architectures on a machine that doesn't have the universal SDK. This led to build failures. Because the CMake build tests act as regular user projects, now they are configured with a single architecture that is automtically detected by CMake. Pick-to: 6.1 Task-number: QTBUG-85447 Change-Id: Id1b7e78d7e67c1796efed10751416e5f857c16d2 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
210 lines
12 KiB
CMake
210 lines
12 KiB
CMake
# Create a CMake toolchain file for convenient configuration of both internal Qt builds
|
|
# as well as CMake application projects.
|
|
# Expects various global variables to be set.
|
|
function(qt_internal_create_toolchain_file)
|
|
if(NOT "${QT_HOST_PATH}" STREQUAL "")
|
|
# TODO: Figure out how to make these relocatable.
|
|
|
|
get_filename_component(__qt_host_path_absolute "${QT_HOST_PATH}" ABSOLUTE)
|
|
set(init_qt_host_path "
|
|
set(__qt_initial_qt_host_path \"${__qt_host_path_absolute}\")
|
|
if(NOT DEFINED QT_HOST_PATH AND EXISTS \"\${__qt_initial_qt_host_path}\")
|
|
set(QT_HOST_PATH \"\${__qt_initial_qt_host_path}\" CACHE PATH \"\" FORCE)
|
|
endif()")
|
|
|
|
get_filename_component(__qt_host_path_cmake_dir_absolute
|
|
"${Qt${PROJECT_VERSION_MAJOR}HostInfo_DIR}/.." ABSOLUTE)
|
|
set(init_qt_host_path_cmake_dir
|
|
"
|
|
set(__qt_initial_qt_host_path_cmake_dir \"${__qt_host_path_cmake_dir_absolute}\")
|
|
if(NOT DEFINED QT_HOST_PATH_CMAKE_DIR AND EXISTS \"\${__qt_initial_qt_host_path_cmake_dir}\")
|
|
set(QT_HOST_PATH_CMAKE_DIR \"\${__qt_initial_qt_host_path_cmake_dir}\" CACHE PATH \"\" FORCE)
|
|
endif()")
|
|
|
|
set(init_qt_host_path_checks "
|
|
if(\"\${QT_HOST_PATH}\" STREQUAL \"\" OR NOT EXISTS \"\${QT_HOST_PATH}\")
|
|
message(FATAL_ERROR \"To use a cross-compiled Qt, please specify a path to a host Qt installation by setting the QT_HOST_PATH cache variable.\")
|
|
endif()
|
|
if(\"\${QT_HOST_PATH_CMAKE_DIR}\" STREQUAL \"\" OR NOT EXISTS \"\${QT_HOST_PATH_CMAKE_DIR}\")
|
|
message(FATAL_ERROR \"To use a cross-compiled Qt, please specify a path to a host Qt installation CMake directory by setting the QT_HOST_PATH_CMAKE_DIR cache variable.\")
|
|
endif()")
|
|
endif()
|
|
|
|
if(CMAKE_TOOLCHAIN_FILE)
|
|
file(TO_CMAKE_PATH "${CMAKE_TOOLCHAIN_FILE}" __qt_chainload_toolchain_file)
|
|
set(init_original_toolchain_file
|
|
"set(__qt_chainload_toolchain_file \"${__qt_chainload_toolchain_file}\")")
|
|
endif()
|
|
|
|
if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
|
|
list(APPEND init_vcpkg
|
|
"set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE \"${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}\")")
|
|
endif()
|
|
|
|
if(VCPKG_TARGET_TRIPLET)
|
|
list(APPEND init_vcpkg
|
|
"set(VCPKG_TARGET_TRIPLET \"${VCPKG_TARGET_TRIPLET}\" CACHE STRING \"\")")
|
|
endif()
|
|
|
|
# By default we don't want to allow mixing compilers for building different repositories, so we
|
|
# embed the initially chosen compilers into the toolchain.
|
|
# This is because on Windows compilers aren't easily mixed.
|
|
# We want to avoid that qtbase is built using cl.exe for example, and then for another repo
|
|
# gcc is picked up from %PATH%.
|
|
# The same goes when using a custom compiler on other platforms, such as ICC.
|
|
#
|
|
# There are a few exceptions though.
|
|
#
|
|
# When crosscompiling using Boot2Qt, the environment setup shell script sets up the CXX env var,
|
|
# which is used by CMake to determine the initial compiler that should be used.
|
|
# Unfortunately, the CXX env var contains not only the compiler name, but also a few required
|
|
# arch-specific compiler flags. This means that when building qtsvg, if the Qt created toolchain
|
|
# file sets the CMAKE_CXX_COMPILER variable, the CXX env var is ignored and thus the extra
|
|
# arch specific compiler flags are not picked up anymore, leading to a configuration failure.
|
|
#
|
|
# To avoid this issue, disable automatic embedding of the compilers into the qt toolchain when
|
|
# cross compiling. This is merely a heuristic, becacuse we don't have enough data to decide
|
|
# when to do it or not.
|
|
# For example on Linux one might want to allow mixing of clang and gcc (maybe).
|
|
#
|
|
# To allow such use cases when the default is wrong, one can provide a flag to explicitly opt-in
|
|
# or opt-out of the compiler embedding into the Qt toolchain.
|
|
#
|
|
# Passing -DQT_EMBED_TOOLCHAIN_COMPILER=ON will force embedding of the compilers.
|
|
# Passing -DQT_EMBED_TOOLCHAIN_COMPILER=OFF will disable embedding of the compilers.
|
|
set(__qt_embed_toolchain_compilers TRUE)
|
|
if(CMAKE_CROSSCOMPILING)
|
|
set(__qt_embed_toolchain_compilers FALSE)
|
|
endif()
|
|
if(DEFINED QT_EMBED_TOOLCHAIN_COMPILER)
|
|
if(QT_EMBED_TOOLCHAIN_COMPILER)
|
|
set(__qt_embed_toolchain_compilers TRUE)
|
|
else()
|
|
set(__qt_embed_toolchain_compilers FALSE)
|
|
endif()
|
|
endif()
|
|
if(__qt_embed_toolchain_compilers)
|
|
list(APPEND init_platform "
|
|
set(__qt_initial_c_compiler \"${CMAKE_C_COMPILER}\")
|
|
set(__qt_initial_cxx_compiler \"${CMAKE_CXX_COMPILER}\")
|
|
if(NOT DEFINED CMAKE_C_COMPILER AND EXISTS \"\${__qt_initial_c_compiler}\")
|
|
set(CMAKE_C_COMPILER \"\${__qt_initial_c_compiler}\" CACHE STRING \"\")
|
|
endif()
|
|
if(NOT DEFINED CMAKE_CXX_COMPILER AND EXISTS \"\${__qt_initial_cxx_compiler}\")
|
|
set(CMAKE_CXX_COMPILER \"\${__qt_initial_cxx_compiler}\" CACHE STRING \"\")
|
|
endif()")
|
|
endif()
|
|
|
|
unset(init_additional_used_variables)
|
|
if(APPLE)
|
|
# 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 UIKIT)
|
|
list(APPEND init_platform "
|
|
set(__qt_initial_cmake_osx_sysroot \"${CMAKE_OSX_SYSROOT}\")
|
|
if(NOT DEFINED CMAKE_OSX_SYSROOT AND EXISTS \"\${__qt_initial_cmake_osx_sysroot}\")
|
|
set(CMAKE_OSX_SYSROOT \"\${__qt_initial_cmake_osx_sysroot}\" CACHE PATH \"\")
|
|
endif()")
|
|
endif()
|
|
|
|
if(CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
list(APPEND init_platform
|
|
"set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")")
|
|
endif()
|
|
|
|
# Save list of initial architectures Qt was configured with.
|
|
set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}")
|
|
string(REPLACE ";" "LITERAL_SEMICOLON"
|
|
_qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}")
|
|
set(docstring "List of architectures Qt was built with")
|
|
list(APPEND init_platform
|
|
"set(QT_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"${docstring}\")")
|
|
list(APPEND init_platform "")
|
|
|
|
# When building another qt repo, ensure the same list of architectures is used by default.
|
|
# Detection of a qt repo is done by checking for QT_REPO_MODULE_VERSION which is set in
|
|
# the repo's .cmake.conf file.
|
|
# Standalone tests will be not be built with multiple architectures to avoid issues in the
|
|
# CI when trying to run cmake build tests on VMs that do not have a universal macOS
|
|
# SDK.
|
|
list(APPEND init_platform "# Only build multiple architectures when building Qt itself")
|
|
list(APPEND init_platform "if((QT_REPO_MODULE_VERSION AND NOT QT_BUILD_STANDALONE_TESTS) OR QT_FORCE_QT_OSX_ARCHITECTURES)")
|
|
list(APPEND init_platform " set(__qt_toolchain_building_qt_repo TRUE)")
|
|
list(APPEND init_platform " set(CMAKE_OSX_ARCHITECTURES \"\${QT_OSX_ARCHITECTURES}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "endif()")
|
|
list(APPEND init_platform "")
|
|
|
|
# For macOS user projects, default to not specifying any architecture. This means CMake will
|
|
# not pass an -arch flag to the compiler and the compiler will choose the default
|
|
# architecture to build for.
|
|
# On Apple Silicon, CMake will introspect whether it's running under Rosetta and will
|
|
# pass the detected architecture (x86_64 under Rosetta or arm64 natively) to the compiler.
|
|
# This is line with default CMake behavior for user projects.
|
|
#
|
|
# For iOS, we provide a bit more convenience.
|
|
# When the user project is built using the Xcode generator, don't specify a default
|
|
# architecture and let Xcode and the developer handle it.
|
|
# When using the Ninja generator, specify the first architecture from QT_OSX_ARCHITECTURES
|
|
# (even with a simulator_and_device Qt build). This ensures that the default configuration
|
|
# at least tries to build something.
|
|
if(UIKIT)
|
|
qt_internal_get_first_osx_arch(osx_first_arch)
|
|
list(APPEND init_platform "if(NOT CMAKE_GENERATOR STREQUAL \"Xcode\" AND NOT __qt_toolchain_building_qt_repo)")
|
|
list(APPEND init_platform
|
|
" set(CMAKE_OSX_ARCHITECTURES \"${osx_first_arch}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "endif()")
|
|
list(APPEND init_platform "")
|
|
endif()
|
|
|
|
if(UIKIT)
|
|
list(APPEND init_platform
|
|
"set(CMAKE_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "if(CMAKE_GENERATOR STREQUAL \"Xcode\" AND NOT QT_NO_XCODE_EMIT_EPN)")
|
|
list(APPEND init_platform " set_property(GLOBAL PROPERTY XCODE_EMIT_EFFECTIVE_PLATFORM_NAME OFF)")
|
|
list(APPEND init_platform "endif()")
|
|
endif()
|
|
elseif(ANDROID)
|
|
foreach(var ANDROID_NATIVE_API_LEVEL ANDROID_STL ANDROID_ABI
|
|
ANDROID_SDK_ROOT ANDROID_NDK_ROOT)
|
|
list(APPEND init_additional_used_variables
|
|
"list(APPEND __qt_toolchain_used_variables ${var})")
|
|
endforeach()
|
|
list(APPEND init_platform
|
|
"set(ANDROID_NATIVE_API_LEVEL \"${ANDROID_NATIVE_API_LEVEL}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "set(ANDROID_STL \"${ANDROID_STL}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "set(ANDROID_ABI \"${ANDROID_ABI}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "if (NOT DEFINED ANDROID_SDK_ROOT)")
|
|
file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" __qt_android_sdk_root)
|
|
list(APPEND init_platform
|
|
" set(ANDROID_SDK_ROOT \"${__qt_android_sdk_root}\" CACHE STRING \"\")")
|
|
list(APPEND init_platform "endif()")
|
|
|
|
list(APPEND init_platform "if(NOT \"$\{ANDROID_NDK_ROOT\}\" STREQUAL \"\")")
|
|
list(APPEND init_platform
|
|
" set(__qt_toolchain_file_candidate \"$\{ANDROID_NDK_ROOT\}/build/cmake/android.toolchain.cmake\")")
|
|
list(APPEND init_platform " if(EXISTS \"$\{__qt_toolchain_file_candidate\}\")")
|
|
list(APPEND init_platform
|
|
" message(STATUS \"Android toolchain file within NDK detected: $\{__qt_toolchain_file_candidate\}\")")
|
|
list(APPEND init_platform " set(__qt_chainload_toolchain_file \"$\{__qt_toolchain_file_candidate\}\")")
|
|
list(APPEND init_platform " else()")
|
|
list(APPEND init_platform
|
|
" message(FATAL_ERROR \"Cannot find the toolchain file '$\{__qt_toolchain_file_candidate\}'. \"")
|
|
list(APPEND init_platform
|
|
" \"Please specify the toolchain file with -DQT_CHAINLOAD_TOOLCHAIN_FILE=<file>.\")")
|
|
list(APPEND init_platform " endif()")
|
|
list(APPEND init_platform "endif()")
|
|
endif()
|
|
|
|
string(REPLACE ";" "\n" init_additional_used_variables
|
|
"${init_additional_used_variables}")
|
|
string(REPLACE ";" "\n" init_vcpkg "${init_vcpkg}")
|
|
string(REPLACE ";" "\n" init_platform "${init_platform}")
|
|
string(REPLACE "LITERAL_SEMICOLON" ";" init_platform "${init_platform}")
|
|
qt_compute_relative_path_from_cmake_config_dir_to_prefix()
|
|
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)
|
|
endfunction()
|