2014-02-10 01:10:30 +00:00
import os
import platform
2022-06-01 07:54:08 +00:00
import subprocess
2024-05-21 13:14:59 +00:00
import sys
2022-08-23 13:21:46 +00:00
from typing import TYPE_CHECKING
2024-05-21 13:14:59 +00:00
from methods import print_error , print_warning
2024-09-27 18:36:52 +00:00
from platform_methods import validate_arch
2024-05-21 13:14:59 +00:00
2022-08-23 13:21:46 +00:00
if TYPE_CHECKING :
2023-11-24 19:31:05 +00:00
from SCons . Script . SConscript import SConsEnvironment
2022-08-23 13:21:46 +00:00
2016-10-30 18:05:14 +00:00
2014-02-10 01:10:30 +00:00
def get_name ( ) :
2016-10-30 17:44:57 +00:00
return " Android "
2014-02-10 01:10:30 +00:00
2016-10-30 18:05:14 +00:00
2014-02-10 01:10:30 +00:00
def can_build ( ) :
2022-06-01 07:54:08 +00:00
return os . path . exists ( get_env_android_sdk_root ( ) )
2017-12-18 15:39:09 +00:00
2014-02-10 01:10:30 +00:00
def get_opts ( ) :
2023-03-01 22:09:30 +00:00
from SCons . Variables import BoolVariable
2016-10-30 17:44:57 +00:00
return [
2023-11-01 16:17:19 +00:00
( " ANDROID_HOME " , " Path to the Android SDK " , get_env_android_sdk_root ( ) ) ,
2022-10-19 04:39:43 +00:00
(
" ndk_platform " ,
' Target platform (android-<api>, e.g. " android- ' + str ( get_min_target_api ( ) ) + ' " ) ' ,
" android- " + str ( get_min_target_api ( ) ) ,
) ,
2023-03-01 22:09:30 +00:00
BoolVariable ( " store_release " , " Editor build for Google Play Store (for official builds only) " , False ) ,
2023-12-11 18:50:44 +00:00
BoolVariable ( " generate_apk " , " Generate an APK/AAB after building Android library by calling Gradle " , False ) ,
2016-10-30 17:44:57 +00:00
]
2014-02-10 01:10:30 +00:00
2016-03-20 09:22:48 +00:00
2023-04-19 09:23:22 +00:00
def get_doc_classes ( ) :
return [
" EditorExportPlatformAndroid " ,
]
def get_doc_path ( ) :
return " doc_classes "
2023-11-01 16:17:19 +00:00
# Return the ANDROID_HOME environment variable.
2022-06-01 07:54:08 +00:00
def get_env_android_sdk_root ( ) :
2023-11-01 16:17:19 +00:00
return os . environ . get ( " ANDROID_HOME " , os . environ . get ( " ANDROID_SDK_ROOT " , " " ) )
2021-01-05 21:40:42 +00:00
2022-06-01 07:54:08 +00:00
def get_min_sdk_version ( platform ) :
return int ( platform . split ( " - " ) [ 1 ] )
2023-11-24 19:31:05 +00:00
def get_android_ndk_root ( env : " SConsEnvironment " ) :
2023-11-01 16:17:19 +00:00
return env [ " ANDROID_HOME " ] + " /ndk/ " + get_ndk_version ( )
2022-06-01 07:54:08 +00:00
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
def get_ndk_version ( ) :
return " 23.2.8568313 "
2021-01-05 21:40:42 +00:00
2022-10-19 04:39:43 +00:00
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
def get_min_target_api ( ) :
return 21
2014-02-10 01:10:30 +00:00
def get_flags ( ) :
2024-05-19 14:41:03 +00:00
return {
2024-05-10 10:07:59 +00:00
" arch " : " arm64 " ,
2024-05-19 14:41:03 +00:00
" target " : " template_debug " ,
" supported " : [ " mono " ] ,
}
2014-02-10 01:10:30 +00:00
2022-06-01 07:54:08 +00:00
# Check if Android NDK version is installed
# If not, install it.
2023-11-24 19:31:05 +00:00
def install_ndk_if_needed ( env : " SConsEnvironment " ) :
2023-11-01 16:17:19 +00:00
sdk_root = env [ " ANDROID_HOME " ]
2022-06-01 07:54:08 +00:00
if not os . path . exists ( get_android_ndk_root ( env ) ) :
2021-01-05 21:40:42 +00:00
extension = " .bat " if os . name == " nt " else " "
2022-06-01 07:54:08 +00:00
sdkmanager = sdk_root + " /cmdline-tools/latest/bin/sdkmanager " + extension
if os . path . exists ( sdkmanager ) :
# Install the Android NDK
print ( " Installing Android NDK... " )
ndk_download_args = " ndk; " + get_ndk_version ( )
subprocess . check_call ( [ sdkmanager , ndk_download_args ] )
else :
2024-04-26 17:35:07 +00:00
print_error (
f ' Cannot find " { sdkmanager } " . Please ensure ANDROID_HOME is correct and cmdline-tools '
2024-05-05 03:51:21 +00:00
f ' are installed, or install NDK version " { get_ndk_version ( ) } " manually. '
2022-06-01 07:54:08 +00:00
)
2024-04-26 17:35:07 +00:00
sys . exit ( 255 )
2022-06-01 07:54:08 +00:00
env [ " ANDROID_NDK_ROOT " ] = get_android_ndk_root ( env )
2021-01-05 21:40:42 +00:00
2024-05-05 22:15:56 +00:00
def detect_swappy ( ) :
archs = [ " arm64-v8a " , " armeabi-v7a " , " x86 " , " x86_64 " ]
has_swappy = True
for arch in archs :
if not os . path . isfile ( " thirdparty/swappy-frame-pacing/ " + arch + " /libswappy_static.a " ) :
has_swappy = False
return has_swappy
2023-11-24 19:31:05 +00:00
def configure ( env : " SConsEnvironment " ) :
2021-12-16 01:38:10 +00:00
# Validate arch.
supported_arches = [ " x86_32 " , " x86_64 " , " arm32 " , " arm64 " ]
2024-09-27 18:36:52 +00:00
validate_arch ( env [ " arch " ] , get_name ( ) , supported_arches )
2021-12-16 01:38:10 +00:00
2022-10-19 04:39:43 +00:00
if get_min_sdk_version ( env [ " ndk_platform " ] ) < get_min_target_api ( ) :
2024-04-26 17:35:07 +00:00
print_warning (
" Minimum supported Android target api is %d . Forcing target api %d . "
2022-10-19 04:39:43 +00:00
% ( get_min_target_api ( ) , get_min_target_api ( ) )
)
env [ " ndk_platform " ] = " android- " + str ( get_min_target_api ( ) )
2021-01-05 21:40:42 +00:00
install_ndk_if_needed ( env )
2022-06-01 07:54:08 +00:00
ndk_root = env [ " ANDROID_NDK_ROOT " ]
2016-10-30 17:44:57 +00:00
2019-08-27 09:16:33 +00:00
# Architecture
2016-10-30 17:44:57 +00:00
2021-12-16 01:38:10 +00:00
if env [ " arch " ] == " arm32 " :
2022-06-01 07:54:08 +00:00
target_triple = " armv7a-linux-androideabi "
2021-12-16 01:38:10 +00:00
elif env [ " arch " ] == " arm64 " :
2022-06-01 07:54:08 +00:00
target_triple = " aarch64-linux-android "
2021-12-16 01:38:10 +00:00
elif env [ " arch " ] == " x86_32 " :
2022-06-01 07:54:08 +00:00
target_triple = " i686-linux-android "
2021-12-16 01:38:10 +00:00
elif env [ " arch " ] == " x86_64 " :
2022-06-01 07:54:08 +00:00
target_triple = " x86_64-linux-android "
target_option = [ " -target " , target_triple + str ( get_min_sdk_version ( env [ " ndk_platform " ] ) ) ]
2022-07-07 10:26:31 +00:00
env . Append ( ASFLAGS = [ target_option , " -c " ] )
2022-06-01 07:54:08 +00:00
env . Append ( CCFLAGS = target_option )
env . Append ( LINKFLAGS = target_option )
2016-10-30 17:44:57 +00:00
2022-07-21 13:15:54 +00:00
# LTO
2022-09-13 15:01:47 +00:00
if env [ " lto " ] == " auto " : # LTO benefits for Android (size, performance) haven't been clearly established yet.
env [ " lto " ] = " none "
2022-07-21 13:15:54 +00:00
if env [ " lto " ] != " none " :
if env [ " lto " ] == " thin " :
env . Append ( CCFLAGS = [ " -flto=thin " ] )
env . Append ( LINKFLAGS = [ " -flto=thin " ] )
else :
env . Append ( CCFLAGS = [ " -flto " ] )
env . Append ( LINKFLAGS = [ " -flto " ] )
2019-08-27 09:16:33 +00:00
# Compiler configuration
2017-06-30 17:21:38 +00:00
2020-03-30 06:28:32 +00:00
env [ " SHLIBSUFFIX " ] = " .so "
2017-06-30 17:21:38 +00:00
2020-03-30 06:28:32 +00:00
if env [ " PLATFORM " ] == " win32 " :
2017-06-30 17:21:38 +00:00
env . use_windows_spawn_fix ( )
2020-03-30 06:28:32 +00:00
if sys . platform . startswith ( " linux " ) :
2016-11-13 22:54:06 +00:00
host_subpath = " linux-x86_64 "
2020-03-30 06:28:32 +00:00
elif sys . platform . startswith ( " darwin " ) :
2016-11-02 09:54:51 +00:00
host_subpath = " darwin-x86_64 "
2020-03-30 06:28:32 +00:00
elif sys . platform . startswith ( " win " ) :
if platform . machine ( ) . endswith ( " 64 " ) :
2016-11-02 09:54:51 +00:00
host_subpath = " windows-x86_64 "
2016-10-30 17:44:57 +00:00
else :
2016-11-13 22:54:06 +00:00
host_subpath = " windows "
2016-10-30 17:57:40 +00:00
2022-06-01 07:54:08 +00:00
toolchain_path = ndk_root + " /toolchains/llvm/prebuilt/ " + host_subpath
compiler_path = toolchain_path + " /bin "
2016-10-30 17:44:57 +00:00
2022-06-01 07:54:08 +00:00
env [ " CC " ] = compiler_path + " /clang "
env [ " CXX " ] = compiler_path + " /clang++ "
env [ " AR " ] = compiler_path + " /llvm-ar "
env [ " RANLIB " ] = compiler_path + " /llvm-ranlib "
2022-07-07 10:26:31 +00:00
env [ " AS " ] = compiler_path + " /clang "
2019-07-30 13:33:24 +00:00
2020-03-30 06:28:32 +00:00
env . Append (
2024-10-21 11:33:42 +00:00
CCFLAGS = ( " -fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden " . split ( ) )
2020-03-30 06:28:32 +00:00
)
2014-10-07 04:31:49 +00:00
2024-05-05 22:15:56 +00:00
has_swappy = detect_swappy ( )
if not has_swappy :
print_warning (
" Swappy Frame Pacing not detected! It is strongly recommended you download it from https://github.com/darksylinc/godot-swappy/releases and extract it so that the following files can be found: \n "
+ " thirdparty/swappy-frame-pacing/arm64-v8a/libswappy_static.a \n "
+ " thirdparty/swappy-frame-pacing/armeabi-v7a/libswappy_static.a \n "
+ " thirdparty/swappy-frame-pacing/x86/libswappy_static.a \n "
+ " thirdparty/swappy-frame-pacing/x86_64/libswappy_static.a \n "
+ " Without Swappy, Godot apps on Android will inevitable suffer stutter and struggle to keep consistent 30/60/90/120 fps. Though Swappy cannot guarantee your app will be stutter-free, not having Swappy will guarantee there will be stutter even on the best phones and the most simple of scenes. "
)
if env [ " swappy " ] :
print_error ( " Use build option `swappy=no` to ignore missing Swappy dependency and build without it. " )
sys . exit ( 255 )
2022-06-01 07:54:08 +00:00
if get_min_sdk_version ( env [ " ndk_platform " ] ) > = 24 :
2019-03-26 17:51:13 +00:00
env . Append ( CPPDEFINES = [ ( " _FILE_OFFSET_BITS " , 64 ) ] )
2021-12-16 01:38:10 +00:00
if env [ " arch " ] == " x86_32 " :
2022-06-01 07:54:08 +00:00
# The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
2020-03-30 06:28:32 +00:00
env . Append ( CCFLAGS = [ " -mstackrealign " ] )
2024-05-05 22:15:56 +00:00
if has_swappy :
env . Append ( LIBPATH = [ " ../../thirdparty/swappy-frame-pacing/x86 " ] )
elif env [ " arch " ] == " x86_64 " :
if has_swappy :
env . Append ( LIBPATH = [ " ../../thirdparty/swappy-frame-pacing/x86_64 " ] )
2021-12-16 01:38:10 +00:00
elif env [ " arch " ] == " arm32 " :
2020-03-30 06:28:32 +00:00
env . Append ( CCFLAGS = " -march=armv7-a -mfloat-abi=softfp " . split ( ) )
env . Append ( CPPDEFINES = [ " __ARM_ARCH_7__ " , " __ARM_ARCH_7A__ " ] )
2021-10-12 13:27:30 +00:00
env . Append ( CPPDEFINES = [ " __ARM_NEON__ " ] )
2024-05-05 22:15:56 +00:00
if has_swappy :
env . Append ( LIBPATH = [ " ../../thirdparty/swappy-frame-pacing/armeabi-v7a " ] )
2021-12-16 01:38:10 +00:00
elif env [ " arch " ] == " arm64 " :
2020-03-30 06:28:32 +00:00
env . Append ( CCFLAGS = [ " -mfix-cortex-a53-835769 " ] )
env . Append ( CPPDEFINES = [ " __ARM_ARCH_8A__ " ] )
2024-05-05 22:15:56 +00:00
if has_swappy :
env . Append ( LIBPATH = [ " ../../thirdparty/swappy-frame-pacing/arm64-v8a " ] )
2017-07-25 10:28:31 +00:00
2024-07-23 05:52:40 +00:00
env . Append ( CCFLAGS = [ " -ffp-contract=off " ] )
2019-08-27 09:16:33 +00:00
# Link flags
2019-07-30 13:49:31 +00:00
2022-06-01 07:54:08 +00:00
env . Append ( LINKFLAGS = " -Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now " . split ( ) )
env . Append ( LINKFLAGS = " -Wl,-soname,libgodot_android.so " )
2020-03-30 06:28:32 +00:00
env . Prepend ( CPPPATH = [ " #platform/android " ] )
2022-10-03 09:43:20 +00:00
env . Append ( CPPDEFINES = [ " ANDROID_ENABLED " , " UNIX_ENABLED " ] )
2022-11-11 23:30:06 +00:00
env . Append ( LIBS = [ " OpenSLES " , " EGL " , " android " , " log " , " z " , " dl " ] )
2021-08-12 11:24:54 +00:00
if env [ " vulkan " ] :
2023-12-22 12:49:29 +00:00
env . Append ( CPPDEFINES = [ " VULKAN_ENABLED " , " RD_ENABLED " ] )
2024-05-05 22:15:56 +00:00
if has_swappy :
env . Append ( CPPDEFINES = [ " SWAPPY_FRAME_PACING_ENABLED " ] )
env . Append ( LIBS = [ " swappy_static " ] )
2021-08-12 11:24:54 +00:00
if not env [ " use_volk " ] :
env . Append ( LIBS = [ " vulkan " ] )
2022-11-11 23:30:06 +00:00
if env [ " opengl3 " ] :
env . Append ( CPPDEFINES = [ " GLES3_ENABLED " ] )
env . Append ( LIBS = [ " GLESv3 " ] )