Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/android/detect.py
10277 views
1
import os
2
import platform
3
import subprocess
4
import sys
5
from typing import TYPE_CHECKING
6
7
from methods import print_error, print_warning
8
from platform_methods import validate_arch
9
10
if TYPE_CHECKING:
11
from SCons.Script.SConscript import SConsEnvironment
12
13
14
def get_name():
15
return "Android"
16
17
18
def can_build():
19
return os.path.exists(get_env_android_sdk_root())
20
21
22
def get_tools(env: "SConsEnvironment"):
23
return ["clang", "clang++", "as", "ar", "link"]
24
25
26
def get_opts():
27
from SCons.Variables import BoolVariable
28
29
return [
30
("ANDROID_HOME", "Path to the Android SDK", get_env_android_sdk_root()),
31
(
32
"ndk_platform",
33
'Target platform (android-<api>, e.g. "android-' + str(get_min_target_api()) + '")',
34
"android-" + str(get_min_target_api()),
35
),
36
BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False),
37
BoolVariable(
38
("generate_android_binaries", "generate_apk"),
39
"Generate APK, AAB & AAR binaries after building Android library by calling Gradle",
40
False,
41
),
42
BoolVariable("swappy", "Use Swappy Frame Pacing library", False),
43
]
44
45
46
def get_doc_classes():
47
return [
48
"EditorExportPlatformAndroid",
49
]
50
51
52
def get_doc_path():
53
return "doc_classes"
54
55
56
# Return the ANDROID_HOME environment variable.
57
def get_env_android_sdk_root():
58
return os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT", ""))
59
60
61
def get_min_sdk_version(platform):
62
return int(platform.split("-")[1])
63
64
65
def get_android_ndk_root(env: "SConsEnvironment"):
66
return os.path.join(env["ANDROID_HOME"], "ndk", get_ndk_version())
67
68
69
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
70
def get_ndk_version():
71
return "28.1.13356709"
72
73
74
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
75
def get_min_target_api():
76
return 24
77
78
79
def get_flags():
80
return {
81
"arch": "arm64",
82
"target": "template_debug",
83
"supported": ["mono"],
84
}
85
86
87
# Check if Android NDK version is installed
88
# If not, install it.
89
def install_ndk_if_needed(env: "SConsEnvironment"):
90
sdk_root = env["ANDROID_HOME"]
91
if not os.path.exists(get_android_ndk_root(env)):
92
extension = ".bat" if os.name == "nt" else ""
93
sdkmanager = os.path.join(sdk_root, "cmdline-tools", "latest", "bin", "sdkmanager" + extension)
94
if os.path.exists(sdkmanager):
95
# Install the Android NDK
96
print("Installing Android NDK...")
97
ndk_download_args = "ndk;" + get_ndk_version()
98
subprocess.check_call([sdkmanager, ndk_download_args])
99
else:
100
print_error(
101
f'Cannot find "{sdkmanager}". Please ensure ANDROID_HOME is correct and cmdline-tools'
102
f' are installed, or install NDK version "{get_ndk_version()}" manually.'
103
)
104
sys.exit(255)
105
env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
106
107
108
def detect_swappy():
109
archs = ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"]
110
has_swappy = True
111
for arch in archs:
112
if not os.path.isfile(f"thirdparty/swappy-frame-pacing/{arch}/libswappy_static.a"):
113
has_swappy = False
114
return has_swappy
115
116
117
def configure(env: "SConsEnvironment"):
118
# Validate arch.
119
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
120
validate_arch(env["arch"], get_name(), supported_arches)
121
122
if get_min_sdk_version(env["ndk_platform"]) < get_min_target_api():
123
print_warning(
124
"Minimum supported Android target api is %d. Forcing target api %d."
125
% (get_min_target_api(), get_min_target_api())
126
)
127
env["ndk_platform"] = "android-" + str(get_min_target_api())
128
129
install_ndk_if_needed(env)
130
ndk_root = env["ANDROID_NDK_ROOT"]
131
132
# Architecture
133
134
if env["arch"] == "arm32":
135
target_triple = "armv7a-linux-androideabi"
136
elif env["arch"] == "arm64":
137
target_triple = "aarch64-linux-android"
138
elif env["arch"] == "x86_32":
139
target_triple = "i686-linux-android"
140
elif env["arch"] == "x86_64":
141
target_triple = "x86_64-linux-android"
142
143
target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))]
144
env.Append(ASFLAGS=[target_option, "-c"])
145
env.Append(CCFLAGS=target_option)
146
env.Append(LINKFLAGS=target_option)
147
148
# LTO
149
150
if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet.
151
env["lto"] = "none"
152
153
if env["lto"] != "none":
154
if env["lto"] == "thin":
155
env.Append(CCFLAGS=["-flto=thin"])
156
env.Append(LINKFLAGS=["-flto=thin"])
157
else:
158
env.Append(CCFLAGS=["-flto"])
159
env.Append(LINKFLAGS=["-flto"])
160
161
# Compiler configuration
162
163
env["SHLIBSUFFIX"] = ".so"
164
165
if env["PLATFORM"] == "win32":
166
env.use_windows_spawn_fix()
167
168
if sys.platform.startswith("linux"):
169
host_subpath = "linux-x86_64"
170
elif sys.platform.startswith("darwin"):
171
host_subpath = "darwin-x86_64"
172
elif sys.platform.startswith("win"):
173
if platform.machine().endswith("64"):
174
host_subpath = "windows-x86_64"
175
else:
176
host_subpath = "windows"
177
178
toolchain_path = os.path.join(ndk_root, "toolchains", "llvm", "prebuilt", host_subpath)
179
compiler_path = os.path.join(toolchain_path, "bin")
180
181
env["CC"] = os.path.join(compiler_path, "clang")
182
env["CXX"] = os.path.join(compiler_path, "clang++")
183
env["AR"] = os.path.join(compiler_path, "llvm-ar")
184
env["RANLIB"] = os.path.join(compiler_path, "llvm-ranlib")
185
env["AS"] = os.path.join(compiler_path, "clang")
186
187
env.Append(
188
CCFLAGS=(["-fpic", "-ffunction-sections", "-funwind-tables", "-fstack-protector-strong", "-fvisibility=hidden"])
189
)
190
191
has_swappy = detect_swappy()
192
if not has_swappy:
193
print_warning(
194
"Swappy Frame Pacing not detected! It is strongly recommended you download it from https://github.com/godotengine/godot-swappy/releases and extract it so that the following files can be found:\n"
195
+ " thirdparty/swappy-frame-pacing/arm64-v8a/libswappy_static.a\n"
196
+ " thirdparty/swappy-frame-pacing/armeabi-v7a/libswappy_static.a\n"
197
+ " thirdparty/swappy-frame-pacing/x86/libswappy_static.a\n"
198
+ " thirdparty/swappy-frame-pacing/x86_64/libswappy_static.a\n"
199
+ "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."
200
)
201
if env["swappy"]:
202
print_error("Use build option `swappy=no` to ignore missing Swappy dependency and build without it.")
203
sys.exit(255)
204
205
if get_min_sdk_version(env["ndk_platform"]) >= 24:
206
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
207
208
if env["arch"] == "x86_32":
209
if has_swappy:
210
env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86"])
211
elif env["arch"] == "x86_64":
212
if has_swappy:
213
env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86_64"])
214
elif env["arch"] == "arm32":
215
env.Append(CCFLAGS=["-march=armv7-a", "-mfloat-abi=softfp"])
216
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
217
env.Append(CPPDEFINES=["__ARM_NEON__"])
218
if has_swappy:
219
env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/armeabi-v7a"])
220
elif env["arch"] == "arm64":
221
env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
222
env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
223
if has_swappy:
224
env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/arm64-v8a"])
225
226
env.Append(CCFLAGS=["-ffp-contract=off"])
227
228
# Link flags
229
230
env.Append(LINKFLAGS=["-Wl,--gc-sections", "-Wl,--no-undefined", "-Wl,-z,now"])
231
env.Append(LINKFLAGS=["-Wl,--build-id"])
232
env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
233
234
env.Prepend(CPPPATH=["#platform/android"])
235
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
236
env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"])
237
238
if env["vulkan"]:
239
env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
240
if has_swappy:
241
env.Append(CPPDEFINES=["SWAPPY_FRAME_PACING_ENABLED"])
242
env.Append(LIBS=["swappy_static"])
243
if not env["use_volk"]:
244
env.Append(LIBS=["vulkan"])
245
246
if env["opengl3"]:
247
env.Append(CPPDEFINES=["GLES3_ENABLED"])
248
env.Append(LIBS=["GLESv3"])
249
250