This commit is contained in:
Hennadii Stepanov 2025-04-29 11:52:27 +02:00 committed by GitHub
commit 9cc58038c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 536 additions and 45 deletions

View file

@ -702,7 +702,11 @@ message(" bench_bitcoin ....................... ${BUILD_BENCH}")
message(" fuzz binary ......................... ${BUILD_FUZZ_BINARY}")
message("")
if(CMAKE_CROSSCOMPILING)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
if(ANDROID)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_ANDROID_ARCH_ABI}")
else()
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
endif()
else()
set(cross_status "FALSE")
endif()

View file

@ -97,6 +97,10 @@ host_os+=$(findstring netbsd,$(full_host_os))
host_os+=$(findstring openbsd,$(full_host_os))
host_os+=$(findstring mingw32,$(full_host_os))
ifeq (android,$(findstring android,$(full_host_os)))
host_os:=android
endif
host_os:=$(strip $(host_os))
ifeq ($(host_os),)
host_os=$(full_host_os)
@ -235,6 +239,10 @@ $(host_prefix)/toolchain.cmake : toolchain.cmake.in $(host_prefix)/.stamp_$(fina
-e 's|@bdb_packages@|$(bdb_packages_)|' \
-e 's|@usdt_packages@|$(usdt_packages_)|' \
-e 's|@multiprocess@|$(MULTIPROCESS)|' \
-e 's|@android_abi@|$(android_abi)|' \
-e 's|@android_ndk@|$(ANDROID_NDK)|' \
-e 's|@android_toolchain_bin_dir@|$(android_toolchain_bin_dir)|' \
-e 's|@android_libcxx_shared_dir@|$(android_libcxx_shared_dir)|' \
$< > $@
touch $@

View file

@ -34,8 +34,11 @@ Common `host-platform-triplet`s for cross compilation are:
- `riscv32-linux-gnu` for Linux RISC-V 32 bit
- `riscv64-linux-gnu` for Linux RISC-V 64 bit
- `s390x-linux-gnu` for Linux S390X
- `armv7a-linux-android` for Android ARM 32 bit
- `aarch64-linux-android` for Android ARM 64 bit
- `x86_64-linux-android` for Android x86 64 bit
The paths are automatically configured and no other options are needed.
The paths are automatically configured and no other options are needed unless targeting [Android](../doc/build-android.md).
### Install the required dependencies: Ubuntu & Debian

View file

@ -207,33 +207,45 @@ ifneq ($($(1)_ldflags),)
$(1)_autoconf += LDFLAGS="$$($(1)_ldflags)"
endif
$(1)_cmake = env CFLAGS="$$($(1)_cppflags) $$($(1)_cflags)" \
CXXFLAGS="$$($(1)_cppflags) $$($(1)_cxxflags)" \
LDFLAGS="$$($(1)_ldflags)"
ifeq ($(host_os),android)
# For Android, we use the toolchain file provided by the Android SDK.
# See: https://developer.android.com/ndk/guides/cmake
$(1)_cmake += cmake \
-DANDROID_ABI=$(android_abi) \
-DANDROID_PLATFORM=android-$(android_cmake_system_version) \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$(ANDROID_NDK)/build/cmake/android.toolchain.cmake
else
$(1)_cmake += CC="$$($(1)_cc)" \
CXX="$$($(1)_cxx)"
$(1)_cmake += cmake \
-DCMAKE_AR=`which $$($(1)_ar)` \
-DCMAKE_NM=`which $$($FILEPATH(1)_nm)` \
-DCMAKE_RANLIB=`which $$($(1)_ranlib)`
endif
$(1)_cmake += -G "Unix Makefiles" \
-DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=$(V) \
$$($(1)_config_opts)
# We hardcode the library install path to "lib" to match the PKG_CONFIG_PATH
# setting in depends/toolchain.cmake.in, which also hardcodes "lib".
# Without this setting, CMake by default would use the OS library
# directory, which might be "lib64" or something else, not "lib", on multiarch systems.
$(1)_cmake=env CC="$$($(1)_cc)" \
CFLAGS="$$($(1)_cppflags) $$($(1)_cflags)" \
CXX="$$($(1)_cxx)" \
CXXFLAGS="$$($(1)_cppflags) $$($(1)_cxxflags)" \
LDFLAGS="$$($(1)_ldflags)" \
cmake -G "Unix Makefiles" \
-DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" \
-DCMAKE_AR=`which $$($(1)_ar)` \
-DCMAKE_NM=`which $$($(1)_nm)` \
-DCMAKE_RANLIB=`which $$($(1)_ranlib)` \
-DCMAKE_INSTALL_LIBDIR=lib/ \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=$(V) \
$$($(1)_config_opts)
$(1)_cmake += -DCMAKE_INSTALL_LIBDIR=lib/
ifeq ($($(1)_type),build)
$(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib"
else
ifneq ($(host),$(build))
ifneq ($(host_os),android)
$(1)_cmake += -DCMAKE_SYSTEM_NAME=$($(host_os)_cmake_system_name)
$(1)_cmake += -DCMAKE_C_COMPILER_TARGET=$(host)
$(1)_cmake += -DCMAKE_CXX_COMPILER_TARGET=$(host)
endif
endif
endif
endef
define int_add_cmds

31
depends/hosts/android.mk Normal file
View file

@ -0,0 +1,31 @@
ANDROID_API_LEVEL ?= 26
android_toolchain_bin_dir := $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(build_os)-$(build_arch)/bin
ifeq ($(HOST),armv7a-linux-android)
android_CXX := $(android_toolchain_bin_dir)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang++
android_CC := $(android_toolchain_bin_dir)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang
android_libcxx_shared_dir := arm-linux-androideabi
else
android_CXX := $(android_toolchain_bin_dir)/$(HOST)$(ANDROID_API_LEVEL)-clang++
android_CC := $(android_toolchain_bin_dir)/$(HOST)$(ANDROID_API_LEVEL)-clang
android_libcxx_shared_dir := $(host_arch)-linux-android
endif
android_CXXFLAGS := -std=$(CXX_STANDARD)
android_CFLAGS := -std=$(C_STANDARD)
android_AR := $(android_toolchain_bin_dir)/llvm-ar
android_RANLIB := $(android_toolchain_bin_dir)/llvm-ranlib
android_cmake_system_name := Android
android_cmake_system_version := $(ANDROID_API_LEVEL)
# https://developer.android.com/ndk/guides/abis
ifeq ($(host_arch),armv7a)
android_abi := armeabi-v7a
else ifeq ($(host_arch),aarch64)
android_abi := arm64-v8a
else ifeq ($(host_arch),x86_64)
android_abi := x86_64
endif

View file

@ -4,6 +4,7 @@ $(package)_download_path=https://github.com/libevent/libevent/releases/download/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb
$(package)_patches=cmake_fixups.patch
$(package)_patches += android_threads_fixup.patch
$(package)_patches += netbsd_fixup.patch
$(package)_build_subdir=build
@ -21,6 +22,7 @@ endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch && \
patch -p1 < $($(package)_patch_dir)/android_threads_fixup.patch && \
patch -p1 < $($(package)_patch_dir)/netbsd_fixup.patch
endef

View file

@ -5,10 +5,12 @@ boost_packages = boost
libevent_packages = libevent
qrencode_linux_packages = qrencode
qrencode_android_packages = qrencode
qrencode_darwin_packages = qrencode
qrencode_mingw32_packages = qrencode
qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
qt_android_packages=qt
qt_darwin_packages=qt
qt_mingw32_packages=qt
ifneq ($(host),$(build))

View file

@ -10,6 +10,8 @@ endif
$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
$(package)_patches_path := $(qt_details_patches_path)
$(package)_patches := dont_hardcode_pwd.patch
$(package)_patches += fix_android_duplicate_symbol.patch
$(package)_patches += fix_android_jni_static.patch
$(package)_patches += qtbase-moc-ignore-gcc-macro.patch
$(package)_patches += qtbase_avoid_native_float16.patch
$(package)_patches += qtbase_avoid_qmain.patch
@ -154,6 +156,16 @@ ifneq ($(LTO),)
$(package)_config_opts_mingw32 += -ltcg
endif
$(package)_config_opts_android = -android-sdk $(ANDROID_SDK)
$(package)_config_opts_android += -android-ndk $(ANDROID_NDK)
$(package)_config_opts_android += -android-ndk-platform android-$(ANDROID_API_LEVEL)
$(package)_config_opts_android += -android-abis $(android_abi)
$(package)_config_opts_android += -egl
$(package)_config_opts_android += -no-dbus
$(package)_config_opts_android += -no-fontconfig
$(package)_config_opts_android += -opengl es2
$(package)_config_opts_android += -qt-freetype
# CMake build options.
$(package)_config_env := CC="$$($(package)_cc)"
$(package)_config_env += CXX="$$($(package)_cxx)"
@ -257,6 +269,8 @@ endif
define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_android_duplicate_symbol.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase_avoid_native_float16.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase_avoid_qmain.patch && \
@ -281,6 +295,9 @@ endef
define $(package)_stage_cmds
cmake --install . --prefix $($(package)_staging_prefix_dir)
endef
ifeq ($(host_os),android)
$(package)_stage_cmds += && cp -r $($(package)_extract_dir)/qtbase/src/android/jar/src $($(package)_staging_prefix_dir)/src/android/java
endif
define $(package)_postprocess_cmds
rm -rf doc/

View file

@ -0,0 +1,21 @@
cmake: Fix Android build.
Android/Bionic C library needs no special flags to have threading support.
Found when trying to build with vcpkg.
See https://github.com/libevent/libevent/commit/8f47d8de281b877450474734594fdc0a60ee35d1.
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -858,6 +858,11 @@ endif()
if (NOT EVENT__DISABLE_THREAD_SUPPORT)
if (WIN32)
list(APPEND SRC_CORE evthread_win32.c)
+ elseif(ANDROID)
+ # pthreads is built in to bionic
+ set(EVENT__HAVE_PTHREADS 1)
+ CHECK_TYPE_SIZE(pthread_t EVENT__SIZEOF_PTHREAD_T)
+ list(APPEND SYMBOLS_TO_CHECK pthread_mutexattr_setprotocol)
else()
find_package(Threads REQUIRED)
if (NOT CMAKE_USE_PTHREADS_INIT)

View file

@ -0,0 +1,157 @@
Fix "duplicate symbol: JNI_OnLoad" linker error
Qt does not officially support static linking on Android. See:
- https://bugreports.qt.io/browse/QTBUG-36097
- https://bugreports.qt.io/browse/QTBUG-102326
Reverting upstream commit 175e3ac8fabc864ffcc23c7769eaf7f220bddf59
avoids the linker error.
Note: the revert is not clean and required minor adjustments.
--- a/qtbase/src/corelib/CMakeLists.txt
+++ b/qtbase/src/corelib/CMakeLists.txt
@@ -1016,6 +1016,7 @@ qt_internal_extend_target(Core CONDITION ANDROID
kernel/qjnienvironment.cpp kernel/qjnienvironment.h
kernel/qjniobject.cpp kernel/qjniobject.h
kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h
+ kernel/qjnionload.cpp
platform/android/qandroidextras_p.h platform/android/qandroidextras.cpp
platform/android/qandroidnativeinterface.cpp
NO_UNITY_BUILD_SOURCES
--- a/qtbase/src/corelib/kernel/qjnihelpers.cpp
+++ b/qtbase/src/corelib/kernel/qjnihelpers.cpp
@@ -12,7 +12,6 @@
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qlocking_p.h>
-#include <android/log.h>
#include <deque>
#include <memory>
@@ -349,38 +348,3 @@ void QtAndroidPrivate::releaseAndroidDeadlockProtector()
}
QT_END_NAMESPACE
-
-JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
-{
- Q_UNUSED(reserved);
-
- static const char logTag[] = "QtCore";
- static bool initialized = false;
- if (initialized)
- return JNI_VERSION_1_6;
- initialized = true;
-
- typedef union {
- JNIEnv *nenv;
- void *venv;
- } _JNIEnv;
-
- __android_log_print(ANDROID_LOG_INFO, logTag, "Start");
-
- _JNIEnv uenv;
- uenv.venv = nullptr;
-
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
- return JNI_ERR;
- }
-
- JNIEnv *env = uenv.nenv;
- const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, env));
- if (ret != 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "initJNI failed");
- return ret;
- }
-
- return JNI_VERSION_1_6;
-}
--- /dev/null
+++ b/qtbase/src/corelib/kernel/qjnionload.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module 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$
+**
+****************************************************************************/
+
+#include "qjnihelpers_p.h"
+
+#include <jni.h>
+#include <android/log.h>
+
+static const char logTag[] = "QtCore";
+
+Q_CORE_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ Q_UNUSED(reserved);
+
+ static bool initialized = false;
+ if (initialized)
+ return JNI_VERSION_1_6;
+ initialized = true;
+
+ typedef union {
+ JNIEnv *nenv;
+ void *venv;
+ } _JNIEnv;
+
+ __android_log_print(ANDROID_LOG_INFO, logTag, "Start");
+
+ _JNIEnv uenv;
+ uenv.venv = nullptr;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
+ return JNI_ERR;
+ }
+
+ JNIEnv *env = uenv.nenv;
+ const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, env));
+ if (ret != 0) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "initJNI failed");
+ return ret;
+ }
+
+ return JNI_VERSION_1_6;
+}

