2
0

detect.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import os
  2. import sys
  3. import platform
  4. import subprocess
  5. from typing import TYPE_CHECKING
  6. if TYPE_CHECKING:
  7. from SCons import Environment
  8. def is_active():
  9. return True
  10. def get_name():
  11. return "Android"
  12. def can_build():
  13. return os.path.exists(get_env_android_sdk_root())
  14. def get_opts():
  15. return [
  16. ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()),
  17. ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"),
  18. ]
  19. # Return the ANDROID_SDK_ROOT environment variable.
  20. def get_env_android_sdk_root():
  21. return os.environ.get("ANDROID_SDK_ROOT", -1)
  22. def get_min_sdk_version(platform):
  23. return int(platform.split("-")[1])
  24. def get_android_ndk_root(env):
  25. return env["ANDROID_SDK_ROOT"] + "/ndk/" + get_ndk_version()
  26. # This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
  27. def get_ndk_version():
  28. return "23.2.8568313"
  29. def get_flags():
  30. return [
  31. ("arch", "arm64"), # Default for convenience.
  32. ("target", "template_debug"),
  33. ]
  34. # Check if Android NDK version is installed
  35. # If not, install it.
  36. def install_ndk_if_needed(env):
  37. print("Checking for Android NDK...")
  38. sdk_root = env["ANDROID_SDK_ROOT"]
  39. if not os.path.exists(get_android_ndk_root(env)):
  40. extension = ".bat" if os.name == "nt" else ""
  41. sdkmanager = sdk_root + "/cmdline-tools/latest/bin/sdkmanager" + extension
  42. if os.path.exists(sdkmanager):
  43. # Install the Android NDK
  44. print("Installing Android NDK...")
  45. ndk_download_args = "ndk;" + get_ndk_version()
  46. subprocess.check_call([sdkmanager, ndk_download_args])
  47. else:
  48. print("Cannot find " + sdkmanager)
  49. print(
  50. "Please ensure ANDROID_SDK_ROOT is correct and cmdline-tools are installed, or install NDK version "
  51. + get_ndk_version()
  52. + " manually."
  53. )
  54. sys.exit()
  55. env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
  56. def configure(env: "Environment"):
  57. # Validate arch.
  58. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
  59. if env["arch"] not in supported_arches:
  60. print(
  61. 'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.'
  62. % (env["arch"], ", ".join(supported_arches))
  63. )
  64. sys.exit()
  65. install_ndk_if_needed(env)
  66. ndk_root = env["ANDROID_NDK_ROOT"]
  67. # Architecture
  68. if get_min_sdk_version(env["ndk_platform"]) < 21 and env["arch"] in ["x86_64", "arm64"]:
  69. print(
  70. 'WARNING: arch="%s" is not supported with "ndk_platform" lower than "android-21". Forcing platform 21.'
  71. % env["arch"]
  72. )
  73. env["ndk_platform"] = "android-21"
  74. if env["arch"] == "arm32":
  75. target_triple = "armv7a-linux-androideabi"
  76. elif env["arch"] == "arm64":
  77. target_triple = "aarch64-linux-android"
  78. elif env["arch"] == "x86_32":
  79. target_triple = "i686-linux-android"
  80. elif env["arch"] == "x86_64":
  81. target_triple = "x86_64-linux-android"
  82. target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))]
  83. env.Append(ASFLAGS=[target_option, "-c"])
  84. env.Append(CCFLAGS=target_option)
  85. env.Append(LINKFLAGS=target_option)
  86. # LTO
  87. if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet.
  88. env["lto"] = "none"
  89. if env["lto"] != "none":
  90. if env["lto"] == "thin":
  91. env.Append(CCFLAGS=["-flto=thin"])
  92. env.Append(LINKFLAGS=["-flto=thin"])
  93. else:
  94. env.Append(CCFLAGS=["-flto"])
  95. env.Append(LINKFLAGS=["-flto"])
  96. # Compiler configuration
  97. env["SHLIBSUFFIX"] = ".so"
  98. if env["PLATFORM"] == "win32":
  99. env.use_windows_spawn_fix()
  100. if sys.platform.startswith("linux"):
  101. host_subpath = "linux-x86_64"
  102. elif sys.platform.startswith("darwin"):
  103. host_subpath = "darwin-x86_64"
  104. elif sys.platform.startswith("win"):
  105. if platform.machine().endswith("64"):
  106. host_subpath = "windows-x86_64"
  107. else:
  108. host_subpath = "windows"
  109. toolchain_path = ndk_root + "/toolchains/llvm/prebuilt/" + host_subpath
  110. compiler_path = toolchain_path + "/bin"
  111. env["CC"] = compiler_path + "/clang"
  112. env["CXX"] = compiler_path + "/clang++"
  113. env["AR"] = compiler_path + "/llvm-ar"
  114. env["RANLIB"] = compiler_path + "/llvm-ranlib"
  115. env["AS"] = compiler_path + "/clang"
  116. # Disable exceptions on template builds
  117. if not env.editor_build:
  118. env.Append(CXXFLAGS=["-fno-exceptions"])
  119. env.Append(
  120. CCFLAGS=(
  121. "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split()
  122. )
  123. )
  124. if get_min_sdk_version(env["ndk_platform"]) >= 24:
  125. env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
  126. if env["arch"] == "x86_32":
  127. # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
  128. env.Append(CCFLAGS=["-mstackrealign"])
  129. elif env["arch"] == "arm32":
  130. env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
  131. env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
  132. env.Append(CPPDEFINES=["__ARM_NEON__"])
  133. elif env["arch"] == "arm64":
  134. env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
  135. env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
  136. # Link flags
  137. env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split())
  138. env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so")
  139. env.Prepend(CPPPATH=["#platform/android"])
  140. env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
  141. env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"])
  142. if env["vulkan"]:
  143. env.Append(CPPDEFINES=["VULKAN_ENABLED"])
  144. if not env["use_volk"]:
  145. env.Append(LIBS=["vulkan"])
  146. if env["opengl3"]:
  147. env.Append(CPPDEFINES=["GLES3_ENABLED"])
  148. env.Append(LIBS=["GLESv3"])