android.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import os
  2. import sys
  3. import my_spawn
  4. from SCons.Script import ARGUMENTS
  5. def options(opts):
  6. opts.Add(
  7. "android_api_level",
  8. "Target Android API level",
  9. "18" if "32" in ARGUMENTS.get("arch", "arm64") else "21",
  10. )
  11. opts.Add(
  12. "ANDROID_NDK_ROOT",
  13. "Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.",
  14. os.environ.get("ANDROID_NDK_ROOT", None),
  15. )
  16. def exists(env):
  17. if not "ANDROID_NDK_ROOT" in os.environ:
  18. return False
  19. return True
  20. def generate(env):
  21. if not "ANDROID_NDK_ROOT" in os.environ:
  22. raise ValueError(
  23. "To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation."
  24. )
  25. env["ANDROID_NDK_ROOT"] = os.environ["ANDROID_NDK_ROOT"]
  26. if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
  27. print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
  28. Exit()
  29. if sys.platform == "win32" or sys.platform == "msys":
  30. my_spawn.configure(env)
  31. # Validate API level
  32. api_level = int(env["android_api_level"])
  33. if "64" in env["arch"] and api_level < 21:
  34. print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
  35. env["android_api_level"] = "21"
  36. api_level = 21
  37. # Setup toolchain
  38. toolchain = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/"
  39. if sys.platform == "win32" or sys.platform == "msys":
  40. toolchain += "windows"
  41. import platform as pltfm
  42. if pltfm.machine().endswith("64"):
  43. toolchain += "-x86_64"
  44. elif sys.platform.startswith("linux"):
  45. toolchain += "linux-x86_64"
  46. elif sys.platform == "darwin":
  47. toolchain += "darwin-x86_64"
  48. env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
  49. # Get architecture info
  50. arch_info_table = {
  51. "arm32": {
  52. "march": "armv7-a",
  53. "target": "armv7a-linux-androideabi",
  54. "compiler_path": "armv7a-linux-androideabi",
  55. "ccflags": ["-mfpu=neon"],
  56. },
  57. "arm64": {
  58. "march": "armv8-a",
  59. "target": "aarch64-linux-android",
  60. "compiler_path": "aarch64-linux-android",
  61. "ccflags": [],
  62. },
  63. "x86_32": {
  64. "march": "i686",
  65. "target": "i686-linux-android",
  66. "compiler_path": "i686-linux-android",
  67. "ccflags": ["-mstackrealign"],
  68. },
  69. "x86_64": {
  70. "march": "x86-64",
  71. "target": "x86_64-linux-android",
  72. "compiler_path": "x86_64-linux-android",
  73. "ccflags": [],
  74. },
  75. }
  76. arch_info = arch_info_table[env["arch"]]
  77. # Setup tools
  78. env["CC"] = toolchain + "/bin/clang"
  79. env["CXX"] = toolchain + "/bin/clang++"
  80. env["LINK"] = toolchain + "/bin/clang++"
  81. env["AR"] = toolchain + "/bin/llvm-ar"
  82. env["AS"] = toolchain + "/bin/llvm-as"
  83. env["STRIP"] = toolchain + "/bin/llvm-strip"
  84. env["RANLIB"] = toolchain + "/bin/llvm-ranlib"
  85. env["SHLIBSUFFIX"] = ".so"
  86. env.Append(
  87. CCFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"], "-fPIC"]
  88. ) # , '-fPIE', '-fno-addrsig', '-Oz'])
  89. env.Append(CCFLAGS=arch_info["ccflags"])
  90. env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
  91. if env["target"] == "debug":
  92. env.Append(CCFLAGS=["-Og", "-g"])
  93. elif env["target"] == "release":
  94. env.Append(CCFLAGS=["-O3"])