From a4bb4eef730718a8c464d8c72d763fe75ad54725 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Mon, 27 Mar 2023 12:03:42 +0200
Subject: [PATCH] cmake: create Android jars + apks for tests
---
.github/workflows/android.yml | 17 +-
CMakeLists.txt | 69 ++++-
cmake/android/FindSdlAndroid.cmake | 103 +++++++
cmake/android/FindSdlAndroidBuildTools.cmake | 115 ++++++++
cmake/android/FindSdlAndroidPlatform.cmake | 123 ++++++++
cmake/android/SdlAndroidFunctions.cmake | 276 ++++++++++++++++++
cmake/android/SdlAndroidScript.cmake | 74 +++++
docs/README-android.md | 76 +++++
test/CMakeLists.txt | 135 +++++++++
test/android/cmake/AndroidManifest.xml.cmake | 70 +++++
.../cmake/SDLEntryTestActivity.java.cmake | 121 ++++++++
test/android/cmake/SDLTestActivity.java.cmake | 33 +++
.../cmake/res/values/strings.xml.cmake | 5 +
.../android/cmake/res/xml/shortcuts.xml.cmake | 24 ++
.../res/drawable/sdl-test_foreground.xml | 102 +++++++
test/android/res/layout/arguments_layout.xml | 26 ++
.../res/mipmap-anydpi-v26/sdl-test.xml | 5 +
.../res/mipmap-anydpi-v26/sdl-test_round.xml | 5 +
test/android/res/mipmap-hdpi/sdl-test.png | Bin 0 -> 3041 bytes
.../res/mipmap-hdpi/sdl-test_round.png | Bin 0 -> 5292 bytes
test/android/res/mipmap-mdpi/sdl-test.png | Bin 0 -> 1881 bytes
.../res/mipmap-mdpi/sdl-test_round.png | Bin 0 -> 3150 bytes
test/android/res/mipmap-xhdpi/sdl-test.png | Bin 0 -> 4426 bytes
.../res/mipmap-xhdpi/sdl-test_round.png | Bin 0 -> 7789 bytes
test/android/res/mipmap-xxhdpi/sdl-test.png | Bin 0 -> 7389 bytes
.../res/mipmap-xxhdpi/sdl-test_round.png | Bin 0 -> 13232 bytes
test/android/res/mipmap-xxxhdpi/sdl-test.png | Bin 0 -> 11218 bytes
.../res/mipmap-xxxhdpi/sdl-test_round.png | Bin 0 -> 19626 bytes
test/android/res/values/arg_strings.xml | 7 +
.../res/values/sdl-test_background.xml | 4 +
30 files changed, 1387 insertions(+), 3 deletions(-)
create mode 100644 cmake/android/FindSdlAndroid.cmake
create mode 100644 cmake/android/FindSdlAndroidBuildTools.cmake
create mode 100644 cmake/android/FindSdlAndroidPlatform.cmake
create mode 100644 cmake/android/SdlAndroidFunctions.cmake
create mode 100644 cmake/android/SdlAndroidScript.cmake
create mode 100644 test/android/cmake/AndroidManifest.xml.cmake
create mode 100644 test/android/cmake/SDLEntryTestActivity.java.cmake
create mode 100644 test/android/cmake/SDLTestActivity.java.cmake
create mode 100644 test/android/cmake/res/values/strings.xml.cmake
create mode 100644 test/android/cmake/res/xml/shortcuts.xml.cmake
create mode 100644 test/android/res/drawable/sdl-test_foreground.xml
create mode 100644 test/android/res/layout/arguments_layout.xml
create mode 100644 test/android/res/mipmap-anydpi-v26/sdl-test.xml
create mode 100644 test/android/res/mipmap-anydpi-v26/sdl-test_round.xml
create mode 100644 test/android/res/mipmap-hdpi/sdl-test.png
create mode 100644 test/android/res/mipmap-hdpi/sdl-test_round.png
create mode 100644 test/android/res/mipmap-mdpi/sdl-test.png
create mode 100644 test/android/res/mipmap-mdpi/sdl-test_round.png
create mode 100644 test/android/res/mipmap-xhdpi/sdl-test.png
create mode 100644 test/android/res/mipmap-xhdpi/sdl-test_round.png
create mode 100644 test/android/res/mipmap-xxhdpi/sdl-test.png
create mode 100644 test/android/res/mipmap-xxhdpi/sdl-test_round.png
create mode 100644 test/android/res/mipmap-xxxhdpi/sdl-test.png
create mode 100644 test/android/res/mipmap-xxxhdpi/sdl-test_round.png
create mode 100644 test/android/res/values/arg_strings.xml
create mode 100644 test/android/res/values/sdl-test_background.xml
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index 2805ebc2cc78..20a09fe48312 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -16,7 +16,7 @@ jobs:
matrix:
platform:
- { name: Android.mk }
- - { name: CMake, cmake: 1, android_abi: "arm64-v8a", android_platform: 23, arch: "aarch64", artifact: "SDL-android-arm64" }
+ - { name: CMake, cmake: 1, android_abi: "arm64-v8a", android_platform: 23, arch: "aarch64", artifact: "SDL-android-arm64", apk-artifact: "SDL-android-apks-arm64" }
steps:
- uses: actions/checkout@v3
@@ -28,6 +28,11 @@ jobs:
if: ${{ matrix.platform.name == 'Android.mk' }}
run: |
./build-scripts/androidbuildlibs.sh
+ - uses: actions/setup-java@v3
+ if: ${{ matrix.platform.name == 'CMake' }}
+ with:
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup (CMake)
if: ${{ matrix.platform.name == 'CMake' }}
run: |
@@ -56,6 +61,10 @@ jobs:
if: ${{ matrix.platform.name == 'CMake' }}
run: |
cmake --build build --config Release --parallel --verbose
+ - name: Build test apk's (CMake)
+ if: ${{ matrix.platform.name == 'CMake' }}
+ run: |
+ cmake --build build --config Release --parallel --verbose --target testaudiocapture-apk testcontroller-apk testmultiaudio-apk testsprite-apk
- name: Install (CMake)
if: ${{ matrix.platform.name == 'CMake' }}
run: |
@@ -88,3 +97,9 @@ jobs:
if-no-files-found: error
name: ${{ matrix.platform.artifact }}
path: build/dist/SDL3*
+ - uses: actions/upload-artifact@v3
+ if: ${{ matrix.platform.name == 'CMake' }}
+ with:
+ if-no-files-found: error
+ name: ${{ matrix.platform.apk-artifact }}
+ path: build/test/*.apk
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e420b65c603b..c289ad043217 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -368,9 +368,11 @@ endforeach()
# Allow some projects to be built conditionally.
set_option(SDL_DISABLE_INSTALL "Disable installation of SDL3" ${SDL3_SUBPROJECT})
cmake_dependent_option(SDL_DISABLE_INSTALL_CPACK "Create binary SDL3 archive using CPack" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL" ON)
-cmake_dependent_option(SDL_DISABLE_INSTALL_MAN "Install man pages for SDL3" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL;NOT SDL_FRAMEWORK" ON)
+cmake_dependent_option(SDL_DISABLE_INSTALL_DOCS "Install docs for SDL3" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL;NOT SDL_FRAMEWORK" ON)
set_option(SDL_DISABLE_UNINSTALL "Disable uninstallation of SDL3" OFF)
+cmake_dependent_option(SDL_DISABLE_ANDROID_JAR "Disable creation of SDL3.jar" ${SDL3_SUBPROJECT} "ANDROID" ON)
+
option_string(SDL_ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto")
#set_option(SDL_DEPENDENCY_TRACKING "Use gcc -MMD -MT dependency tracking" ON)
set_option(SDL_ASSEMBLY "Enable assembly routines" ${SDL_ASSEMBLY_DEFAULT})
@@ -1310,6 +1312,8 @@ endif()
# Platform-specific options and settings
if(ANDROID)
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
+
file(GLOB ANDROID_CORE_SOURCES ${SDL3_SOURCE_DIR}/src/core/android/*.c)
list(APPEND SOURCE_FILES ${ANDROID_CORE_SOURCES} ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
@@ -1442,6 +1446,50 @@ if(ANDROID)
set(HAVE_CLOCK_GETTIME 1)
endif()
+ if(NOT SDL_DISABLE_ANDROID_JAR)
+ find_package(Java)
+ find_package(SdlAndroidPlatform MODULE)
+
+ if(Java_FOUND AND SdlAndroidPlatform_FOUND)
+ include(UseJava)
+ set(path_android_jar "${SDL_ANDROID_PLATFORM_ROOT}/android.jar")
+ set(android_java_sources_root "${SDL3_SOURCE_DIR}/android-project/app/src/main/java")
+ file(GLOB SDL_JAVA_SOURCES "${android_java_sources_root}/org/libsdl/app/*.java")
+ set(CMAKE_JAVA_COMPILE_FLAGS "-encoding;utf-8")
+ add_jar(SDL3-jar
+ SOURCES ${SDL_JAVA_SOURCES}
+ INCLUDE_JARS "${path_android_jar}"
+ OUTPUT_NAME "SDL3"
+ VERSION "${SDL3_VERSION}"
+ )
+ set_property(TARGET SDL3-jar PROPERTY OUTPUT "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}.jar")
+ set(javasourcesjar "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-sources.jar")
+ string(REGEX REPLACE "${android_java_sources_root}/" "" sdl_relative_java_sources "${SDL_JAVA_SOURCES}")
+ add_custom_command(
+ OUTPUT "${javasourcesjar}"
+ COMMAND ${Java_JAR_EXECUTABLE} cf "${javasourcesjar}" ${sdl_relative_java_sources}
+ WORKING_DIRECTORY "${android_java_sources_root}"
+ DEPENDS ${SDL_JAVA_SOURCES}
+ )
+ add_custom_target(SDL3-javasources ALL DEPENDS "${javasourcesjar}")
+ if(NOT SDL_DISABLE_INSTALL_DOCS)
+ set(javadocdir "${SDL3_BINARY_DIR}/docs/javadoc")
+ set(javadocjar "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-javadoc.jar")
+ set(javadoc_index_html "${javadocdir}/index.html")
+ add_custom_command(
+ OUTPUT "${javadoc_index_html}"
+ COMMAND ${CMAKE_COMMAND} -E rm -rf "${javadocdir}"
+ COMMAND ${Java_JAVADOC_EXECUTABLE} -encoding utf8 -d "${javadocdir}"
+ -classpath "${path_android_jar}"
+ -author -use -version ${SDL_JAVA_SOURCES}
+ DEPENDS ${SDL_JAVA_SOURCES} "${path_android_jar}"
+ )
+ add_custom_target(SDL3-javadoc ALL DEPENDS "${javadoc_index_html}")
+ set_property(TARGET SDL3-javadoc PROPERTY OUTPUT_DIR "${javadocdir}")
+ endif()
+ endif()
+ endif()
+
elseif(EMSCRIPTEN)
# Hide noisy warnings that intend to aid mostly during initial stages of porting a new
# project. Uncomment at will for verbose cross-compiling -I/../ path info.
@@ -3695,11 +3743,28 @@ if(NOT SDL_DISABLE_INSTALL)
include(CPack)
endif()
- if(NOT SDL_DISABLE_INSTALL_MAN)
+ if(ANDROID)
+ set(SDL_INSTALL_JAVADIR "${CMAKE_INSTALL_DATAROOTDIR}/java" CACHE PATH "Path where to install java clases + java sources")
+ if(TARGET SDL3-jar)
+ install(FILES "${SDL3_BINARY_DIR}/SDL3.jar" "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}.jar"
+ DESTINATION "${SDL_INSTALL_JAVADIR}/SDL3")
+ endif()
+ if(TARGET SDL3-javasources)
+ install(FILES "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-sources.jar"
+ DESTINATION "${SDL_INSTALL_JAVADIR}/SDL3")
+ endif()
+ endif()
+
+ if(NOT SDL_DISABLE_INSTALL_DOCS)
SDL_generate_manpages(
SYMBOL "SDL_Init"
WIKIHEADERS_PL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build-scripts/wikiheaders.pl"
)
+ if(TARGET SDL3-javadoc)
+ set(SDL_INSTALL_JAVADOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/javadoc" CACHE PATH "Path where to install SDL3 javadoc")
+ install(DIRECTORY "${SDL3_BINARY_DIR}/docs/javadoc/"
+ DESTINATION "${SDL_INSTALL_JAVADOCDIR}/SDL3")
+ endif()
endif()
endif()
diff --git a/cmake/android/FindSdlAndroid.cmake b/cmake/android/FindSdlAndroid.cmake
new file mode 100644
index 000000000000..38a2d7a136c0
--- /dev/null
+++ b/cmake/android/FindSdlAndroid.cmake
@@ -0,0 +1,103 @@
+#[=======================================================================[
+
+FindSdlAndroid
+----------------------
+
+Locate various executables that are essential to creating an Android APK archive.
+This find module uses the FindSdlAndroidBuildTools module to locate some Android utils.
+
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` target(s):
+
+`` SdlAndroid::aapt2 ``
+ Imported executable for the "android package tool" v2
+
+`` SdlAndroid::apksigner``
+ Imported executable for the APK signer tool
+
+`` SdlAndroid::d8 ``
+ Imported executable for the dex compiler
+
+`` SdlAndroid::zipalign ``
+ Imported executable for the zipalign util
+
+`` SdlAndroid::adb ``
+ Imported executable for the "android debug bridge" tool
+
+`` SdlAndroid::keytool ``
+ Imported executable for the keytool, a key and certificate management utility
+
+`` SdlAndroid::zip ``
+ Imported executable for the zip, for packaging and compressing files
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+`` AAPT2_BIN ``
+ Path of aapt2
+
+`` APKSIGNER_BIN ``
+ Path of apksigner
+
+`` D8_BIN ``
+ Path of d8
+
+`` ZIPALIGN_BIN ``
+ Path of zipalign
+
+`` ADB_BIN ``
+ Path of adb
+
+`` KEYTOOL_BIN ``
+ Path of keytool
+
+`` ZIP_BIN ``
+ Path of zip
+
+#]=======================================================================]
+
+cmake_minimum_required(VERSION 3.7)
+
+if(NOT PROJECT_NAME MATCHES "^SDL.*")
+ message(WARNING "This module is internal to SDL and is currently not supported.")
+endif()
+
+find_package(SdlAndroidBuildTools MODULE)
+
+function(_sdl_android_find_create_imported_executable NAME)
+ string(TOUPPER "${NAME}" NAME_UPPER)
+ set(varname "${NAME_UPPER}_BIN")
+ find_program("${varname}" NAMES "${NAME}" PATHS ${SDL_ANDROID_BUILD_TOOLS_ROOT})
+ if(EXISTS "${${varname}}" AND NOT TARGET SdlAndroid::${NAME})
+ add_executable(SdlAndroid::${NAME} IMPORTED)
+ set_property(TARGET SdlAndroid::${NAME} PROPERTY IMPORTED_LOCATION "${${varname}}")
+ endif()
+endfunction()
+
+if(SdlAndroidBuildTools_FOUND)
+ _sdl_android_find_create_imported_executable(aapt2)
+ _sdl_android_find_create_imported_executable(apksigner)
+ _sdl_android_find_create_imported_executable(d8)
+ _sdl_android_find_create_imported_executable(zipalign)
+endif()
+
+_sdl_android_find_create_imported_executable(adb)
+_sdl_android_find_create_imported_executable(keytool)
+_sdl_android_find_create_imported_executable(zip)
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(SdlAndroid
+ VERSION_VAR
+ REQUIRED_VARS
+ AAPT2_BIN
+ APKSIGNER_BIN
+ D8_BIN
+ ZIPALIGN_BIN
+ KEYTOOL_BIN
+ ZIP_BIN
+)
diff --git a/cmake/android/FindSdlAndroidBuildTools.cmake b/cmake/android/FindSdlAndroidBuildTools.cmake
new file mode 100644
index 000000000000..b8825d92b572
--- /dev/null
+++ b/cmake/android/FindSdlAndroidBuildTools.cmake
@@ -0,0 +1,115 @@
+#[=======================================================================[
+
+FindSdlAndroidBuildTools
+----------------------
+
+Locate the Android build tools directory.
+
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This find module defines the following :prop_tgt:`IMPORTED` target(s):
+
+<none>
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+`` SdlAndroidBuildTools_FOUND
+ if false, no Android build tools have been found
+
+`` SDL_ANDROID_BUILD_TOOLS_ROOT
+ path of the Android build tools root directory if found
+
+`` SDL_ANDROID_BUILD_TOOLS_VERSION
+ the human-readable string containing the android build tools version if found
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+These variables may optionally be set to help this module find the correct files:
+
+``SDL_ANDROID_BUILD_TOOLS_ROOT``
+ path of the Android build tools root directory
+
+
+Variables for locating Android platform
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This module responds to the flags:
+
+``SDL_ANDROID_HOME
+ First, this module will look for platforms in this CMake variable.
+
+``ANDROID_HOME
+ If no platform was found in `SDL_ANDROID_HOME`, then try `ANDROID_HOME`.
+
+``$ENV{ANDROID_HOME}
+ If no platform was found in neither `SDL_ANDROID_HOME` or `ANDROID_HOME`, then try `ANDROID_HOME}`
+
+#]=======================================================================]
+
+cmake_minimum_required(VERSION 3.7)
+
+if(NOT PROJECT_NAME MATCHES "^SDL.*")
+ message(WARNING "This module is internal to SDL and is currently not supported.")
+endif()
+
+function(_sdl_is_valid_android_build_tools_root RESULT VERSION BUILD_TOOLS_ROOT)
+ set(result TRUE)
+ set(version -1)
+
+ string(REGEX MATCH "/([0-9.]+)$" root_match "${BUILD_TOOLS_ROOT}")
+ if(root_match
+ AND EXISTS "${BUILD_TOOLS_ROOT}/aapt2"
+ AND EXISTS "${BUILD_TOOLS_ROOT}/apksigner"
+ AND EXISTS "${BUILD_TOOLS_ROOT}/d8"
+ AND EXISTS "${BUILD_TOOLS_ROOT}/zipalign")
+ set(result "${BUILD_TOOLS_ROOT}")
+ set(version "${CMAKE_MATCH_1}")
+ endif()
+
+ set(${RESULT} ${result} PARENT_SCOPE)
+ set(${VERSION} ${version} PARENT_SCOPE)
+endfunction()
+
+function(_find_sdl_android_build_tools_root ROOT)
+ cmake_parse_arguments(fsabtr "" "" "" ${ARGN})
+ set(homes ${SDL_ANDROID_HOME} ${ANDROID_HOME} $ENV{ANDROID_HOME})
+ set(root ${ROOT}-NOTFOUND)
+ foreach(home IN LISTS homes)
+ if(NOT IS_DIRECTORY "${home}")
+ continue()
+ endif()
+ file(GLOB build_tools_roots LIST_DIRECTORIES true "${home}/build-tools/*")
+ set(max_build_tools_version -1)
+ set(max_build_tools_root "")
+ foreach(build_tools_root IN LISTS build_tools_roots)
+ _sdl_is_valid_android_build_tools_root(is_valid build_tools_version "${build_tools_root}")
+ if(is_valid AND build_tools_version GREATER max_build_tools_version)
+ set(max_build_tools_version "${build_tools_version}")
+ set(max_build_tools_root "${build_tools_root}")
+ endif()
+ endforeach()
+ if(max_build_tools_version GREATER -1)
+ set(root ${max_build_tools_root})
+ break()
+ endif()
+ endforeach()
+ set(${ROOT} ${root} PARENT_SCOPE)
+endfunction()
+
+if(NOT DEFINED SDL_ANDROID_BUILD_TOOLS_ROOT)
+ _find_sdl_android_build_tools_root(SDL_ANDROID_BUILD_TOOLS_ROOT)
+ set(SDL_ANDROID_BUILD_TOOLS_ROOT "${SDL_ANDROID_BUILD_TOOLS_ROOT}" CACHE PATH "Path of Android build tools")
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(SdlAndroidBuildTools
+ VERSION_VAR SDL_ANDROID_BUILD_TOOLS_VERSION
+ REQUIRED_VARS SDL_ANDROID_BUILD_TOOLS_ROOT
+)
diff --git a/cmake/android/FindSdlAndroidPlatform.cmake b/cmake/android/FindSdlAndroidPlatform.cmake
new file mode 100644
index 000000000000..0f9584906caf
--- /dev/null
+++ b/cmake/android/FindSdlAndroidPlatform.cmake
@@ -0,0 +1,123 @@
+#[=======================================================================[
+
+FindSdlAndroidPlatform
+----------------------
+
+Locate the Android SDK platform.
+
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` target(s):
+
+<none>
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This find module will set the following variables in your project:
+
+`` SdlAndroidPlatform_FOUND
+ if false, no Android platform has been found
+
+`` SDL_ANDROID_PLATFORM_ROOT
+ path of the Android SDK platform root directory if found
+
+`` SDL_ANDROID_PLATFORM_ANDROID_JAR
+ path of the Android SDK platform jar file if found
+
+`` SDL_ANDROID_PLATFORM_VERSION
+ the human-readable string containing the android platform version if found
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+These variables may optionally be set to help this module find the correct files:
+
+``SDL_ANDROID_PLATFORM_ROOT``
+ path of the Android SDK platform root directory
+
+
+Variables for locating Android platform
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This module responds to the flags:
+
+``SDL_ANDROID_HOME
+ First, this module will look for platforms in this CMake variable.
+
+``ANDROID_HOME
+ If no platform was found in `SDL_ANDROID_HOME`, then try `ANDROID_HOME`.
+
+``$ENV{ANDROID_HOME}
+ If no platform was found in neither `SDL_ANDROID_HOME` or `ANDROID_HOME`, then try `ANDROID_HOME}`
+
+#]=======================================================================]
+
+cmake_minimum_required(VERSION 3.7)
+
+if(NOT PROJECT_NAME MATCHES "^SDL.*")
+ message(WARNING "This module is internal to SDL and is currently not supported.")
+endif()
+
+function(_sdl_is_valid_android_platform_root RESULT VERSION PLATFORM_ROOT)
+ set(result FALSE)
+ set(version -1)
+
+ string(REGEX MATCH "/android-([0-9]+)$" root_match "${PLATFORM_ROOT}")
+ if(root_match AND EXISTS "${PLATFORM_ROOT}/android.jar")
+ set(result TRUE)
+ set(version "${CMAKE_MATCH_1}")
+ endif()
+
+ set(${RESULT} ${result} PARENT_SCOPE)
+ set(${VERSION} ${version} PARENT_SCOPE)
+endfunction()
+
+function(_sdl_find_android_platform_root ROOT)
+ cmake_parse_arguments(sfapr "" "" "" ${ARGN})
+ set(homes ${SDL_ANDROID_HOME} ${ANDROID_HOME} $ENV{ANDROID_HOME})
+ set(root ${ROOT}-NOTFOUND)
+ foreach(home IN LISTS homes)
+ if(NOT IS_DIRECTORY "${home}")
+ continue()
+ endif()
+ file(GLOB platform_roots LIST_DIRECTORIES true "${home}/platforms/*")
+ set(max_platform_version -1)
+ set(max_platform_root "")
+ foreach(platform_root IN LISTS platform_roots)
+ _sdl_is_valid_android_platform_root(is_valid platform_version "${platform_root}")
+ if(is_valid AND platform_version GREATER max_platform_version)
+ set(max_platform_version "${platform_version}")
+ set(max_platform_root "${platform_root}")
+ endif()
+ endforeach()
+ if(max_platform_version GREATER -1)
+ set(root ${max_platform_root})
+ break()
+ endif()
+ endforeach()
+ set(${ROOT} ${root} PARENT_SCOPE)
+endfunction()
+
+set(SDL_ANDROID_PLATFORM_ANDROID_JAR "SDL_ANDROID_PLATFORM_ANDROID_JAR-NOTFOUND")
+
+if(NOT DEFINED SDL_ANDROID_PLATFORM_ROOT)
+ _sdl_find_android_platform_root(SDL_ANDROID_PLATFORM_ROOT)
+ set(SDL_ANDROID_PLATFORM_ROOT "${SDL_ANDROID_PLATFORM_ROOT}" CACHE PATH "Path of Android platform")
+endif()
+if(SDL_ANDROID_PLATFORM_ROOT)
+ _sdl_is_valid_android_platform_root(_valid SDL_ANDROID_PLATFORM_VERSION "${SDL_ANDROID_PLATFORM_ROOT}")
+ if(_valid)
+ set(SDL_ANDROID_PLATFORM_ANDROID_JAR "${SDL_ANDROID_PLATFORM_ROOT}/android.jar")
+ endif()
+ unset(_valid)
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(SdlAndroidPlatform
+ VERSION_VAR SDL_ANDROID_PLATFORM_VERSION
+ REQUIRED_VARS SDL_ANDROID_PLATFORM_ROOT SDL_ANDROID_PLATFORM_ANDROID_JAR
+)
diff --git a/cmake/android/SdlAndroidFunctions.cmake b/cmake/android/SdlAndroidFunctions.cmake
new file mode 100644
index 000000000000..b7b3aa84962f
--- /dev/null
+++ b/cmake/android/SdlAndroidFunctions.cmake
@@ -0,0 +1,276 @@
+#[=======================================================================[
+
+This CMake script contains functions to build an Android APK.
+It is (currently) limited to packaging binaries for a single architecture.
+
+#]=======================================================================]
+
+cmake_minimum_required(VERSION 3.7)
+
+if(NOT PROJECT_NAME MATCHES "^SDL.*")
+ message(WARNING "This module is internal to SDL and is currently not supported.")
+endif()
+
+function(_sdl_create_outdir_for_target OUTDIRECTORY TARGET)
+ set(outdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET}.dir")
+ # Some CMake versions have a slow `cmake -E make_directory` implementation
+ if(NOT IS_DIRECTORY "${outdir}")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${outdir}")
+ endif()
+ set("${OUTDIRECTORY}" "${outdir}" PARENT_SCOPE)
+endfunction()
+
+function(sdl_create_android_debug_keystore TARGET)
+ set(output "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_debug.keystore")
+ add_custom_command(OUTPUT ${output}
+ COMMAND ${CMAKE_COMMAND} -E rm -f "${output}"
+ COMMAND SdlAndroid::keytool -genkey -keystore "${output}" -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "C=US, O=Android, CN=Android Debug"
+ )
+ add_custom_target(${TARGET} DEPENDS "${output}")
+ set_property(TARGET ${TARGET} PROPERTY OUTPUT "${output}")
+endfunction()
+
+function(sdl_android_compile_resources TARGET)
+ cmake_parse_arguments(arg "" "RESFOLDER" "RESOURCES" ${ARGN})
+
+ if(NOT arg_RESFOLDER AND NOT arg_RESOURCES)
+ message(FATAL_ERROR "Missing RESFOLDER or RESOURCES argument (need one or both)")
+ endif()
+ _sdl_create_outdir_for_target(outdir "${TARGET}")
+ set(out_files "")
+
+ set(res_files "")
+ if(arg_RESFOLDER)
+ get_filename_component(arg_RESFOLDER "${arg_RESFOLDER}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ file(GLOB_RECURSE res_folder_files "${arg_RESFOLDER}/*")
+ list(APPEND res_files ${res_folder_files})
+
+ foreach(res_file IN LISTS res_files)
+ file(RELATIVE_PATH rel_res_file "${arg_RESFOLDER}" "${res_file}")
+ string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
+ if(res_file MATCHES ".*res/values.*\\.xml$")
+ string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
+ endif()
+ set(comp_path "${outdir}/${rel_comp_path}.flat")
+ add_custom_command(
+ OUTPUT "${comp_path}"
+ COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
+ DEPENDS ${res_file}
+ )
+ list(APPEND out_files "${comp_path}")
+ endforeach()
+ endif()
+
+ if(arg_RESOURCES)
+ list(APPEND res_files ${arg_RESOURCES})
+ foreach(res_file IN LISTS arg_RESOURCES)
+ string(REGEX REPLACE ".*/res/" "" rel_res_file ${res_file})
+ string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
+ if(res_file MATCHES ".*res/values.*\\.xml$")
+ string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
+ endif()
+ set(comp_path "${outdir}/${rel_comp_path}.flat")
+ add_custom_command(
+ OUTPUT "${comp_path}"
+ COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
+ DEPENDS ${res_file}
+ )
+ list(APPEND out_files "${comp_path}")
+ endforeach()
+ endif()
+
+ add_custom_target(${TARGET} DEPENDS ${out_files})
+ set_property(TARGET "${TARGET}" PROPERTY OUTPUTS "${out_files}")
+ set_property(TARGET "${TARGET}" PROPERTY SOURCES "${res_files}")
+endfunction()
+
+function(sdl_android_link_resources TARGET)
+ cmake_parse_arguments(arg "NO_DEBUG" "MIN_SDK_VERSION;TARGET_SDK_VERSION;ANDROID_JAR;OUTPUT_APK;MANIFEST;PACKAGE" "RES_TARGETS" ${ARGN})
+
+ if(arg_MANIFEST)
+ get_filename_component(arg_MANIFEST "${arg_MANIFEST}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ else()
+ message(FATAL_ERROR "sdl_add_android_link_resources_target requires a Android MANIFEST path (${arg_MANIFEST})")
+ endif()
+ if(NOT arg_PACKAGE)
+ file(READ "${arg_MANIFEST}" manifest_contents)
+ string(REGEX MATCH "package=\"([a-zA-Z0-9_.]+)\"" package_match "${manifest_contents}")
+ if(NOT package_match)
+ message(FATAL_ERROR "Could not extract package from Android manifest (${arg_MANIFEST})")
+ endif()
+ set(arg_PACKAGE "${CMAKE_MATCH_1}")
+ endif()
+
+ set(depends "")
+
+ _sdl_create_outdir_for_target(outdir "${TARGET}")
+ string(REPLACE "." "/" java_r_path "${arg_PACKAGE}")
+ get_filename_component(java_r_path "${java_r_path}" ABSOLUTE BASE_DIR "${outdir}")
+ set(java_r_path "${java_r_path}/R.java")
+
+ set(command SdlAndroid::aapt2 link)
+ if(NOT arg_NO_DEBUG)
+ list(APPEND command --debug-mode)
+ endif()
+ if(arg_MIN_SDK_VERSION)
+ list(APPEND command --min-sdk-version ${arg_MIN_SDK_VERSION})
+ endif()
+ if(arg_TARGET_SDK_VERSION)
+ list(APPEND command --target-sdk-version ${arg_TARGET_SDK_VERSION})
+ endif()
+ if(arg_ANDROID_JAR)
+ list(APPEND command -I "${arg_ANDROID_JAR}")
+ else()
+ list(APPEND command -I "${SDL_ANDROID_PLATFORM_ANDROID_JAR}")
+ endif()
+ if(NOT arg_OUTPUT_APK)
+ set(arg_OUTPUT_APK "${TARGET}.apk")
+ endif()
+ get_filename_component(arg_OUTPUT_APK "${arg_OUTPUT_APK}" ABSOLUTE BASE_DIR "${outdir}")
+ list(APPEND command -o "${arg_OUTPUT_APK}")
+ list(APPEND command --java "${outdir}")
+ list(APPEND command --manifest "${arg_MANIFEST}")
+ foreach(res_target IN LISTS arg_RES_TARGETS)
+ list(APPEND command $<TARGET_PROPERTY:${res_target},OUTPUTS>)
+ list(APPEND depends $<TARGET_PROPERTY:${res_target},OUTPUTS>)
+ endforeach()
+ add_custom_command(
+ OUTPUT "${arg_OUTPUT_APK}" "${java_r_path}"
+ COMMAND ${command}
+ DEPENDS ${depends} ${arg_MANIFEST}
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+ )
+ add_custom_target(${TARGET} DEPENDS "${arg_OUTPUT_APK}" "${java_r_path}")
+ set_property(TARGET ${TARGET} PROPERTY OUTPUT "${arg_OUTPUT_APK}")
+ set_property(TARGET ${TARGET} PROPERTY JAVA_R "${java_r_path}")
+ set_property(TARGET ${TARGET} PROPERTY OUTPUTS "${${arg_OUTPUT_APK}};${java_r_path}")
+endfunction()
+
+function(sdl_add_to_apk_unaligned TARGET)
+ cmake_parse_arguments(arg "" "APK_IN;NAME;OUTDIR" "ASSETS;NATIVE_LIBS;DEX" ${ARGN})
+
+ if(NOT arg_APK_IN)
+ message(FATAL_ERROR "Missing APK_IN argument")
+ endif()
+
+ if(NOT TARGET ${arg_APK_IN})
+ message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
+ endif()
+
+ _sdl_create_outdir_for_target(workdir ${TARGET})
+
+ if(NOT arg_OUTDIR)
+ set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ if(NOT arg_NAME)
+ string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
+ if(NOT arg_NAME MATCHES "\\.apk")
+ set(arg_NAME "${arg_NAME}.apk")
+ endif()
+ endif()
+ get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
+
+ set(apk_libdir "lib/${ANDROID_ABI}")
+
+ set(depends "")
+
+ set(commands
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory -rf "${apk_libdir}" "assets"
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${apk_libdir}" "assets"
+ COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>" "${apk_file}"
+ )
+
+ set(dex_i "1")
+ foreach(dex IN LISTS arg_DEX)
+ set(suffix "${dex_i}")
+ if(suffix STREQUAL "1")
+ set(suffix "")
+ endif()
+ list(APPEND commands
+ COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${dex},OUTPUT>" "classes${suffix}.dex"
+ COMMAND SdlAndroid::zip -u -q -j "${apk_file}" "classes${suffix}.dex"
+ )
+ math(EXPR dex_i "${dex_i}+1")
+ list(APPEND depends "$<TARGET_PROPERTY:${dex},OUTPUT>")
+ endforeach()
+
+ foreach(native_lib IN LISTS arg_NATIVE_LIBS)
+ list(APPEND commands
+ COMMAND "${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${native_lib}> "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
+ COMMAND SdlAndroid::zip -u -q "${apk_file}" "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
+ )
+ endforeach()
+ if(arg_ASSETS)
+ list(APPEND commands
+ COMMAND "${CMAKE_COMMAND}" -E copy ${arg_ASSETS} "assets"
+ COMMAND SdlAndroid::zip -u -r -q "${apk_file}" "assets"
+ )
+ endif()
+
+ add_custom_command(OUTPUT "${apk_file}"
+ ${commands}
+ DEPENDS ${arg_NATIVE_LIBS} ${depends} "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>"
+ WORKING_DIRECTORY "${workdir}"
+ )
+ add_custom_target(${TARGET} DEPENDS "${apk_file}")
+ set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
+endfunction()
+
+function(sdl_apk_align TARGET APK_IN)
+ cmake_parse_arguments(arg "" "NAME;OUTDIR" "" ${ARGN})
+
+ if(NOT TARGET ${arg_APK_IN})
+ message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
+ endif()
+
+ if(NOT arg_OUTDIR)
+ set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ if(NOT arg_NAME)
+ string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
+ if(NOT arg_NAME MATCHES "\\.apk")
+ set(arg_NAME "${arg_NAME}.apk")
+ endif()
+ endif()
+ get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
+
+ add_custom_command(OUTPUT "${apk_file}"
+ COMMAND SdlAndroid::zipalign -f 4 "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" "${apk_file}"
+ DEPENDS "$<TARGET_PROPERTY:${APK_IN},OUTPUT>"
+ )
+ add_custom_target(${TARGET} DEPENDS "${apk_file}")
+ set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
+endfunction()
+
+function(sdl_apk_sign TARGET APK_IN)
+ cmake_parse_arguments(arg "" "OUTPUT;KEYSTORE" "" ${ARGN})
+
+ if
(Patch may be truncated, please check the link at the top of this post.)