From f8a7e7000024c67abfa58eb89e2e26a29a9ef100 Mon Sep 17 00:00:00 2001 From: zhangbin Date: Wed, 30 Jul 2014 15:44:15 +0800 Subject: [PATCH] Add tools to generate prebuilt engine for Cocos Engine. --- tools/gen-prebuilt/.gitignore | 4 + tools/gen-prebuilt/README.md | 41 +++ tools/gen-prebuilt/build_config.json | 19 ++ tools/gen-prebuilt/excopy.py | 100 +++++++ tools/gen-prebuilt/gen_prebuilt_libs.py | 361 ++++++++++++++++++++++++ tools/gen-prebuilt/module_config.json | 329 +++++++++++++++++++++ tools/gen-prebuilt/module_organize.py | 239 ++++++++++++++++ 7 files changed, 1093 insertions(+) create mode 100644 tools/gen-prebuilt/.gitignore create mode 100644 tools/gen-prebuilt/README.md create mode 100644 tools/gen-prebuilt/build_config.json create mode 100644 tools/gen-prebuilt/excopy.py create mode 100644 tools/gen-prebuilt/gen_prebuilt_libs.py create mode 100644 tools/gen-prebuilt/module_config.json create mode 100644 tools/gen-prebuilt/module_organize.py diff --git a/tools/gen-prebuilt/.gitignore b/tools/gen-prebuilt/.gitignore new file mode 100644 index 0000000000..71c422c076 --- /dev/null +++ b/tools/gen-prebuilt/.gitignore @@ -0,0 +1,4 @@ +.idea/* +build/* +prebuilt* +cocos2d-x/* diff --git a/tools/gen-prebuilt/README.md b/tools/gen-prebuilt/README.md new file mode 100644 index 0000000000..e762a37e06 --- /dev/null +++ b/tools/gen-prebuilt/README.md @@ -0,0 +1,41 @@ + +# Generate prebuilt engine + +## Purpose + +The tools in `gen-prebuilt` are used for generating prebuilt engine. + +## Steps + +1. Generate prebuilt libs + * First, build libs for `Mac, iOS & android`: Run `python gen_prebuilt_libs.py` on Mac. + * Second, build libs for `Windows`: Run `python gen_prebuilt_libs.py -n` on Windows. +2. Organize the prebuilt libs with modules + Run command `python module_organize.py` on Windows or Mac. + +## Script Details + +1. gen_prebuilt_libs.py + + ``` + Usage: gen_prebuilt_libs.py [options] + + Options: + -c Remove the "prebuilt" directory first. + -n, --no-android Not build android libs. + -s, --strip Enable strip when generating iOS, Mac & Android libs. + -i, --incredibuild Use incredibuild to build win32 projects. Only available on windows. + ``` + + The result of the script is : A folder named `prebuilt` which contains prebuilt libs will generated. + +2. module_organize.py + + ``` + Usage: module_organize.py [options] + + Options: + -d, --dst-root Specify a path where to place the engine organized by modules. Default value is the same path with `module_organize.py`. + ``` + + The result of the script is : A folder named `cocos2d-x` will generated in the `dst-root`. \ No newline at end of file diff --git a/tools/gen-prebuilt/build_config.json b/tools/gen-prebuilt/build_config.json new file mode 100644 index 0000000000..e41969c1cd --- /dev/null +++ b/tools/gen-prebuilt/build_config.json @@ -0,0 +1,19 @@ +{ + "xcode_proj_info" : { + "build/cocos2d_libs.xcodeproj" : { + "outputdir" : "prebuilt", + "targets" :[ "build all libs" ] + } + }, + "win32_proj_info" : { + "build/cocos2d-win32.vc2012.sln" : { + "outputdir" : "prebuilt/win32", + "targets" : [ + "libcocosdenshion", "libbox2d", "libchipmunk", + "libcocos2d", "libcocosbuilder", "libcocostudio", + "libextension", "libui", "liblua", + "libnetwork", "libspine" + ] + } + } +} diff --git a/tools/gen-prebuilt/excopy.py b/tools/gen-prebuilt/excopy.py new file mode 100644 index 0000000000..4b4877d726 --- /dev/null +++ b/tools/gen-prebuilt/excopy.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# ---------------------------------------------------------------------------- +# extend methods for copy files/dirs +# +# Copyright 2014 (C) zhangbin +# +# License: MIT +# ---------------------------------------------------------------------------- + +import os +import shutil + +def copy_files_in_dir(src, dst): + + for item in os.listdir(src): + path = os.path.join(src, item) + if os.path.isfile(path): + shutil.copy(path, dst) + if os.path.isdir(path): + new_dst = os.path.join(dst, item) + if not os.path.isdir(new_dst): + os.makedirs(new_dst) + copy_files_in_dir(path, new_dst) + +def copy_files_with_config(config, src_root, dst_root): + src_dir = config["from"] + dst_dir = config["to"] + + src_dir = os.path.join(src_root, src_dir) + dst_dir = os.path.join(dst_root, dst_dir) + + include_rules = None + if config.has_key("include"): + include_rules = config["include"] + include_rules = convert_rules(include_rules) + + exclude_rules = None + if config.has_key("exclude"): + exclude_rules = config["exclude"] + exclude_rules = convert_rules(exclude_rules) + + copy_files_with_rules(src_dir, src_dir, dst_dir, include_rules, exclude_rules) + +def copy_files_with_rules(src_rootDir, src, dst, include = None, exclude = None): + if os.path.isfile(src): + if not os.path.exists(dst): + os.makedirs(dst) + shutil.copy(src, dst) + return + + if (include is None) and (exclude is None): + if not os.path.exists(dst): + os.makedirs(dst) + copy_files_in_dir(src, dst) + elif (include is not None): + # have include + for name in os.listdir(src): + abs_path = os.path.join(src, name) + rel_path = os.path.relpath(abs_path, src_rootDir) + if os.path.isdir(abs_path): + sub_dst = os.path.join(dst, name) + copy_files_with_rules(src_rootDir, abs_path, sub_dst, include = include) + elif os.path.isfile(abs_path): + if _in_rules(rel_path, include): + if not os.path.exists(dst): + os.makedirs(dst) + shutil.copy(abs_path, dst) + elif (exclude is not None): + # have exclude + for name in os.listdir(src): + abs_path = os.path.join(src, name) + rel_path = os.path.relpath(abs_path, src_rootDir) + if os.path.isdir(abs_path): + sub_dst = os.path.join(dst, name) + copy_files_with_rules(src_rootDir, abs_path, sub_dst, exclude = exclude) + elif os.path.isfile(abs_path): + if not _in_rules(rel_path, exclude): + if not os.path.exists(dst): + os.makedirs(dst) + shutil.copy(abs_path, dst) + +def _in_rules(rel_path, rules): + import re + ret = False + path_str = rel_path.replace("\\", "/") + for rule in rules: + if re.match(rule, path_str): + ret = True + + return ret + +def convert_rules(rules): + ret_rules = [] + for rule in rules: + ret = rule.replace('.', '\\.') + ret = ret.replace('*', '.*') + ret = "%s" % ret + ret_rules.append(ret) + + return ret_rules diff --git a/tools/gen-prebuilt/gen_prebuilt_libs.py b/tools/gen-prebuilt/gen_prebuilt_libs.py new file mode 100644 index 0000000000..d8d3e06119 --- /dev/null +++ b/tools/gen-prebuilt/gen_prebuilt_libs.py @@ -0,0 +1,361 @@ +#!/usr/bin/python +# ---------------------------------------------------------------------------- +# generate the prebuilt libs of engine +# +# Copyright 2014 (C) zhangbin +# +# License: MIT +# ---------------------------------------------------------------------------- +''' +Generate the prebuilt libs of engine +''' + +import os +import subprocess +import shutil +import sys +import excopy +import json + +from argparse import ArgumentParser + +if sys.platform == 'win32': + import _winreg + +ANDROID_SO_PATH = "frameworks/runtime-src/proj.android/libs" +ANDROID_A_PATH = "frameworks/runtime-src/proj.android/obj/local" +MK_PATH = "frameworks/runtime-src/proj.android/jni/Application.mk" +CONSOLE_PATH = "tools/cocos2d-console/bin" + +def os_is_win32(): + return sys.platform == 'win32' + +def os_is_mac(): + return sys.platform == 'darwin' + +def run_shell(cmd, cwd=None): + p = subprocess.Popen(cmd, shell=True, cwd=cwd) + p.wait() + + if p.returncode: + raise subprocess.CalledProcessError(returncode=p.returncode, cmd=cmd) + + return p.returncode + +class Generator(object): + + XCODE_CMD_FMT = "xcodebuild -project \"%s\" -configuration Release -target \"%s\" %s CONFIGURATION_BUILD_DIR=%s" + + CONFIG_FILE = "build_config.json" + KEY_XCODE_PROJ_INFO = "xcode_proj_info" + KEY_WIN32_PROJ_INFO = "win32_proj_info" + + KEY_OUTPUT_DIR = "outputdir" + KEY_TARGETS = "targets" + + def __init__(self, args): + self.need_clean = args.need_clean + self.enable_strip = args.enable_strip + self.use_incredibuild = args.use_incredibuild + self.tool_dir = os.path.realpath(os.path.dirname(__file__)) + self.no_android = args.no_android + + self.engine_dir = os.path.join(self.tool_dir, os.path.pardir, os.path.pardir) + + self.load_config() + + def load_config(self): + cfg_json = os.path.join(self.tool_dir, Generator.CONFIG_FILE) + f = open(cfg_json) + cfg_info = json.load(f) + f.close() + + self.xcode_proj_info = cfg_info[Generator.KEY_XCODE_PROJ_INFO] + self.win32_proj_info = cfg_info[Generator.KEY_WIN32_PROJ_INFO] + + def modify_mk(self, mk_file): + if os.path.isfile(mk_file): + file_obj = open(mk_file, "a") + file_obj.write("\nAPP_ABI :=armeabi armeabi-v7a\n") + file_obj.close() + + def build_android(self): + # build .so for android + language = "lua" + + console_dir = os.path.join(self.engine_dir, CONSOLE_PATH) + cmd_path = os.path.join(console_dir, "cocos") + proj_name = "My%sGame" % language + proj_path = os.path.join(self.engine_dir, proj_name) + if os.path.exists(proj_path): + shutil.rmtree(proj_path) + + # create a runtime project + create_cmd = "%s new -l %s -t runtime -d %s %s" % (cmd_path, language, self.engine_dir, proj_name) + run_shell(create_cmd) + + # Add multi ABI in Application.mk + mk_file = os.path.join(proj_path, MK_PATH) + self.modify_mk(mk_file) + + # build it + build_cmd = "%s compile -s %s -p android --ndk-mode release -j 4" % (cmd_path, proj_path) + run_shell(build_cmd) + + # copy .a to prebuilt dir + obj_dir = os.path.join(proj_path, ANDROID_A_PATH) + prebuilt_dir = os.path.join(self.tool_dir, "prebuilt", "android") + copy_cfg = { + "from": obj_dir, + "to": prebuilt_dir, + "include": [ + "*.a$" + ] + } + excopy.copy_files_with_config(copy_cfg, obj_dir, prebuilt_dir) + + if self.enable_strip: + # strip the android libs + ndk_root = os.environ["NDK_ROOT"] + if os_is_win32(): + if self.is_32bit_windows(): + bit_str = "x86" + else: + bit_str = "x86_64" + + sys_folder_name = "windows-%s" % bit_str + elif os_is_mac(): + sys_folder_name = "darwin-x86_64" + + strip_cmd_path = os.path.join(ndk_root, "toolchains/arm-linux-androideabi-4.8/prebuilt/%s/arm-linux-androideabi/bin/strip" % sys_folder_name) + if os.path.exists(strip_cmd_path): + strip_cmd = "%s -S %s/armeabi*/*.a" % (strip_cmd_path, prebuilt_dir) + run_shell(strip_cmd) + + # remove the project + shutil.rmtree(proj_path) + + def get_required_vs_version(self, proj_file): + # get the VS version required by the project + import re + file_obj = open(proj_file) + pattern = re.compile(r"^# Visual Studio.+(\d{4})") + num = None + for line in file_obj: + match = pattern.match(line) + if match is not None: + num = match.group(1) + break + + if num is not None: + if num == "2012": + ret = "11.0" + elif num == "2013": + ret = "12.0" + else: + ret = None + else: + ret = None + + return ret + + def get_vs_cmd_path(self, require_version): + # find the VS in register, if system is 64bit, should find vs in both 32bit & 64bit register + if self.is_32bit_windows(): + reg_flag_list = [ _winreg.KEY_WOW64_32KEY ] + else: + reg_flag_list = [ _winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY ] + + needUpgrade = False + vsPath = None + + try: + for reg_flag in reg_flag_list: + print("find vs in reg : %s" % ("32bit" if reg_flag == _winreg.KEY_WOW64_32KEY else "64bit")) + vs = _winreg.OpenKey( + _winreg.HKEY_LOCAL_MACHINE, + r"SOFTWARE\Microsoft\VisualStudio", + 0, + _winreg.KEY_READ | reg_flag + ) + + try: + i = 0 + while True: + try: + # enum the keys in vs reg + version = _winreg.EnumKey(vs, i) + find_ver = float(version) + + # find the vs which version >= required version + if find_ver >= float(require_version): + key = _winreg.OpenKey(vs, r"SxS\VS7") + vsPath, type = _winreg.QueryValueEx(key, version) + + if os.path.exists(vsPath): + if float(version) > float(require_version): + needUpgrade = True + break + else: + vsPath = None + except: + continue + finally: + i += 1 + except: + pass + + # if find one right vs, break + if vsPath is not None: + break + except WindowsError as e: + message = "Visual Studio wasn't installed" + print(e) + raise Exception(message) + + commandPath = os.path.join(vsPath, "Common7", "IDE", "devenv") + return (needUpgrade, commandPath) + + def is_32bit_windows(self): + arch = os.environ['PROCESSOR_ARCHITECTURE'].lower() + archw = os.environ.has_key("PROCESSOR_ARCHITEW6432") + return (arch == "x86" and not archw) + + def build_win32_proj(self, cmd_path, sln_path, proj_name, mode): + build_cmd = " ".join([ + "\"%s\"" % cmd_path, + "\"%s\"" % sln_path, + "/%s \"Release|Win32\"" % mode, + "/Project \"%s\"" % proj_name + ]) + run_shell(build_cmd) + + def build_win32(self): + print("Building Win32") + + for key in self.win32_proj_info.keys(): + output_dir = self.win32_proj_info[key][Generator.KEY_OUTPUT_DIR] + proj_path = os.path.join(self.engine_dir, key) + require_vs_version = self.get_required_vs_version(proj_path) + needUpgrade, vs_command = self.get_vs_cmd_path(require_vs_version) + + # get the build folder & win32 output folder + build_folder_path = os.path.join(os.path.dirname(proj_path), "Release.win32") + if os.path.exists(build_folder_path): + shutil.rmtree(build_folder_path) + os.makedirs(build_folder_path) + + win32_output_dir = os.path.join(self.tool_dir, output_dir) + if os.path.exists(win32_output_dir): + shutil.rmtree(win32_output_dir) + os.makedirs(win32_output_dir) + + # upgrade projects + if needUpgrade: + commandUpgrade = ' '.join([ + "\"%s\"" % vs_command, + "\"%s\"" % proj_path, + "/Upgrade" + ]) + run_shell(commandUpgrade) + + if self.use_incredibuild: + # use incredibuild, build whole sln + build_cmd = " ".join([ + "BuildConsole", + "%s" % proj_path, + "/build", + "/cfg=\"Release|Win32\"" + ]) + run_shell(build_cmd) + + if not self.use_incredibuild: + # build the projects + for proj_name in self.win32_proj_info[key][Generator.KEY_TARGETS]: + self.build_win32_proj(vs_command, proj_path, proj_name, "build") + + lib_file_path = os.path.join(build_folder_path, "%s.lib" % proj_name) + if not os.path.exists(lib_file_path): + # if the lib is not generated, rebuild the project + self.build_win32_proj(vs_command, proj_path, proj_name, "rebuild") + + if not os.path.exists(lib_file_path): + raise Exception("Library %s not generated as expected!" % lib_file_path) + + # copy the libs into prebuilt dir + for file_name in os.listdir(build_folder_path): + file_path = os.path.join(build_folder_path, file_name) + shutil.copy(file_path, win32_output_dir) + + print("Win32 build succeeded.") + + def build_ios_mac(self): + for key in self.xcode_proj_info.keys(): + output_dir = self.xcode_proj_info[key][Generator.KEY_OUTPUT_DIR] + proj_path = os.path.join(self.engine_dir, key) + ios_out_dir = os.path.join(self.tool_dir, output_dir, "ios") + mac_out_dir = os.path.join(self.tool_dir, output_dir, "mac") + + ios_sim_libs_dir = os.path.join(ios_out_dir, "simulator") + ios_dev_libs_dir = os.path.join(ios_out_dir, "device") + for target in self.xcode_proj_info[key][Generator.KEY_TARGETS]: + build_cmd = Generator.XCODE_CMD_FMT % (proj_path, "%s iOS" % target, "-sdk iphonesimulator", ios_sim_libs_dir) + run_shell(build_cmd, self.tool_dir) + + build_cmd = Generator.XCODE_CMD_FMT % (proj_path, "%s iOS" % target, "-sdk iphoneos", ios_dev_libs_dir) + run_shell(build_cmd, self.tool_dir) + + build_cmd = Generator.XCODE_CMD_FMT % (proj_path, "%s Mac" % target, "", mac_out_dir) + run_shell(build_cmd, self.tool_dir) + + # generate fat libs for iOS + for lib in os.listdir(ios_sim_libs_dir): + sim_lib = os.path.join(ios_sim_libs_dir, lib) + dev_lib = os.path.join(ios_dev_libs_dir, lib) + output_lib = os.path.join(ios_out_dir, lib) + lipo_cmd = "lipo -create -output \"%s\" \"%s\" \"%s\"" % (output_lib, sim_lib, dev_lib) + + run_shell(lipo_cmd) + + # remove the simulator & device libs in iOS + shutil.rmtree(ios_sim_libs_dir) + shutil.rmtree(ios_dev_libs_dir) + + if self.enable_strip: + # strip the libs + ios_strip_cmd = "xcrun -sdk iphoneos strip -S %s/*.a" % ios_out_dir + run_shell(ios_strip_cmd) + mac_strip_cmd = "xcrun strip -S %s/*.a" % mac_out_dir + run_shell(mac_strip_cmd) + + def build_all_libs(self): + if os_is_mac(): + # build for iOS & Mac + self.build_ios_mac() + + if os_is_win32(): + # build for win32 + self.build_win32() + + if not self.no_android: + self.build_android() + + def do_generate(self): + output_dir = os.path.join(self.tool_dir, "prebuilt") + if self.need_clean and os.path.exists(output_dir): + shutil.rmtree(output_dir) + self.build_all_libs() + +if __name__ == "__main__": + parser = ArgumentParser(description="Generate prebuilt engine for Cocos Engine.") + parser.add_argument('-c', dest='need_clean', action="store_true", help='Remove the \"prebuilt\" directory first.') + parser.add_argument('-n', "--no-android", dest='no_android', action="store_true", help='Not build android libs.') + parser.add_argument('-s', "--strip", dest='enable_strip', action="store_true", help='Strip the generated libs.') + parser.add_argument('-i', "--incredibuild", dest='use_incredibuild', action="store_true", help='Use incredibuild to build win32 projects. Only available on windows.') + (args, unknown) = parser.parse_known_args() + + if len(unknown) > 0: + print("unknown arguments: %s" % unknown) + + gen_obj = Generator(args) + gen_obj.do_generate() diff --git a/tools/gen-prebuilt/module_config.json b/tools/gen-prebuilt/module_config.json new file mode 100644 index 0000000000..3e787f9f8b --- /dev/null +++ b/tools/gen-prebuilt/module_config.json @@ -0,0 +1,329 @@ +{ + "cocos2d" : { + "module_type" : "compiled", + "target_dir" : "cocos", + "win32_lib_file_name" : "libcocos2d", + "ios_lib_file_name" : "libcocos2d iOS.a", + "mac_lib_file_name" : "libcocos2d Mac.a", + "android_lib_name" : "cocos2dx_static", + "android_lib_file_name" : "libcocos2d", + "include" : [ + { + "from": "cocos", + "to": "cocos/include", + "include" : [ + "2d/*.h", "3d/*.h", "3d/*.inl", "base/*.h", + "deprecated/*.h", "math/*.h", "math/*.inl", + "physics/*.h", "platform/*.h", "renderer/*.h", + "storage/*.h", "cocos2d.h", "2d/*.props" + ] + }, + { + "from": "cocos/platform/android/java", + "to": "cocos/include/platform/android/java" + }, + { + "from": "external", + "to": "external", + "include": [ + "tinyxml2/*.h", + "unzip/*.h", + "xxhash/*.h", + "json/*.h", + "win32-specific/*" + ] + } + ], + "export_include" : [ + "../../include", + "../../../modules", + "../../../external/tinyxml2", + "../../../external/unzip", + "../../../external/chipmunk/include/chipmunk", + "../../../external/edtaa3func", + "../../../external/xxhash", + "../../../external/ConvertUTF", + "../../../external" + ], + "depend_modules" : [ + "chipmunk", "freetype", "jpeg", + "png", "webp", "tiff", + "cocos_android", "curl", "websockets" + ], + "export_ldlibs" : [ + "GLESv2", "log", "z", "android" + ], + "export_cflags" : [ + "-Wno-psabi", "-DUSE_FILE32API" + ], + "export_cppflags" : [ + "-Wno-literal-suffix", "-Wno-deprecated-declarations" + ] + }, + "freetype" : { + "module_type" : "prebuilt", + "from_dir" : "external/freetype2", + "target_dir" : "external/freetype2", + "android_lib_name" : "cocos_freetype2_static" + }, + "jpeg" : { + "module_type" : "prebuilt", + "from_dir" : "external/jpeg", + "target_dir" : "external/jpeg", + "android_lib_name" : "cocos_jpeg_static" + }, + "png" : { + "module_type" : "prebuilt", + "from_dir" : "external/png", + "target_dir" : "external/png", + "android_lib_name" : "cocos_png_static" + }, + "webp" : { + "module_type" : "prebuilt", + "from_dir" : "external/webp", + "target_dir" : "external/webp", + "android_lib_name" : "cocos_webp_static" + }, + "tiff" : { + "module_type" : "prebuilt", + "from_dir" : "external/tiff", + "target_dir" : "external/tiff", + "android_lib_name" : "cocos_tiff_static" + }, + "curl" : { + "module_type" : "prebuilt", + "from_dir" : "external/curl", + "target_dir" : "external/curl", + "android_lib_name" : "cocos_curl_static" + }, + "websockets" : { + "module_type" : "prebuilt", + "from_dir" : "external/websockets", + "target_dir" : "external/websockets", + "android_lib_name" : "websockets_static" + }, + "glfw3": { + "module_type" : "prebuilt", + "from_dir" : "external/glfw3", + "target_dir" : "external/glfw3" + }, + "cocos_android" : { + "module_type" : "compiled", + "target_dir" : "cocos/include/platform/android", + "android_lib_name" : "cocos2dxandroid_static", + "android_lib_file_name" : "libcocos2dandroid", + "export_include" : [ + "../../" + ], + "export_ldlibs" : [ + "GLESv1_CM", "GLESv2", "EGL", "log", "z", "android" + ] + }, + "chipmunk" : { + "module_type" : "compiled", + "target_dir" : "modules/chipmunk", + "win32_lib_file_name" : "libchipmunk", + "ios_lib_file_name" : "libchipmunk iOS.a", + "mac_lib_file_name" : "libchipmunk Mac.a", + "android_lib_name" : "chipmunk_static", + "android_lib_file_name" : "libchipmunk", + "include" : [ + { + "from": "external/chipmunk", + "to": "modules/chipmunk", + "include" : [ + "include/*.h" + ] + } + ], + "export_include" : [ + "../../include/chipmunk" + ] + }, + "box2d" : { + "module_type" : "compiled", + "target_dir" : "modules/Box2D", + "win32_lib_file_name" : "libbox2d", + "ios_lib_file_name" : "libbox2d iOS.a", + "mac_lib_file_name" : "libbox2d Mac.a", + "android_lib_name" : "box2d_static", + "android_lib_file_name" : "libbox2d", + "include" : [ + { + "from": "external/Box2D", + "to": "modules/Box2D/include/Box2D", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ] + }, + "audio" : { + "module_type" : "compiled", + "target_dir" : "modules/audio", + "win32_lib_file_name" : "libcocosdenshion", + "ios_lib_file_name" : "libcocosdenshion iOS.a", + "mac_lib_file_name" : "libcocosdenshion Mac.a", + "android_lib_name" : "cocosdenshion_static", + "android_lib_file_name" : "libcocosdenshion", + "include" : [ + { + "from": "cocos/audio", + "to": "modules/audio", + "include" : [ + "include/*.h" + ] + } + ], + "export_include" : [ + "../../include" + ] + }, + "network" : { + "module_type" : "compiled", + "target_dir" : "modules/network", + "win32_lib_file_name" : "libnetwork", + "ios_lib_file_name" : "libnetwork iOS.a", + "mac_lib_file_name" : "libnetwork Mac.a", + "android_lib_name" : "cocos_network_static", + "android_lib_file_name" : "libnetwork", + "include" : [ + { + "from": "cocos/network", + "to": "modules/network/include/network", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "cocos2d", "curl", "websockets" + ] + }, + "ui" : { + "module_type" : "compiled", + "target_dir" : "modules/ui", + "win32_lib_file_name" : "libui", + "ios_lib_file_name" : "libui iOS.a", + "mac_lib_file_name" : "libui Mac.a", + "android_lib_name" : "cocos_ui_static", + "android_lib_file_name" : "libui", + "include" : [ + { + "from": "cocos/ui", + "to": "modules/ui/include/ui", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "cocos2d", "extensions" + ] + }, + "extensions" : { + "module_type" : "compiled", + "target_dir" : "modules/extensions", + "win32_lib_file_name" : "libextension", + "ios_lib_file_name" : "libextension iOS.a", + "mac_lib_file_name" : "libextension Mac.a", + "android_lib_name" : "cocos_extension_static", + "android_lib_file_name" : "libextension", + "include" : [ + { + "from": "extensions", + "to": "modules/extensions/include/extensions", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "cocos2d", "curl", "box2d" + ] + }, + "cocostudio" : { + "module_type" : "compiled", + "target_dir" : "modules/cocostudio", + "win32_lib_file_name" : "libcocostudio", + "ios_lib_file_name" : "libcocostudio iOS.a", + "mac_lib_file_name" : "libcocostudio Mac.a", + "android_lib_name" : "cocostudio_static", + "android_lib_file_name" : "libcocostudio", + "include" : [ + { + "from": "cocos/editor-support/cocostudio", + "to": "modules/cocostudio/include/cocostudio", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "ui", "audio" + ] + }, + "spine" : { + "module_type" : "compiled", + "target_dir" : "modules/spine", + "win32_lib_file_name" : "libspine", + "ios_lib_file_name" : "libspine iOS.a", + "mac_lib_file_name" : "libspine Mac.a", + "android_lib_name" : "spine_static", + "android_lib_file_name" : "libspine", + "include" : [ + { + "from": "cocos/editor-support/spine", + "to": "modules/spine/include/spine", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "cocos2d" + ] + }, + "cocosbuilder" : { + "module_type" : "compiled", + "target_dir" : "modules/cocosbuilder", + "win32_lib_file_name" : "libcocosbuilder", + "ios_lib_file_name" : "libcocosbuilder iOS.a", + "mac_lib_file_name" : "libcocosbuilder Mac.a", + "android_lib_name" : "cocosbuilder_static", + "android_lib_file_name" : "libcocosbuilder", + "include" : [ + { + "from": "cocos/editor-support/cocosbuilder", + "to": "modules/cocosbuilder/include/cocosbuilder", + "include" : [ + "*.h" + ] + } + ], + "export_include" : [ + "../../include" + ], + "depend_modules" : [ + "extensions" + ] + } +} diff --git a/tools/gen-prebuilt/module_organize.py b/tools/gen-prebuilt/module_organize.py new file mode 100644 index 0000000000..ee3f32514a --- /dev/null +++ b/tools/gen-prebuilt/module_organize.py @@ -0,0 +1,239 @@ +import os +import shutil +import json +import excopy + +from argparse import ArgumentParser + +class ModuleOrganizer(object): + + CFG_FILE = "module_config.json" + + KEY_MODULE_TYPE = "module_type" + MODULE_TYPE_COMPILED = "compiled" + MODULE_TYPE_PREBUILT = "prebuilt" + + KEY_MODULE_FROM_DIR = "from_dir" + KEY_MODULE_TARGET_DIR = "target_dir" + KEY_MODULE_INCLUDE = "include" + KEY_MODULE_ANDROID_LIB_NAME = "android_lib_name" + KEY_MODULE_ANDROID_LIB_FILE_NAME = "android_lib_file_name" + KEY_MODULE_EXPORT_INCLUDE = "export_include" + KEY_MODULE_DEPEND_MODULES = "depend_modules" + KEY_MODULE_EXPORT_LDLIBS = "export_ldlibs" + KEY_MODULE_EXPORT_CFLAGS = "export_cflags" + KEY_MODULE_EXPORT_CPPFLAGS = "export_cppflags" + KEY_MODULE_WIN32_LIB_FILE_NAME = "win32_lib_file_name" + KEY_MODULE_IOS_LIB_FILE_NAME = "ios_lib_file_name" + KEY_MODULE_MAC_LIB_FILE_NAME = "mac_lib_file_name" + + # Parameter 5--9 means: + # 5. LOCAL_EXPORT_LDLIBS + # 6. LOCAL_EXPORT_CFLAGS + # 7. LOCAL_EXPORT_CPPFLAGS + # 8. LOCAL_WHOLE_STATIC_LIBRARIES + # 9. $(call import-module, xxx) + MK_FORMAT = "LOCAL_PATH := $(call my-dir)\n\n" \ + "include $(CLEAR_VARS)\n\n" \ + "LOCAL_MODULE := %s\n" \ + "LOCAL_MODULE_FILENAME := %s\n\n" \ + "LOCAL_SRC_FILES := %s\n\n" \ + "LOCAL_EXPORT_C_INCLUDES := %s\n\n" \ + "%s" \ + "%s" \ + "%s" \ + "%s" \ + "include $(PREBUILT_STATIC_LIBRARY)\n\n" \ + "%s\n" + + def __init__(self, dst_root): + self.local_path = os.path.realpath(os.path.dirname(__file__)) + self.modules_info = self._parse_modules() + + self.src_root = os.path.join(self.local_path, os.path.pardir, os.path.pardir) + self.prebuilt_dir = os.path.join(self.local_path, "prebuilt") + + if dst_root is None: + dst = self.local_path + else: + if os.path.isabs(dst_root): + dst = dst_root + else: + dst = os.path.abspath(dst_root) + self.dst_root = os.path.join(dst, "cocos2d-x") + + def _parse_modules(self): + cfg_path = os.path.join(self.local_path, ModuleOrganizer.CFG_FILE) + f = open(cfg_path) + cfg_info = json.load(f) + f.close() + + return cfg_info + + def gen_android_depend_str(self, depends): + whole_libs_str = "" + call_import_str = "" + i = 0 + for module in depends: + depend_info = self.modules_info[module] + if i == 0: + flag = ":" + else: + flag = "+" + whole_libs_str += ("LOCAL_WHOLE_STATIC_LIBRARIES %s= %s\n" % (flag, depend_info[ModuleOrganizer.KEY_MODULE_ANDROID_LIB_NAME])) + call_import_str += ("$(call import-module,%s/prebuilt/android)\n" % depend_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR]) + i += 1 + + whole_libs_str += "\n" + return (whole_libs_str, call_import_str) + + def handle_for_android(self, module_info): + # copy libs file + android_lib_file_name = module_info[ModuleOrganizer.KEY_MODULE_ANDROID_LIB_FILE_NAME] + copy_android_lib_cfg = {} + copy_android_lib_cfg["from"] = "android" + copy_android_lib_cfg["to"] = "%s/prebuilt/android" % module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR] + copy_android_lib_cfg["include"] = [ + "*/%s.a" % android_lib_file_name + ] + excopy.copy_files_with_config(copy_android_lib_cfg, self.prebuilt_dir, self.dst_root) + + # generate the prebuilt Android.mk for the module + android_lib_name = module_info[ModuleOrganizer.KEY_MODULE_ANDROID_LIB_NAME] + local_src_file = "./$(TARGET_ARCH_ABI)/%s.a" % android_lib_file_name + export_include_paths = [] + for include_path in module_info[ModuleOrganizer.KEY_MODULE_EXPORT_INCLUDE]: + temp_path = "${LOCAL_PATH}/%s" % include_path + export_include_paths.append(temp_path) + export_include_str = " \\\n".join(export_include_paths) + + export_ldlibs_str = "" + if module_info.has_key(ModuleOrganizer.KEY_MODULE_EXPORT_LDLIBS): + export_ldlibs_str = "LOCAL_EXPORT_LDLIBS := " + for ldlib in module_info[ModuleOrganizer.KEY_MODULE_EXPORT_LDLIBS]: + export_ldlibs_str += ("-l%s " % ldlib) + export_ldlibs_str += "\n\n" + + export_cflags_str = "" + if module_info.has_key(ModuleOrganizer.KEY_MODULE_EXPORT_CFLAGS): + export_cflags_str = "LOCAL_EXPORT_CFLAGS := " + export_cflags_str += " ".join(module_info[ModuleOrganizer.KEY_MODULE_EXPORT_CFLAGS]) + export_cflags_str += "\n\n" + + export_cppflags_str = "" + if module_info.has_key(ModuleOrganizer.KEY_MODULE_EXPORT_CPPFLAGS): + export_cppflags_str = "LOCAL_EXPORT_CPPFLAGS := " + export_cppflags_str += " ".join(module_info[ModuleOrganizer.KEY_MODULE_EXPORT_CPPFLAGS]) + export_cppflags_str += "\n\n" + + whole_libs = "" + call_libs = "" + if module_info.has_key(ModuleOrganizer.KEY_MODULE_DEPEND_MODULES): + whole_libs, call_libs = self.gen_android_depend_str(module_info[ModuleOrganizer.KEY_MODULE_DEPEND_MODULES]) + + mk_content = ModuleOrganizer.MK_FORMAT % \ + (android_lib_name, + android_lib_file_name, + local_src_file, + export_include_str, + export_ldlibs_str, + export_cflags_str, + export_cppflags_str, + whole_libs, + call_libs + ) + + mk_file_path = os.path.join(self.dst_root, module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR], "prebuilt/android/Android.mk") + mk_dir = os.path.dirname(mk_file_path) + if not os.path.exists(mk_dir): + os.makedirs(mk_dir) + mk_obj = open(mk_file_path, "w") + mk_obj.write(mk_content) + mk_obj.close() + + def handle_for_win32(self, module_info): + if module_info.has_key(ModuleOrganizer.KEY_MODULE_WIN32_LIB_FILE_NAME): + dst_dir = os.path.join(self.dst_root, module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR], "prebuilt", "win32") + src_lib_file = os.path.join(self.prebuilt_dir, "win32", "%s.lib" % module_info[ModuleOrganizer.KEY_MODULE_WIN32_LIB_FILE_NAME]) + src_dll_file = os.path.join(self.prebuilt_dir, "win32", "%s.dll" % module_info[ModuleOrganizer.KEY_MODULE_WIN32_LIB_FILE_NAME]) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + + if os.path.exists(src_lib_file): + shutil.copy(src_lib_file, dst_dir) + else: + print("\t%s is not existed" % src_lib_file) + + if os.path.exists(src_dll_file): + shutil.copy(src_dll_file, dst_dir) + + def handle_for_ios_mac(self, module_info): + if module_info.has_key(ModuleOrganizer.KEY_MODULE_IOS_LIB_FILE_NAME): + dst_dir = os.path.join(self.dst_root, module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR], "prebuilt", "ios") + src_lib_file = os.path.join(self.prebuilt_dir, "ios", module_info[ModuleOrganizer.KEY_MODULE_IOS_LIB_FILE_NAME]) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + + if os.path.exists(src_lib_file): + shutil.copy(src_lib_file, dst_dir) + else: + print("\t%s is not existed" % src_lib_file) + + if module_info.has_key(ModuleOrganizer.KEY_MODULE_MAC_LIB_FILE_NAME): + dst_dir = os.path.join(self.dst_root, module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR], "prebuilt", "mac") + src_lib_file = os.path.join(self.prebuilt_dir, "mac", module_info[ModuleOrganizer.KEY_MODULE_MAC_LIB_FILE_NAME]) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + + if os.path.exists(src_lib_file): + shutil.copy(src_lib_file, dst_dir) + else: + print("\t%s is not existed" % src_lib_file) + + def gen_compiled_module(self, module_name): + print("generate compiled module : %s" % module_name) + module_info = self.modules_info[module_name] + # copy the include files + if module_info.has_key(ModuleOrganizer.KEY_MODULE_INCLUDE): + for inclue_cfg in module_info[ModuleOrganizer.KEY_MODULE_INCLUDE]: + excopy.copy_files_with_config(inclue_cfg, self.src_root, self.dst_root) + + # handle the process for android + self.handle_for_android(module_info) + + # handle the process for win32 + self.handle_for_win32(module_info) + + # handle the process for ios and mac + self.handle_for_ios_mac(module_info) + + def gen_prebuilt_module(self, module_name): + print("generate prebuilt module : %s" % module_name) + module_info = self.modules_info[module_name] + copy_cfg = { + "from" : module_info[ModuleOrganizer.KEY_MODULE_FROM_DIR], + "to": module_info[ModuleOrganizer.KEY_MODULE_TARGET_DIR] + } + excopy.copy_files_with_config(copy_cfg, self.src_root, self.dst_root) + + def gen_modules(self): + if os.path.exists(self.dst_root): + shutil.rmtree(self.dst_root) + + for module in self.modules_info.keys(): + module_info = self.modules_info[module] + if module_info[ModuleOrganizer.KEY_MODULE_TYPE] == ModuleOrganizer.MODULE_TYPE_COMPILED: + self.gen_compiled_module(module) + elif module_info[ModuleOrganizer.KEY_MODULE_TYPE] == ModuleOrganizer.MODULE_TYPE_PREBUILT: + self.gen_prebuilt_module(module) + +if __name__ == '__main__': + parser = ArgumentParser(description="Organize the modules of engine from prebuilt engine.") + parser.add_argument('-d', "--dst-root", dest='dst_root', help='The path where to place the engine organized by modules.') + (args, unknown) = parser.parse_known_args() + + if len(unknown) > 0: + print("unknown arguments: %s" % unknown) + + organizer = ModuleOrganizer(args.dst_root) + organizer.gen_modules()