android-ndk.configure (11340B)
1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- 2 # vim: set filetype=python: 3 # This Source Code Form is subject to the terms of the Mozilla Public 4 # License, v. 2.0. If a copy of the MPL was not distributed with this 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 8 @depends(toolchains_base_dir, "--help") 9 @imports(_from="os.path", _import="isdir") 10 @imports(_from="mozboot.android", _import="NDK_VERSION") 11 def default_android_ndk_root(toolchains_base_dir, _): 12 for ndk in ("android-ndk-%s" % NDK_VERSION, "android-ndk"): 13 path = os.path.join(toolchains_base_dir, ndk) 14 if isdir(path): 15 return path 16 17 18 option( 19 "--with-android-ndk", 20 nargs=1, 21 default=default_android_ndk_root, 22 help="Location where the Android NDK can be found{|}", 23 ) 24 25 option("--with-android-toolchain", nargs=1, help="Location of the Android toolchain") 26 27 option( 28 "--with-android-lldb-server", nargs=1, help="Location of the Android LLDB server" 29 ) 30 31 option( 32 "--with-android-googlevr-sdk", nargs=1, help="Location of the Android GoogleVR SDK" 33 ) 34 35 36 @dependable 37 def min_android_version(): 38 # Sync with android_sdk_version.min_sdk_version 39 return "26" 40 41 42 option( 43 "--with-android-version", 44 nargs=1, 45 help="Android platform version{|}", 46 default=min_android_version, 47 ) 48 49 50 @depends("--with-android-version", min_android_version) 51 @imports(_from="__builtin__", _import="ValueError") 52 def android_version(value, min_version): 53 if not value: 54 # Someone has passed --without-android-version. 55 die("--with-android-version cannot be disabled.") 56 57 try: 58 version = int(value[0]) 59 except ValueError: 60 die("--with-android-version expects an integer value") 61 62 if version < int(min_version): 63 die( 64 "--with-android-version must be at least %s (got %s)", min_version, value[0] 65 ) 66 67 return version 68 69 70 @depends("--with-android-ndk", want_bootstrap) 71 @imports(_from="os.path", _import="isdir") 72 @imports(_from="mozboot.android", _import="get_os_name_for_android") 73 @imports(_from="mozboot.android", _import="ensure_android_ndk") 74 @imports(_from="mozboot.android", _import="NDK_PATH") 75 def ndk(value, want_bootstrap): 76 if value: 77 ndk_path = value[0] 78 if not isdir(ndk_path): 79 die( 80 "The path you specified with --with-android-ndk (%s) is not " 81 "a directory" % ndk_path 82 ) 83 return ndk_path 84 if not want_bootstrap("android-ndk"): 85 die( 86 "You must specify --with-android-ndk=/path/to/ndk when targeting Android, " 87 "or try |mach bootstrap|." 88 ) 89 90 os_name = get_os_name_for_android() 91 92 ensure_android_ndk(os_name) 93 94 return str(NDK_PATH) 95 96 97 set_config("ANDROID_NDK", ndk) 98 99 100 @depends(ndk) 101 @checking("for android ndk version") 102 @imports(_from="__builtin__", _import="open") 103 @imports(_from="mozboot.android", _import="NDK_VERSION") 104 @imports(_from="mozboot.android", _import="get_ndk_version") 105 @imports(_from="mozboot.android", _import="GetNdkVersionError") 106 def ndk_version(ndk): 107 if not ndk: 108 # Building 'js/src' for non-Android. 109 return 110 111 try: 112 major, minor, human = get_ndk_version(ndk) 113 except GetNdkVersionError as e: 114 die(str(e)) 115 116 if NDK_VERSION != human: 117 die( 118 "The only supported version of the NDK is %s (have %s)\n" 119 "Please run |mach bootstrap| " 120 "to install the correct NDK." % (NDK_VERSION, human) 121 ) 122 return namespace( 123 major=major, 124 minor=minor, 125 ) 126 127 128 set_config("ANDROID_NDK_MAJOR_VERSION", ndk_version.major) 129 set_config("ANDROID_NDK_MINOR_VERSION", ndk_version.minor) 130 131 132 @imports(_from="os.path", _import="isdir") 133 @imports(_from="mozshellutil", _import="quote") 134 def host_dir(host, base_dir): 135 dir_format = "%s/%s-%s" 136 host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower() 137 138 dir = dir_format % (base_dir, host_kernel, host.cpu) 139 log.debug("Trying %s" % quote(dir)) 140 if not isdir(dir) and host.cpu == "x86_64": 141 dir = dir_format % (base_dir, host_kernel, "x86") 142 log.debug("Trying %s" % quote(dir)) 143 if not isdir(dir) and host.kernel == "Darwin" and host.cpu == "aarch64": 144 dir = dir_format % (base_dir, host_kernel, "x86_64") 145 log.debug("Trying %s" % quote(dir)) 146 if isdir(dir): 147 return dir 148 149 150 @depends(host, ndk, "--with-android-toolchain") 151 @checking("for the Android toolchain directory", lambda x: x or "not found") 152 def android_toolchain(host, ndk, toolchain): 153 if not ndk: 154 return 155 if toolchain: 156 return toolchain[0] 157 158 toolchain = host_dir(host, os.path.join(ndk, "toolchains", "llvm", "prebuilt")) 159 if toolchain: 160 return toolchain 161 die("You have to specify --with-android-toolchain=" "/path/to/ndk/toolchain.") 162 163 164 @depends(target, android_toolchain) 165 @checking("for android sysroot directory") 166 @imports(_from="os.path", _import="isdir") 167 def android_sysroot(target, android_toolchain): 168 if target.os != "Android": 169 return 170 171 search_dirs = [ 172 os.path.join(android_toolchain, "sysroot"), 173 ] 174 175 for sysroot_dir in search_dirs: 176 if isdir(sysroot_dir): 177 return sysroot_dir 178 179 die( 180 "Android sysroot directory not found in %s." 181 % str([sysroot_dir for sysroot_dir in search_dirs]) 182 ) 183 184 185 @depends(target, host, ndk, "--with-android-lldb-server") 186 @checking("for the Android LLDB server", lambda x: x or "not found") 187 @imports(_from="os", _import="listdir") 188 @imports(_from="os.path", _import="isdir") 189 @imports(_from="os.path", _import="isfile") 190 @imports(_from="mozshellutil", _import="quote") 191 def android_lldb_server(target, host, ndk, lldb): 192 if not ndk: 193 return 194 if lldb: 195 return lldb[0] 196 else: 197 clang_format = "toolchains/llvm/prebuilt/%s-%s/lib/clang" 198 llvm_lib = "lib/linux" 199 200 host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower() 201 clang_path = os.path.join(ndk, clang_format % (host_kernel, host.cpu)) 202 if not isdir(clang_path) and host.kernel == "Darwin" and host.cpu == "aarch64": 203 clang_path = os.path.join(ndk, clang_format % (host_kernel, "x86_64")) 204 log.debug("Listing subdirectories of %s" % quote(clang_path)) 205 clang_subdirs = [ 206 x for x in listdir(clang_path) if isdir(os.path.join(clang_path, x)) 207 ] 208 log.debug("Got %r" % clang_subdirs) 209 if len(clang_subdirs) == 0: 210 die( 211 "Could not resolve lldb-server in %s. Please specify --with-android-lldb-server=/path/to/android/lldb-server" 212 % quote(clang_path) 213 ) 214 sorted_versions = sorted(clang_subdirs, key=Version) 215 highest_version = sorted_versions[-1] 216 217 if len(sorted_versions) > 1: 218 log.warning("Using highest version available: %s" % quote(highest_version)) 219 log.warning( 220 " Available versions: " 221 + ", ".join(str(version) for version in sorted_versions) 222 ) 223 log.warning( 224 "(To use an older version, please specify --with-android-lldb-server=/path/to/desired/android/lldb-server)" 225 ) 226 227 if target.cpu == "x86": 228 target_cpu = "i386" 229 else: 230 target_cpu = target.cpu 231 232 full_path = os.path.join( 233 clang_path, highest_version, llvm_lib, target_cpu, "lldb-server" 234 ) 235 log.debug("Trying %s" % quote(full_path)) 236 237 if isfile(full_path): 238 return full_path 239 die("Please specify --with-android-lldb-server=/path/to/android/lldb-server") 240 241 242 set_config("ANDROID_LLDB_SERVER", android_lldb_server) 243 244 245 option( 246 env="STLPORT_LIBS", 247 nargs=1, 248 help="Options linker should pass for standard C++ library", 249 ) 250 251 252 @depends("STLPORT_LIBS", ndk) 253 @imports(_from="os.path", _import="isfile") 254 def stlport_libs(value, ndk): 255 if value and len(value): 256 return value.split() 257 if not ndk: 258 return 259 260 return ["-static-libstdc++"] 261 262 263 set_config("STLPORT_LIBS", stlport_libs) 264 265 266 @depends(android_sysroot, android_toolchain) 267 def extra_toolchain_flags(android_sysroot, toolchain_dir): 268 if not android_sysroot: 269 return [] 270 flags = [ 271 "--sysroot={}".format(android_sysroot), 272 "--gcc-toolchain={}".format(toolchain_dir), 273 ] 274 return flags 275 276 277 @depends(extra_toolchain_flags) 278 def android_flags(extra_toolchain_flags): 279 wead_symbols_defines = [ 280 "-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__", 281 ] 282 weak_symbols_flags = wead_symbols_defines + [ 283 "-Werror=unguarded-availability", 284 ] 285 return namespace( 286 cflags=extra_toolchain_flags 287 + [ 288 "-fno-short-enums", 289 ] 290 + weak_symbols_flags, 291 cxxflags=extra_toolchain_flags 292 + [ 293 "-fno-short-enums", 294 ] 295 + weak_symbols_flags, 296 ldflags=extra_toolchain_flags, 297 asflags=extra_toolchain_flags 298 + [ 299 "-DANDROID", 300 ] 301 + wead_symbols_defines, 302 ) 303 304 305 @depends(host, ndk) 306 @imports(_from="os", _import="listdir") 307 @imports(_from="os.path", _import="isfile") 308 @imports(_from="os.path", _import="isdir") 309 def android_system_headers(host, ndk): 310 if not ndk: 311 return 312 host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower() 313 android_fmt = "toolchains/llvm/prebuilt/{}-{}/sysroot/usr/include/android" 314 android_includes = os.path.join(ndk, android_fmt.format(host_kernel, host.cpu)) 315 316 if ( 317 not isdir(android_includes) 318 and host.kernel == "Darwin" 319 and host.cpu == "aarch64" 320 ): 321 android_includes = os.path.join(ndk, android_fmt.format(host_kernel, "x86_64")) 322 323 return [ 324 f"android/{header}" 325 for header in listdir(android_includes) 326 if isfile(os.path.join(android_includes, header)) 327 ] 328 329 330 set_config("ANDROID_SYSTEM_HEADERS", android_system_headers) 331 332 333 @depends(extra_toolchain_flags) 334 def bindgen_cflags_android(toolchain_flags): 335 return toolchain_flags 336 337 338 @depends("--with-android-googlevr-sdk", target) 339 @checking("for GoogleVR SDK", lambda x: x.result) 340 @imports(_from="os.path", _import="exists") 341 @imports(_from="os.path", _import="abspath") 342 def googlevr_sdk(value, target): 343 if not value: 344 return namespace(result="Not specified") 345 path = abspath(value[0]) 346 if not exists(path): 347 die("Could not find GoogleVR SDK %s", path) 348 include = "%s/libraries/headers/" % path 349 if "arm" == target.cpu: 350 arch = "armeabi-v7a" 351 elif "aarch64" == target.cpu: 352 arch = "arm64-v8a" 353 elif "x86" == target.cpu: 354 arch = "x86" 355 else: 356 die("Unsupported GoogleVR cpu architecture %s" % target.cpu) 357 358 libs = "{0}/libraries/jni/{1}/".format(path, arch) 359 360 if not exists(libs): 361 die( 362 "Could not find GoogleVR NDK at %s. Did you try running " 363 "'./gradlew :extractNdk' in %s?", 364 libs, 365 path, 366 ) 367 368 return namespace( 369 result=path, 370 include=include, 371 libs=libs, 372 enabled=True, 373 ) 374 375 376 set_define("MOZ_ANDROID_GOOGLE_VR", googlevr_sdk.enabled) 377 set_config("MOZ_ANDROID_GOOGLE_VR", googlevr_sdk.enabled) 378 set_config("MOZ_ANDROID_GOOGLE_VR_LIBS", googlevr_sdk.libs)