View file

@ -0,0 +1,16 @@
--- a/qtbase/src/plugins/platforms/android/androidjnimain.cpp
+++ b/qtbase/src/plugins/platforms/android/androidjnimain.cpp
@@ -895,6 +895,13 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
+
+ const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, QJniEnvironment::getJniEnv()));
+ if (ret != 0) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "initJNI failed");
+ return ret;
+ }
+
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
// attach qt main thread data to this thread

View file

@ -2,21 +2,54 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.
# This file is expected to be highly volatile and may still change substantially.
if("@host_system_name@" STREQUAL "Android")
# For Android, we use the toolchain file provided by the Android SDK.
# See: https://developer.android.com/ndk/guides/cmake
set(ANDROID_ABI @android_abi@)
set(ANDROID_PLATFORM android-@host_system_version@)
include(@android_ndk@/build/cmake/android.toolchain.cmake)
# Qt's Java sources for Android Application Package (APK).
cmake_path(SET ANDROID_APK_SRC "${CMAKE_CURRENT_LIST_DIR}/src/android/java")
# The libc++_shared.so shared library, provided by the Android SDK,
# is required to build an Android Application Package (APK).
cmake_path(SET ANDROID_SHARED_CXX_LIB NORMALIZE "@android_toolchain_bin_dir@/../sysroot/usr/lib/@android_libcxx_shared_dir@/libc++_shared.so")
# Qt recommends using the same Gradle version that it comes with.
# Therefore, we use the Gradle wrapper provided by Qt to build
# an Android Application Package (APK).
# See:
# - https://doc.qt.io/qt-6/deployment-android.html
# - https://doc.qt.io/qt-6/qtcore-attribution-android-gradle-wrapper.html
cmake_path(SET GRADLEW_EXECUTABLE "${CMAKE_CURRENT_LIST_DIR}/src/3rdparty/gradle/gradlew")
else()
# If CMAKE_SYSTEM_NAME is set within a toolchain file, CMake will also
# set CMAKE_CROSSCOMPILING to TRUE, even if CMAKE_SYSTEM_NAME matches
# CMAKE_HOST_SYSTEM_NAME. To avoid potential misconfiguration of CMake,
# it is best not to touch CMAKE_SYSTEM_NAME unless cross-compiling is
# intended.
if(@depends_crosscompiling@)
set(CMAKE_SYSTEM_NAME @host_system_name@)
set(CMAKE_SYSTEM_VERSION @host_system_version@)
set(CMAKE_SYSTEM_PROCESSOR @host_arch@)
# If CMAKE_SYSTEM_NAME is set within a toolchain file, CMake will also
# set CMAKE_CROSSCOMPILING to TRUE, even if CMAKE_SYSTEM_NAME matches
# CMAKE_HOST_SYSTEM_NAME. To avoid potential misconfiguration of CMake,
# it is best not to touch CMAKE_SYSTEM_NAME unless cross-compiling is
# intended.
if(@depends_crosscompiling@)
set(CMAKE_SYSTEM_NAME @host_system_name@)
set(CMAKE_SYSTEM_VERSION @host_system_version@)
set(CMAKE_SYSTEM_PROCESSOR @host_arch@)
set(CMAKE_C_COMPILER_TARGET @host@)
set(CMAKE_CXX_COMPILER_TARGET @host@)
set(CMAKE_OBJCXX_COMPILER_TARGET @host@)
endif()
set(CMAKE_C_COMPILER_TARGET @host@)
set(CMAKE_CXX_COMPILER_TARGET @host@)
set(CMAKE_OBJCXX_COMPILER_TARGET @host@)
if(NOT DEFINED CMAKE_C_COMPILER)
set(CMAKE_C_COMPILER @CC@)
endif()
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_CXX_COMPILER @CXX@)
set(CMAKE_OBJCXX_COMPILER ${CMAKE_CXX_COMPILER})
endif()
set(CMAKE_AR "@AR@")
set(CMAKE_RANLIB "@RANLIB@")
set(CMAKE_STRIP "@STRIP@")
set(CMAKE_OBJCOPY "@OBJCOPY@")
set(CMAKE_OBJDUMP "@OBJDUMP@")
endif()
if(NOT DEFINED CMAKE_C_FLAGS_INIT)
@ -29,10 +62,6 @@ if(NOT DEFINED CMAKE_C_FLAGS_DEBUG_INIT)
set(CMAKE_C_FLAGS_DEBUG_INIT "@CFLAGS_DEBUG@")
endif()
if(NOT DEFINED CMAKE_C_COMPILER)
set(CMAKE_C_COMPILER @CC@)
endif()
if(NOT DEFINED CMAKE_CXX_FLAGS_INIT)
set(CMAKE_CXX_FLAGS_INIT "@CXXFLAGS@")
set(CMAKE_OBJCXX_FLAGS_INIT "@CXXFLAGS@")
@ -46,11 +75,6 @@ if(NOT DEFINED CMAKE_CXX_FLAGS_DEBUG_INIT)
set(CMAKE_OBJCXX_FLAGS_DEBUG_INIT "@CXXFLAGS_DEBUG@")
endif()
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_CXX_COMPILER @CXX@)
set(CMAKE_OBJCXX_COMPILER ${CMAKE_CXX_COMPILER})
endif()
# The DEPENDS_COMPILE_DEFINITIONS* variables are to be treated as lists.
set(DEPENDS_COMPILE_DEFINITIONS @CPPFLAGS@)
set(DEPENDS_COMPILE_DEFINITIONS_RELWITHDEBINFO @CPPFLAGS_RELEASE@)
@ -75,12 +99,6 @@ if(NOT DEFINED CMAKE_SHARED_LINKER_FLAGS_DEBUG_INIT)
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG_INIT "@LDFLAGS_DEBUG@")
endif()
set(CMAKE_AR "@AR@")
set(CMAKE_RANLIB "@RANLIB@")
set(CMAKE_STRIP "@STRIP@")
set(CMAKE_OBJCOPY "@OBJCOPY@")
set(CMAKE_OBJDUMP "@OBJDUMP@")
# Using our own built dependencies should not be
# affected by a potentially random environment.
set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH OFF)

