qt5base-lts/cmake/QtQmakeHelpers.cmake
Fab Stz 979a21dc4e Add support for MultiABI with custom install dir of the android-build
Right now, "multi abi builds" of android projects works only if the
android-build installation doesn't use custom install dirs
(INSTALL_PREFIX, INSTALL_BINDIR...)

At the same time, it fixes QTBUG-106533. The patches are the same as the
ones in that bugreport.

Add new items to android-*-deployment-settings.json:

    qtDataDirectory
    qtLibsDirectory
    qtLibExecsDirectory
    qtPluginsDirectory
    qtQmlDirectory

Update androiddeployqt to be able to get files from their install location

BTW (fixes QTBUG-106533):
    Install src/android/templates into INSTALL_DATADIR
    Install src/3rdparty/gradle into INSTALL_DATADIR
    Install src/android/java files into INSTALL_DATADIR
    Install all jars into INSTALL_DATADIR

Add missing path to target_qt.conf
    Update target_qt.conf to have all path. Otherwise qmake wouldn't have
    the path when installing the android-build with custom install dirs
    like INSTALL_LIBDIR & friends

Add support for a new cmake variable that can be set at build time of the
android projects: QT_ANDROID_PATH_CMAKE_DIR_${abi} (Name chosen as
brother of QT_HOST_PATH_CMAKE_DIR)

Pick-to: 6.5
Fixes: QTBUG-106533
Fixes: QTBUG-107207
Change-Id: Ia3751362ab1b5f877ecafbe02f263feac167119c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
2023-01-30 14:08:14 +01:00

