android.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import os
  2. import sys
  3. import common_compiler_flags
  4. import my_spawn
  5. def options(opts):
  6. opts.Add(
  7. "android_api_level",
  8. "Target Android API level",
  9. "21",
  10. )
  11. opts.Add(
  12. "ANDROID_HOME",
  13. "Path to your Android SDK installation. By default, uses ANDROID_HOME from your defined environment variables.",
  14. os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")),
  15. )
  16. def exists(env):
  17. return get_android_ndk_root(env) is not None
  18. # This must be kept in sync with the value in https://github.com/godotengine/godot/blob/master/platform/android/detect.py#L58.
  19. def get_ndk_version():
  20. return "23.2.8568313"
  21. def get_android_ndk_root(env):
  22. if env["ANDROID_HOME"]:
  23. return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
  24. else:
  25. return os.environ.get("ANDROID_NDK_ROOT")
  26. def generate(env):
  27. if get_android_ndk_root(env) is None:
  28. raise ValueError(
  29. "To build for Android, the path to the NDK must be defined. Please set ANDROID_HOME to the root folder of your Android SDK installation."
  30. )
  31. if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
  32. print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
  33. env.Exit(1)
  34. if sys.platform == "win32" or sys.platform == "msys":
  35. my_spawn.configure(env)
  36. # Validate API level
  37. if int(env["android_api_level"]) < 21:
  38. print("WARNING: minimum supported Android target api is 21. Forcing target api 21.")
  39. env["android_api_level"] = "21"
  40. # Setup toolchain
  41. toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"
  42. if sys.platform == "win32" or sys.platform == "msys":
  43. toolchain += "windows"
  44. import platform as pltfm
  45. if pltfm.machine().endswith("64"):
  46. toolchain += "-x86_64"
  47. elif sys.platform.startswith("linux"):
  48. toolchain += "linux-x86_64"
  49. elif sys.platform == "darwin":
  50. toolchain += "darwin-x86_64"
  51. env.Append(LINKFLAGS=["-shared"])
  52. if not os.path.exists(toolchain):
  53. print("ERROR: Could not find NDK toolchain at " + toolchain + ".")
  54. print("Make sure NDK version " + get_ndk_version() + " is installed.")
  55. env.Exit(1)
  56. env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
  57. # Get architecture info
  58. arch_info_table = {
  59. "arm32": {
  60. "march": "armv7-a",
  61. "target": "armv7a-linux-androideabi",
  62. "compiler_path": "armv7a-linux-androideabi",
  63. "ccflags": ["-mfpu=neon"],
  64. },
  65. "arm64": {
  66. "march": "armv8-a",
  67. "target": "aarch64-linux-android",
  68. "compiler_path": "aarch64-linux-android",
  69. "ccflags": [],
  70. },
  71. "x86_32": {
  72. "march": "i686",
  73. "target": "i686-linux-android",
  74. "compiler_path": "i686-linux-android",
  75. "ccflags": ["-mstackrealign"],
  76. },
  77. "x86_64": {
  78. "march": "x86-64",
  79. "target": "x86_64-linux-android",
  80. "compiler_path": "x86_64-linux-android",
  81. "ccflags": [],
  82. },
  83. }
  84. arch_info = arch_info_table[env["arch"]]
  85. # Setup tools
  86. env["CC"] = toolchain + "/bin/clang"
  87. env["CXX"] = toolchain + "/bin/clang++"
  88. env["LINK"] = toolchain + "/bin/clang++"
  89. env["AR"] = toolchain + "/bin/llvm-ar"
  90. env["AS"] = toolchain + "/bin/llvm-as"
  91. env["STRIP"] = toolchain + "/bin/llvm-strip"
  92. env["RANLIB"] = toolchain + "/bin/llvm-ranlib"
  93. env["SHLIBSUFFIX"] = ".so"
  94. env.Append(
  95. CCFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"], "-fPIC"]
  96. )
  97. env.Append(CCFLAGS=arch_info["ccflags"])
  98. env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
  99. env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
  100. # Refer to https://github.com/godotengine/godot/blob/master/platform/android/detect.py
  101. # LTO benefits for Android (size, performance) haven't been clearly established yet.
  102. if env["lto"] == "auto":
  103. env["lto"] = "none"
  104. common_compiler_flags.generate(env)