Merge pull request #7624 from natural-law/gen-prebuilt-script

Add tools to generate prebuilt engine for Cocos Engine.
This commit is contained in:
minggo 2014-07-30 15:49:27 +08:00
commit 8fe5ea390d
7 changed files with 1093 additions and 0 deletions

4
tools/gen-prebuilt/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea/*
build/*
prebuilt*
cocos2d-x/*

View File

@ -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`.

View File

@ -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"
]
}
}
}

View File

@ -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

View File

@ -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()

View File

@ -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"
]
}
}

View File

@ -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()