axmol/tools/console/plugins/plugin_generate/gen_prebuilt_mk.py

353 lines
12 KiB
Python

#!/usr/bin/python
# ----------------------------------------------------------------------------
# generate the prebuilt Android.mk from source code Android.mk
#
# Copyright 2014 (C) zhangbin
#
# License: MIT
# ----------------------------------------------------------------------------
'''
generate the prebuilt Android.mk from source code Android.mk
'''
import os
import shutil
import re
from argparse import ArgumentParser
class MKGenerator(object):
SRC_FILE_CFG_PATTERN = r"^LOCAL_SRC_FILES[ \t]*[\:\+]*=[ \t]*.+"
INCLUDE_CFG_PATTERN = r"^include[ \t]+\$\(BUILD_STATIC_LIBRARY\)"
LIB_MODULE_PATTERN = r"^LOCAL_MODULE[ \t]*[\:]*=[ \t]*(.+)"
LIB_MODULE_FILENAME_PATTERN = r"^LOCAL_MODULE_FILENAME[ \t]*[\:]*=[ \t]*(.+)"
EXPORT_INCLUDE_PATTERN = r"^LOCAL_EXPORT_C_INCLUDES[ \t]*[\:\+]*=[ \t]*(.+)"
INCLUDE_MODULE_PATTERN = r"^\$\(call[ \t]*import-module,[ \t]*(.*)\)"
KEY_IS_MODULE = 'is_module'
KEY_MODULE_LINES = 'lines'
def __init__(self, src_mk_path, lib_file_path, dst_mk_path=None):
if os.path.isabs(src_mk_path):
self.src_mk_path = src_mk_path
else:
self.src_mk_path = os.path.abspath(src_mk_path)
if os.path.isabs(lib_file_path):
self.lib_file_path = lib_file_path
else:
self.lib_file_path = os.path.abspath(lib_file_path)
if dst_mk_path is None:
self.dst_mk_path = os.path.join(os.path.dirname(src_mk_path), "Android-prebuilt.mk")
else:
if os.path.isabs(dst_mk_path):
self.dst_mk_path = dst_mk_path
else:
self.dst_mk_path = os.path.abspath(dst_mk_path)
dst_mk_dir = os.path.dirname(self.dst_mk_path)
if not os.path.exists(dst_mk_dir):
os.makedirs(dst_mk_dir)
def get_lib_file_name(self, lines):
module_file_name = None
module_name = None
for line in lines:
trim_line = line.lstrip(" ")
trim_line = trim_line.rstrip(" ")
match1 = re.match(MKGenerator.LIB_MODULE_FILENAME_PATTERN, trim_line)
if match1 is not None:
module_file_name = match1.group(1)
match2 = re.match(MKGenerator.LIB_MODULE_PATTERN, trim_line)
if match2 is not None:
module_name = match2.group(1)
ret = None
if module_file_name is not None:
ret = "%s.a" % module_file_name
elif module_name is not None:
if module_name.startswith('lib'):
ret = "%s.a" % module_name
else:
ret = "lib%s.a" % module_name
return ret
def modidy_src_file(self, lines, new_src_file):
new_lines = []
src_file_begin_flag = False
added = False
found_src_file_cfg = False
for line in lines:
trim_line = line.lstrip(" ")
if re.match(MKGenerator.SRC_FILE_CFG_PATTERN, trim_line):
found_src_file_cfg = True
if not added:
new_lines.append("LOCAL_SRC_FILES := %s\n" % new_src_file)
added = True
if line.endswith("\\\n"):
src_file_begin_flag = True
elif src_file_begin_flag:
if not line.endswith("\\\n"):
src_file_begin_flag = False
else:
new_lines.append(line)
if not found_src_file_cfg:
ret_lines = []
for line in new_lines:
ret_lines.append(line)
if re.match(MKGenerator.LIB_MODULE_FILENAME_PATTERN, line):
ret_lines.append("LOCAL_SRC_FILES := %s\n" % new_src_file)
else:
ret_lines = new_lines
return ret_lines
def remove_config(self, lines, cfg_key):
new_lines = []
cfg_begin = False
line_pattern = r"^%s[ ]+[\+\:]=[ ]+.+" % cfg_key
for line in lines:
trim_line = line.lstrip(" ")
if re.match(line_pattern, trim_line):
if line.endswith("\\\n"):
cfg_begin = True
elif cfg_begin:
if not line.endswith("\\\n"):
cfg_begin = False
else:
new_lines.append(line)
return new_lines
def modify_export_c_include(self, lines):
if self.src_mk_path == self.dst_mk_path:
return lines
new_lines = []
insert_idx = -1
cur_idx = 0
include_paths = []
cfg_begin = False
for line in lines:
trim_line = line.lstrip(" ")
match = re.match(MKGenerator.EXPORT_INCLUDE_PATTERN, trim_line)
if match is not None:
if insert_idx == -1:
insert_idx = cur_idx
path_str = match.group(1)
if line.endswith("\\\n"):
cfg_begin = True
path_str = path_str.replace("\\", "")
include_paths += path_str.split()
elif cfg_begin:
path_str = trim_line
if line.endswith("\\\n"):
path_str = path_str.replace("\\\n", "")
else:
cfg_begin = False
include_paths += path_str.split()
else:
new_lines.append(line)
cur_idx += 1
src_dir = os.path.dirname(self.src_mk_path)
dst_dir = os.path.dirname(self.dst_mk_path)
rel_path = os.path.relpath(src_dir, dst_dir)
new_include_paths = []
for include_path in include_paths:
if include_path.startswith("$(LOCAL_PATH)"):
new_path = include_path.replace("$(LOCAL_PATH)", "$(LOCAL_PATH)/%s" % rel_path)
else:
new_path = "$(LOCAL_PATH)/%s/%s" % (rel_path, include_path)
new_include_paths.append(new_path)
if len(new_include_paths) > 0:
new_path_str = "LOCAL_EXPORT_C_INCLUDES := "
new_path_str += " \\\n".join(new_include_paths)
new_path_str += "\n"
if insert_idx >= 0:
new_lines.insert(insert_idx, new_path_str)
else:
new_lines.append(new_path_str)
return new_lines
def modify_include_cfg(self, lines):
new_lines = []
for line in lines:
trim_line = line.lstrip(" ")
if re.match(MKGenerator.INCLUDE_CFG_PATTERN, trim_line):
new_lines.append("include $(PREBUILT_STATIC_LIBRARY)\n")
else:
new_lines.append(line)
return new_lines
def modify_import_module(self, lines):
if self.src_mk_path == self.dst_mk_path:
return lines
new_lines = []
ignore_strs = [
"prebuilt", "cpufeatures"
]
for line in lines:
trim_line = line.lstrip(" ")
match = re.match(MKGenerator.INCLUDE_MODULE_PATTERN, trim_line)
if match is not None:
module = match.group(1)
need_modify = True
for str in ignore_strs:
if module.find(str) >= 0:
need_modify = False
break
if need_modify:
new_lines.append("$(call import-module, %s/prebuilt-mk)\n" % module)
else:
new_lines.append(line)
else:
new_lines.append(line)
return new_lines
def use_whole_lib(self, lines):
new_lines = []
for line in lines:
new_line = line.replace("LOCAL_STATIC_LIBRARIES", "LOCAL_WHOLE_STATIC_LIBRARIES")
new_lines.append(new_line)
ret_lines = []
is_first_time = True
pattern = r'LOCAL_WHOLE_STATIC_LIBRARIES[ \t]*:=.*'
for line in new_lines:
ret_line = line
if re.match(pattern, line):
if is_first_time:
is_first_time = False
else:
ret_line = line.replace(":=", "+=")
ret_lines.append(ret_line)
return ret_lines
def split_modules(self, origin_lines):
ret = []
cur_module = {}
cur_module[MKGenerator.KEY_MODULE_LINES] = []
cur_module[MKGenerator.KEY_IS_MODULE] = False
pattern_begin = r'include[ \t]+\$\(CLEAR_VARS\)'
pattern_end = r'include[ \t]+\$\(BUILD_STATIC_LIBRARY\)'
for line in origin_lines:
if re.match(pattern_begin, line):
if len(cur_module[MKGenerator.KEY_MODULE_LINES]) > 0:
ret.append(cur_module)
cur_module = {}
cur_module[MKGenerator.KEY_MODULE_LINES] = []
cur_module[MKGenerator.KEY_IS_MODULE] = True
cur_module[MKGenerator.KEY_MODULE_LINES].append(line)
if re.match(pattern_end, line):
if len(cur_module[MKGenerator.KEY_MODULE_LINES]) > 0:
ret.append(cur_module)
cur_module = {}
cur_module[MKGenerator.KEY_MODULE_LINES] = []
cur_module[MKGenerator.KEY_IS_MODULE] = False
if len(cur_module[MKGenerator.KEY_MODULE_LINES]) > 0:
ret.append(cur_module)
return ret
def handle_module(self, module_lines, relative_path):
# modify the LOCAL_SRC_FILES
lib_file_name = self.get_lib_file_name(module_lines)
if lib_file_name is None:
raise Exception("The mk file %s not specify module name." % self.src_mk_path)
relative_path = "%s/$(TARGET_ARCH_ABI)/%s" % (relative_path, lib_file_name)
dst_lines = self.modidy_src_file(module_lines, relative_path)
# remove the LOCAL_C_INCLUDES & LOCAL_LDLIBS
dst_lines = self.remove_config(dst_lines, "LOCAL_C_INCLUDES")
dst_lines = self.remove_config(dst_lines, "LOCAL_LDLIBS")
# modify the LOCAL_EXPORT_C_INCLUDES
dst_lines = self.modify_export_c_include(dst_lines)
# modify the line $(include BUILD_STATIC_LIBRARY)
dst_lines = self.modify_include_cfg(dst_lines)
# use whole libs
dst_lines = self.use_whole_lib(dst_lines)
return dst_lines
def do_generate(self):
src_mk_obj = open(self.src_mk_path)
# open the dst file
tmp_file = "%s-tmp" % self.src_mk_path
use_tmp_file = False
if self.dst_mk_path == self.src_mk_path:
use_tmp_file = True
dst_mk_obj = open(tmp_file, "w")
else:
dst_mk_obj = open(self.dst_mk_path, "w")
relative_path = os.path.relpath(self.lib_file_path, os.path.dirname(self.dst_mk_path))
# read the src file
src_lines = src_mk_obj.readlines()
modules = self.split_modules(src_lines)
dst_lines = []
for module in modules:
if module[MKGenerator.KEY_IS_MODULE]:
ret_lines = self.handle_module(module[MKGenerator.KEY_MODULE_LINES], relative_path)
else:
ret_lines = module[MKGenerator.KEY_MODULE_LINES]
for l in ret_lines:
dst_lines.append(l)
# modify the import-module
dst_lines = self.modify_import_module(dst_lines)
dst_mk_obj.writelines(dst_lines)
#close files
dst_mk_obj.close()
src_mk_obj.close()
# rename the file if temp file used
if use_tmp_file:
os.remove(self.src_mk_path)
os.rename(tmp_file, self.dst_mk_path)
if __name__ == "__main__":
parser = ArgumentParser(description="Generate prebuilt engine for Cocos Engine.")
parser.add_argument('-s', '--src-mk', dest='src_mk', help='The source Android.mk path.')
parser.add_argument('-d', "--dst-mk", dest='dst_mk', help='The output path of Android.mk. Default is beside the source mk with name \"Android-prebuilt.mk\".')
parser.add_argument('-l', "--lib-path", dest='lib_path', help='The lib file path.')
(args, unknown) = parser.parse_known_args()
gen_obj = MKGenerator(args.src_mk, args.lib_path, args.dst_mk)
gen_obj.do_generate()