GPCS4/Tools/GenerateCode.py
2019-06-21 15:18:09 +08:00

337 lines
10 KiB
Python

from collections import OrderedDict
import os
import json
def ParseImportFile(fname):
mod_dic = OrderedDict()
with open(fname, 'r') as src:
for line in src.readlines():
if line == '' or line == '\n':
continue
line = line.rstrip('\n')
mod_name, lib_name, nid_str = line.split(' ')
nid = int(nid_str, 16)
if not mod_name in mod_dic:
mod_dic[mod_name] = OrderedDict()
lib_dic = mod_dic[mod_name]
if not lib_name in lib_dic:
lib_dic[lib_name] = []
nid_list = lib_dic[lib_name]
nid_list.append([nid, 'null'])
return mod_dic
# some files in ps4libdoc stands for a library
# while most stands for a module
# so we have to fix this
def FixFileName(old_fname):
new_fname = old_fname
if old_fname == 'libSceAppContentUtil.sprx.json':
new_fname = 'libSceAppContent.sprx.json'
elif old_fname == 'libSceNpScore.sprx.json':
new_fname = 'libSceNpScoreRanking.sprx.json'
elif old_fname == 'libSceJson.sprx.json':
new_fname = 'libSceJson2.sprx.json'
return new_fname
# https://github.com/idc/ps4libdoc/tree/5.05
def GetFuncNameFromDB(db_root, imp_mods):
for mod_name in imp_mods:
print('process module {}'.format(mod_name))
db_basename = mod_name + '.sprx.json'
db_basename = FixFileName(db_basename)
db_fname = os.path.join(db_root, db_basename)
if not os.path.exists(db_fname):
print('file not exist {}'.format(db_fname))
exit(1)
src = open(db_fname)
db_obj = json.load(src)
lib_dic = imp_mods[mod_name]
db_mod_list = db_obj['modules']
for db_mod_dic in db_mod_list:
if db_mod_dic['name'] == mod_name:
db_lib_list = db_mod_dic['libraries']
break
found_lib = False
for lib_name in lib_dic:
print('process library {}'.format(lib_name))
for db_lib_dic in db_lib_list:
if db_lib_dic['name'] == lib_name:
db_sym_list = db_lib_dic['symbols']
found_lib = True
break
if not found_lib:
print('can not find lib {} in {}'.format(lib_name, db_fname))
func_list = lib_dic[lib_name]
for func_pair in func_list:
for db_sym_dic in db_sym_list:
db_nid = db_sym_dic['id']
if db_nid == func_pair[0]:
db_sym_name = db_sym_dic['name']
if not db_sym_name:
func_name = '_import_{:016X}'.format(func_pair[0])
else:
func_name = db_sym_name
func_pair[1] = func_name
break
def SortDic(imp_mods):
def TakeFunc(elem):
return elem[1]
for mod_name in imp_mods:
lib_dic = imp_mods[mod_name]
for lib_name in lib_dic:
func_list = lib_dic[lib_name]
func_list.sort(key = TakeFunc)
def GetModFolderName(mod_name):
if len(mod_name) < 6 or mod_name[:6] != 'libSce':
folder_name = 'Sce' + mod_name.capitalize()
else:
folder_name = mod_name[3:]
return folder_name
def GetCodeFileNames(mod_name):
if len(mod_name) < 6 or mod_name[:6] != 'libSce':
base_name = 'sce_' + mod_name.lower()
else:
base_name = 'sce_' + mod_name[6:].lower()
return base_name + '.h', base_name + '.cpp', base_name + '_export.cpp'
def WriteHeadComment(dst, mod_name, lib_dic):
dst.write('/*' + '\n')
dst.write(' *' + ' ' + 'GPCS4' + '\n')
dst.write(' *' + ' ' + '\n')
dst.write(' *' + ' ' + 'This file implements:' + '\n')
dst.write(' *' + ' ' + 'module: {}'.format(mod_name) + '\n')
for lib_name in lib_dic:
dst.write(' *' + ' ' + ' library: {}'.format(lib_name) + '\n')
dst.write(' *' + ' ' + '\n')
dst.write(' */'+ '\n')
def WriteNote(dst):
dst.write('// Note:' + '\n')
dst.write('// ' + 'The codebase is generated using {}'.format(os.path.basename(__file__)) + '\n')
dst.write('// ' + 'You may need to modify the code manually to fit development needs' + '\n')
def FuncNameByNid(nid):
func_name = '_import_{:016X}'.format(nid)
return func_name
def WriteOneDecl(dst, func_name, nid):
if not func_name:
func_name = FuncNameByNid(nid)
func_decl = 'int PS4API {}(void);'.format(func_name)
dst.write(func_decl + '\n')
dst.write('\n')
def WriteOneImpl(dst, func_name, nid):
if not func_name:
func_name = FuncNameByNid(nid)
func_impl = 'int PS4API {}(void)'.format(func_name)
dst.write(func_impl + '\n')
dst.write('{' + '\n')
dst.write('\tLOG_FIXME("Not implemented");' + '\n')
dst.write('\treturn SCE_OK;' + '\n')
dst.write('}' + '\n')
dst.write('\n')
def WriteDeclaration(dst, func_list):
for nid, func_name in func_list:
WriteOneDecl(dst, func_name, nid)
dst.write('\n')
def WriteDefination(dst, func_list):
for nid, func_name in func_list:
WriteOneImpl(dst, func_name, nid)
dst.write('\n')
def GetExpModuleName(mod_name):
fmt_mod_name = GetModFolderName(mod_name)
var_name = 'g_ExpModule{}'.format(fmt_mod_name)
return var_name
# extern SCE_EXPORT_MODULE g_ExpModuleSceLibc;
def WriteExpTabExtern(dst, mod_name):
var_name = GetExpModuleName(mod_name)
dst.write('extern const SCE_EXPORT_MODULE {};\n'.format(var_name))
def GetFuncTableName(mod_name, lib_name):
func_tab_name = 'g_p{}_{}_FunctionTable'.format(mod_name, lib_name)
return func_tab_name
def WriteExpTabDefination(dst, mod_name, lib_dic):
fmt_mod_name = GetModFolderName(mod_name)
for lib_name in lib_dic:
func_tab_name = GetFuncTableName(fmt_mod_name, lib_name)
lib_def_line = 'static const SCE_EXPORT_FUNCTION {}[] =\n'.format(func_tab_name)
dst.write(lib_def_line)
dst.write('{\n')
func_list = lib_dic[lib_name]
for nid, func in func_list:
func_ent_line = '\t{{ 0x{0:016X}, "{1:}", (void*){1:} }},\n'.format(nid, func)
dst.write(func_ent_line)
dst.write('\tSCE_FUNCTION_ENTRY_END\n')
dst.write('};\n')
dst.write('\n')
lib_ent_name = 'g_p{}_LibTable'.format(fmt_mod_name)
lib_ent_def = 'static const SCE_EXPORT_LIBRARY {}[] =\n'.format(lib_ent_name)
dst.write(lib_ent_def)
dst.write('{\n')
for lib_name in lib_dic:
func_tab_name = GetFuncTableName(fmt_mod_name, lib_name)
lib_ent_line = '\t{{ "{}", {} }},\n'.format(lib_name, func_tab_name)
dst.write(lib_ent_line)
dst.write('\tSCE_LIBRARY_ENTRY_END\n')
dst.write('};\n')
dst.write('\n')
mod_def_name = GetExpModuleName(mod_name)
mod_def_line = 'const SCE_EXPORT_MODULE {} =\n'.format(mod_def_name)
dst.write(mod_def_line)
dst.write('{\n')
dst.write('\t"{}",\n'.format(mod_name))
dst.write('\t{}\n'.format(lib_ent_name))
dst.write('};\n')
dst.write('\n\n')
def WriteInclude(dst, h_name):
dst.write('#include "{}"'.format(h_name) + '\n')
def WritePragmaOnce(dst):
dst.write('#pragma once' + '\n')
def WriteLibComment(dst, lib_name):
dst.write('//////////////////////////////////////////////////////////////////////////' + '\n')
dst.write('// library: {}'.format(lib_name) + '\n')
dst.write('//////////////////////////////////////////////////////////////////////////' + '\n')
def WriteModuleFuncDecl(dst):
dst.write('bool module_start(void* ctx);\n')
dst.write('void module_exit(void);\n')
def WriteModuleFuncImpl(dst):
dst.write('bool module_start(void* ctx)\n')
dst.write('{\n')
dst.write('\treturn true;\n')
dst.write('}\n')
dst.write('\n\n')
dst.write('void module_exit(void)\n')
dst.write('{\n')
dst.write('}\n')
def WriteSourceFiles(fname_h, fname_cpp, fname_exp, mod_name, lib_dic):
with open(fname_h, 'w') as dst_h, open(fname_cpp, 'w') as dst_cpp, open(fname_exp, 'w') as dst_exp:
print('write source file {} {} {}'.format(os.path.basename(fname_h), os.path.basename(fname_cpp), os.path.basename(fname_exp)))
WriteHeadComment(dst_h, mod_name, lib_dic)
dst_h.write('\n')
WritePragmaOnce(dst_h)
dst_h.write('\n')
WriteInclude(dst_h, 'sce_module_common.h')
dst_h.write('\n\n')
WriteExpTabExtern(dst_h, mod_name)
dst_h.write('\n\n')
# WriteModuleFuncDecl(dst_h)
# dst_h.write('\n\n')
WriteNote(dst_h)
dst_h.write('\n\n\n')
WriteInclude(dst_cpp, os.path.basename(fname_h))
dst_cpp.write('\n\n')
WriteNote(dst_cpp)
dst_cpp.write('\n\n\n')
for lib_name in lib_dic:
func_list = lib_dic[lib_name]
WriteLibComment(dst_h, lib_name)
dst_h.write('\n')
WriteDeclaration(dst_h, func_list)
dst_h.write('\n\n')
WriteLibComment(dst_cpp, lib_name)
dst_cpp.write('\n')
WriteDefination(dst_cpp, func_list)
dst_cpp.write('\n\n')
# WriteModuleFuncImpl(dst_cpp)
WriteInclude(dst_exp, os.path.basename(fname_h))
dst_exp.write('\n\n')
WriteNote(dst_exp)
dst_exp.write('\n\n')
WriteExpTabDefination(dst_exp, mod_name, lib_dic)
def WriteCodeFile(root_dir, imp_mods):
if not os.path.exists(root_dir):
os.mkdir(root_dir)
for mod_name in imp_mods:
mod_folder = GetModFolderName(mod_name)
mod_folder = os.path.join(root_dir, mod_folder)
if not os.path.exists(mod_folder):
os.mkdir(mod_folder)
mod_h, mod_cpp, mod_exp_cpp = GetCodeFileNames(mod_name)
fname_h = os.path.join(mod_folder, mod_h)
fname_cpp = os.path.join(mod_folder, mod_cpp)
fname_exp = os.path.join(mod_folder, mod_exp_cpp)
# if not os.path.exists(fname_h) and not os.path.exists(fname_cpp):
if True:
lib_dic = imp_mods[mod_name]
WriteSourceFiles(fname_h, fname_cpp, fname_exp, mod_name, lib_dic)
def Main():
# this file is generated by eboot import table, from VS log ouput
imp_mods = ParseImportFile('import_modules.txt')
GetFuncNameFromDB('system\\common\\lib', imp_mods)
SortDic(imp_mods)
WriteCodeFile('SceModules', imp_mods)
print('done!')
if __name__ == '__main__':
Main()