Files
envi-code/autoCompile/WF2026/SHSCompile.py
T

488 lines
12 KiB
Python
Raw Normal View History

2026-09-28 15:28:50 +08:00
import json
import os
import glob
import subprocess
import multiprocessing
import platform
import shutil
import string
import sys
import hashlib
import argparse
############################################################################
def exitPy():
os.system('pause')
os._exit(0)
def getFiles(postfix):
fs = glob.glob(os.getcwd() + "\\" + postfix)
return fs
def getWindowsTargetPlatformVersion():
return ["10.0.19041.0"]
def getProjectList(projs):
print("选择要编译的工程:")
print("\t1.全部工程")
print("\t2.编译单个工程")
print("\t其它键退出")
no = input("选择要编译的工程:")
projectList = {}
if no == "1":
projectList = projs
elif no == "2":
idx = 1
prolst = list(projs.keys())
strPrj = "\t{}.{}"
print("选择要编译的工程:")
for prj in prolst:
print(strPrj.format(idx, prj))
idx += 1
no = input("选择要编译的工程,多个工程用空格分割:")
nolst = no.split(" ", -1)
for _no in nolst:
i = 0
try:
i = int(_no)
except:
continue
if i > len(prolst): continue
prjName = prolst[i - 1]
if prjName in projs:
projectList[prjName] = projs[prjName]
else:
os._exit(0)
return projectList
def startCompile(cmd):
compile = subprocess.Popen(cmd)
compile.wait()
def clearLogs(all):
logs = getFiles("*.log")
for f in logs:
if all == True:
os.remove(f)
else:
if os.path.getsize(f) == 0:
os.remove(f)
def printErrorList():
logs = getFiles("*.log")
i = 0
for f in logs:
if os.path.getsize(f) != 0:
print("compile failed : " + f)
i += 1
if i == 0: print("all success!")
return i != 0
def cleanDir(path):
if not os.path.exists(path):
os.makedirs(path)
return
shutil.rmtree(path)
os.mkdir(path)
def parseCommands(pathLst, argLst):
allcmds = list()
cmds = list()
_cmds = list()
for obj in pathLst:
cmds.clear()
_cmds.clear()
cmds.append(string.Template(obj["cmd"]))
for arg in obj["args"]:
_cmds.clear()
for x in argLst[arg]:
d = dict()
d[arg] = x
for cmd in cmds:
_cmds.append(string.Template(cmd.safe_substitute(d)))
cmds.clear()
cmds += _cmds
allcmds += cmds
paths = list()
for x in allcmds:
paths.append(x.safe_substitute())
return paths
def copyFile(cpy, args):
try:
argLst = cpy["arg-list"]
cleanLst = cpy["clean-list"]
copyLst = cpy["copy-list"]
except:
return False
argLst = {**argLst, **args}
pathLst = parseCommands(cleanLst, argLst)
for x in pathLst:
cleanDir(x)
pathLst.clear()
pathLst = parseCommands(copyLst, argLst)
for x in pathLst:
print(x)
os.system(x)
return True
def package(pk, product):
iscc = pk["iscc"]
iss = pk["iss-list"][product]
iss = os.path.abspath(iss)
os.system("\"{cc}\" {ss}".format(cc = iscc, ss = iss))
def md5File(path):
f = open(path, 'rb')
md5_obj = hashlib.md5()
while True:
d = f.read(8096)
if not d:
break
md5_obj.update(d)
hash_code = md5_obj.hexdigest()
f.close()
md5 = str(hash_code).lower()
return md5
def compileStartUp(startup, compiler, product):
prjPath = startup["path"]
iconPath = startup["iconPath"]
iconTarget = startup["iconName"]["targetIcon"]
iconSrc = startup["iconName"][product]
bt = 'rebuild'
#现在只需要copy环境即可
os.system("copy {pa}{na} {pa}{tn} /y".format(pa = iconPath, na = iconSrc, tn = iconTarget))
#判断两个文件是否相同,如果相同,说明不需要编译
#md5Target = md5File(iconPath + iconTarget)
#md5Src = md5File(iconPath + iconSrc)
#if md5Target == md5Src:
# bt = 'build'
'''
comp = startup["compiler"]
if comp not in compiler:
print("未找到编译嚣{}".format(comp))
os._exit(0)
vc2005 = compiler[comp]
'''
'''
不需要编译,在json文件中统一编译
prjPath = os.path.abspath(prjPath)
olddir = os.getcwd()
os.chdir(vc2005)
os.system("devenv.exe {pa} /{bt} \"release|win32\" /out \"{od}\\startup-win32.slog\"".format(pa = prjPath, od = olddir, bt = bt))
os.chdir(olddir)
'''
def printCompileInfomation():
print("**********************************************************")
print("编译机信息:")
for x in platform.uname():
print(x)
print("**********************************************************")
return
def getCompileProject(compileFile):
if os.path.exists(compileFile) == False:
print("未找到 {} 文件。".format(compileFile))
os.system("pause")
os._exit(0)
jsonstr = ""
try:
file = open(compileFile, "r", encoding="utf-8")
jsonstr = file.read()
file.close()
except Exception as e:
print("打开文件失败。")
print(type(e).__name__, e)
os.system("pause")
os._exit(0)
try:
project = json.loads(jsonstr)
except:
print("文件解析失败。")
os.system("pause")
os._exit(0)
return project
def getProperty(desc, propertyLst, getall):
print (desc)
#如果只有一个选项,直接用
if len(propertyLst) == 1:
return [propertyLst[0]]
delta = 1
if getall == True:
print('1.全部')
delta = 2
for idx, val in enumerate(propertyLst):
print('{i}.{v}'.format(i = idx + delta, v = val))
no = input('请选择序号(其它键退出):')
if not no.isdigit():
exitPy()
index = int(no)
if getall:
if index == 1:
return list(propertyLst)
index -= delta
if index >= 0 and index < len(propertyLst):
return [propertyLst[index]]
else:
exitPy()
def getYesOrNo(desc):
no = input(desc)
if no == "y" or no == "Y":
return True
else:
return False
def getArgs(desc, arg, _global, getall):
if len(_global) == 1:
return _global
if arg == None:
return getProperty(desc, _global, getall)
else:
return arg
############################################################################
if __name__ == '__main__':
if len(sys.argv) > 1 and os.path.exists(sys.argv[1]) == True:
project = getCompileProject(sys.argv[1])
del sys.argv[1]
else:
g_fs = getFiles("*.json")
fs = getProperty('请选择要编译的配置文件', g_fs, False)
project = getCompileProject(fs[0])
g_lm = []
if 'lockMode-list' in project:
g_lm = project['lockMode-list']
try:
g_pd = project['product-list']
g_bt = project['buildType-list']
g_pf = project['platform-list']
g_cf = project['config-list']
g_ts = project['toolset-list']
except:
print('''json文件丢失数据。请检查如下字段: 'product-list', 'lockMode-list', 'buildType-list', 'platform-list', 'config-list', 'toolset-list'。''')
exitPy()
argParse = argparse.ArgumentParser(description='收集参数')
if len(g_pd) != 0:
argParse.add_argument('--pd'
, help = '''产品名称:'EW2020'或'WF2020' '''
, type = str
, nargs = 1
, choices = g_pd)
if len(g_lm) != 0:
argParse.add_argument('--lm'
, help = '''加密方式:'BAL_LOCAL'或'BAL_REMOTE' '''
, type = str
, nargs = '*'
, choices = g_lm)
if len(g_pf) != 0:
argParse.add_argument('--pf'
, help = '''系统平台:'win32'或'x64' '''
, type = str
, nargs = '*'
, choices = g_pf)
if len(g_ts) != 0:
argParse.add_argument('--ts'
, help = '''vc平台,'v90'、'v100'、'v110'或'v140' '''
, type = str
, nargs = '*'
, choices = g_ts)
if len(g_cf) != 0:
argParse.add_argument('--cf'
, help = '''编译配置:'release'或'debug' '''
, type = str
, nargs = '*'
, choices = g_cf)
if len(g_bt) != 0:
argParse.add_argument('--bt'
, help = '''编译行为:'build'、'rebuild'或'clean' '''
, type = str
, nargs = '*'
, choices = g_bt)
argParse.add_argument('--autopk', help = '设置此标志,将会自动打包', nargs = '*')
argParse.add_argument('--svn', help = '设置此标志,将会自动更新代码', nargs = '*')
argParse.add_argument('--allcompile', help = '设置此标志,将会编译所有代码', nargs = '*')
#xx = argParse.parse_args('--pd WF2020 --lm BAL_LOCAL BAL_REMOTE --pf win32 x64 --ts v90 v100 v110 v140 --cf release --bt build'.split())
#args = argParse.parse_args('--pd WF2020 --lm BAL_LOCAL BAL_REMOTE --pf win32 x64 --ts v90 v100 v110 v140 --cf release --bt build --autopk --svn --allcompile'.split())
args = argParse.parse_args()
printCompileInfomation()
clearLogs(True)
pd = []
lm = []
bt = []
pf = []
cf = []
ts = []
#tsrv专门为copy命令构建,详细请查看配置文件
tsrv = []
if len(g_pd) != 0: pd = getArgs('请选择产品', args.pd, g_pd, False)
if len(g_lm) != 0: lm = getArgs('请选择加密方式', args.lm, g_lm, True)
if len(g_bt) != 0: bt = getArgs('请选择编译行为', args.bt, g_bt, False)
if len(g_pf) != 0: pf = getArgs('请选择系统平台', args.pf, g_pf, True)
if len(g_cf) != 0: cf = getArgs('请选择编译配置', args.cf, g_cf, True)
if len(g_ts) != 0: ts = getArgs('请选择VC器平台', args.ts, g_ts, True)
autoPK = False
if "copy-list" in project and "package" in project:
if args.autopk == None: autoPK = getYesOrNo("是否自动打包?(Y/N):")
elif (len(args.autopk) == 0 or args.autopk[0] == "Y" or args.autopk[0] == "y"): autoPK = True
else: autoPK = False
if "SVN" in project:
autoSVN = False
if args.svn == None: autoSVN = getYesOrNo("是否更新代码?(Y/N):")
elif (len(args.svn) == 0 or args.svn[0] == "Y" or args.svn[0] == "y"): autoSVN = True
else: autoSVN = False
if autoSVN:
os.system("svn update {pa}".format(pa = project["SVN"]))
prjLst = dict()
if args.allcompile == None:
prjLst = getProjectList(project["project-list"][pd[0]])
elif len(args.allcompile) > 0:
dic = project["project-list"][pd[0]]
for prjName in args.allcompile:
if dic.get(prjName) != None:
prjLst[prjName] = dic[prjName]
else:
prjLst = project["project-list"][pd[0]]
if len(prjLst) == 0:
print('没有需要编译的工程。')
exitPy()
if "compiler-list" not in project:
print("未找到编译器列表.")
os._exit()
compilerLst = project["compiler-list"]
''' 构造公共参数列表
其参数对应 json文件
'''
global_args = dict()
#编译器列表
for x, y in compilerLst.items():
lst = list()
lst.append(y)
global_args[x] = lst
#产品
if len(pd) != 0:
global_args["pd"] = pd
#编译类型
if len(bt) != 0:
global_args["bt"] = bt
#编译配置项
if len(cf) != 0:
global_args["cf"] = cf
#编译平台
if len(pf) != 0:
global_args["pf"] = pf
#加密方式
if len(lm) != 0:
global_args["lm"] = lm
# slm是为了给依赖earthwormcore的工程指名一个lib路径
# 原因是,earthwormcore.lib生成到了 LOCKMODE 宏指定的目录里,
# LOCKMODE可能会有多个值,但是没有关系,
# 只需要依赖任何一个LOCKMODE下的earthwormcore.lib就好
# 因为依赖earthowrmcore.lib的工程并不使用LOCKMODE宏
global_args["slm"] = [lm[0]]
#编译版本,注意,此版本可能还带有objectarx的版本信息以"v90;RVER=R18"的形式
#通过 ts 来解析出 tsrv
_ts = []
if len(ts) != 0:
for t in ts:
pr = t.split('+')
if len(pr) == 2:
_ts.append('{};RVER={}'.format(pr[0], pr[1]))
tsrv.append(pr[0] + pr[1])
else:
_ts.append(pr[0])
tsrv.append(pr[0])
if len(_ts) != 0:
global_args["ts"] = _ts
if len(tsrv) != 0:
global_args["tsrv"] = tsrv
#SDK版本
global_args["wtpv"] = getWindowsTargetPlatformVersion()
buildlines = dict()
argsLst = dict()
for na, prj in prjLst.items():
argsLst.clear()
argsLst["na"] = [na]
argsLst = {**argsLst, **global_args}
argsLst = {**argsLst, **prj["arg-list"]}
buildlines[na] = parseCommands([{'cmd': prj['cmd'], 'args': prj['args']}], argsLst)
# 在这里先处理一下命令行中的 log 文件名,由于 toolset 可能带有 objectarx版本信息,需要剔除
for na, cmds in buildlines.items():
for i in range(len(cmds)):
cmd = cmds[i]
if cmd.count(';RVER=') == 2:
cmd = cmd[::-1]
cmd = cmd.replace(str(';RVER=')[::-1], '', 1)
cmd = cmd[::-1]
cmds[i] = cmd
#buildlines[na] = cmd
#准备编译 先处理startup工程
if "startup" in project:
compileStartUp(project["startup"], compilerLst, pd[0])
for cmds in buildlines.values():
pool = multiprocessing.Pool(processes = 4)
for cmd in cmds:
pool.apply_async(startCompile, args = (cmd, ))
pool.close()
pool.join()
clearLogs(False)
clearLogs(False)
hasErr = printErrorList()
if hasErr == True:
os.system("pause")
os._exit(0)
if (autoPK == True) and ("copy-list" in project) and ("package" in project):
copyFile(project["copy-list"][pd[0]], global_args)
package(project["package"], pd[0])