#TODO: | |
import os | |
import string | |
import random | |
import sys | |
import fnmatch | |
import copy | |
import glob | |
libProj = 'libProj.vcxproj' | |
sourceExtensions = ['c', 'cpp', 'cxx','l','y','ll','yy', 'crc'] | |
headerExtensions = ['h', 'hxx', 'hrc'] | |
libExtensions = ['lib'] | |
deliverFileName = "d.lst" | |
# The path to the main OO directory | |
# If this isn't working on a new machine, this | |
# is probably why | |
mainPaths = ["C:/steve/TestARea/main","C:/steve/TestArea/main"] | |
# Use this to figure out which step we are in | |
# Most modules will end with the same string | |
# that they began with | |
findModuleStr = "Making:" | |
# These commands are in the output but should not be part | |
# of the resulting input | |
skipCommands = ["Microsoft", "Copyright", "-------", "using:"] | |
badMapStr = "-map:" | |
outStr = "/OUT:" | |
moduleName = "" | |
buildFolder = "wntmsci12.pro" | |
curDir = "" | |
it = 0 | |
# Keep track of everywhere we have seen a source file at | |
# and automatically add it as an include directory | |
# This fixes some issues with include directories | |
# not being detected properly when we have changed into that | |
# directory via cd | |
extraIncludeDirs = [] | |
outputString = "" | |
deliverBatName = "WinDeliver.bat" | |
FILESIZE_LIMIT = 1024*500 | |
inFileGroup = [] | |
outFileGroup = [] | |
# prjTuple = prjName, prjId, outputFile, dependencies, fileName | |
allProjects = [] | |
# Visual studio doesn't like projects sharing the same name | |
# so keep track of ones that we've seen and append a 1 to the end of them | |
usedPrjNames = [] | |
preBuildId = "" | |
includeDebug = False | |
postBuildName = 'postbuild.bat' | |
## NEW | |
def getDirPath(filePath): | |
dirPath = filePath.rsplit("/",1) | |
return dirPath[0] | |
beginDepComment = "#Begin Dependencies\n" | |
endDepComment = "#End Dependencies\n" | |
def addPrebuild(): | |
patchVCProjMake(moduleName,False,"","","") | |
# Description: | |
# Generates a random 32-character project id. Each character represents | |
# a hexadecimal character (0-9, A-F). Visual Studio uses the following format | |
# for project ids: 8-4-4-4-12 hexadecimal characters. For example, the string | |
# "0462A45F-E456-A56B-0289-CF4630B744E2" is a valid project id. Dashes ("-") | |
# are inserted between characters as specified by the format, resulting in a | |
# string with a length of 32+4. | |
# Note: | |
# return: 36-character string. | |
def ProjectGUID(): | |
output = "" | |
for x in range(0,36): | |
if x == 8 or x == 12+1 or x == 16+2 or x == 20+3: | |
output += '-' | |
else: | |
output += random.choice('0123456789ABCDEF') | |
return output | |
def printAndOutput(outputFile, out, indentationLevel): | |
for i in range(indentationLevel): | |
outputFile.write('\t') | |
print ('\t') | |
print (out) | |
outputFile.write(out + '\r\n') | |
def loadLibFiles(projFile, mainPath, indentationLevel): | |
path = mainPath + '\\solver\\410\\wntmsci12.pro\\lib\\' # This should always be the lib path | |
for file in os.listdir(path): | |
fileExt = file.split('.') # index 0 is name, 1 is ext | |
if (len(fileExt) > 1 and fileExt[1] in libExtensions): | |
printAndOutput(projFile, file + ';', indentationLevel) | |
def formatOutput(str): | |
str1 = "\nMicrosoft (R) Library Manager Version 9.00.30729.01\nCopyright (C) Microsoft Corporation. All rights reserved.\n" | |
str2 = "\nMicrosoft (R) Incremental Linker Version 9.00.30729.01\nCopyright (C) Microsoft Corporation. All rights reserved.\n" | |
str = str.replace(str1,"") | |
str = str.replace(str2,"") | |
return str | |
def findNext(str,it): | |
findStrs = ["cl.exe ","\nlib ","\nlink "] | |
ret_it = len(str)+1 | |
fStr = "" | |
for findStr in findStrs: | |
tmp_it = str.find(findStr,it) | |
if (tmp_it < ret_it and tmp_it != -1): | |
ret_it = tmp_it | |
fStr = findStr | |
fStr = fStr.strip() | |
return ret_it, fStr | |
def parseNext(str,it,lastArgs,inFileGroup,outFileGroup,cmdGroup): | |
it, type = findNext(str,it) | |
end_it = -1 | |
tmp_it = -1 | |
tmp = [] | |
#Obj Tuple = Name, inFiles, outFiles, args | |
if (type == "cl.exe"): | |
tmp_it = str.find("\n",it) | |
end_it = str.find("\n",tmp_it+1) | |
out = str[it:end_it] | |
out = fixPaths(out) | |
tmp_it2 = out.find(" ",end_it) | |
tmp_it3 = out.rfind(" ",0,tmp_it2) | |
out_it = out.find("-Fo") | |
out_end_it = out.find(" ",out_it) | |
tmp_it = out.rfind("/",0,out_end_it)+1 | |
args = out[len("cl.exe "):tmp_it] | |
args = fixPaths(args) | |
outFileName = out[out_it+len("-Fo"):out_end_it] | |
in_end_it = out.rfind(" ") | |
in_end_it = out.rfind(" ",0,in_end_it-1) | |
in_it = out.rfind(" ",0,in_end_it-1)+len(" ") | |
inFileName = out[in_it:in_end_it] | |
if args != lastArgs and lastArgs != "": | |
tmp = (lastArgs,inFileGroup,outFileGroup,"cl.exe") | |
if (tmp[1] != [] or tmp[2] != []): | |
cmdGroup.append(tmp) | |
inFileGroup = [] | |
outFileGroup = [] | |
lastArgs = args | |
inFileGroup.append(inFileName) | |
outFileGroup.append(outFileName) | |
elif (type == "lib"): | |
#If we have any leftover files from cl.exe | |
#then add them as a tuple | |
if (inFileGroup != []): | |
tmp = (lastArgs,inFileGroup,outFileGroup,"cl.exe") | |
if (tmp[1] != [] or tmp[2] != []): | |
cmdGroup.append(tmp) | |
inFileGroup = [] | |
outFileGroup = [] | |
objs = [] | |
tmp_it = str.find("\n",it+1) | |
end_it = str.find("\n",tmp_it+1) | |
tempStr = str[it:end_it] | |
while (tempStr.find(".obj") != -1 or tempStr.find(".lib") != -1): | |
tmp_it = end_it | |
end_it = str.find("\n",tmp_it+1) | |
tempStr = str[tmp_it:end_it] | |
#Move back one so we are able to match the following newline | |
#with the link or lib strings | |
end_it = end_it-1 | |
out = str[it:tmp_it] | |
out = fixPaths(out) | |
objs = out.split() | |
tmpObjs = [] | |
for tmpObj in objs: | |
if (tmpObj != "lib" and tmpObj[0] != "@" and tmpObj[0:4] != "/OUT"): | |
tmpObjs.append(tmpObj) | |
objs = tmpObjs | |
tmp_it = out.find("/OUT:")+len("/OUT:") | |
outFile = out[tmp_it:out.find(" ",tmp_it)] | |
args = out[tmp_it:out.find("@")] | |
args = args.replace(outFile,"") | |
tmp = (args,objs,[outFile],"lib") | |
if (tmp[1] != [] or tmp[2] != []): | |
cmdGroup.append(tmp) | |
elif (type == "link"): | |
#If we have any leftover files from cl.exe | |
#then add them as a tuple | |
if (inFileGroup != []): | |
tmp = (lastArgs,inFileGroup,outFileGroup,"cl.exe") | |
if (tmp[1] != [] or tmp[2] != []): | |
cmdGroup.append(tmp) | |
inFileGroup = [] | |
outFileGroup = [] | |
argList = "" | |
objList = [] | |
tmp_it = str.find("\n",it+1) | |
end_it = str.find("\n",tmp_it+1) | |
out = str[it:end_it] | |
out = fixPaths(out) | |
tmp_it = out.find("-out:")+len("-out:") | |
outFile = out[tmp_it:out.find(" ",tmp_it)] | |
argList = out.split(" ") | |
endArgList = "" | |
#print argList | |
for arg in argList: | |
if arg == "": | |
continue | |
if arg == 'link': | |
continue | |
if arg[0] == '@': | |
continue | |
if arg[0] == '/' or arg[0] == '-': | |
endArgList += arg + " " | |
else: | |
objList.append(arg) | |
inFileGroup = objList | |
outFileGroup.append(outFile) | |
tmp = (endArgList,inFileGroup,outFileGroup,"link") | |
if (tmp[1] != [] or tmp[2] != []): | |
cmdGroup.append(tmp) | |
outFileGroup = [] | |
inFileGroup = [] | |
else: | |
if (inFileGroup != []): | |
tmp = (lastArgs,inFileGroup,outFileGroup,"cl.exe") | |
cmdGroup.append(tmp) | |
inFileGroup = [] | |
outFileGroup = [] | |
return end_it, lastArgs, inFileGroup, outFileGroup, cmdGroup | |
#Matching object: Add as child of project | |
#Multiple objects: add dependency | |
#Matching lib: add as dependency | |
def newParse(fileName): | |
file = open(fileName,"r") | |
outputString = file.read() | |
#Remove the Copyright Microsoft text etc | |
#from the output | |
outputString = formatOutput(outputString) | |
it = -1 | |
lastCmd = "" | |
cmdGroup = [] | |
inFileGroup = [] | |
outFileGroup = [] | |
lastArgs = "" | |
while (1): | |
it, lastArgs, inFileGroup, outFileGroup, cmdGroup = parseNext(outputString,it+1,lastArgs, inFileGroup,outFileGroup,cmdGroup) | |
if (it == -1): | |
break | |
cmdGroup = verifyArgs(cmdGroup) | |
groupChild(cmdGroup) | |
def verifyArgs(cmdGroup): | |
resultCmds = [] | |
for cmd in cmdGroup: | |
argList = [] | |
for arg in cmd[0].split(): | |
if (arg.find("~") == -1): | |
argList.append(arg) | |
newCmd = (" ".join(argList),cmd[1],cmd[2],cmd[3]) | |
resultCmds.append(newCmd) | |
return resultCmds | |
def union(set1,set2): | |
objs = [] | |
sources = [] | |
y = 0 | |
for elem1 in set1: | |
x = 0 | |
for elem2 in set2: | |
if (elem1.strip() == elem2.strip()): | |
objs.append(x) | |
sources.append(y) | |
x += 1 | |
y += 1 | |
return objs, sources | |
#Find any .lib or .exe/dll commands that utilize this | |
#lib file | |
def findLibChildren(libCmd,cmdGroup): | |
childList = [] | |
depList = [] | |
for cmd in cmdGroup: | |
if (union(libCmd[2],cmd[1]) != []): | |
childList.append(cmd) | |
#Base cmd, lib children, cmd children, dependencies | |
def groupChild(cmdGroup): | |
tmpCmd = [[],[]] | |
compileCmds = [] | |
libCmds = [] | |
linkCmds = [] | |
resultCmds = [] | |
for cmd in cmdGroup: | |
if (cmd[3] == "cl.exe"): | |
compileCmds.append(cmd) | |
elif (cmd[3].strip() == "link"): | |
linkCmds.append(cmd) | |
elif (cmd[3] == "lib"): | |
libCmds.append(cmd) | |
#Cmd Tuple: (compileArgs,inFiles,outObj,inObj,outLib,inLib,outLink) | |
for cmd in compileCmds: | |
tmpLib = [] | |
tmpLink = [] | |
#FixMe: Support multiple lib and link cmds | |
#Find any library commands built with these obj files | |
for libCmd in libCmds: | |
tmpUn, tmpSources = union(libCmd[1],cmd[2]) | |
if (tmpUn != []): | |
tmpCmd = [] | |
sourceFiles = [] | |
for i in tmpUn: | |
sourceFiles.append(cmd[1][i]) | |
for i in tmpSources: | |
tmpCmd.append(libCmd[1][i]) | |
newClCmd = (cmd[0],sourceFiles,tmpCmd,cmd[3]) | |
newLibCmd = (libCmd[0],tmpCmd,libCmd[2],libCmd[3]) | |
tmpLib = (newClCmd,newLibCmd) | |
#Also find any exe or dll files built with these obj files | |
for linkCmd in linkCmds: | |
tmpUn, tmpSources = union(linkCmd[1],cmd[2]) | |
if (tmpUn != []): | |
tmpCmd = [] | |
sourceFiles = [] | |
for i in tmpUn: | |
sourceFiles.append(cmd[1][i]) | |
for i in tmpSources: | |
tmpCmd.append(linkCmd[1][i]) | |
newClCmd = (cmd[0],sourceFiles,tmpCmd,cmd[3]) | |
newLinkCmd = (linkCmd[0],linkCmd[1],linkCmd[2],linkCmd[3]) | |
resultCmds.append((newClCmd,newLinkCmd)) | |
if (tmpLib != []): | |
resultCmds.append(tmpLib) | |
for resultCmd in resultCmds: | |
prjName = resultCmd[1][2][0] | |
prjName = prjName[prjName.rfind("/")+1:] | |
prjName = prjName.replace("/","_") | |
prjName = prjName.replace(".","_") | |
prjName = prjName.replace("\\","_") | |
while (prjName in usedPrjNames): | |
print "Name " + prjName + " already used, appending 1" | |
prjName += '1' | |
usedPrjNames.append(prjName) | |
#Fix Me: Rewrite this abomination | |
files = resultCmd[0][1] | |
arguments = resultCmd[0][0].split() | |
libArgs = exeArgs = resultCmd[1][0] | |
cfgType = resultCmd[1][2][0] | |
cfgType = cfgType[-3:] | |
if (cfgType == "dll"): | |
cfgType = "DynamicLibrary" | |
elif (cfgType == "exe"): | |
cfgType = "Application" | |
elif (cfgType != "lib"): | |
print "Unknown file extension: " + cfgType | |
end_it = resultCmd[0][2][0].rfind("/") | |
objOut = resultCmd[0][2][0][0:end_it+1] | |
outputFile = resultCmd[1][2][0] | |
mapName = findMap(resultCmd[1][0]) | |
libIn = [] | |
for l in resultCmd[1][1]: | |
print l | |
if l[-4:] == ".lib": | |
libIn.append(l) | |
allLibFiles = outputFile | |
if resultCmd[1][3] == "link": | |
patchVCProjExeDll(prjName,files,arguments,exeArgs,cfgType,objOut,outputFile,mapName,libIn) | |
elif resultCmd[1][3] == "lib": | |
patchVCProjLib(prjName,files,arguments,libArgs,objOut,allLibFiles,outputFile,libIn) | |
def findMap(str): | |
tmp_it = str.find(badMapStr) | |
#Append a space so that if the map is the last command | |
#it will be found properly | |
str += " " | |
if (tmp_it == -1): | |
return "" | |
return str[tmp_it+len(badMapStr):str.find(" ",tmp_it)] | |
# origFilePath = "../one/two/afile.txt" | |
# pathStr = "*/one/two/" | |
# filename = "afile.txt" | |
# pathStr = moduleName + "/one/two/afile.txt" if(filename does not contain "*") | |
# pathStr = moduleName + "/one/two/" if(filename contains "*") | |
# files = search for all files matching pathStr | |
# for each file: | |
# remove moduleName from curfilename | |
# add curfilename to retFiles if curfilename != '' | |
# return retFiles | |
def tryToFindFile(inStr,repCmd,initStr): | |
retFiles = [] | |
origStr = inStr | |
origRepCmd = repCmd | |
numDirectoriesUp = -1 | |
minStr = min(inStr.find("/"),inStr.find(".")) | |
maxStr = inStr.rfind("/") | |
fileName = inStr[maxStr+1:] | |
inStr = inStr[minStr:maxStr+1] | |
if (len(repCmd) > len(inStr)): | |
strLen = len(repCmd) - len(inStr) | |
repCmd = "" | |
for i in 0, strLen: | |
repCmd += "*/" | |
pathStr = repCmd | |
else: | |
repCmd = repCmd.replace(inStr,"",1) | |
pathStr = repCmd.replace("..","*") | |
if (fileName.find("*") == -1): | |
pathStr = os.path.join(moduleName,pathStr+fileName) | |
else: | |
pathStr = os.path.join(moduleName,pathStr) | |
pathStr = pathStr.replace("\\","/") | |
files = glob.glob(pathStr) | |
#if len(files) == 0: | |
# print "WARNING! Path " + origStr + " was unable to be found" | |
# print "Using an initial string of " + initStr | |
# print "Manual action is required to fix this" | |
# print "Assuming that the named directory does exist" | |
# print pathStr | |
#if len(files) > 1: | |
# print "WARNING! Multiple matching paths found for path " | |
# print origStr + ". Defaulting to include all paths" | |
# print "User action may be required to fix this" | |
# print "Matches found: " | |
# for f in files: | |
# print f | |
for f in files: | |
f = f[len(moduleName)+1:] | |
if f != "": | |
retFiles.append(f) | |
return retFiles | |
# while(more cmds): | |
# if(can find buildFolder+"/" in curCmd): | |
# repCmd = text between "." and buildFolder+"/" | |
# break | |
# while(more cmds): | |
# tmpCmd = curCmd.remove(repCmd) | |
# if(can find "../"): | |
# error if repCmd = '' | |
# | |
def fixPaths(cmd): | |
newCmds = cmd.split() | |
retCmd = "" | |
repCmd = "" | |
for newCmd in newCmds: | |
build_it = newCmd.find(buildFolder+"/") | |
if (build_it == -1): | |
continue | |
repCmd = newCmd[:build_it] | |
if (repCmd.find(".") == -1): | |
return cmd | |
repCmd = repCmd[repCmd.find("."):] | |
#print "RepCmd found: " + repCmd | |
break | |
for newCmd in newCmds: | |
if (newCmd == "cl.exe" or newCmd == "link" or newCmd == "lib"): | |
continue | |
newerCmd = newCmd | |
newerCmd = newerCmd.replace(repCmd,"") | |
#if newerCmd.find("../") != -1: | |
if newerCmd[0] != '-' and newerCmd[0] != '/' and newerCmd[0] != '@': | |
#If we have a lib file that is just a filename then it must | |
#be a library included from outside the module | |
if (newerCmd[-4:] == ".lib" and newerCmd.find("/") == -1): | |
print "Skipped: ",newerCmd | |
continue | |
if (repCmd == ""): | |
print "No wntmsci12.pro path found, unable to determine proper file location" | |
else: | |
foundFiles = tryToFindFile(newerCmd,repCmd,newCmd) | |
if len(foundFiles) > 0: | |
newerCmd = "" | |
for f in foundFiles: | |
newerCmd += "-I" + f + " " | |
for mainPath in mainPaths: | |
newerCmd = newerCmd.replace(mainPath + "/" + moduleName + "/","") | |
newerCmd = newerCmd.replace(mainPath,"..") | |
#print newerCmd | |
retCmd += newerCmd + " " | |
return retCmd | |
def addExtraDirs(arguments): | |
newArg = "" | |
for includeDir in extraIncludeDirs: | |
includeDir.strip() | |
includeDir = includeDir.split("/",1)[1] | |
includeDir = " -I" + includeDir + " " | |
newArg += " " + includeDir | |
arguments.append(newArg) | |
return arguments | |
def parseDLst(path): | |
repStrs = [("%_DEST%","..\solver\\410\\" + buildFolder),("%_EXT%",""),("%__SRC%",buildFolder)] | |
copyStr = "xcopy \"^SRC^\" \"^DEST^\\\" /D /Y /c" | |
try: | |
d = open(path) | |
except: | |
print ("Warning: Failed to load prj.lst; WinDeliver.bat will not be made") | |
return | |
data = d.read() | |
d.close() | |
data = data.split("\n") | |
outputBuf = "" | |
for line in data: | |
#We need to be one directory up from where we started | |
tmpLines = line.split() | |
line = "" | |
for tmpLine in tmpLines: | |
tmpLine = tmpLine.replace("..\\","",1) | |
line += tmpLine + " " | |
for repStr in repStrs: | |
line = line.replace(repStr[0],repStr[1]) | |
if (tmpLines != []): | |
lines = line.split(":",1) | |
#print lines | |
cmd = "" | |
#print lines | |
if (len(lines) == 1): | |
isDir = True | |
#Don't need the second filenames with XCopy | |
#print tmpLines | |
#tmpLines[1] = (tmpLines[1].rsplit("\\"))[0] | |
copyCmd = copyStr | |
files = line.split(" ") | |
newFiles = [] | |
for f in files: | |
if f == "": | |
continue | |
if f.find("*") != -1: | |
tmp = tryToFindFile(f,"","") | |
if len(tmp) == 0: | |
isDir = isDir | |
#print "Warning: no match for file " + f + " found" | |
elif len(tmp) > 1: | |
print "Warning: Multiple matches for file: " + f + " found" | |
print "Defaulting to use the first match" | |
f = tmp[0] | |
else: | |
print len(tmp) | |
print tmp[0] | |
f = tmp[0] | |
f = f.replace("/","\\") | |
if f.strip() != "" and f.strip() != []: | |
newFiles.append(f) | |
files = newFiles | |
dot_it = newFiles[0].rfind(".") | |
if dot_it > newFiles[0].rfind("\\"): | |
isDir = False | |
#print files | |
if (len(files) != 2): | |
print "Warning: unable to parse d.lst copy command" | |
#print files | |
continue | |
files[1] = (files[1].rsplit("\\",1))[0] | |
copyCmd = copyCmd.replace("^SRC^",files[0]) | |
copyCmd = copyCmd.replace("^DEST^",files[1]) | |
#Add these commands to copy over folders (including empty) | |
#and specify that the destination is a folder as well | |
if isDir: | |
copyCmd += " /i /E" | |
outputBuf += copyCmd + "\r\n" | |
else: | |
if (lines[0].strip() == "mkdir"): | |
outputBuf += lines[0].strip() + " " + lines[1] + "\n" | |
else: | |
print "Unknown command " + lines[0].strip() + "; ignoring" | |
out = open(os.path.join(moduleName,deliverBatName),"w") | |
out.write(outputBuf) | |
out.close() | |
#Open the last file used and add the batch file to its post build events | |
#patchLastVcProj() | |
def insert(original, new, pos): | |
'''Inserts new inside original at pos.''' | |
return original[:pos] + new + original[pos:] | |
def loadGlobalDeps(fileName): | |
endStr = "NULL" | |
f = open(fileName,"r") | |
contents = f.read() | |
f.close() | |
contents = contents[contents.find(":")+1:contents.find("\n")] | |
contents = contents.split() | |
globalDeps = [] | |
for module in contents: | |
#Some modules contain an uppercase name | |
#as well as a lower | |
if module.find(":") != -1: | |
module = module[module.find(":")+1:] | |
if module != "NULL": | |
globalDeps.append(module) | |
return globalDeps | |
def findAllDependencies(projects): | |
newPrjs = [] | |
for prj in projects: | |
deps = [preBuildId] | |
print prj | |
if (prj[1] == preBuildId): | |
continue | |
for prj2 in projects: | |
if (prj[0] == prj2[0]): | |
continue | |
for lib in prj[5]: | |
lib = lib[lib.rfind("/")+1:] | |
if (lib == prj2[2]): | |
deps.append(prj2[1]) | |
prj[3].extend(deps) | |
newPrj = prj[0], prj[1], prj[2], prj[3], prj[4], prj[5] | |
newPrjs.append(newPrj) | |
return newPrjs | |
def patchSolution(projects,fileName): | |
masterFileName = "solutionMaster.sln" | |
prjHeader = "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2012\n" | |
startDependStr = "\tProjectSection(ProjectDependencies) = postProject\n" | |
endDependStr = "\tEndProjectSection\n" | |
dependStr = "\t\t{^DEPENDENCY_GUID^} = {^DEPENDENCY_GUID^}" | |
dependStrId = "^DEPENDENCY_GUID^" | |
startPrjStr = "Project(\"{^SOLUTION_GUID^}\") = \"^PRJ_NAME^\", \"^FILENAME^\", \"{^THIS_PRJ_ID^}\"" | |
endPrjStr = "EndProject\n" | |
prjNameStr = "^PRJ_NAME^" | |
fileNameStr = "^FILENAME^" | |
thisPrjStr = "^THIS_PRJ_ID^" | |
slnIdStr = "^SOLUTION_GUID^" | |
globalStartStr = "Global\n" | |
globalEndStr = "EndGlobal\n" | |
globalPreStr = "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tRelease|Win32 = Release|Win32\n\tEndGlobalSection\n" | |
globalPreSolution = "\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n" | |
startGlobalPostStr = "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n" | |
endGlobalPostStr = "EndGlobalSection\n" | |
nestStart = "GlobalSection(NestedProjects) = preSolution\n" | |
nestMiddle = "{^PRJ_ID^} = {^FOLDER_ID^}\n" | |
nestEnd = "EndGlobalSection\n" | |
globalSettingsStr = "\t\t{^PRJ_ID^}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{^PRJ_ID^}.Release|Win32.Build.0 = Release|Win32\n" | |
#Not 100% certain if the first GUID is supposed to be the solution's | |
#but I can't find that GUID in any of the generated files so... | |
slnIdStr = "^SOLUTION_GUID^" | |
outFile = open(fileName,"w") | |
outputBuf = prjHeader | |
slnId = ProjectGUID() | |
projects = findAllDependencies(projects) | |
allPrjIds = [] | |
if len(projects) > 0: | |
#ToDo: Add all projects from dependency | |
#solution files if they exist, or add placeholder | |
#Makefile projects | |
for prj in projects: | |
allPrjIds.append(prj[1]) | |
prjStr = startPrjStr | |
prjStr = prjStr.replace(prjNameStr,prj[0]) | |
tempPrj = prj[4] | |
tempPrj = tempPrj.replace(moduleName + "\\","",1) | |
prjStr = prjStr.replace(fileNameStr,tempPrj) | |
prjStr = prjStr.replace(slnIdStr,slnId) | |
prjStr = prjStr.replace(thisPrjStr,prj[1]) | |
outputBuf += prjStr + "\n" | |
#Add any dependencies | |
if len(prj[3]) > 0: | |
outputBuf += startDependStr | |
allDepsStr = "" | |
#outputBuf += | |
#Add each dependency | |
for dep in prj[3]: | |
newDepStr = dependStr.replace(dependStrId, dep) | |
allDepsStr += newDepStr + "\n" | |
outputBuf += allDepsStr | |
outputBuf += endDependStr | |
outputBuf += endPrjStr | |
outputBuf += beginDepComment | |
outputBuf += globalStartStr | |
outputBuf += globalPreStr | |
outputBuf += startGlobalPostStr | |
for prjId in allPrjIds: | |
outputBuf += globalSettingsStr.replace("^PRJ_ID^",prjId) | |
outputBuf += endGlobalPostStr | |
outputBuf += globalPreSolution | |
#Include projects from the global dependencies here | |
outputBuf += nestStart | |
outputBuf += globalEndStr | |
outFile.write(outputBuf) | |
else: | |
print "No projects were found for this solution, so the solution file will not be written" | |
outFile.close() | |
def patchVCProjExeDll(prjName,files,arguments,exeArgs,cfgType,objOut,outputFile,mapName,libIn): | |
print "EXE/DLL Project" | |
prjName = sanitizeArg(prjName) | |
dependencies = [] | |
#Remove any file extenions from the project name | |
if (prjName.find(".") != -1): | |
prjName = prjName[0:prjName.find(".")] | |
rootFile = "exeProj.vcxproj" | |
cfgStr = "^CFG_TYPE^" | |
compileStr = "^BEGIN_CLCOMPILE^" | |
endCompileStr = "^END_CLCOMPILE^" | |
clFileName = "^CLFILENAME^" | |
guidStr = "^GUID^" | |
addStr = "^ADDITIONAL_OPTIONS^" | |
nameStr = "^PROJ_NAME^" | |
outputStr = "^OUTPUT^" | |
linkStr = "^LINK_OPTIONS^" | |
linkOutStr = "^LINK_OUT^" | |
objStr = "^OBJ_FILE_NAME^" | |
preStr = "^PREBUILD^" | |
postStr = "^POSTBUILD^" | |
libDirStr = "^LIBRARY_DIR^" | |
doMapStr = "^BOOL_DO_MAP^" | |
mapFileStr = "^MAP_NAME^" | |
outputFileStr = "^OUTPUT_FILE_NAME^" | |
arguments = addExtraDirs(arguments) | |
ourLib = [] | |
#Find any files that look like they were generated by this module | |
for l in libIn: | |
if (l.find("/") != -1): | |
ourLib.append(l) | |
files.extend(ourLib) | |
if mapName != "": | |
doMap = "true" | |
else: | |
doMap = "" | |
libraryPath = "..\\solver\\410\\wntmsci12.pro\\lib;wntmsci12.pro\\lib;wntmsci12.pro\\slb" | |
linkOut = "wntmsci12.pro\\bin\\"+ outputFile[outputFile.rfind("/")+1:] | |
targetName = outputFile[max(outputFile.rfind("/"),outputFile.rfind("\\"))+1:outputFile.rfind(".")] | |
targetNameWExt = outputFile[max(outputFile.rfind("/"),outputFile.rfind("\\"))+1:] | |
f = open(rootFile,"r") | |
origFile = f.read() | |
f.close() | |
it = origFile.find(compileStr)+len(compileStr) | |
end_it = origFile.find(endCompileStr,it) | |
compileLine = origFile[it:end_it] | |
prjId = sanitizeArg(ProjectGUID()) | |
fileOut = "" | |
for fName in files: | |
fileOut += compileLine.replace(clFileName,sanitizeArg(fName)) + "\n\t" | |
origFile = origFile.replace(origFile[it-len(compileStr):end_it+len(endCompileStr)],fileOut) | |
origFile = origFile.replace(guidStr,prjId) | |
origFile = origFile.replace(addStr, ' '.join(map(str, arguments))) | |
origFile = origFile.replace(nameStr,sanitizeArg(prjName)) | |
origFile = origFile.replace(linkStr,exeArgs) | |
origFile = origFile.replace(objStr,sanitizeArg(objOut)) | |
origFile = origFile.replace(preStr,"") | |
origFile = origFile.replace(postStr,"") | |
origFile = origFile.replace(cfgStr,sanitizeArg(cfgType)) | |
origFile = origFile.replace(linkOutStr,sanitizeArg(linkOut)) | |
origFile = origFile.replace(libDirStr,sanitizeArg(libraryPath)) | |
origFile = origFile.replace(doMapStr,sanitizeArg(doMap)) | |
origFile = origFile.replace(mapFileStr,sanitizeArg(mapName)) | |
origFile = origFile.replace(outputStr,objOut) | |
origFile = origFile.replace(outputFileStr,sanitizeArg(targetName)) | |
moduleFileName = os.path.join(moduleName, prjName + ".vcxproj") | |
outFile = open(moduleFileName,"w") | |
if (len(origFile) > FILESIZE_LIMIT): | |
print "Warning: string size exceeds 500kb, file will not be written" | |
return | |
prjTuple = prjName, prjId, targetNameWExt, dependencies, moduleFileName, ourLib | |
allProjects.append(prjTuple) | |
outFile.write(origFile) | |
outFile.close() | |
return | |
def sanitizeArg(arg): | |
arg = arg.replace("\n","") | |
arg = arg.replace("\r","") | |
arg = arg.strip() | |
return arg | |
#Check if the input is a valid command line argument or junk | |
#left over | |
def isArg(arg): | |
arg = arg.strip() | |
if arg == "": | |
return False | |
#Check if we have a dash or slash, denoting a command | |
if arg[0] == '/' or arg[0] == '-': | |
return True | |
#Check for a filename | |
if arg[0].find(".") != -1: | |
return True | |
return False | |
def patchVCProjMake(prjName,isPostBuild,buildCmd,rebuildCmd,cleanCmd): | |
rootFile = "make_proj_master.vcxproj" | |
f = open(rootFile,"r") | |
guidStr = "^GUID^" | |
prjNameStr = "^PRJ_NAME^" | |
buildTypeStr = "^BUILD_TYPE^" | |
buildCmdStr = "^BUILD_CMD^" | |
rebuildCmdStr = "^REBUILD_CMD^" | |
cleanCmdStr = "^CLEAN_CMD^" | |
origFile = f.read() | |
moduleFileName = "" | |
if isPostBuild: | |
buildType = "deliver" | |
else: | |
buildType = "prebuild" | |
f.close() | |
if (isPostBuild): | |
moduleFileName = prjName+"/"+prjName+"_deliver.vcxproj" | |
f = open(moduleFileName,"w") | |
else: | |
moduleFileName = prjName+"/"+prjName+"_prebuild.vcxproj" | |
f = open(moduleFileName,"w") | |
prjId = ProjectGUID() | |
if (isPostBuild): | |
newName = prjName + "_deliver" | |
else: | |
newName = prjName + "_prebuild" | |
origFile = origFile.replace(guidStr,sanitizeArg(prjId)) | |
origFile = origFile.replace(prjNameStr,sanitizeArg(newName.strip())) | |
origFile = origFile.replace(buildTypeStr,sanitizeArg(buildType)) | |
origFile = origFile.replace(buildCmdStr,buildCmd) | |
origFile = origFile.replace(rebuildCmdStr,rebuildCmd) | |
origFile = origFile.replace(cleanCmdStr,cleanCmd) | |
f.write(origFile) | |
f.close() | |
dependencies = [] | |
if (isPostBuild): | |
for prj in allProjects: | |
dependencies.append(prj[1]) | |
else: | |
preBuildId = prjId | |
prjTuple = newName.strip(), prjId, "", dependencies, moduleFileName[moduleFileName.rfind("/")+1:], [] | |
allProjects.append(prjTuple) | |
def patchVCProjLib(prjName,files,arguments,libArgs,objOut,allLibFiles,libOut,libIn): | |
#allLibFiles needs to be added as a copy command in postbuild from the | |
#output of the original build | |
print "Lib project" | |
dependencies = [] | |
rootFile = "libProj.vcxproj" | |
prjName = sanitizeArg(prjName) | |
ourLib = [] | |
#Find any files that look like they were generated by this module | |
for l in libIn: | |
if (l.find("/") != -1): | |
ourLib.append(l) | |
files.extend(ourLib) | |
#Remove any file extenions from the project name | |
if (prjName.find(".") != -1): | |
prjName = prjName[0:prjName.find(".")] | |
print prjName | |
#print "##########################################" | |
#print prjName | |
#print files | |
#print arguments | |
#print outDir | |
compileStr = "^BEGIN_CLCOMPILE^" | |
endCompileStr = "^END_CLCOMPILE^" | |
clFileName = "^CLFILENAME^" | |
guidStr = "^GUID^" | |
addStr = "^ADDITIONAL_OPTIONS^" | |
nameStr = "^PROJ_NAME^" | |
outputStr = "^OUTPUT^" | |
libStr = "^LIB_OPTIONS^" | |
linkOutStr = "^LINK_OUT^" | |
objStr = "^OBJ_FILE_NAME^" | |
libStrOut = "^LIB_OUTPUT_FILE^" | |
preStr = "^PREBUILD^" | |
postStr = "^POSTBUILD^" | |
outputFileStr = "^OUTPUT_FILE_NAME^" | |
outDirStr = "^OUTDIR^" | |
targetName = libOut[max(libOut.rfind("/"),libOut.rfind("\\"))+1:libOut.rfind(".")] | |
targetNameWExt = libOut[max(libOut.rfind("/"),libOut.rfind("\\"))+1:] | |
outputFile = libOut | |
arguments = addExtraDirs(arguments) | |
f = open(rootFile,"r") | |
origFile = f.read() | |
f.close() | |
it = origFile.find(compileStr)+len(compileStr) | |
end_it = origFile.find(endCompileStr,it) | |
compileLine = origFile[it:end_it] | |
fileOut = "" | |
for fName in files: | |
fName = fName.replace("\n","") | |
fName = fName.replace("\r","") | |
fileOut += compileLine.replace(clFileName,fName) + "\n\t" | |
prjId = sanitizeArg(ProjectGUID()) | |
origFile = origFile.replace(origFile[it-len(compileStr):end_it+len(endCompileStr)],sanitizeArg(fileOut)) | |
origFile = origFile.replace(guidStr,prjId) | |
origFile = origFile.replace(preStr,"") | |
origFile = origFile.replace(postStr,"") | |
origFile = origFile.replace(addStr, ' '.join(map(str, arguments))) | |
origFile = origFile.replace(nameStr,sanitizeArg(prjName)) | |
origFile = origFile.replace(libStr,sanitizeArg(libArgs)) | |
origFile = origFile.replace(objStr,sanitizeArg(objOut)) | |
origFile = origFile.replace(outputFileStr,sanitizeArg(targetName)) | |
origFile = origFile.replace(libStrOut,sanitizeArg(outputFile)) | |
origFile = origFile.replace(outDirStr,libOut[:max(libOut.rfind("\\"),libOut.rfind("/"))+1]) | |
print "Lib out: " + libOut | |
moduleFileName = os.path.join(moduleName, prjName + ".vcxproj") | |
outFile = open(moduleFileName,"w") | |
print moduleFileName | |
if (len(origFile) > FILESIZE_LIMIT): | |
print "Warning: string size exceeds 500kb, file will not be written" | |
return | |
prjTuple = prjName.strip(), prjId, targetNameWExt, dependencies, moduleFileName, ourLib | |
allProjects.append(prjTuple) | |
outFile.write(origFile) | |
outFile.close() | |
def checkFilename(inputName, names, extensions): | |
temp = inputName.split(".") | |
if temp[0] in names: | |
return True | |
elif (len(temp) > 1 and temp[1] in extensions): | |
return True | |
else: | |
return False | |
def directories(path): | |
for file in os.listdir(path): | |
if os.path.isdir(os.path.join(path, file)): | |
yield file | |
def runEveryFolder(startDir): | |
try: | |
os.mkdir(startDir + '\\' + outputDir) | |
except: | |
pass | |
for d in directories(startDir): | |
print ('######################') | |
main(os.path.join(startDir + '\\' + d),startDir) | |
print ('######################') | |
# Run the script from the AOO main directory - alternatively, pass in the path to the main directory below | |
if (len(sys.argv) != 2): | |
print "Usage: python vcGen.py moduleName\nRun from main AOO directory and have output file in the name <modulename>/<modulename>.txt" | |
exit | |
moduleName = sys.argv[1] | |
print ############################################### | |
try: | |
os.mkdir(os.getcwd() + "\\" + moduleName) | |
except: | |
pass | |
addPrebuild() | |
newParse(moduleName + "/" + moduleName + ".txt") | |
patchVCProjMake(moduleName,True,"WinDeliver.bat","","") | |
patchSolution(allProjects,os.path.join(moduleName, moduleName + ".sln")) | |
parseDLst(os.path.join(moduleName,"prj",deliverFileName)) | |
print allProjects |