250 lines
9.7 KiB
CMake

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Create a QMake list (values space-separated) containing paths.
# Entries that contain whitespace characters are quoted.
function(qt_to_qmake_path_list out_var)
set(quoted_paths "")
foreach(path ${ARGN})
if(path MATCHES "[ \t]")
list(APPEND quoted_paths "\"${path}\"")
else()
list(APPEND quoted_paths "${path}")
endif()
endforeach()
list(JOIN quoted_paths " " result)
set("${out_var}" "${result}" PARENT_SCOPE)
endfunction()
function(qt_generate_qconfig_cpp in_file out_file)
set(QT_CONFIG_STRS "")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_DOCDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_INCLUDEDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_LIBDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_LIBEXECDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_BINDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_PLUGINSDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_QMLDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_ARCHDATADIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_DATADIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_TRANSLATIONSDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_EXAMPLESDIR})qconfig\",\n")
string(APPEND QT_CONFIG_STRS " R\"qconfig(${INSTALL_TESTSDIR})qconfig\"")
# Settings path / sysconf dir.
set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}")
# Compute and set relocation prefixes.
if(WIN32)
set(lib_location_absolute_path
"${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
else()
set(lib_location_absolute_path
"${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
endif()
file(RELATIVE_PATH from_lib_location_to_prefix
"${lib_location_absolute_path}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}")
# Ensure Windows drive letter is prepended to the install prefix hardcoded
# into qconfig.cpp, otherwise qmake can't find Qt modules in a static Qt
# build if there's no qt.conf. Mostly relevant for CI.
# Given input like
# \work/qt/install
# or
# \work\qt\install
# Expected output is something like
# C:/work/qt/install
# so it includes a drive letter and forward slashes.
if(QT_FEATURE_relocatable)
# A relocatable Qt does not need a hardcoded prefix path.
# This makes reproducible builds a closer reality, because we don't embed a CI path
# into the binaries.
set(QT_CONFIGURE_PREFIX_PATH_STR "")
else()
set(QT_CONFIGURE_PREFIX_PATH_STR "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
if(CMAKE_HOST_WIN32)
get_filename_component(
QT_CONFIGURE_PREFIX_PATH_STR
"${QT_CONFIGURE_PREFIX_PATH_STR}" REALPATH)
endif()
endif()
configure_file(${in_file} ${out_file} @ONLY)
endfunction()
# In the cross-compiling case, creates a wrapper around the host Qt's
# qmake and qtpaths executables. Also creates a qmake configuration file that sets
# up the host qmake's properties for cross-compiling with this Qt
# build.
function(qt_generate_qmake_and_qtpaths_wrapper_for_target)
if(NOT CMAKE_CROSSCOMPILING)
return()
endif()
# Call the configuration file something else but qt.conf to avoid
# being picked up by the qmake executable that's created if
# QT_FORCE_BUILD_TOOLS is enabled.
qt_path_join(qt_conf_path "${INSTALL_BINDIR}" "target_qt.conf")
set(prefix "${CMAKE_INSTALL_PREFIX}")
set(ext_prefix "${QT_STAGING_PREFIX}")
set(host_prefix "${QT_HOST_PATH}")
file(RELATIVE_PATH host_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
"${host_prefix}")
file(RELATIVE_PATH ext_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}"
"${ext_prefix}")
file(RELATIVE_PATH ext_datadir_relative_to_host_prefix "${host_prefix}"
"${ext_prefix}/${INSTALL_MKSPECSDIR}/..")
set(content "")
# On Android CMAKE_SYSROOT is set, but from qmake's point of view it should not be set, because
# then qmake generates incorrect Qt module include flags (among other things). Do the same for
# darwin uikit cross-compilation.
set(sysroot "")
if(CMAKE_SYSROOT AND NOT ANDROID AND NOT UIKIT)
set(sysroot "${CMAKE_SYSROOT}")
endif()
# Detect if automatic sysrootification should happen. All of the following must be true:
# sysroot is set (CMAKE_SYSRROT)
# prefix is set (CMAKE_INSTALL_PREFIX)
# extprefix is explicitly NOT set (CMAKE_STAGING_PREFIX, not QT_STAGING_PREFIX because that
# always ends up having a value)
if(NOT CMAKE_STAGING_PREFIX AND sysroot)
set(sysrootify_prefix true)
else()
set(sysrootify_prefix false)
if(NOT ext_prefix STREQUAL prefix)
string(APPEND content "[DevicePaths]
Prefix=${prefix}
")
endif()
endif()
string(APPEND content
"[Paths]
Prefix=${ext_prefix_relative_to_conf_file}
Documentation=${INSTALL_DOCDIR}
Headers=${INSTALL_INCLUDEDIR}
Libraries=${INSTALL_LIBDIR}
LibraryExecutables=${INSTALL_LIBEXECDIR}
Binaries=${INSTALL_BINDIR}
Plugins=${INSTALL_PLUGINSDIR}
QmlImports=${INSTALL_QMLDIR}
ArchData=${INSTALL_ARCHDATADIR}
Data=${INSTALL_DATADIR}
Translations=${INSTALL_TRANSLATIONSDIR}
Examples=${INSTALL_EXAMPLESDIR}
Tests=${INSTALL_TESTSDIR}
Settings=${INSTALL_SYSCONFDIR}
HostPrefix=${host_prefix_relative_to_conf_file}
HostBinaries=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}
HostLibraries=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBDIR}
HostLibraryExecutables=${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_LIBEXECDIR}
HostData=${ext_datadir_relative_to_host_prefix}
Sysroot=${sysroot}
SysrootifyPrefix=${sysrootify_prefix}
TargetSpec=${QT_QMAKE_TARGET_MKSPEC}
HostSpec=${QT_QMAKE_HOST_MKSPEC}
")
file(GENERATE OUTPUT "${qt_conf_path}" CONTENT "${content}")
qt_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${qt_conf_path}"
DESTINATION "${INSTALL_BINDIR}")
if(QT_GENERATE_WRAPPER_SCRIPTS_FOR_ALL_HOSTS)
set(hosts "unix" "non-unix")
elseif(CMAKE_HOST_UNIX)
set(hosts "unix")
else()
set(hosts "non-unix")
endif()
set(wrapper_prefix)
if(QT_FORCE_BUILD_TOOLS)
# Avoid collisions with the cross-compiled qmake/qtpaths binaries.
set(wrapper_prefix "host-")
endif()
set(host_qt_bindir "${host_prefix}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}")
file(TO_NATIVE_PATH "${host_qt_bindir}" host_qt_bindir)
if(QT_CREATE_VERSIONED_HARD_LINK AND QT_WILL_INSTALL)
set(tool_version "${PROJECT_VERSION_MAJOR}")
endif()
foreach(host_type ${hosts})
foreach(tool_name qmake qtpaths)
set(wrapper_extension)
set(newline_style LF)
if(host_type STREQUAL "non-unix")
set(wrapper_extension ".bat")
set(newline_style CRLF)
endif()
set(wrapper_in_file
"${CMAKE_CURRENT_SOURCE_DIR}/bin/qmake-and-qtpaths-wrapper${wrapper_extension}.in")
set(wrapper "preliminary/${wrapper_prefix}${tool_name}${wrapper_extension}")
configure_file("${wrapper_in_file}" "${wrapper}" @ONLY NEWLINE_STYLE ${newline_style})
qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${wrapper}"
DESTINATION "${INSTALL_BINDIR}")
# Configuring a new wrapper file, this type setting the tool_version
if(QT_CREATE_VERSIONED_HARD_LINK AND QT_WILL_INSTALL)
set(versioned_wrapper "preliminary/${wrapper_prefix}${tool_name}${tool_version}${wrapper_extension}")
configure_file("${wrapper_in_file}" "${versioned_wrapper}" @ONLY NEWLINE_STYLE ${newline_style})
qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${versioned_wrapper}"
DESTINATION "${INSTALL_BINDIR}")
endif()
endforeach()
endforeach()
endfunction()
# Transforms a CMake Qt module name to a qmake Qt module name.
# Example: Qt6FooPrivate becomes foo_private
function(qt_get_qmake_module_name result module)
string(REGEX REPLACE "^Qt6" "" module "${module}")
string(REGEX REPLACE "Private$" "_private" module "${module}")
string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}")
string(TOLOWER "${module}" module)
set(${result} ${module} PARENT_SCOPE)
endfunction()
function(qt_cmake_build_type_to_qmake_build_config out_var build_type)
if(build_type STREQUAL "Debug")
set(cfg debug)
else()
set(cfg release)
endif()
set(${out_var} ${cfg} PARENT_SCOPE)
endfunction()
function(qt_guess_qmake_build_config out_var)
if(QT_GENERATOR_IS_MULTI_CONFIG)
unset(cfg)
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
qt_cmake_build_type_to_qmake_build_config(tmp ${config_type})
list(APPEND cfg ${tmp})
endforeach()
if(cfg)
list(REMOVE_DUPLICATES cfg)
else()
set(cfg debug)
endif()
else()
qt_cmake_build_type_to_qmake_build_config(cfg ${CMAKE_BUILD_TYPE})
endif()
set(${out_var} ${cfg} PARENT_SCOPE)
endfunction()
macro(qt_add_qmake_lib_dependency lib dep)
string(REPLACE "-" "_" dep ${dep})
string(TOUPPER "${dep}" ucdep)
list(APPEND QT_QMAKE_LIB_DEPS_${lib} ${ucdep})
endmacro()