View file

@ -45,6 +45,7 @@ The following are developer notes on how to build Bitcoin Core on your native pl
- [FreeBSD Build Notes](build-freebsd.md)
- [OpenBSD Build Notes](build-openbsd.md)
- [NetBSD Build Notes](build-netbsd.md)
- [Android Build Notes](build-android.md)
Development
---------------------

44
doc/build-android.md Normal file
View file

@ -0,0 +1,44 @@
# Android Build Guide
This guide describes how to build and package the `bitcoin-qt` GUI for Android on Linux and macOS.
## Dependencies
Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level).
Qt 6.7.3 used in depends supports Android NDK version is [r26b (26.1.10909125)](https://github.com/android/ndk/wiki/Changelog-r26).
In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) needs to be set.
Qt 6.7.3 used in depends supports API levels from 26 to 34.
When building [depends](../depends/README.md), additional variables `ANDROID_SDK` and `ANDROID_NDK` need to be set.
This is an example command for a default build with no disabled dependencies:
gmake HOST=aarch64-linux-android ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk/26.1.10909125 ANDROID_API_LEVEL=34
## Building and packaging
After the depends are built configure, build and create an Android Application Package (APK) as follows (based on the example above):
```bash
cmake -B build --toolchain depends/aarch64-linux-android/toolchain.cmake
cmake --build build --target apk_package # Use "-j N" for N parallel jobs.
```
The APKs will be available in the following directory:
```bash
$ tree build/src/qt/android/build/outputs/apk
build/src/qt/android/build/outputs/apk
├── debug
│ ├── android-debug.apk
│ └── output-metadata.json
└── release
├── android-release-unsigned.apk
└── output-metadata.json
3 directories, 4 files
```

