#!/usr/bin/python # This script is used to generate luabinding glue codes. # Android ndk version must be ndk-r9b. import argparse import sys import os, os.path import shutil import subprocess import re from contextlib import contextmanager g_ndk_root = None def _check_ndk_root_env(): ''' Checking the environment ANDROID_NDK, which will be used for building ''' try: ANDROID_NDK = None sdkRoot = os.environ.get('ANDROID_SDK_ROOT', None) for _, ndkVers, _ in os.walk("{0}{1}ndk".format(sdkRoot, os.path.sep)): for ndkVer in ndkVers: if (ndkVer == '19.2.5345600'): ANDROID_NDK = "{0}{1}ndk{1}{2}".format(sdkRoot, os.path.sep, ndkVer) break break if ANDROID_NDK == None: ANDROID_NDK = os.environ.get('ANDROID_NDK', None) except: print('Exception occurred when check_ndk_root_env!') return ANDROID_NDK def _check_python_bin_env(): ''' Checking the environment PYTHON_BIN, which will be used for building ''' try: PYTHON_BIN = os.environ['PYTHON_BIN'] except Exception: print("PYTHON_BIN not defined, use current python.") PYTHON_BIN = sys.executable return PYTHON_BIN def _find_first_file_in_dir(dir, fn): if os.path.isfile(dir): if os.path.basename(dir) == fn: return os.path.join(os.path.dirname(dir), fn) else : return None elif os.path.isdir(dir): for subdir in os.listdir(dir): searchPath = _find_first_file_in_dir(os.path.join(dir, subdir), fn) if searchPath is not None: return searchPath else: return None def _find_all_files_match(dir, cond, all): if cond(dir): all.append(dir) elif os.path.isdir(dir): for subdir in os.listdir(dir): _find_all_files_match(os.path.join(dir, subdir), cond, all) def _find_toolchain_include_path(): global g_ndk_root ''' Search gcc prebuilt include path for instance: "$ANDROID_NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/include" ''' foundFiles = [] _find_all_files_match(os.path.join(g_ndk_root, "toolchains"), lambda x : os.path.basename(x) == "stdarg.h" and "arm-linux-androideabi" in x , foundFiles) if len(foundFiles) == 0: return "" else: return "-I" + os.path.dirname(foundFiles[0]) def _find_llvm_include_path(): ''' Search llvm prebuilt include path. for instance: "$ANDROID_NDK/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/6.0.2/include" ''' global g_ndk_root versionFile = _find_first_file_in_dir(g_ndk_root, "AndroidVersion.txt") if versionFile is None: return "" versionDir = os.path.dirname(versionFile) includeDir = _find_first_file_in_dir(versionDir, "stdarg.h") llvmIncludePath = os.path.dirname(includeDir) return "-I"+llvmIncludePath def _defaultIncludePath(): '''default include path for libclang, llvm & gcc include path ''' llvmInclude = _find_llvm_include_path() toolchainInclude = _find_toolchain_include_path() exactIncludes = llvmInclude + " " + toolchainInclude return exactIncludes class CmdError(Exception): pass @contextmanager def _pushd(newDir): previousDir = os.getcwd() os.chdir(newDir) yield os.chdir(previousDir) def _run_cmd(command): ret = subprocess.call(command, shell=True) if ret != 0: message = "Error running command" raise CmdError(message) def main(): global g_ndk_root cur_platform= '??' llvm_path = '??' if (g_ndk_root == None or not os.path.isdir(g_ndk_root)): g_ndk_root = _check_ndk_root_env() if not os.path.isdir(g_ndk_root): print("The ndk-r19c root not specified, please specifiy via --ndk_root '/path/to/ndk'") sys.exit(1) # del the " in the path g_ndk_root = re.sub(r"\"", "", g_ndk_root) python_bin = _check_python_bin_env() platform = sys.platform if platform == 'win32': cur_platform = 'windows' elif platform == 'darwin': cur_platform = platform elif 'linux' in platform: cur_platform = 'linux' else: print('Your platform is not supported!') sys.exit(1) x86_llvm_path = "" x64_llvm_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/llvm/prebuilt', '%s-%s' % (cur_platform, 'x86_64'))) if not os.path.exists(x64_llvm_path): x86_llvm_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/llvm/prebuilt', '%s' % (cur_platform))) if not os.path.exists(x86_llvm_path): x86_llvm_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/llvm/prebuilt', '%s-%s' % (cur_platform, 'x86'))) if os.path.isdir(x64_llvm_path): llvm_path = x64_llvm_path elif os.path.isdir(x86_llvm_path): llvm_path = x86_llvm_path else: print('llvm toolchain not found!') print('path: %s or path: %s are not valid! ' % (x86_llvm_path, x64_llvm_path)) sys.exit(1) x86_gcc_toolchain_path = "" x64_gcc_toolchain_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/arm-linux-androideabi-4.9/prebuilt', '%s-%s' % (cur_platform, 'x86_64'))) if not os.path.exists(x64_gcc_toolchain_path): x86_gcc_toolchain_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/arm-linux-androideabi-4.9/prebuilt', '%s' % (cur_platform))) if not os.path.exists(x86_gcc_toolchain_path): x86_gcc_toolchain_path = os.path.abspath(os.path.join(g_ndk_root, 'toolchains/arm-linux-androideabi-4.9/prebuilt', '%s-%s' % (cur_platform, 'x86'))) if os.path.isdir(x64_gcc_toolchain_path): gcc_toolchain_path = x64_gcc_toolchain_path elif os.path.isdir(x86_gcc_toolchain_path): gcc_toolchain_path = x86_gcc_toolchain_path else: print('gcc toolchain not found!') print('path: %s or path: %s are not valid! ' % (x64_gcc_toolchain_path, x86_gcc_toolchain_path)) sys.exit(1) project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) ax_root = os.path.abspath(os.path.join(project_root, '')) cxx_generator_root = os.path.abspath(os.path.join(project_root, 'tools/bindings-generator')) extraFlags = _defaultIncludePath() # save config to file if(sys.version_info.major >= 3): import configparser # import ConfigParser config = configparser.ConfigParser() else: import ConfigParser config = ConfigParser.ConfigParser() config.set('DEFAULT', 'androidndkdir', g_ndk_root) config.set('DEFAULT', 'clangllvmdir', llvm_path) config.set('DEFAULT', 'gcc_toolchain_dir', gcc_toolchain_path) config.set('DEFAULT', 'axdir', ax_root) config.set('DEFAULT', 'cxxgeneratordir', cxx_generator_root) config.set('DEFAULT', 'extra_flags', extraFlags) conf_ini_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'userconf.ini')) print('generating userconf.ini...') with open(conf_ini_file, 'w') as configfile: config.write(configfile) # set proper environment variables if 'linux' in platform or platform == 'darwin': os.putenv('LD_LIBRARY_PATH', '%s/libclang' % cxx_generator_root) if platform == 'win32': path_env = os.environ['PATH'] os.putenv('PATH', r'%s;%s\libclang;%s\tools\win32;' % (path_env, cxx_generator_root, cxx_generator_root)) try: tolua_root = '%s/tools/tolua' % project_root output_dir = '%s/extensions/scripting/lua-bindings/auto' % project_root cmd_args = { 'ax_base.ini' : ('ax_base', 'axlua_base_auto'), \ 'ax_backend.ini' : ('ax_backend', 'axlua_backend_auto'), \ 'ax_extension.ini' : ('ax_extension', 'axlua_extension_auto'), \ 'ax_ui.ini' : ('ax_ui', 'axlua_ui_auto'), \ 'ax_studio.ini' : ('ax_studio', 'axlua_studio_auto'), \ 'ax_spine.ini' : ('ax_spine', 'axlua_spine_auto'), \ 'ax_physics.ini' : ('ax_physics', 'axlua_physics_auto'), \ 'ax_video.ini' : ('ax_video', 'axlua_video_auto'), \ 'ax_controller.ini' : ('ax_controller', 'axlua_controller_auto'), \ 'ax_3d.ini': ('ax_3d', 'axlua_3d_auto'), \ 'ax_audioengine.ini': ('ax_audioengine', 'axlua_audioengine_auto'), \ 'ax_csloader.ini' : ('ax_csloader', 'axlua_csloader_auto'), \ 'ax_webview.ini' : ('ax_webview', 'axlua_webview_auto'), \ 'ax_physics3d.ini' : ('ax_physics3d', 'axlua_physics3d_auto'), \ 'ax_navmesh.ini' : ('ax_navmesh', 'axlua_navmesh_auto'), \ } target = 'lua' generator_py = '%s/generator.py' % cxx_generator_root for key in cmd_args.keys(): args = cmd_args[key] cfg = '%s/%s' % (tolua_root, key) print('Generating bindings for %s...' % (key[:-4])) command = '%s %s %s -s %s -t %s -o %s -n %s' % (python_bin, generator_py, cfg, args[0], target, output_dir, args[1]) print(command) _run_cmd(command) print('---------------------------------') print('Generating lua bindings succeeds.') print('---------------------------------') except Exception as e: if e.__class__.__name__ == 'CmdError': print('---------------------------------') print('Generating lua bindings fails.') print('---------------------------------') sys.exit(1) else: raise # -------------- main -------------- if __name__ == '__main__': parser = argparse.ArgumentParser(description='Install android sdk/ndk') parser.add_argument("--ndk_root", help="Specificy ndk root") args = parser.parse_args() g_ndk_root = args.ndk_root main()