diff --git a/pkg/android/build.bash b/pkg/android/build.bash new file mode 100755 index 0000000000..2a00106323 --- /dev/null +++ b/pkg/android/build.bash @@ -0,0 +1,242 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT +# Performs local Android builds. Only tested to work on Linux. + +carp() { + echo "$@" 1>&2 +} + +croak() { + carp "$@" + exit 1 +} + +croak_with_usage() { + carp + carp "Usage:" + carp " $0 setup" + carp " to set up the Android SDK and dependencies" + carp " $0 configure" + carp " to configure the cmake build of Drawpile" + carp + carp "The following environment variables can be set:" + carp " BUILD_TYPE (release, debug) [$BUILD_TYPE]" + carp " QT_VERSION [$QT_VERSION]" + carp " ANDROID_ABI (armeabi-v7a, arm64-v8a, x86, x86_64) [$ANDROID_ABI]" + carp " ANDROID_BUILD_TOOLS_VERSION [$ANDROID_BUILD_TOOLS_VERSION]" + carp " ANDROID_NDK_VERSION [$ANDROID_NDK_VERSION]" + carp " ANDROID_PLATFORM_VERSION [$ANDROID_PLATFORM_VERSION]" + carp " ANDROID_SDK_DIR [$ANDROID_SDK_DIR]" + carp + exit 2 +} + +install_sdk() { + local sdkmanager + sdkmanager="$ANDROID_SDK_DIR/cmdline-tools/latest/bin/sdkmanager" + if [[ ! -x "$sdkmanager" ]]; then + croak "sdkmanager is not an executable file '$sdkmanager'" + fi + set -xe + "$sdkmanager" --install \ + "build-tools;$ANDROID_BUILD_TOOLS_VERSION" \ + "ndk;$ANDROID_NDK_VERSION" \ + 'platform-tools' \ + "platforms;$ANDROID_PLATFORM" + set +xe +} + +check_sdk() { + local error expected_java_version + error=0 + + if [[ ! -d $ANDROID_SDK_DIR ]]; then + carp "ANDROID_SDK_DIR is not a directory: '$ANDROID_SDK_DIR'" + error=1 + fi + + if [[ ! -d $ANDROID_NDK_DIR ]]; then + carp "ANDROID_NDK_DIR is not a directory: '$ANDROID_NDK_DIR'" + error=1 + fi + + if [[ ! -f $ANDROID_TOOLCHAIN_FILE ]]; then + carp "ANDROID_TOOLCHAIN_FILE is not a file: '$ANDROID_TOOLCHAIN_FILE'" + error=1 + fi + + case $ANDROID_PLATFORM_VERSION in + '34') + expected_java_version='17' + ;; + *) + carp "Unknown ANDROID_PLATFORM_VERSION '$ANDROID_PLATFORM_VERSION'" + ;; + esac + + if [[ -n $expected_java_version ]]; then + java_version="$(java -version 2>&1 | perl -0777 -ne '/version\s+"([0-9]+)\./ && print $1')" + if [[ "$java_version" != "$expected_java_version" ]]; then + carp "Expected Java version '$expected_java_version' for Android $ANDROID_PLATFORM_VERSION, but got '$java_version'" + error=1 + fi + fi + + if [[ $error -ne 0 ]]; then + exit 1 + fi +} + +run_build_script() { + check_sdk + set -xe + mkdir -p "$build_source_dir" + pushd "$build_source_dir" + cmake \ + -DBUILD_TYPE="$cmake_build_type" \ + -DCMAKE_PREFIX_PATH="$build_prefix_dir" \ + -DCMAKE_INSTALL_PREFIX="$build_prefix_dir" \ + -DANDROID_SDK_ROOT="$ANDROID_SDK_DIR" \ + -DANDROID_NDK_ROOT="$ANDROID_NDK_DIR" \ + -DANDROID_ABI="$ANDROID_ABI" \ + -DANDROID_PLATFORM="$ANDROID_PLATFORM" \ + -DTARGET_ARCH="$TARGET_ARCH" \ + -DKEEP_SOURCE_DIRS=ON \ + -DKEEP_BINARY_DIRS=ON \ + "$@" + popd + set +xe +} + +build_qt() { + run_build_script \ + -DQT_VERSION="$QT_VERSION" \ + -P "$SRC_DIR/.github/scripts/build-qt.cmake" +} + +build_ffmpeg() { + run_build_script \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_TOOLCHAIN_FILE" \ + -P "$SRC_DIR/.github/scripts/build-ffmpeg.cmake" +} + +build_other() { + run_build_script \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_TOOLCHAIN_FILE" \ + -P "$SRC_DIR/.github/scripts/build-other.cmake" +} + +setup() { + install_sdk + build_qt + build_ffmpeg + build_other + echo + echo "Setup for Android complete." + echo + echo "To configure and build Drawpile now, run:" + echo " $0 configure" + echo " cmake --build $build_dir" + echo +} + +configure() { + check_sdk + set -xe + cmake \ + -DCMAKE_BUILD_TYPE="$cmake_build_type" \ + -DCMAKE_PREFIX_PATH="$build_prefix_dir" \ + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION="$cmake_interprocedural_optimization" \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_TOOLCHAIN_FILE" \ + -DANDROID_ABI="$ANDROID_ABI" \ + -DANDROID_PLATFORM="$ANDROID_PLATFORM" \ + -DANDROID_SDK_BUILD_TOOLS_REVISION="$ANDROID_BUILD_TOOLS_VERSION" \ + -DANDROID_TARGET_SDK_VERSION="$ANDROID_PLATFORM_VERSION" \ + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ + -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ + -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=BOTH \ + -DBUILTINSERVER=OFF \ + -DCLANG_TIDY=OFF \ + -DSERVER=OFF \ + -DTESTS=OFF \ + -DTOOLS=OFF \ + -G Ninja \ + -S "$SRC_DIR" \ + -B "$build_dir" + set +xe +} + +SCRIPT_DIR="$(readlink -f "$(dirname "$0")")" +if [[ -z "$SCRIPT_DIR" ]]; then + croak "Could not figure out script directory of '$0'" +fi + +: "${BUILD_TYPE:=release}" +: "${QT_VERSION:=5.15.14}" +: "${ANDROID_ABI:=arm64-v8a}" +: "${ANDROID_BUILD_TOOLS_VERSION:=34.0.0-rc3}" +: "${ANDROID_NDK_VERSION:=27.0.12077973}" +: "${ANDROID_PLATFORM_VERSION:=34}" +: "${ANDROID_SDK_DIR=$HOME/Android/Sdk}" + +case $ANDROID_ABI in + 'armeabi-v7a') + TARGET_ARCH='arm32' + ;; + 'arm64-v8a') + TARGET_ARCH='arm64' + ;; + 'x86') + TARGET_ARCH='x86' + ;; + 'x86_64') + TARGET_ARCH='x86_64' + ;; + *) + croak "Unknown ANDROID_ABI '$ANDROID_ABI'" + ;; +esac + +case $BUILD_TYPE in + 'debug') + cmake_build_type=Debug + cmake_interprocedural_optimization=OFF + ;; + 'release') + cmake_build_type=Release + cmake_interprocedural_optimization=ON + ;; + *) + croak "Unknown BUILD_TYPE '$BUILD_TYPE'" + ;; +esac + +build_dir="buildandroid-$ANDROID_ABI-$BUILD_TYPE" +build_source_dir="$SCRIPT_DIR/build$ANDROID_ABI/$BUILD_TYPE/source" +build_prefix_dir="$SCRIPT_DIR/build$ANDROID_ABI/$BUILD_TYPE/prefix" + +SRC_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")" +if [[ -z $SRC_DIR ]]; then + croak "Couldn't figure out source directory based on '$SCRIPT_DIR'" +fi + +ANDROID_NDK_DIR="$ANDROID_SDK_DIR/ndk/$ANDROID_NDK_VERSION" +ANDROID_TOOLCHAIN_FILE="$ANDROID_NDK_DIR/build/cmake/android.toolchain.cmake" +ANDROID_PLATFORM="android-$ANDROID_PLATFORM_VERSION" + +if [[ $# -ne 1 ]]; then + croak_with_usage +fi + +case $1 in + 'setup') + setup + ;; + 'configure') + configure + ;; + *) + croak_with_usage + ;; +esac