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])