diff options
31 files changed, 822 insertions, 980 deletions
diff --git a/config.tests/arch/write_info.pri b/config.tests/arch/write_info.pri index 79f980c873..666b9e5cbb 100644 --- a/config.tests/arch/write_info.pri +++ b/config.tests/arch/write_info.pri @@ -3,9 +3,6 @@ targetinfofile ~= s/pro$/target.txt/ win32 { ext = .exe -} else:android { - file_prefix = lib - ext = .so } else:wasm { equals(WASM_OBJECT_FILES, 1): \ ext = .o diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf index 84ad884710..8252f400a1 100644 --- a/mkspecs/android-clang/qmake.conf +++ b/mkspecs/android-clang/qmake.conf @@ -8,35 +8,102 @@ CONFIG += android_install unversioned_soname unversioned_libname include(../common/linux.conf) include(../common/gcc-base-unix.conf) include(../common/clang.conf) -include(../common/android-base-head.conf) + +load(device_config) + +# In early configure setup; nothing useful to be done here. +isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() + +NDK_ROOT = $$(ANDROID_NDK_ROOT) +isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT + +!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") + +NDK_HOST = $$(ANDROID_NDK_HOST) +isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST + +ANDROID_PLATFORM = $$(ANDROID_NDK_PLATFORM) +isEmpty(ANDROID_PLATFORM): ANDROID_PLATFORM = $$DEFAULT_ANDROID_PLATFORM + +ANDROID_SDK_ROOT = $$(ANDROID_SDK_ROOT) +isEmpty(ANDROID_SDK_ROOT): ANDROID_SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT + +ANDROID_SDK_BUILD_TOOLS_REVISION = $$(ANDROID_BUILD_TOOLS_REVISION) +isEmpty(ANDROID_SDK_BUILD_TOOLS_REVISION) { + SDK_BUILD_TOOLS_REVISIONS = $$files($$ANDROID_SDK_ROOT/build-tools/*) + for (REVISION, SDK_BUILD_TOOLS_REVISIONS) { + BASENAME = $$basename(REVISION) + greaterThan(BASENAME, $$ANDROID_SDK_BUILD_TOOLS_REVISION): ANDROID_SDK_BUILD_TOOLS_REVISION = $$BASENAME + } +} + +ALL_ANDROID_ABIS = arm64-v8a armeabi-v7a x86_64 x86 + +CONFIG += $$ANDROID_PLATFORM + +QMAKE_PCH_OUTPUT_EXT = .gch + +QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} +QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} +QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} +QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE NDK_LLVM_PATH = $$NDK_ROOT/toolchains/llvm/prebuilt/$$NDK_HOST QMAKE_CC = $$NDK_LLVM_PATH/bin/clang QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++ +QMAKE_LINK = $$QMAKE_CXX -# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md +QMAKE_CFLAGS_OPTIMIZE = -Oz +QMAKE_CFLAGS_OPTIMIZE_FULL = -Oz -equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") -else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ - QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -else: equals(ANDROID_TARGET_ARCH, x86): \ - QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign -else: equals(ANDROID_TARGET_ARCH, x86_64): \ - QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") +QMAKE_CFLAGS_WARN_ON = -Wall -W +QMAKE_CFLAGS_WARN_OFF = +QMAKE_CFLAGS_SHLIB = -fPIC +QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses +QMAKE_CFLAGS_THREAD = -D_REENTRANT +QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden +QMAKE_CFLAGS_NEON = -mfpu=neon -QMAKE_CFLAGS += -fno-limit-debug-info +QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared +QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared +QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB +QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined +QMAKE_LFLAGS_RPATH = -Wl,-rpath= +QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link= -QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS - -ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/$$NDK_TOOLS_PREFIX/libc++_shared.so +QMAKE_LIBS_X11 = +QMAKE_LIBS_THREAD = +QMAKE_LIBS_OPENGL = +QMAKE_INCDIR_POST = +QMAKE_INCDIR_X11 = +QMAKE_LIBDIR_X11 = +QMAKE_INCDIR_OPENGL = +QMAKE_LIBDIR_OPENGL = ANDROID_USE_LLVM = true -QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz -QMAKE_LIBDIR_POST = -QMAKE_LFLAGS = -QMAKE_LIBS_PRIVATE = -ANDROID_CXX_STL_LIBS = +armeabi-v7a.sdk = armeabi-v7a +armeabi-v7a.target = armeabi-v7a +armeabi-v7a.dir_affix = armeabi-v7a +armeabi-v7a.CONFIG = armeabi-v7a +armeabi-v7a.deployment_identifier = armeabi-v7a + +arm64-v8a.sdk = arm64-v8a +arm64-v8a.target = arm64-v8a +arm64-v8a.dir_affix = arm64-v8a +arm64-v8a.CONFIG = arm64-v8a +arm64-v8a.deployment_identifier = arm64-v8a + +x86.sdk = x86 +x86.target = x86 +x86.dir_affix = x86 +x86.CONFIG = x86 +x86.deployment_identifier = x86 + +x86_64.sdk = x86_64 +x86_64.target = x86_64 +x86_64.dir_affix = x86_64 +x86_64.CONFIG = x86_64 +x86_64.deployment_identifier = x86_64 -include(../common/android-base-tail.conf) +load(qt_config) diff --git a/mkspecs/android-g++/qmake.conf b/mkspecs/android-g++/qmake.conf deleted file mode 100644 index 451e12bc75..0000000000 --- a/mkspecs/android-g++/qmake.conf +++ /dev/null @@ -1,40 +0,0 @@ -# qmake configuration for building with android-g++ -MAKEFILE_GENERATOR = UNIX -QMAKE_PLATFORM = android -QMAKE_COMPILER = gcc - -CONFIG += android_install unversioned_soname unversioned_libname plugin_with_soname android_deployment_settings - -include(../common/linux.conf) -include(../common/gcc-base-unix.conf) -include(../common/android-base-head.conf) - -QMAKE_CC = $${CROSS_COMPILE}gcc -QMAKE_CXX = $${CROSS_COMPILE}g++ -QMAKE_LINK = $$QMAKE_CXX -QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "") - -ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH -ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libgnustl_shared.so -ANDROID_CXX_STL_LIBS = -lgnustl_shared -lgcc -ANDROID_USE_LLVM = false - -exists($$NDK_ROOT/sysroot/usr/include): \ - QMAKE_CFLAGS += --sysroot=$$NDK_ROOT/sysroot \ - -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX -else: QMAKE_CFLAGS += --sysroot=$$ANDROID_PLATFORM_ROOT_PATH - -QMAKE_CFLAGS += -isystem $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/include \ - -isystem $$ANDROID_SOURCES_CXX_STL_LIBDIR/include - -equals(ANDROID_TARGET_ARCH, armeabi)|equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - LIBGCC_PATH_FULL = $$system("$$QMAKE_CXX -mthumb-interwork -print-libgcc-file-name") -else: \ - LIBGCC_PATH_FULL = $$system("$$QMAKE_CXX -print-libgcc-file-name") -ANDROID_SOURCES_CXX_STL_LIBDIR += $$dirname(LIBGCC_PATH_FULL) - -QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR -QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH -equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64 - -include(../common/android-base-tail.conf) diff --git a/mkspecs/android-g++/qplatformdefs.h b/mkspecs/android-g++/qplatformdefs.h deleted file mode 100644 index 0b92709dd5..0000000000 --- a/mkspecs/android-g++/qplatformdefs.h +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the qmake spec of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPLATFORMDEFS_H -#define QPLATFORMDEFS_H - -// Get Qt defines/settings - -#include "qglobal.h" - -// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs - -// 1) need to reset default environment if _BSD_SOURCE is defined -// 2) need to specify POSIX thread interfaces explicitly in glibc 2.0 -// 3) it seems older glibc need this to include the X/Open stuff - -#include <unistd.h> - -// We are hot - unistd.h should have turned on the specific APIs we requested - -#include <features.h> -#include <pthread.h> -#include <dirent.h> -#include <fcntl.h> -#include <grp.h> -#include <pwd.h> -#include <signal.h> -#include <dlfcn.h> - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/ipc.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/wait.h> - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#ifdef QT_LARGEFILE_SUPPORT -#define QT_STATBUF struct stat64 -#define QT_STATBUF4TSTAT struct stat64 -#define QT_STAT ::stat64 -#define QT_FSTAT ::fstat64 -#define QT_LSTAT ::lstat64 -#define QT_OPEN ::open64 -#define QT_TRUNCATE ::truncate64 -#define QT_FTRUNCATE ::ftruncate64 -#define QT_LSEEK ::lseek64 -#else -#define QT_STATBUF struct stat -#define QT_STATBUF4TSTAT struct stat -#define QT_STAT ::stat -#define QT_FSTAT ::fstat -#define QT_LSTAT ::lstat -#define QT_OPEN ::open -#define QT_TRUNCATE ::truncate -#define QT_FTRUNCATE ::ftruncate -#define QT_LSEEK ::lseek -#endif - -#ifdef QT_LARGEFILE_SUPPORT -#define QT_FOPEN ::fopen64 -#define QT_FSEEK ::fseeko64 -#define QT_FTELL ::ftello64 -#define QT_FGETPOS ::fgetpos64 -#define QT_FSETPOS ::fsetpos64 -#define QT_MMAP ::mmap64 -#define QT_FPOS_T fpos64_t -#define QT_OFF_T off64_t -#else -#define QT_FOPEN ::fopen -#define QT_FSEEK ::fseek -#define QT_FTELL ::ftell -#define QT_FGETPOS ::fgetpos -#define QT_FSETPOS ::fsetpos -#define QT_MMAP ::mmap -#define QT_FPOS_T fpos_t -#define QT_OFF_T long -#endif - -#define QT_STAT_REG S_IFREG -#define QT_STAT_DIR S_IFDIR -#define QT_STAT_MASK S_IFMT -#define QT_STAT_LNK S_IFLNK -#define QT_SOCKET_CONNECT ::connect -#define QT_SOCKET_BIND ::bind -#define QT_FILENO fileno -#define QT_CLOSE ::close -#define QT_READ ::read -#define QT_WRITE ::write -#define QT_ACCESS ::access -#define QT_GETCWD ::getcwd -#define QT_CHDIR ::chdir -#define QT_MKDIR ::mkdir -#define QT_RMDIR ::rmdir -#define QT_OPEN_LARGEFILE O_LARGEFILE -#define QT_OPEN_RDONLY O_RDONLY -#define QT_OPEN_WRONLY O_WRONLY -#define QT_OPEN_RDWR O_RDWR -#define QT_OPEN_CREAT O_CREAT -#define QT_OPEN_TRUNC O_TRUNC -#define QT_OPEN_APPEND O_APPEND -#define QT_OPEN_EXCL O_EXCL - -// Directory iteration -#define QT_DIR DIR - -#define QT_OPENDIR ::opendir -#define QT_CLOSEDIR ::closedir - -#if defined(QT_LARGEFILE_SUPPORT) \ - && defined(QT_USE_XOPEN_LFS_EXTENSIONS) \ - && !defined(QT_NO_READDIR64) -#define QT_DIRENT struct dirent64 -#define QT_READDIR ::readdir64 -#define QT_READDIR_R ::readdir64_r -#else -#define QT_DIRENT struct dirent -#define QT_READDIR ::readdir -#define QT_READDIR_R ::readdir_r -#endif - -#define QT_SOCKET_CONNECT ::connect -#define QT_SOCKET_BIND ::bind - - -#define QT_SIGNAL_RETTYPE void -#define QT_SIGNAL_ARGS int -#define QT_SIGNAL_IGNORE SIG_IGN - -#define QT_SOCKLEN_T socklen_t - -#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500) -#define QT_SNPRINTF ::snprintf -#define QT_VSNPRINTF ::vsnprintf -#endif - -#endif // QPLATFORMDEFS_H diff --git a/mkspecs/common/android-base-head.conf b/mkspecs/common/android-base-head.conf deleted file mode 100644 index 7335b7f4cb..0000000000 --- a/mkspecs/common/android-base-head.conf +++ /dev/null @@ -1,71 +0,0 @@ -load(device_config) - -# In early configure setup; nothing useful to be done here. -isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() - -NDK_ROOT = $$(ANDROID_NDK_ROOT) -isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT - -NDK_HOST = $$(ANDROID_NDK_HOST) -isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST - -ANDROID_PLATFORM = $$(ANDROID_NDK_PLATFORM) -isEmpty(ANDROID_PLATFORM): ANDROID_PLATFORM = $$DEFAULT_ANDROID_PLATFORM - -ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) -isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH - -NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX) -isEmpty(NDK_TOOLCHAIN_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86 - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64 - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android - else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi -} - -NDK_TOOLS_PREFIX = $$(ANDROID_NDK_TOOLS_PREFIX) -isEmpty(NDK_TOOLS_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLS_PREFIX = i686-linux-android - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLS_PREFIX = x86_64-linux-android - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLS_PREFIX = aarch64-linux-android - else: NDK_TOOLS_PREFIX = arm-linux-androideabi -} - -NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION) -isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION - -equals(ANDROID_TARGET_ARCH, x86): ANDROID_ARCHITECTURE = x86 -else: equals(ANDROID_TARGET_ARCH, x86_64): ANDROID_ARCHITECTURE = x86_64 -else: equals(ANDROID_TARGET_ARCH, arm64-v8a): ANDROID_ARCHITECTURE = arm64 -else: ANDROID_ARCHITECTURE = arm - -!equals(NDK_TOOLCHAIN_VERSION, 4.4.3): ANDROID_CXXSTL_SUFFIX = -$$NDK_TOOLCHAIN_VERSION - -NDK_TOOLCHAIN = $$NDK_TOOLCHAIN_PREFIX-$$NDK_TOOLCHAIN_VERSION -NDK_TOOLCHAIN_PATH = $$NDK_ROOT/toolchains/$$NDK_TOOLCHAIN/prebuilt/$$NDK_HOST - - -ANDROID_SDK_ROOT = $$(ANDROID_SDK_ROOT) -isEmpty(ANDROID_SDK_ROOT): ANDROID_SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT - -ANDROID_SDK_BUILD_TOOLS_REVISION = $$(ANDROID_BUILD_TOOLS_REVISION) -isEmpty(ANDROID_SDK_BUILD_TOOLS_REVISION) { - SDK_BUILD_TOOLS_REVISIONS = $$files($$ANDROID_SDK_ROOT/build-tools/*) - for (REVISION, SDK_BUILD_TOOLS_REVISIONS) { - BASENAME = $$basename(REVISION) - greaterThan(BASENAME, $$ANDROID_SDK_BUILD_TOOLS_REVISION): ANDROID_SDK_BUILD_TOOLS_REVISION = $$BASENAME - } -} - -CONFIG += $$ANDROID_PLATFORM - -ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/ - -CROSS_COMPILE = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX- - -QMAKE_PCH_OUTPUT_EXT = .gch - -QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} -QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE diff --git a/mkspecs/common/android-base-tail.conf b/mkspecs/common/android-base-tail.conf deleted file mode 100644 index c970379f28..0000000000 --- a/mkspecs/common/android-base-tail.conf +++ /dev/null @@ -1,82 +0,0 @@ -# In early configure setup; nothing useful to be done here. -isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() - -# -fstack-protector-strong offers good protection against stack smashing attacks. -# It is (currently) enabled only on Android because we know for sure that Andoroid compilers supports it -QMAKE_CFLAGS += -fstack-protector-strong -DANDROID - -equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -else: equals(ANDROID_TARGET_ARCH, armeabi): \ - QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float - -QMAKE_CFLAGS_WARN_ON = -Wall -W -QMAKE_CFLAGS_WARN_OFF = -equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { - CONFIG += optimize_size - QMAKE_CFLAGS_DEBUG = -g -marm -O0 - QMAKE_CFLAGS_RELEASE += -mthumb - QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb -} - -QMAKE_CFLAGS_SHLIB = -fPIC -QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden -QMAKE_CFLAGS_NEON = -mfpu=neon - -QMAKE_CFLAGS_GNUC99 = -std=gnu99 -QMAKE_CFLAGS_GNUC11 = -std=gnu11 -QMAKE_CXXFLAGS_CXX11 = -std=c++11 -QMAKE_CXXFLAGS_CXX14 = -std=c++14 -QMAKE_CXXFLAGS_CXX1Z = -std=c++1z -QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 -QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++14 -QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z - -QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF -QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE -QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO -QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG -QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB -QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD -QMAKE_CXXFLAGS_HIDESYMS = $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden - -# modifications to linux.conf -QMAKE_AR = $${CROSS_COMPILE}ar cqs -QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy -QMAKE_NM = $${CROSS_COMPILE}nm -P - -QMAKE_STRIP = -#$${CROSS_COMPILE}strip - -QMAKE_RANLIB = $${CROSS_COMPILE}ranlib - -QMAKE_INCDIR_POST = -QMAKE_INCDIR_X11 = -QMAKE_LIBDIR_X11 = -QMAKE_INCDIR_OPENGL = -QMAKE_LIBDIR_OPENGL = - -QMAKE_LINK_SHLIB = $$QMAKE_LINK -QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared -QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared -QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB -QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined -QMAKE_LFLAGS_RPATH = -Wl,-rpath= -QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link= - -QMAKE_LIBS_PRIVATE = $$ANDROID_CXX_STL_LIBS -llog -lz -lm -ldl -lc -QMAKE_LIBS_X11 = -QMAKE_LIBS_THREAD = -QMAKE_LIBS_EGL = -lEGL -QMAKE_LIBS_OPENGL = -QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 - - -!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") - -load(qt_config) diff --git a/mkspecs/features/android/android.prf b/mkspecs/features/android/android.prf index 0e6f4a4592..a12c17c4ed 100644 --- a/mkspecs/features/android/android.prf +++ b/mkspecs/features/android/android.prf @@ -16,17 +16,22 @@ APK_PATH = $$shell_path($$OUT_PWD/android-build/$${TARGET}.apk) } QMAKE_EXTRA_TARGETS *= apk apk_install_target -contains(TEMPLATE, ".*app") { - !android_app { - !contains(TARGET, ".so"): TARGET = lib$${TARGET}.so - QMAKE_LFLAGS += -Wl,-soname,$$shell_quote($$TARGET) +build_pass { + contains(TEMPLATE, ".*app") { + !android_app { + !contains(TARGET, ".so") { + single_arch:TARGET = lib$${TARGET}.so + else:TARGET = lib$${TARGET}_$${QT_ARCH}.so + } + QMAKE_LFLAGS += -Wl,-soname,$$shell_quote($$TARGET) - android_install { - target.path=/libs/$$ANDROID_TARGET_ARCH/ - INSTALLS *= target + android_install { + target.path=/libs/$$ANDROID_TARGET_ARCH/ + INSTALLS *= target + } } + } else: contains(TEMPLATE, "lib"):!static:!QTDIR_build:android_install { + target.path = /libs/$$ANDROID_TARGET_ARCH/ + INSTALLS *= target } -} else: contains(TEMPLATE, "lib"):!static:!QTDIR_build:android_install { - target.path = /libs/$$ANDROID_TARGET_ARCH/ - INSTALLS *= target } diff --git a/mkspecs/features/android/android_deployment_settings.prf b/mkspecs/features/android/android_deployment_settings.prf index 48943fa0f4..998a985bb5 100644 --- a/mkspecs/features/android/android_deployment_settings.prf +++ b/mkspecs/features/android/android_deployment_settings.prf @@ -17,32 +17,21 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded { isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT FILE_CONTENT += " \"ndk\": $$emitString($$NDK_ROOT)," - equals(ANDROID_USE_LLVM, true) { - FILE_CONTENT += " \"toolchain-prefix\": \"llvm\"," - FILE_CONTENT += " \"tool-prefix\": \"llvm\"," - } else { - NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX) - isEmpty(NDK_TOOLCHAIN_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86 - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64 - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android - else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi - } - FILE_CONTENT += " \"toolchain-prefix\": $$emitString($$NDK_TOOLCHAIN_PREFIX)," - FILE_CONTENT += " \"tool-prefix\": $$emitString($$NDK_TOOLS_PREFIX)," - } - - NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION) - isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION - FILE_CONTENT += " \"toolchain-version\": $$emitString($$NDK_TOOLCHAIN_VERSION)," + FILE_CONTENT += " \"toolchain-prefix\": \"llvm\"," + FILE_CONTENT += " \"tool-prefix\": \"llvm\"," NDK_HOST = $$(ANDROID_NDK_HOST) isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST FILE_CONTENT += " \"ndk-host\": $$emitString($$NDK_HOST)," - ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) - isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH - FILE_CONTENT += " \"target-architecture\": $$emitString($$ANDROID_TARGET_ARCH)," + for (arch, ANDROID_ABIS) { + equals(arch, x86): libs_arch = i686-linux-android + else: equals(arch, x86_64): libs_arch = x86_64-linux-android + else: equals(arch, arm64-v8a): libs_arch = aarch64-linux-android + else: libs_arch = arm-linux-androideabi + ARCHS += "$$emitString($$arch):$$emitString($$libs_arch)" + } + FILE_CONTENT += " \"architectures\": {$$join(ARCHS,", ")}," # Explicitly set qt dependencies of application for deployment !isEmpty(ANDROID_DEPLOYMENT_DEPENDENCIES): \ @@ -74,9 +63,8 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded { QML_ROOT_PATH = $$_PRO_FILE_PWD_ FILE_CONTENT += " \"qml-root-path\": $$emitString($$QML_ROOT_PATH)," FILE_CONTENT += " \"stdcpp-path\": $$emitString($$ANDROID_STDCPP_PATH)," - FILE_CONTENT += " \"useLLVM\": $$ANDROID_USE_LLVM," - - FILE_CONTENT += " \"application-binary\": $$emitString($$absolute_path($$DESTDIR, $$OUT_PWD)/$$TARGET)" + FILE_CONTENT += "" + FILE_CONTENT += " \"application-binary\": $$emitString($$TARGET)" FILE_CONTENT += "}" isEmpty(ANDROID_DEPLOYMENT_SETTINGS_FILE): ANDROID_DEPLOYMENT_SETTINGS_FILE = $$OUT_PWD/android-$$TARGET-deployment-settings.json diff --git a/mkspecs/features/android/default_pre.prf b/mkspecs/features/android/default_pre.prf new file mode 100644 index 0000000000..d4f84a8fcc --- /dev/null +++ b/mkspecs/features/android/default_pre.prf @@ -0,0 +1,76 @@ +load(default_pre) + +build_pass:armeabi-v7a { + QT_ARCH = armeabi-v7a +} else:build_pass:arm64-v8a { + QT_ARCH = arm64-v8a +} else:build_pass:x86 { + QT_ARCH = x86 +} else:build_pass:x86_64 { + QT_ARCH = x86_64 +} else { + # default architecture + QT_ARCH = arm64-v8a +} + +DEFAULT_ANDROID_TARGET_ARCH=$${QT_ARCH} + +ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) +isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH + +# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md + +equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ + QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") +else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ + QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") +else: equals(ANDROID_TARGET_ARCH, x86): \ + QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign +else: equals(ANDROID_TARGET_ARCH, x86_64): \ + QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") + +QMAKE_CFLAGS += -fno-limit-debug-info + +QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS + +ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/ + +# -fstack-protector-strong offers good protection against stack smashing attacks. +# It is (currently) enabled only on Android because we know for sure that Android compilers supports it +QMAKE_CFLAGS += -fPIC -fstack-protector-strong -DANDROID + + +equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { + CONFIG += optimize_size + QMAKE_CFLAGS_DEBUG = -g -marm -O0 + QMAKE_CFLAGS_RELEASE += -mthumb + QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb +} + +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS +QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON +QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG +QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB +QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD + +QMAKE_LIBS_EGL = -lEGL +QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 + +# modifications to linux.conf +QMAKE_AR = $${CROSS_COMPILE}ar cqs +QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy +QMAKE_NM = $${CROSS_COMPILE}nm -P + +QMAKE_STRIP = +#$${CROSS_COMPILE}strip + +QMAKE_RANLIB = $${CROSS_COMPILE}ranlib +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LFLAGS = + +QMAKE_LIBS_PRIVATE = -llog -lz -lm -ldl -lc diff --git a/mkspecs/features/android/resolve_config.prf b/mkspecs/features/android/resolve_config.prf new file mode 100644 index 0000000000..c542017e31 --- /dev/null +++ b/mkspecs/features/android/resolve_config.prf @@ -0,0 +1,10 @@ +load(resolve_config) + +!host_build:!single_arch:!java:android { + isEmpty(ANDROID_ABIS): ANDROID_ABIS = $$ALL_ANDROID_ABIS + + ALL_ABIS = $$join(ANDROID_ABIS, _and_) + CONFIG += $$ALL_ABIS build_all + addExclusiveBuildsProper($$ALL_ABIS, $$ANDROID_ABIS) + unset(ALL_ABIS) +} diff --git a/mkspecs/features/exclusive_builds_post.prf b/mkspecs/features/exclusive_builds_post.prf index 936085af0b..a9c341a2d7 100644 --- a/mkspecs/features/exclusive_builds_post.prf +++ b/mkspecs/features/exclusive_builds_post.prf @@ -1,4 +1,6 @@ +load(qt_functions) + contains(TEMPLATE, subdirs) { for(build, QMAKE_EXCLUSIVE_BUILDS) { prepareRecursiveTarget($$build) diff --git a/mkspecs/features/qmake_use.prf b/mkspecs/features/qmake_use.prf index 64faa4f215..ecb4f7ed41 100644 --- a/mkspecs/features/qmake_use.prf +++ b/mkspecs/features/qmake_use.prf @@ -22,7 +22,11 @@ for(ever) { !defined(QMAKE_LIBS_$$nu, var): \ error("Library '$$lower($$replace(nu, _, -))' is not defined.") - debug: \ + android { + ABI_LIBS = $$eval(QMAKE_LIBS_$${nu}_$${QT_ARCH}) + isEmpty(ABI_LIBS): ABI_LIBS = $$eval(QMAKE_LIBS_$${nu}) + LIBS$${suffix} += $$ABI_LIBS + } else: debug: \ LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu) else: \ LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_RELEASE) $$eval(QMAKE_LIBS_$$nu) diff --git a/mkspecs/features/qt_android_deps.prf b/mkspecs/features/qt_android_deps.prf index c172ca8c4e..e50c24b966 100644 --- a/mkspecs/features/qt_android_deps.prf +++ b/mkspecs/features/qt_android_deps.prf @@ -16,7 +16,7 @@ ANDROID_DEPENDS_DIR = $$MODULE_BASE_OUTDIR/lib/ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml -!build_pass { +build_pass:!isEmpty(QT_ARCH): { !isEmpty(MODULE_PLUGIN_TYPES) { for(PLUGIN_TYPE, MODULE_PLUGIN_TYPES) { ANDROID_BUNDLED_FILES += "plugins/$$PLUGIN_TYPE" @@ -46,6 +46,8 @@ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml EXTENDS = $$section(LIB_FILE, ":", 1, 1) !isEmpty(EXTENDS): EXTENDS = "extends=\"$$EXTENDS\"" LIB_FILE = $$section(LIB_FILE, ":", 0, 0) + LIB_FILE = $$replace(LIB_FILE,".so", "_$${QT_ARCH}.so") + !isEmpty(EXTENDS): EXTENDS = $$replace(EXTENDS,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "<lib file=\"$$LIB_FILE\" $$EXTENDS />" } } @@ -54,12 +56,14 @@ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml for(REPLACEMENT, ANDROID_LIB_DEPENDENCY_REPLACEMENTS) { REPLACEMENT_FILE = $$section(REPLACEMENT, ":", 0, 0) LIB_FILE = $$section(REPLACEMENT, ":", 1, 1) + REPLACEMENT_FILE = $$replace(REPLACEMENT_FILE,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "<lib file=\"$$LIB_FILE\" replaces=\"$$REPLACEMENT_FILE\" />" } } !isEmpty(ANDROID_BUNDLED_FILES) { for (BUNDLED_FILE, ANDROID_BUNDLED_FILES) { + BUNDLED_FILE = $$replace(BUNDLED_FILE,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "<bundled file=\"$$BUNDLED_FILE\" />" } } diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 2b86caebd0..1219fe1443 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -560,7 +560,7 @@ defineTest(qtConfResolveLibs) { } else { paths += $$lp } - } else: contains(l, "^-l.*") { + } else: !android: contains(l, "^-l.*") { lib = $$replace(l, "^-l", ) lcan = integrity:contains(lib, "^.*\\.a") { diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 1903e509c8..ede494eec1 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -1,7 +1,8 @@ defineReplace(qtPlatformTargetSuffix) { suffix = - CONFIG(debug, debug|release) { + android: return($${suffix}_$${QT_ARCH}) + else: CONFIG(debug, debug|release) { !debug_and_release|build_pass { mac: return($${suffix}_debug) win32: return($${suffix}d) diff --git a/mkspecs/features/qt_helper_lib.prf b/mkspecs/features/qt_helper_lib.prf index 2cb54fc547..216c24c7aa 100644 --- a/mkspecs/features/qt_helper_lib.prf +++ b/mkspecs/features/qt_helper_lib.prf @@ -29,19 +29,19 @@ DLLDESTDIR = $$MODULE_BASE_OUTDIR/bin THE_TARGET = $$qt5LibraryTarget($$TARGET) -!build_pass { - MODULE = $$replace(TARGET, ^qt, ) - MODULE ~= s,-,_, - MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri - ucmodule = $$upper($$MODULE) +MODULE = $$replace(TARGET, ^qt, ) +MODULE ~= s,-,_, +MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri +ucmodule = $$upper($$MODULE) +win32|CONFIG(static, static|shared) { + prefix = $$QMAKE_PREFIX_STATICLIB + suffix = $$QMAKE_EXTENSION_STATICLIB +} else { + prefix = $$QMAKE_PREFIX_SHLIB + suffix = $$QMAKE_EXTENSION_SHLIB +} - win32|CONFIG(static, static|shared) { - prefix = $$QMAKE_PREFIX_STATICLIB - suffix = $$QMAKE_EXTENSION_STATICLIB - } else { - prefix = $$QMAKE_PREFIX_SHLIB - suffix = $$QMAKE_EXTENSION_SHLIB - } +!build_pass { CC_USES = LD_USES = for (use, QMAKE_USE) { @@ -58,7 +58,9 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET) "QMAKE_DEPENDS_$${ucmodule}_LD =$$join(LD_USES, " ", " ")" \ "QMAKE_INCDIR_$${ucmodule} = $$val_escape(MODULE_INCLUDEPATH)" \ "QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)" - debug_and_release { + android { + MODULE_PRI_CONT += "QMAKE_LIBS_$${ucmodule} =" + } else: debug_and_release { win32: \ MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}d.$$suffix else: darwin: \ @@ -76,6 +78,11 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET) "QMAKE_LIBS_$${ucmodule} = $$val_escape(MODULE_LIBS)" } write_file($$MODULE_PRI, MODULE_PRI_CONT)|error() +} else: android { + ABI_TARGET = $$qt5LibraryTarget($$TARGET) + ABI_MODULE_LIBS = $$DESTDIR/$$prefix$${ABI_TARGET}.$$suffix + MODULE_PRI_CONT = "QMAKE_LIBS_$${ucmodule}_$${QT_ARCH} = $$val_escape(ABI_MODULE_LIBS)" + write_file($$MODULE_PRI, MODULE_PRI_CONT, append)|error() } TARGET = $$THE_TARGET diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index e892f83432..719caf3d4a 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -51,13 +51,12 @@ defineReplace(qtGetExportsForModule) { return($$result) } -defineReplace(qtExportLibsForModule) { +defineReplace(qtExportDepsForModule) { result = for (lib, QT.$${1}.libraries) { NAME = $$upper($$lib) vars = \ QMAKE_DEPENDS_$${NAME}_CC QMAKE_DEPENDS_$${NAME}_LD \ - QMAKE_LIBS_$$NAME QMAKE_LIBS_$${NAME}_DEBUG QMAKE_LIBS_$${NAME}_RELEASE \ QMAKE_DEFINES_$$NAME QMAKE_INCDIR_$$NAME for (var, vars) { expvar = $$var @@ -71,6 +70,24 @@ defineReplace(qtExportLibsForModule) { return($$result) } +defineReplace(qtExportLibsForModule) { + result = + for (lib, QT.$${1}.libraries) { + NAME = $$upper($$lib) + vars = \ + QMAKE_LIBS_$$NAME QMAKE_LIBS_$${NAME}_DEBUG QMAKE_LIBS_$${NAME}_RELEASE + for (var, vars) { + expvar = $$var + expvar ~= s/^QMAKE_/QMAKE_EXPORT_/ + defined($$expvar, var):equals($$expvar, -): next() + !defined($$expvar, var): expvar = $$var + defined($$expvar, var): \ + result += "$$var$${2} = $$val_escape($$expvar)" + } + } + return($$result) +} + !build_pass { # Create a module .pri file @@ -160,6 +177,7 @@ defineReplace(qtExportLibsForModule) { "QT.$${MODULE}_private.module_config =$$join(module_build_type, " ", " ")" \ $$qtGetFeaturesForModule($${MODULE}_private) \ "" \ + $$qtExportDepsForModule($${MODULE}_private) \ $$qtExportLibsForModule($${MODULE}_private) write_file($$MODULE_PRIVATE_PRI, MODULE_PRIVATE_PRI_CONT)|error() } @@ -220,7 +238,10 @@ defineReplace(qtExportLibsForModule) { } cache(QT_MODULES, transient) -} # !build_pass +} else:android:!no_private_module:!internal_module { + MODULE_PRIVATE_PRI_CONT = $$qtExportLibsForModule($${MODULE}_private, _$${QT_ARCH}) + write_file($$MODULE_PRIVATE_PRI, MODULE_PRIVATE_PRI_CONT, append)|error() +} # Schedule the regular .pri file for installation CONFIG += qt_install_module diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties index bf3de21830..4b7e1f3d38 100644 --- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/android/jar/jar.pro b/src/android/jar/jar.pro index ac6fc79968..24a83d56a1 100644 --- a/src/android/jar/jar.pro +++ b/src/android/jar/jar.pro @@ -1,6 +1,7 @@ TARGET = QtAndroid CONFIG += java + DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/ diff --git a/src/android/java/java.pro b/src/android/java/java.pro index 9d37eb1026..7f0dfa8a1b 100644 --- a/src/android/java/java.pro +++ b/src/android/java/java.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + CONFIG -= qt android_install javaresources.files = \ diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java index d3b0600b2f..45941e8ed8 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, BogDan Vatra <bogdan@kde.org> + Copyright (c) 2019, BogDan Vatra <bogdan@kde.org> Contact: http://www.qt.io/licensing/ Commercial License Usage @@ -63,9 +63,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import dalvik.system.DexClassLoader; @@ -85,7 +88,6 @@ public abstract class QtLoader { public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; public static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; - public static final String QT_LIBS_RESOURCE_ID_KEY = "android.app.qt_libs_resource_id"; public static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id"; public static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id"; public static final String MAIN_LIBRARY_KEY = "main.library"; @@ -153,7 +155,7 @@ public abstract class QtLoader { // this repository is used to push a new release, and should be used to test your application. // * unstable - unstable repository, DO NOT use this repository in production, // this repository is used to push Qt snapshots. - public String[] m_qtLibs = null; // required qt libs + public ArrayList<String> m_qtLibs = null; // required qt libs public int m_displayDensity = -1; private ContextWrapper m_context; protected ComponentInfo m_contextInfo; @@ -191,6 +193,36 @@ public abstract class QtLoader { } // Implement in subclass + private final List<String> supportedAbis = Arrays.asList(Build.SUPPORTED_ABIS); + private String preferredAbi = null; + + private ArrayList<String> prefferedAbiLibs(String []libs) + { + HashMap<String, ArrayList<String>> abisLibs = new HashMap<>(); + for (String lib : libs) { + String[] archLib = lib.split(";", 2); + if (preferredAbi != null && !archLib[0].equals(preferredAbi)) + continue; + if (!abisLibs.containsKey(archLib[0])) + abisLibs.put(archLib[0], new ArrayList<String>()); + abisLibs.get(archLib[0]).add(archLib[1]); + } + + if (preferredAbi != null) { + if (abisLibs.containsKey(preferredAbi)) { + return abisLibs.get(preferredAbi); + } + return new ArrayList<String>(); + } + + for (String abi: supportedAbis) { + if (abisLibs.containsKey(abi)) { + preferredAbi = abi; + return abisLibs.get(abi); + } + } + return new ArrayList<String>(); + } // this function is used to load and start the loader private void loadApplication(Bundle loaderParams) @@ -218,12 +250,14 @@ public abstract class QtLoader { // add all bundled Qt libs to loader params ArrayList<String> libs = new ArrayList<String>(); - if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) - libs.addAll(Arrays.asList(m_context.getResources().getStringArray(m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id")))); + if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) { + int resourceId = m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id"); + libs.addAll(prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))); + } String libName = null; if (m_contextInfo.metaData.containsKey("android.app.lib_name")) { - libName = m_contextInfo.metaData.getString("android.app.lib_name"); + libName = m_contextInfo.metaData.getString("android.app.lib_name") + "_" + preferredAbi; loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function } @@ -278,7 +312,7 @@ public abstract class QtLoader { try { if (m_service != null) { Bundle parameters = new Bundle(); - parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs); + parameters.putStringArray(REQUIRED_MODULES_KEY, (String[]) m_qtLibs.toArray()); parameters.putString(APPLICATION_TITLE_KEY, getTitle()); parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL); parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION); @@ -464,7 +498,8 @@ public abstract class QtLoader { // why can't we load the plugins directly from libs ?!?! String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; if (m_contextInfo.metaData.containsKey(key)) { - String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); + int resourceId = m_contextInfo.metaData.getInt(key); + ArrayList<String> list = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); for (String bundledImportBinary : list) { String[] split = bundledImportBinary.split(":"); @@ -603,7 +638,7 @@ public abstract class QtLoader { if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id"); - m_qtLibs = m_context.getResources().getStringArray(resourceId); + m_qtLibs = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); } if (m_contextInfo.metaData.containsKey("android.app.use_local_qt_libs") @@ -617,6 +652,7 @@ public abstract class QtLoader { apkDeployFromSystem = true; String libsDir = null; + String bundledLibsDir = null; if (apkDeployFromSystem) { String systemLibsPrefix = SYSTEM_LIB_PATH; if (m_contextInfo.metaData.containsKey("android.app.system_libs_prefix")) { @@ -633,8 +669,11 @@ public abstract class QtLoader { } else { String nativeLibraryPrefix = m_context.getApplicationInfo().nativeLibraryDir + "/"; File nativeLibraryDir = new File(nativeLibraryPrefix); - if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) + if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) { libsDir = nativeLibraryPrefix; + bundledLibsDir = nativeLibraryPrefix; + } + } if (apkDeployFromSystem && libsDir == null) @@ -643,8 +682,8 @@ public abstract class QtLoader { if (m_qtLibs != null) { String libPrefix = libsDir + "lib"; - for (int i = 0; i < m_qtLibs.length; i++) - libraryList.add(libPrefix + m_qtLibs[i] + ".so"); + for (String lib : m_qtLibs) + libraryList.add(libPrefix + lib + ".so"); } if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs") @@ -654,22 +693,26 @@ public abstract class QtLoader { String pluginsPrefix = dataPath + "qt-reserved-files/"; if (libsDir == null) - throw new Exception(""); + throw new Exception("Invalid libsDir"); cleanOldCacheIfNecessary(dataPath, pluginsPrefix); extractBundledPluginsAndImports(pluginsPrefix, libsDir); if (m_contextInfo.metaData.containsKey(BUNDLED_IN_LIB_RESOURCE_ID_KEY)) { - String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":"); - for (String lib : extraLibs) { - if (!lib.isEmpty()) - libraryList.add(pluginsPrefix + lib); + int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id"); + for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) { + for (String lib : libs.split(":")) { + if (!lib.isEmpty()) + libraryList.add(libsDir + lib); + } } } ENVIRONMENT_VARIABLES += "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"; + if (bundledLibsDir != null) + ENVIRONMENT_VARIABLES += "\tQT_BUNDLED_LIBS_PATH=" + bundledLibsDir; } Bundle loaderParams = new Bundle(); diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index aed8a3c888..75da314c2b 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -12,7 +12,7 @@ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> - <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --"> + <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true"> <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" @@ -36,10 +36,11 @@ <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/> <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/> + <!-- Run with local libs --> <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/> - <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/> + <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/> <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/> <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/> <!-- Used to specify custom system library path to run with local system libs --> diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle index 8d4aa63153..d2da115936 100644 --- a/src/android/templates/build.gradle +++ b/src/android/templates/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml index 4009a7785a..db777bf433 100644 --- a/src/android/templates/res/values/libs.xml +++ b/src/android/templates/res/values/libs.xml @@ -1,7 +1,7 @@ <?xml version='1.0' encoding='utf-8'?> <resources> <array name="qt_sources"> - <item>https://download.qt.io/ministro/android/qt5/qt-5.9</item> + <item>https://download.qt.io/ministro/android/qt5/qt-5.14</item> </array> <!-- The following is handled automatically by the deployment tool. It should @@ -12,12 +12,17 @@ </array> <array name="qt_libs"> - <!-- %%INSERT_QT_LIBS%% --> + <!-- %%INSERT_QT_LIBS%% --> </array> <array name="bundled_in_lib"> <!-- %%INSERT_BUNDLED_IN_LIB%% --> </array> + + <array name="load_local_libs"> + <!-- %%INSERT_LOCAL_LIBS%% --> + </array> + <array name="bundled_in_assets"> <!-- %%INSERT_BUNDLED_IN_ASSETS%% --> </array> diff --git a/src/android/templates/templates.pro b/src/android/templates/templates.pro index 55387f3af7..9a64251ee3 100644 --- a/src/android/templates/templates.pro +++ b/src/android/templates/templates.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + CONFIG -= qt android_install templates.files = \ diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index b9bcc70e17..121db51eb5 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -12,6 +12,7 @@ CONFIG += qt_tracepoints CONFIG += $$MODULE_CONFIG DEFINES += $$MODULE_DEFINES +android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"' DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x67000000 diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 85ada9197c..44d5513163 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -100,6 +100,9 @@ QStringList QLibraryPrivate::suffixes_sys(const QString& fullVersion) suffixes << QLatin1String(".so.%1").arg(fullVersion); } else { suffixes << QLatin1String(".so"); +# ifdef Q_OS_ANDROID + suffixes << QStringLiteral(LIBS_SUFFIX); +# endif } #endif # ifdef Q_OS_MAC @@ -226,7 +229,14 @@ bool QLibraryPrivate::load_sys() } else { attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix); } + pHnd = dlopen(QFile::encodeName(attempt), dlFlags); +#ifdef Q_OS_ANDROID + if (!pHnd) { + auto attemptFromBundle = attempt; + pHnd = dlopen(QFile::encodeName(attemptFromBundle.replace(QLatin1Char('/'), QLatin1Char('_'))), dlFlags); + } +#endif if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { // We only want to continue if dlopen failed due to that the shared library did not exist. diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 70fccbc378..3b2ced3f58 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -82,7 +82,18 @@ qtConfig(png) { } # SIMD -SSSE3_SOURCES += image/qimage_ssse3.cpp -NEON_SOURCES += image/qimage_neon.cpp -MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp -MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S +!android { + SSSE3_SOURCES += image/qimage_ssse3.cpp + NEON_SOURCES += image/qimage_neon.cpp + MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp + MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S +} else { + # see https://developer.android.com/ndk/guides/abis + arm64-v8a { + SOURCES += image/qimage_neon.cpp + } + x86 | x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3 + SOURCES += image/qimage_ssse3.cpp + } +} diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 972cf387ff..fcf6488edd 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -135,23 +135,41 @@ gcc:equals(QT_GCC_MAJOR_VERSION, 5) { NO_PCH_SOURCES += painting/qdrawhelper.cpp } -SSE2_SOURCES += painting/qdrawhelper_sse2.cpp -SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp -SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ - painting/qimagescale_sse4.cpp -ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp +!android { + SSE2_SOURCES += painting/qdrawhelper_sse2.cpp + SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp + SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ + painting/qimagescale_sse4.cpp + ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp -NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp -NEON_HEADERS += painting/qdrawhelper_neon_p.h + NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp + NEON_HEADERS += painting/qdrawhelper_neon_p.h +} !uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as -!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") { +!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") { NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S DEFINES += ENABLE_PIXMAN_DRAWHELPERS } -MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp -MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h -MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S -MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S +!android { + MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp + MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h + MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S + MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S +} else { + # see https://developer.android.com/ndk/guides/abis + x86 | x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3 + SOURCES += painting/qdrawhelper_sse2.cpp painting/qdrawhelper_ssse3.cpp + } + x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE4_1 QT_COMPILER_SUPPORTS_SSE4_2 + SOURCES += painting/qdrawhelper_sse4.cpp painting/qimagescale_sse4.cpp + } + arm64-v8a { + SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp + HEADERS += painting/qdrawhelper_neon_p.h + } +} include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/plugins/bearer/android/jar/jar.pro b/src/plugins/bearer/android/jar/jar.pro index f988019dac..8277a8abc1 100644 --- a/src/plugins/bearer/android/jar/jar.pro +++ b/src/plugins/bearer/android/jar/jar.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + TARGET = QtAndroidBearer load(qt_build_paths) diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 10bbd59bfb..4c7b8a6917 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -91,7 +91,7 @@ FILE *openProcess(const QString &command) #if defined(Q_OS_WIN32) QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"'); #else - QString processedCommand = command; + const QString& processedCommand = command; #endif return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ); @@ -99,7 +99,7 @@ FILE *openProcess(const QString &command) struct QtDependency { - QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {} + QtDependency(const QString &rpath, const QString &apath) : relativePath(rpath), absolutePath(apath) {} bool operator==(const QtDependency &other) const { @@ -127,7 +127,6 @@ struct Options , sectionsOnly(false) , protectedAuthenticationPath(false) , jarSigner(false) - , gdbServer(Auto) , installApk(false) , uninstallApk(false) {} @@ -150,7 +149,6 @@ struct Options bool generateAssetsFileList; bool build; bool auxMode; - bool stripLibraries = true; ActionTimer timer; // External tools @@ -175,22 +173,22 @@ struct Options // lib c++ path QString stdCppPath; - QString stdCppName = QStringLiteral("gnustl_shared"); + QString stdCppName = QStringLiteral("c++_shared"); // Build information QString androidPlatform; - QString architecture; - QString toolchainVersion; + QHash<QString, QString> architectures; + QString currentArchitecture; QString toolchainPrefix; - QString toolPrefix; - bool useLLVM = false; QString ndkHost; // Package information DeploymentMechanism deploymentMechanism; QString packageName; QStringList extraLibs; + QHash<QString, QStringList> archExtraLibs; QStringList extraPlugins; + QHash<QString, QStringList> archExtraPlugins; // Signing information bool releasePackage; @@ -211,25 +209,36 @@ struct Options bool jarSigner; QString apkPath; - // Gdbserver - TriState gdbServer; - // Installation information bool installApk; bool uninstallApk; QString installLocation; - // Collected information + // Per architecture collected information + void clear(const QString &arch) + { + currentArchitecture = arch; + } typedef QPair<QString, QString> BundledFile; - QList<BundledFile> bundledFiles; - QList<QtDependency> qtDependencies; - QStringList localLibs; + QHash<QString, QList<BundledFile>> bundledFiles; + QHash<QString, QList<QtDependency>> qtDependencies; + QHash<QString, QStringList> localLibs; + bool usesOpenGL = false; + + // Per package collected information QStringList localJars; QStringList initClasses; QStringList permissions; QStringList features; }; +static const QHash<QByteArray, QByteArray> elfArchitecures = { + {"aarch64", "arm64-v8a"}, + {"arm", "armeabi-v7a"}, + {"i386", "x86"}, + {"x86_64", "x86_64"} +}; + // Copy-pasted from qmake/library/ioutil.cpp inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) { @@ -301,6 +310,59 @@ static QString shellQuote(const QString &arg) return shellQuoteUnix(arg); } +QString architecureFromName(const QString &name) +{ + QRegExp architecture(QStringLiteral(".*_(.*)\\.so")); + if (!architecture.exactMatch(name)) + return {}; + return architecture.capturedTexts().last(); +} + +QString fileArchitecture(const Options &options, const QString &path) +{ + auto arch = architecureFromName(path); + if (!arch.isEmpty()) + return arch; + + QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath, + options.toolchainPrefix, + options.ndkHost); +#if defined(Q_OS_WIN32) + readElf += QStringLiteral(".exe"); +#endif + + if (!QFile::exists(readElf)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf)); + return {}; + } + + readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(path)); + + FILE *readElfCommand = openProcess(readElf); + if (!readElfCommand) { + fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); + return {}; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { + QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); + QString library; + line = line.trimmed(); + if (line.startsWith("Arch: ")) { + auto it = elfArchitecures.find(line.mid(6)); + pclose(readElfCommand); + return it != elfArchitecures.constEnd() ? QString::fromLatin1(it.value()) : QString{}; + } + } + pclose(readElfCommand); + return {}; +} + +bool checkArchitecture(const Options &options, const QString &fileName) +{ + return fileArchitecture(options, fileName) == options.currentArchitecture; +} void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir) { @@ -388,10 +450,6 @@ Options parseOptions() options.installLocation = arguments.at(++i); } else if (argument.compare(QLatin1String("--release"), Qt::CaseInsensitive) == 0) { options.releasePackage = true; - } else if (argument.compare(QLatin1String("--gdbserver"), Qt::CaseInsensitive) == 0) { - options.gdbServer = Options::True; - } else if (argument.compare(QLatin1String("--no-gdbserver"), Qt::CaseInsensitive) == 0) { - options.gdbServer = Options::False; } else if (argument.compare(QLatin1String("--jdk"), Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) options.helpRequested = true; @@ -462,8 +520,6 @@ Options parseOptions() options.generateAssetsFileList = false; } else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) { options.auxMode = true; - } else if (argument.compare(QLatin1String("--no-strip"), Qt::CaseInsensitive) == 0) { - options.stripLibraries = false; } } @@ -533,10 +589,6 @@ void printHelp() " --protected: Keystore has protected authentication path.\n" " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n" " used if available.\n" - " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n" - " is bundled for debug pacakges.\n" - " --no-gdbserver: Prevents the gdbserver from being added to the package\n" - " By default the gdbserver is bundled for debug pacakges.\n" " --jdk <path/to/jdk>: Used to find the jarsigner tool when used\n" " in combination with the --release argument. By default,\n" " an attempt is made to detect the tool using the JAVA_HOME and\n" @@ -549,7 +601,6 @@ void printHelp() " --aux-mode: Operate in auxiliary mode. This will only copy the\n" " dependencies into the build directory and update the XML templates.\n" " The project will not be built or installed.\n" - " --no-strip: Do not strip debug symbols from libraries.\n" " --apk <path/where/to/copy/the/apk>: Path where to copy the built apk.\n" " --help: Displays this information.\n\n", qPrintable(QCoreApplication::arguments().at(0)) @@ -580,9 +631,10 @@ bool alwaysOverwritableFile(const QString &fileName) || fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java"))); } + bool copyFileIfNewer(const QString &sourceFileName, const QString &destinationFileName, - bool verbose, + const Options &options, bool forceOverwrite = false) { if (QFile::exists(destinationFileName)) { @@ -592,7 +644,7 @@ bool copyFileIfNewer(const QString &sourceFileName, if (!forceOverwrite && sourceFileInfo.lastModified() <= destinationFileInfo.lastModified() && !alwaysOverwritableFile(destinationFileName)) { - if (verbose) + if (options.verbose) fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName)); return true; } else { @@ -611,11 +663,10 @@ bool copyFileIfNewer(const QString &sourceFileName, if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) { fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName)); return false; - } else if (verbose) { + } else if (options.verbose) { fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName)); fflush(stdout); } - return true; } @@ -666,7 +717,7 @@ QString cleanPackageName(QString packageName) } } if (keywords.contains(word)) { - packageName.insert(next, QLatin1String("_")); + packageName.insert(next, QStringLiteral("_")); index = next + 1; } else { index = next; @@ -678,7 +729,7 @@ QString cleanPackageName(QString packageName) QString detectLatestAndroidPlatform(const QString &sdkPath) { - QDir dir(sdkPath + QLatin1String("/platforms")); + QDir dir(sdkPath + QStringLiteral("/platforms")); if (!dir.exists()) { fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath())); return QString(); @@ -795,53 +846,22 @@ bool readInputFile(Options *options) } { - const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); - if (applicationBinary.isUndefined()) { - fprintf(stderr, "No application binary defined in json file.\n"); - return false; - } - options->applicationBinary = applicationBinary.toString(); - - if (!QFile::exists(options->applicationBinary)) { - fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + const QJsonObject targetArchitectures = jsonObject.value(QStringLiteral("architectures")).toObject(); + if (targetArchitectures.isEmpty()) { + fprintf(stderr, "No target architecture defined in json file.\n"); return false; } - } - - { - const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); - if (!deploymentDependencies.isUndefined()) { - QString deploymentDependenciesString = deploymentDependencies.toString(); - const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); - for (const QStringRef &dependency : dependencies) { - QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; - if (QFileInfo(path).isDir()) { - QDirIterator iterator(path, QDirIterator::Subdirectories); - while (iterator.hasNext()) { - iterator.next(); - if (iterator.fileInfo().isFile()) { - QString subPath = iterator.filePath(); - options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), - subPath)); - } - } - } else { - options->qtDependencies.append(QtDependency(dependency.toString(), path)); - } + for (auto it = targetArchitectures.constBegin(); it != targetArchitectures.constEnd(); ++it) { + if (it.value().isUndefined()) { + fprintf(stderr, "Invalid architecure.\n"); + return false; } + if (it.value().isNull()) + continue; + options->architectures.insert(it.key(), it.value().toString()); } } - - { - const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture")); - if (targetArchitecture.isUndefined()) { - fprintf(stderr, "No target architecture defined in json file.\n"); - return false; - } - options->architecture = targetArchitecture.toString(); - } - { const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk")); if (ndk.isUndefined()) { @@ -852,11 +872,6 @@ bool readInputFile(Options *options) } { - const QJsonValue value = jsonObject.value(QStringLiteral("useLLVM")); - options->useLLVM = value.toBool(false); - } - - { const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix")); if (toolchainPrefix.isUndefined()) { fprintf(stderr, "No toolchain prefix defined in json file.\n"); @@ -866,25 +881,6 @@ bool readInputFile(Options *options) } { - const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix")); - if (toolPrefix.isUndefined()) { - fprintf(stderr, "Warning: No tool prefix defined in json file.\n"); - options->toolPrefix = options->toolchainPrefix; - } else { - options->toolPrefix = toolPrefix.toString(); - } - } - - if (!options->useLLVM) { - const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version")); - if (toolchainVersion.isUndefined()) { - fprintf(stderr, "No toolchain version defined in json file.\n"); - return false; - } - options->toolchainVersion = toolchainVersion.toString(); - } - - { const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host")); if (ndkHost.isUndefined()) { fprintf(stderr, "No NDK host defined in json file.\n"); @@ -893,10 +889,6 @@ bool readInputFile(Options *options) options->ndkHost = ndkHost.toString(); } - options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml")); - if (options->packageName.isEmpty()) - options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1))); - { const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs")); if (!extraLibs.isUndefined()) @@ -916,12 +908,6 @@ bool readInputFile(Options *options) return false; } options->stdCppPath = stdcppPath.toString(); - auto name = QFileInfo(options->stdCppPath).baseName(); - if (!name.startsWith(QLatin1String("lib"))) { - fprintf(stderr, "Invalid STD C++ library name.\n"); - return false; - } - options->stdCppName = name.mid(3); } { @@ -935,10 +921,68 @@ bool readInputFile(Options *options) if (!qmlImportPaths.isUndefined()) options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(',')); } + + { + const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); + if (applicationBinary.isUndefined()) { + fprintf(stderr, "No application binary defined in json file.\n"); + return false; + } + options->applicationBinary = applicationBinary.toString(); + if (options->build) { + for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) { + if (!QFile::exists(QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, it.key(), options->applicationBinary))) { + fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + return false; + } + } + } + } + + { + const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); + if (!deploymentDependencies.isUndefined()) { + QString deploymentDependenciesString = deploymentDependencies.toString(); + const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); + for (const QStringRef &dependency : dependencies) { + QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; + if (QFileInfo(path).isDir()) { + QDirIterator iterator(path, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + if (iterator.fileInfo().isFile()) { + QString subPath = iterator.filePath(); + auto arch = fileArchitecture(*options, subPath); + if (!arch.isEmpty()) { + options->qtDependencies[arch].append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), + subPath)); + } else if (options->verbose) { + fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(subPath)); + fflush(stderr); + } + } + } + } else { + auto arch = fileArchitecture(*options, path); + if (!arch.isEmpty()) { + options->qtDependencies[arch].append(QtDependency(dependency.toString(), path)); + } else if (options->verbose) { + fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path)); + fflush(stderr); + } + } + } + } + } + + options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QStringLiteral("/AndroidManifest.xml")); + if (options->packageName.isEmpty()) + options->packageName = cleanPackageName(QStringLiteral("org.qtproject.example.%1").arg(options->applicationBinary)); + return true; } -bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false) +bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false) { const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); for (const QFileInfo &entry : entries) { @@ -949,11 +993,11 @@ bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bo return false; } - if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite)) + if (!copyFiles(dir, QDir(destinationDirectory.path() + QStringLiteral("/") + dir.dirName()), options, forceOverwrite)) return false; } else { QString destination = destinationDirectory.absoluteFilePath(entry.fileName()); - if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite)) + if (!copyFileIfNewer(entry.absoluteFilePath(), destination, options, forceOverwrite)) return false; } } @@ -993,7 +1037,7 @@ bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, return false; } - return copyFiles(sourceDirectory, QDir(outDir), options.verbose); + return copyFiles(sourceDirectory, QDir(outDir), options); } bool copyGradleTemplate(const Options &options) @@ -1010,7 +1054,7 @@ bool copyGradleTemplate(const Options &options) return false; } - return copyFiles(sourceDirectory, QDir(outDir), options.verbose); + return copyFiles(sourceDirectory, QDir(outDir), options); } bool copyAndroidTemplate(const Options &options) @@ -1041,38 +1085,42 @@ bool copyAndroidSources(const Options &options) return false; } - return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true); + return copyFiles(sourceDirectory, QDir(options.outputDirectory), options, true); } -bool copyAndroidExtraLibs(const Options &options) +bool copyAndroidExtraLibs(Options *options) { - if (options.extraLibs.isEmpty()) + if (options->extraLibs.isEmpty()) return true; - if (options.verbose) - fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size()); + if (options->verbose) + fprintf(stdout, "Copying %d external libraries to package.\n", options->extraLibs.size()); - for (const QString &extraLib : options.extraLibs) { + for (const QString &extraLib : options->extraLibs) { QFileInfo extraLibInfo(extraLib); if (!extraLibInfo.exists()) { fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib)); return false; } - - if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) { + if (!checkArchitecture(*options, extraLibInfo.filePath())) { + if (options->verbose) + fprintf(stdout, "Skipping \"%s\", architecture mismatch.\n", qPrintable(extraLib)); + continue; + } + if (!extraLibInfo.fileName().startsWith(QStringLiteral("lib")) || extraLibInfo.suffix() != QStringLiteral("so")) { fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n", qPrintable(extraLib)); return false; } - - QString destinationFile(options.outputDirectory - + QLatin1String("/libs/") - + options.architecture + QString destinationFile(options->outputDirectory + + QStringLiteral("/libs/") + + options->currentArchitecture + QLatin1Char('/') + extraLibInfo.fileName()); - if (!copyFileIfNewer(extraLib, destinationFile, options.verbose)) + if (!copyFileIfNewer(extraLib, destinationFile, *options)) return false; + options->archExtraLibs[options->currentArchitecture] += extraLib; } return true; @@ -1093,15 +1141,15 @@ QStringList allFilesInside(const QDir& current, const QDir& rootDir) return result; } -bool copyAndroidExtraResources(const Options &options) +bool copyAndroidExtraResources(Options *options) { - if (options.extraPlugins.isEmpty()) + if (options->extraPlugins.isEmpty()) return true; - if (options.verbose) - fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size()); + if (options->verbose) + fprintf(stdout, "Copying %d external resources to package.\n", options->extraPlugins.size()); - for (const QString &extraResource : options.extraPlugins) { + for (const QString &extraResource : options->extraPlugins) { QFileInfo extraResourceInfo(extraResource); if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) { fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource)); @@ -1109,20 +1157,22 @@ bool copyAndroidExtraResources(const Options &options) } QDir resourceDir(extraResource); - QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); - QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/'); + QString assetsDir = options->outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); + QString libsDir = options->outputDirectory + QStringLiteral("/libs/") + options->currentArchitecture + QLatin1Char('/'); const QStringList files = allFilesInside(resourceDir, resourceDir); for (const QString &resourceFile : files) { QString originFile(resourceDir.filePath(resourceFile)); QString destinationFile; - if (!resourceFile.endsWith(QLatin1String(".so"))) { + if (!resourceFile.endsWith(QStringLiteral(".so"))) { destinationFile = assetsDir + resourceFile; } else { + if (!checkArchitecture(*options, originFile)) + continue; destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_')); + options->archExtraPlugins[options->currentArchitecture] += resourceFile; } - - if (!copyFileIfNewer(originFile, destinationFile, options.verbose)) + if (!copyFileIfNewer(originFile, destinationFile, *options)) return false; } } @@ -1174,75 +1224,118 @@ bool updateFile(const QString &fileName, const QHash<QString, QString> &replacem } -bool updateLibsXml(const Options &options) +bool updateLibsXml(Options *options) { - if (options.verbose) + if (options->verbose) fprintf(stdout, " -- res/values/libs.xml\n"); - QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml"); + QString fileName = options->outputDirectory + QStringLiteral("/res/values/libs.xml"); if (!QFile::exists(fileName)) { fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName)); return false; } - QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/'); - - QString qtLibs = QLatin1String("<item>") + options.stdCppName + QLatin1String("</item>\n"); + QString qtLibs; QString bundledInLibs; QString bundledInAssets; - for (const Options::BundledFile &bundledFile : options.bundledFiles) { - if (bundledFile.second.startsWith(QLatin1String("lib/"))) { - QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); - s.chop(sizeof(".so") - 1); - qtLibs += QString::fromLatin1("<item>%1</item>\n").arg(s); - } else if (bundledFile.first.startsWith(libsPath)) { - QString s = bundledFile.first.mid(libsPath.length()); - bundledInLibs += QString::fromLatin1("<item>%1:%2</item>\n") - .arg(s).arg(bundledFile.second); - } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) { - QString s = bundledFile.first.mid(sizeof("assets/") - 1); - bundledInAssets += QString::fromLatin1("<item>%1:%2</item>\n") - .arg(s).arg(bundledFile.second); + QString allLocalLibs; + QString extraLibs; + + for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) { + QString libsPath = QStringLiteral("libs/") + it.key() + QLatin1Char('/'); + + qtLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), options->stdCppName); + for (const Options::BundledFile &bundledFile : options->bundledFiles[it.key()]) { + if (bundledFile.second.startsWith(QStringLiteral("lib/"))) { + QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); + s.chop(sizeof(".so") - 1); + qtLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), s); + } else if (bundledFile.first.startsWith(libsPath)) { + QString s = bundledFile.first.mid(libsPath.length()); + bundledInLibs += QString::fromLatin1(" <item>%1;%2:%3</item>\n") + .arg(it.key(), s, bundledFile.second); + } else if (bundledFile.first.startsWith(QStringLiteral("assets/"))) { + QString s = bundledFile.first.mid(sizeof("assets/") - 1); + bundledInAssets += QString::fromLatin1(" <item>%1:%2</item>\n") + .arg(s).arg(bundledFile.second); + } } - } - if (!options.extraPlugins.isEmpty()) { - for (const QString &extraRes : options.extraPlugins) { - QDir resourceDir(extraRes); - const QStringList files = allFilesInside(resourceDir, resourceDir); - for (const QString &file : files) { - QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; - if (!file.endsWith(QLatin1String(".so"))) { - bundledInAssets += QStringLiteral("<item>%1:%1</item>\n") - .arg(destinationPath); - } else { - bundledInLibs += QStringLiteral("<item>lib%1:%2</item>\n") - .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_'))) - .arg(destinationPath); + if (!options->archExtraPlugins[it.key()].isEmpty()) { + for (const QString &extraRes : options->archExtraPlugins[it.key()]) { + QDir resourceDir(extraRes); + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &file : files) { + QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; + if (!file.endsWith(QStringLiteral(".so"))) { + bundledInAssets += QStringLiteral(" <item>%1:%1</item>\n") + .arg(destinationPath); + } else { + bundledInLibs += QStringLiteral(" <item>%1;lib%2:%3</item>\n") + .arg(it.key(), + QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')), + destinationPath); + } } } } - } - QHash<QString, QString> replacements; - replacements[QLatin1String("<!-- %%INSERT_QT_LIBS%% -->")] = qtLibs; + if (!options->archExtraLibs[it.key()].isEmpty()) { + for (const QString &extraLib : options->archExtraLibs[it.key()]) { + QFileInfo extraLibInfo(extraLib); + QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); + name.chop(sizeof(".so") - 1); + extraLibs += QStringLiteral(" <item>%1;%2").arg(it.key(), name); + } + } - if (options.deploymentMechanism == Options::Bundled) { - replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] = bundledInLibs; - replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] = bundledInAssets; - } + QStringList localLibs; + localLibs = options->localLibs[it.key()]; + // If .pro file overrides dependency detection, we need to see which platform plugin they picked + if (localLibs.isEmpty()) { + QString plugin; + for (const QtDependency &qtDependency : options->qtDependencies[it.key()]) { + if (qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroid.so")) + || qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroidGL.so"))) { + if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { + fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); + return false; + } - QString extraLibs; - if (!options.extraLibs.isEmpty()) { - for (const QString extraLib : options.extraLibs) { - QFileInfo extraLibInfo(extraLib); - QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); - name.chop(sizeof(".so") - 1); + plugin = qtDependency.relativePath; + } + if (qtDependency.relativePath.contains(QStringLiteral("libQt5OpenGL")) + || qtDependency.relativePath.contains(QStringLiteral("libQt5Quick"))) { + options->usesOpenGL |= true; + break; + } + } - extraLibs += QLatin1String("<item>") + name + QLatin1String("</item>\n"); + if (plugin.isEmpty()) { + fflush(stdout); + fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); + fflush(stderr); + return false; + } + + localLibs.append(plugin); + if (options->verbose) + fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); } + allLocalLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), localLibs.join(QLatin1Char(':')) + .replace(QStringLiteral("lib/"), QString{}) + .replace(QLatin1Char('/'), QLatin1Char('_'))); + } + + QHash<QString, QString> replacements; + replacements[QStringLiteral("<!-- %%INSERT_QT_LIBS%% -->")] += qtLibs.trimmed(); + replacements[QStringLiteral("<!-- %%INSERT_LOCAL_LIBS%% -->")] = allLocalLibs.trimmed(); + replacements[QStringLiteral("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs.trimmed(); + + if (options->deploymentMechanism == Options::Bundled) { + replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] += bundledInLibs.trimmed(); + replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] += bundledInAssets.trimmed(); } - replacements[QLatin1String("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs; if (!updateFile(fileName, replacements)) return false; @@ -1256,9 +1349,9 @@ bool updateStringsXml(const Options &options) fprintf(stdout, " -- res/values/strings.xml\n"); QHash<QString, QString> replacements; - replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = options.applicationBinary; - QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml"); + QString fileName = options.outputDirectory + QStringLiteral("/res/values/strings.xml"); if (!QFile::exists(fileName)) { if (options.verbose) fprintf(stdout, " -- Create strings.xml since it's missing.\n"); @@ -1268,7 +1361,7 @@ bool updateStringsXml(const Options &options) return false; } file.write(QByteArray("<?xml version='1.0' encoding='utf-8'?><resources><string name=\"app_name\" translatable=\"false\">") - .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1()) + .append(options.applicationBinary.toLatin1()) .append("</string></resources>\n")); return true; } @@ -1284,71 +1377,34 @@ bool updateAndroidManifest(Options &options) if (options.verbose) fprintf(stdout, " -- AndroidManifest.xml \n"); - QStringList localLibs = options.localLibs; - - // If .pro file overrides dependency detection, we need to see which platform plugin they picked - if (localLibs.isEmpty()) { - QString plugin; - for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { - if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so")) - || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) { - if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { - fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); - return false; - } - - plugin = qtDependency.relativePath; - } - } - - if (plugin.isEmpty()) { - fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); - return false; - } - - localLibs.append(plugin); - if (options.verbose) - fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); - } - - bool usesGL = false; - for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { - if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so")) - || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) { - usesGL = true; - break; - } - } - options.localJars.removeDuplicates(); options.initClasses.removeDuplicates(); QHash<QString, QString> replacements; - replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); - replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); - replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_VERSION_NAME%% --")] = options.versionName; - replacements[QLatin1String("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; - replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName); - replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] - = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0"); - replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")] - = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary; + replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary; + replacements[QStringLiteral("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); + replacements[QStringLiteral("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); + replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName; + replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; + replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QStringLiteral("package=\"%1\"").arg(options.packageName); + replacements[QStringLiteral("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism == Options::Bundled) ? QStringLiteral("1") : QStringLiteral("0"); + replacements[QStringLiteral("-- %%USE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism != Options::Ministro) ? QStringLiteral("1") : QStringLiteral("0"); QString permissions; for (const QString &permission : qAsConst(options.permissions)) - permissions += QString::fromLatin1(" <uses-permission android:name=\"%1\" />\n").arg(permission); - replacements[QLatin1String("<!-- %%INSERT_PERMISSIONS -->")] = permissions; + permissions += QStringLiteral(" <uses-permission android:name=\"%1\" />\n").arg(permission); + replacements[QStringLiteral("<!-- %%INSERT_PERMISSIONS -->")] = permissions.trimmed(); QString features; for (const QString &feature : qAsConst(options.features)) features += QStringLiteral(" <uses-feature android:name=\"%1\" android:required=\"false\" />\n").arg(feature); - if (usesGL) + if (options.usesOpenGL) features += QStringLiteral(" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />"); - replacements[QLatin1String("<!-- %%INSERT_FEATURES -->")] = features; + replacements[QStringLiteral("<!-- %%INSERT_FEATURES -->")] = features.trimmed(); QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml"); if (!updateFile(androidManifestPath, replacements)) @@ -1409,7 +1465,7 @@ bool updateAndroidFiles(Options &options) if (options.verbose) fprintf(stdout, "Updating Android package files with project settings.\n"); - if (!updateLibsXml(options)) + if (!updateLibsXml(&options)) return false; if (!updateAndroidManifest(options)) @@ -1466,7 +1522,7 @@ bool readAndroidDependencyXml(Options *options, QSet<QString> *usedDependencies, QSet<QString> *remainingDependencies) { - QString androidDependencyName = absoluteFilePath(options, QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName)); + QString androidDependencyName = absoluteFilePath(options, QStringLiteral("/lib/%1-android-dependencies.xml").arg(moduleName)); QFile androidDependencyFile(androidDependencyName); if (androidDependencyFile.exists()) { @@ -1505,7 +1561,7 @@ bool readAndroidDependencyXml(Options *options, if (options->verbose) fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath)); - options->qtDependencies.append(fileName); + options->qtDependencies[options->currentArchitecture].append(fileName); } } else if (reader.name() == QLatin1String("jar")) { int bundling = reader.attributes().value(QLatin1String("bundling")).toInt(); @@ -1513,7 +1569,7 @@ bool readAndroidDependencyXml(Options *options, if (bundling == (options->deploymentMechanism == Options::Bundled)) { QtDependency dependency(fileName, absoluteFilePath(options, fileName)); if (!usedDependencies->contains(dependency.absolutePath)) { - options->qtDependencies.append(dependency); + options->qtDependencies[options->currentArchitecture].append(dependency); usedDependencies->insert(dependency.absolutePath); } } @@ -1529,15 +1585,15 @@ bool readAndroidDependencyXml(Options *options, if (reader.attributes().hasAttribute(QLatin1String("replaces"))) { QString replaces = reader.attributes().value(QLatin1String("replaces")).toString(); for (int i=0; i<options->localLibs.size(); ++i) { - if (options->localLibs.at(i) == replaces) { - options->localLibs[i] = fileName; + if (options->localLibs[options->currentArchitecture].at(i) == replaces) { + options->localLibs[options->currentArchitecture][i] = fileName; break; } } } else if (!fileName.isEmpty()) { - options->localLibs.append(fileName); + options->localLibs[options->currentArchitecture].append(fileName); } - if (fileName.endsWith(QLatin1String(".so"))) { + if (fileName.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName)) { remainingDependencies->insert(fileName); } } else if (reader.name() == QLatin1String("permission")) { @@ -1557,26 +1613,19 @@ bool readAndroidDependencyXml(Options *options, } else if (options->verbose) { fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName)); } + options->permissions.removeDuplicates(); + options->features.removeDuplicates(); return true; } QStringList getQtLibsFromElf(const Options &options, const QString &fileName) { - QString readElf = options.ndkPath - + QLatin1String("/toolchains/") - + options.toolchainPrefix; - - if (!options.useLLVM) - readElf += QLatin1Char('-') + options.toolchainVersion; - - readElf += QLatin1String("/prebuilt/") - + options.ndkHost - + QLatin1String("/bin/") - + options.toolPrefix + - (options.useLLVM ? QLatin1String("-readobj") : QLatin1String("-readelf")); + QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath, + options.toolchainPrefix, + options.ndkHost); #if defined(Q_OS_WIN32) - readElf += QLatin1String(".exe"); + readElf += QStringLiteral(".exe"); #endif if (!QFile::exists(readElf)) { @@ -1584,14 +1633,11 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) return QStringList(); } - if (options.useLLVM) - readElf = QString::fromLatin1("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName)); - else - readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf), shellQuote(fileName)); + readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName)); FILE *readElfCommand = openProcess(readElf); if (!readElfCommand) { - fprintf(stderr, "Cannot execute command %s", qPrintable(readElf)); + fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); return QStringList(); } @@ -1599,23 +1645,26 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) bool readLibs = false; char buffer[512]; - while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) { + while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); QString library; - if (options.useLLVM) { - line = line.trimmed(); - if (!readLibs) { - readLibs = line.startsWith("NeededLibraries"); - continue; + line = line.trimmed(); + if (!readLibs) { + if (line.startsWith("Arch: ")) { + auto it = elfArchitecures.find(line.mid(6)); + if (it == elfArchitecures.constEnd() || *it != options.currentArchitecture.toLatin1()) { + if (options.verbose) + fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName)); + return {}; + } } - if (!line.startsWith("lib")) - continue; - library = QString::fromLatin1(line); - } else if (line.contains("(NEEDED)") && line.contains("Shared library:")) { - const int pos = line.lastIndexOf('[') + 1; - library = QString::fromLatin1(line.mid(pos, line.length() - pos - 2)); + readLibs = line.startsWith("NeededLibraries"); + continue; } - QString libraryName = QLatin1String("lib/") + library; + if (!line.startsWith("lib")) + continue; + library = QString::fromLatin1(line); + QString libraryName = QStringLiteral("lib/") + library; if (QFile::exists(absoluteFilePath(&options, libraryName))) ret += libraryName; } @@ -1653,7 +1702,7 @@ bool readDependenciesFromElf(Options *options, return false; } - options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath)); + options->qtDependencies[options->currentArchitecture].append(QtDependency(dependency, absoluteDependencyPath)); if (options->verbose) fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency)); dependenciesToCheck.append(dependency); @@ -1797,10 +1846,10 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath)); // Put all imports in default import path in assets - fileName.relativePath.prepend(QLatin1String("qml/")); - options->qtDependencies.append(fileName); + fileName.relativePath.prepend(QStringLiteral("qml/")); + options->qtDependencies[options->currentArchitecture].append(fileName); - if (fileName.absolutePath.endsWith(QLatin1String(".so"))) { + if (fileName.absolutePath.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName.absolutePath)) { QSet<QString> remainingDependencies; if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies)) return false; @@ -1819,7 +1868,7 @@ bool readDependencies(Options *options) fprintf(stdout, "Detecting dependencies of application.\n"); // Override set in .pro file - if (!options->qtDependencies.isEmpty()) { + if (!options->qtDependencies[options->currentArchitecture].isEmpty()) { if (options->verbose) fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n"); return true; @@ -1829,11 +1878,7 @@ bool readDependencies(Options *options) QSet<QString> remainingDependencies; // Add dependencies of application binary first - if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies)) - return false; - - // Jam in the dependencies of the platform plugin, since the application will crash without it - if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies)) + if (!readDependenciesFromElf(options, QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, options->currentArchitecture, options->applicationBinary), &usedDependencies, &remainingDependencies)) return false; while (!remainingDependencies.isEmpty()) { @@ -1853,14 +1898,14 @@ bool readDependencies(Options *options) } } - QStringList::iterator it = options->localLibs.begin(); - while (it != options->localLibs.end()) { + QStringList::iterator it = options->localLibs[options->currentArchitecture].begin(); + while (it != options->localLibs[options->currentArchitecture].end()) { QStringList unmetDependencies; if (!goodToCopy(options, absoluteFilePath(options, *it), &unmetDependencies)) { fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", qPrintable(*it), qPrintable(unmetDependencies.join(QLatin1Char(',')))); - it = options->localLibs.erase(it); + it = options->localLibs[options->currentArchitecture].erase(it); } else { ++it; } @@ -1872,94 +1917,33 @@ bool readDependencies(Options *options) return true; } -bool stripFile(const Options &options, const QString &fileName) -{ - QString strip = options.ndkPath - + QLatin1String("/toolchains/") - + options.toolchainPrefix; - - if (!options.useLLVM) - strip += QLatin1Char('-') + options.toolchainVersion; - - strip += QLatin1String("/prebuilt/") - + options.ndkHost - + QLatin1String("/bin/") - + options.toolPrefix - + QLatin1String("-strip"); -#if defined(Q_OS_WIN32) - strip += QLatin1String(".exe"); -#endif - - if (!QFile::exists(strip)) { - fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip)); - return false; - } - - if (options.useLLVM) - strip = QString::fromLatin1("%1 -strip-all %2").arg(shellQuote(strip), shellQuote(fileName)); - else - strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip), shellQuote(fileName)); - - FILE *stripCommand = openProcess(strip); - if (stripCommand == 0) { - fprintf(stderr, "Cannot execute command %s", qPrintable(strip)); - return false; - } - - pclose(stripCommand); - - return true; -} - -bool stripLibraries(const Options &options) +bool containsApplicationBinary(Options *options) { - if (!options.stripLibraries) + if (!options->build) return true; - if (options.verbose) - fprintf(stdout, "Stripping libraries to minimize size.\n"); - - - QString libraryPath = options.outputDirectory - + QLatin1String("/libs/") - + options.architecture; - const QStringList libraries = QDir(libraryPath).entryList(QDir::Files); - for (const QString &library : libraries) { - if (library.endsWith(QLatin1String(".so"))) { - if (!stripFile(options, libraryPath + QLatin1Char('/') + library)) - return false; - } - } - - return true; -} - -bool containsApplicationBinary(const Options &options) -{ - if (options.verbose) + if (options->verbose) fprintf(stdout, "Checking if application binary is in package.\n"); - QFileInfo applicationBinary(options.applicationBinary); - QString destinationFileName = options.outputDirectory - + QLatin1String("/libs/") - + options.architecture - + QLatin1Char('/') - + applicationBinary.fileName(); + QFileInfo applicationBinary(options->applicationBinary); + QString applicationFileName = QStringLiteral("lib%1_%2.so").arg(options->applicationBinary, + options->currentArchitecture); - if (!QFile::exists(destinationFileName)) { + QString applicationPath = QStringLiteral("%1/libs/%2/%3").arg(options->outputDirectory, + options->currentArchitecture, + applicationFileName); + if (!QFile::exists(applicationPath)) { #if defined(Q_OS_WIN32) QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently #else QLatin1String makeTool("make"); #endif - fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n", - qPrintable(destinationFileName), + qPrintable(applicationFileName), qPrintable(makeTool), - qPrintable(options.outputDirectory)); + qPrintable(options->outputDirectory)); return false; } - return true; } @@ -1997,10 +1981,13 @@ bool goodToCopy(const Options *options, const QString &file, QStringList *unmetD if (!file.endsWith(QLatin1String(".so"))) return true; + if (!checkArchitecture(*options, file)) + return false; + bool ret = true; const auto libs = getQtLibsFromElf(*options, file); for (const QString &lib : libs) { - if (!options->qtDependencies.contains(QtDependency(lib, absoluteFilePath(options, lib)))) { + if (!options->qtDependencies[options->currentArchitecture].contains(QtDependency(lib, absoluteFilePath(options, lib)))) { ret = false; unmetDependencies->append(lib); } @@ -2027,25 +2014,22 @@ bool copyQtFiles(Options *options) QString libsDirectory = QLatin1String("libs/"); + // Copy other Qt dependencies - QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/'); - QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/"); - for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) { + QString assetsDestinationDirectory = QStringLiteral("assets/--Added-by-androiddeployqt--/"); + for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) { QString sourceFileName = qtDependency.absolutePath; QString destinationFileName; - if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) { + if (qtDependency.relativePath.endsWith(QStringLiteral(".so"))) { QString garbledFileName; - if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) { + if (qtDependency.relativePath.startsWith(QStringLiteral("lib/"))) { garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1); } else { - garbledFileName = QLatin1String("lib") - + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); - + garbledFileName = QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); } - destinationFileName = libDestinationDirectory + garbledFileName; - - } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) { + destinationFileName = libsDirectory + options->currentArchitecture + QLatin1Char('/') + garbledFileName; + } else if (qtDependency.relativePath.startsWith(QStringLiteral("jar/"))) { destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1); } else { destinationFileName = assetsDestinationDirectory + qtDependency.relativePath; @@ -2058,20 +2042,34 @@ bool copyQtFiles(Options *options) QStringList unmetDependencies; if (!goodToCopy(options, sourceFileName, &unmetDependencies)) { - fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", - qPrintable(sourceFileName), - qPrintable(unmetDependencies.join(QLatin1Char(',')))); + if (unmetDependencies.isEmpty()) { + if (options->verbose) { + fprintf(stdout, " -- Skipping %s, architecture mismatch.\n", + qPrintable(sourceFileName)); + } + } else { + if (unmetDependencies.isEmpty()) { + if (options->verbose) { + fprintf(stdout, " -- Skipping %s, architecture mismatch.\n", + qPrintable(sourceFileName)); + } + } else { + fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", + qPrintable(sourceFileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + } + } continue; } if (options->deploymentMechanism == Options::Bundled && !copyFileIfNewer(sourceFileName, options->outputDirectory + QLatin1Char('/') + destinationFileName, - options->verbose)) { + *options)) { return false; } - options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath); + options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath); } return true; @@ -2409,21 +2407,18 @@ bool copyStdCpp(Options *options) if (options->verbose) fprintf(stdout, "Copying STL library\n"); - if (!QFile::exists(options->stdCppPath)) { - fprintf(stderr, "STL library does not exist at %s\n", qPrintable(options->stdCppPath)); - return false; - } - - const QString destinationDirectory = options->outputDirectory - + QLatin1String("/libs/") + options->architecture; - - if (!copyFileIfNewer(options->stdCppPath, destinationDirectory + QLatin1String("/lib") - + options->stdCppName + QLatin1String(".so"), - options->verbose)) { + QString stdCppPath = QStringLiteral("%1/%2/lib%3.so").arg(options->stdCppPath, options->architectures[options->currentArchitecture], options->stdCppName); + if (!QFile::exists(stdCppPath)) { + fprintf(stderr, "STL library does not exist at %s\n", qPrintable(stdCppPath)); + fflush(stdout); + fflush(stderr); return false; } - return true; + const QString destinationFile = QStringLiteral("%1/libs/%2/lib%3.so").arg(options->outputDirectory, + options->currentArchitecture, + options->stdCppName); + return copyFileIfNewer(stdCppPath, destinationFile, *options); } bool jarSignerSignPackage(const Options &options) @@ -2654,55 +2649,6 @@ bool signPackage(const Options &options) return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK)); } -bool copyGdbServer(const Options &options) -{ - if (options.verbose) - fprintf(stdout, "Copying gdbserver into package.\n"); - - QString architectureSubDirectory; - if (options.architecture == QLatin1String("arm64-v8a")) - architectureSubDirectory = QLatin1String("android-arm64"); - else if (options.architecture.startsWith(QLatin1String("arm"))) - architectureSubDirectory = QLatin1String("android-arm"); - else - architectureSubDirectory = QLatin1String("android-") + options.architecture; - - QString gdbServerBinary = options.ndkPath - + QLatin1String("/prebuilt/") - + architectureSubDirectory - + QLatin1String("/gdbserver/gdbserver"); - if (!QFile::exists(gdbServerBinary)) { - fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary)); - return false; - } - - QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture; - - if (!copyFileIfNewer(gdbServerBinary, - gdbServerTarget + QLatin1String("/gdbserver"), - options.verbose) - || !copyFileIfNewer(gdbServerBinary, - gdbServerTarget + QLatin1String("/libgdbserver.so"), - options.verbose)) { - return false; - } - - QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/"); - if (!QDir().mkpath(addedByAndroidDeployQtPath)) { - fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); - return false; - } - QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command")); - if (!f.open(QIODevice::WriteOnly)) { - fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); - return false; - } - f.write("lib/libgdbserver.so --multi +"); - f.close(); - - return true; -} - bool generateAssetsFileList(const Options &options) { if (options.verbose) @@ -2764,8 +2710,6 @@ enum ErrorCode CannotCopyGnuStl = 5, CannotCopyQtFiles = 6, CannotFindApplicationBinary = 7, - CannotCopyGdbServer = 8, - CannotStripLibraries = 9, CannotCopyAndroidExtraLibs = 10, CannotCopyAndroidSources = 11, CannotUpdateAndroidFiles = 12, @@ -2813,25 +2757,7 @@ int main(int argc, char *argv[]) : "No" ); - if (options.auxMode) { - if (!readDependencies(&options)) - return CannotReadDependencies; - if (!copyQtFiles(&options)) - return CannotCopyQtFiles; - if (!copyAndroidExtraResources(options)) - return CannotCopyAndroidExtraResources; - if (!copyAndroidExtraLibs(options)) - return CannotCopyAndroidExtraLibs; - if (!stripLibraries(options)) - return CannotStripLibraries; - if (!updateAndroidFiles(options)) - return CannotUpdateAndroidFiles; - if (options.generateAssetsFileList && !generateAssetsFileList(options)) - return CannotGenerateAssetsFileList; - return 0; - } - - if (options.build) { + if (options.build && !options.auxMode) { cleanAndroidFiles(options); if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed()); @@ -2843,60 +2769,68 @@ int main(int argc, char *argv[]) fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed()); } - if (!readDependencies(&options)) - return CannotReadDependencies; - - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); + for (auto it = options.architectures.constBegin(); it != options.architectures.constEnd(); ++it) { + options.clear(it.key()); - if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) - return CannotCopyGnuStl; + if (!readDependencies(&options)) + return CannotReadDependencies; - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); - if (!copyQtFiles(&options)) - return CannotCopyQtFiles; + if (!copyQtFiles(&options)) + return CannotCopyQtFiles; - if (options.build) { if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed()); - if (!containsApplicationBinary(options)) - return CannotFindApplicationBinary; + if (!copyAndroidExtraLibs(&options)) + return CannotCopyAndroidExtraLibs; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); - bool needToCopyGdbServer = options.gdbServer == Options::True - || (options.gdbServer == Options::Auto && !options.releasePackage); - if (needToCopyGdbServer && !copyGdbServer(options)) - return CannotCopyGdbServer; + if (!copyAndroidExtraResources(&options)) + return CannotCopyAndroidExtraResources; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Copied extra resources\n", options.timer.elapsed()); - if (!copyAndroidExtraLibs(options)) - return CannotCopyAndroidExtraLibs; + if (!options.auxMode) { + if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) + return CannotCopyGnuStl; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + } + + if (!containsApplicationBinary(&options)) + return CannotFindApplicationBinary; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); - if (!copyAndroidExtraResources(options)) - return CannotCopyAndroidExtraResources; + if (options.deploymentMechanism != Options::Ministro) { + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Bundled Qt libs\n", options.timer.elapsed()); + } + } + if (options.auxMode) { + if (!updateAndroidFiles(options)) + return CannotUpdateAndroidFiles; + if (options.generateAssetsFileList && !generateAssetsFileList(options)) + return CannotGenerateAssetsFileList; + return 0; + } + + if (options.build) { if (!copyAndroidSources(options)) return CannotCopyAndroidSources; if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed()); - if (!stripLibraries(options)) - return CannotStripLibraries; - - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed()); - if (!updateAndroidFiles(options)) return CannotUpdateAndroidFiles; |