View file

@ -15,13 +15,18 @@ get_target_property(qt_lib_type Qt6::Core TYPE)
function(import_plugins target)
if(qt_lib_type STREQUAL "STATIC_LIBRARY")
set(plugins Qt6::QMinimalIntegrationPlugin)
set(plugins "")
if(TARGET Qt6::QMinimalIntegrationPlugin)
list(APPEND plugins Qt6::QMinimalIntegrationPlugin)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND plugins Qt6::QXcbIntegrationPlugin)
elseif(WIN32)
list(APPEND plugins Qt6::QWindowsIntegrationPlugin Qt6::QModernWindowsStylePlugin)
elseif(APPLE)
list(APPEND plugins Qt6::QCocoaIntegrationPlugin Qt6::QMacStylePlugin)
elseif(ANDROID)
list(APPEND plugins Qt6::QAndroidIntegrationPlugin Qt6::QAndroidStylePlugin)
endif()
qt6_import_plugins(${target}
INCLUDE ${plugins}
@ -357,3 +362,7 @@ else()
VERBATIM
)
endif()
if(ANDROID)
add_subdirectory(android)
endif()

View file

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="Bitcoin Core" android:icon="@drawable/bitcoin">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:name="org.bitcoincore.qt.BitcoinQtActivity"
android:screenOrientation="unspecified"
android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.arguments" android:value="-testnet"/>
<meta-data android:name="android.app.lib_name" android:value="bitcoin-qt"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
<meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/>
<meta-data android:name="android.app.background_running" android:value="true"/>
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="true"/>
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
<meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,19 @@
# Copyright (c) 2025 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
PATTERN "CMakeLists.txt" EXCLUDE
)
file(COPY ${ANDROID_APK_SRC}/src/org DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src)
file(COPY ${ANDROID_SHARED_CXX_LIB} DESTINATION libs/${CMAKE_ANDROID_ARCH_ABI})
cmake_path(RELATIVE_PATH GRADLEW_EXECUTABLE BASE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_custom_target(apk_package
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:bitcoin-qt> libs/${CMAKE_ANDROID_ARCH_ABI}/libbitcoin-qt_${CMAKE_ANDROID_ARCH_ABI}.so
COMMAND ${GRADLEW_EXECUTABLE} build
VERBATIM
)

View file

@ -0,0 +1,51 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
}
}
repositories {
google()
mavenCentral()
}
apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
android {
compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion androidBuildToolsVersion
namespace 'org.bitcoincore.qt'
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qtAndroidDir + '/res', 'res']
resources.srcDirs = ['src']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
lintOptions {
abortOnError false
}
defaultConfig {
minSdkVersion 26
targetSdk 33
}
}

View file

@ -0,0 +1,4 @@
androidBuildToolsVersion=33.0.3
androidCompileSdkVersion=33
qtAndroidDir=new File(".").absolutePath
org.gradle.jvmargs=-Xmx4608M

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="load_local_libs">
<item>
arm64-v8a;libbitcoin-qt_arm64-v8a.so
</item>
<item>
armeabi-v7a;libbitcoin-qt_armeabi-v7a.so
</item>
<item>
x86_64;libbitcoin-qt_x86_64.so
</item>
</array>
</resources>

View file

@ -0,0 +1,23 @@
package org.bitcoincore.qt;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
import org.qtproject.qt.android.bindings.QtActivity;
import java.io.File;
public class BitcoinQtActivity extends QtActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
final File bitcoinDir = new File(getFilesDir().getAbsolutePath() + "/.bitcoin");
if (!bitcoinDir.exists()) {
bitcoinDir.mkdir();
}
super.onCreate(savedInstanceState);
}
}