1*cdf0e10cSrcweir#!/usr/bin/python 2*cdf0e10cSrcweir 3*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 4*cdf0e10cSrcweir# Hacky little delta debug tool to figure out the proper includes for a pch file 5*cdf0e10cSrcweir# 6*cdf0e10cSrcweir# Usage: 7*cdf0e10cSrcweir# 8*cdf0e10cSrcweir# pchdelta.py <pch_target> <dir1> [<dir2> <dir3> ...] 9*cdf0e10cSrcweir# 10*cdf0e10cSrcweir# <pch_target> File to perform delta debugging on. The section to test 11*cdf0e10cSrcweir# is delimeted by '//---MARKER---' lines. 12*cdf0e10cSrcweir# <dir1> .. <dirn> Sequence of directories to run dmake in to test if the 13*cdf0e10cSrcweir# modification works 14*cdf0e10cSrcweir# 15*cdf0e10cSrcweir# Examples: 16*cdf0e10cSrcweir# 17*cdf0e10cSrcweir# pchdelta.py inc/pch/precompiled_sfx2.hxx inc source/dialog 18*cdf0e10cSrcweir# 19*cdf0e10cSrcweir# Run pchdelta inside sfx2 first building the pch files and then files in 20*cdf0e10cSrcweir# source/dialog 21*cdf0e10cSrcweir# 22*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 23*cdf0e10cSrcweir 24*cdf0e10cSrcweirimport os 25*cdf0e10cSrcweirimport os.path 26*cdf0e10cSrcweirimport sys 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir# C++ 29*cdf0e10cSrcweirMARKER="//---MARKER---\n" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir# dmake 32*cdf0e10cSrcweir#MARKER="#---MARKER---\n" 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 35*cdf0e10cSrcweir# Sequentially build all argument directories from scratch 36*cdf0e10cSrcweir 37*cdf0e10cSrcweirdef testSequenceBuild(dirlist): 38*cdf0e10cSrcweir cwd = os.path.abspath(os.getcwd()) 39*cdf0e10cSrcweir for path in dirlist: 40*cdf0e10cSrcweir os.chdir(path) 41*cdf0e10cSrcweir buildcommand = "dmake -u" 42*cdf0e10cSrcweir buildcommand += " >>" + cwd + "/buildlog.txt 2>&1" 43*cdf0e10cSrcweir buildresult = os.system(buildcommand) 44*cdf0e10cSrcweir os.chdir(cwd) 45*cdf0e10cSrcweir if buildresult != 0: 46*cdf0e10cSrcweir return False 47*cdf0e10cSrcweir return True 48*cdf0e10cSrcweir 49*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 50*cdf0e10cSrcweir# Dump out the delta file with corresponding markers 51*cdf0e10cSrcweir 52*cdf0e10cSrcweirdef writePch(pchname, header, footer, acceptedlines, testlines): 53*cdf0e10cSrcweir outputfile = file(pchname, "w") 54*cdf0e10cSrcweir outputfile.write(header) 55*cdf0e10cSrcweir outputfile.write(MARKER) 56*cdf0e10cSrcweir outputfile.write("\n".join(acceptedlines)) 57*cdf0e10cSrcweir if len(testlines) > 0: 58*cdf0e10cSrcweir outputfile.write("\n\n//---Candidate marker---\n") 59*cdf0e10cSrcweir outputfile.write("\n".join(testlines) + "\n") 60*cdf0e10cSrcweir outputfile.write("//---Candidate marker end---\n") 61*cdf0e10cSrcweir outputfile.write(MARKER) 62*cdf0e10cSrcweir outputfile.write(footer) 63*cdf0e10cSrcweir outputfile.close() 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 67*cdf0e10cSrcweir# Recursive tester routine. Test the segment given and if an error is 68*cdf0e10cSrcweir# encountered splits the segment into <fanout> subsegment and recurses. Failing 69*cdf0e10cSrcweir# one liners are rejected. The set of accepted lines are built sequentially from 70*cdf0e10cSrcweir# the beginning. 71*cdf0e10cSrcweir 72*cdf0e10cSrcweirdef binaryTest(dirlist, lines, pchname, header, footer, acceptedlines, indent, startpoint): 73*cdf0e10cSrcweir linecount = len(lines) 74*cdf0e10cSrcweir if linecount == 0: 75*cdf0e10cSrcweir return 76*cdf0e10cSrcweir # Test if this slice passes the buildtest 77*cdf0e10cSrcweir writePch(pchname, header, footer, acceptedlines, lines) 78*cdf0e10cSrcweir if testSequenceBuild(dirlist): 79*cdf0e10cSrcweir return acceptedlines + lines 80*cdf0e10cSrcweir 81*cdf0e10cSrcweir # Reject one liners 82*cdf0e10cSrcweir if linecount == 1: 83*cdf0e10cSrcweir print indent + "Rejected: " + lines[0] 84*cdf0e10cSrcweir return acceptedlines 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir # Recurse with multiline slices 87*cdf0e10cSrcweir fanout = 4 88*cdf0e10cSrcweir splits = [] 89*cdf0e10cSrcweir for i in range(3): 90*cdf0e10cSrcweir splits.append(linecount * (i + 1) / fanout) 91*cdf0e10cSrcweir splits.append(linecount) 92*cdf0e10cSrcweir 93*cdf0e10cSrcweir splitstart = 0 94*cdf0e10cSrcweir for splitend in splits: 95*cdf0e10cSrcweir # avoid splitting in case we have no resulting lines 96*cdf0e10cSrcweir if (splitend - splitstart) == 0: 97*cdf0e10cSrcweir continue 98*cdf0e10cSrcweir splitslice = lines[splitstart:splitend] 99*cdf0e10cSrcweir print indent + "[" + str(startpoint + splitstart) + ":" + str(startpoint + splitend) + "] (" + str(splitend - splitstart) + ")" 100*cdf0e10cSrcweir acceptedlines = binaryTest(dirlist, splitslice, pchname, header, footer, acceptedlines, indent + " ", startpoint + splitstart) 101*cdf0e10cSrcweir splitstart = splitend 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir return acceptedlines 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir# ------------------------------------------------------------------------------ 106*cdf0e10cSrcweir# Main entry point 107*cdf0e10cSrcweir 108*cdf0e10cSrcweirif len(sys.argv) < 3: 109*cdf0e10cSrcweir print "Usage: " + sys.argv[0] + " <pch_target> <dir1> [<dir2> <dir3> ...]" 110*cdf0e10cSrcweir sys.exit(1) 111*cdf0e10cSrcweir 112*cdf0e10cSrcweirpchname = os.path.abspath(sys.argv[1]) 113*cdf0e10cSrcweirdirlist = sys.argv[2:] 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir# remove old build log file 116*cdf0e10cSrcweirif os.path.exists("buildlog.txt"): 117*cdf0e10cSrcweir os.remove("buildlog.txt") 118*cdf0e10cSrcweir 119*cdf0e10cSrcweir# test for corner case of everything working from the start 120*cdf0e10cSrcweirif testSequenceBuild(dirlist): 121*cdf0e10cSrcweir print "pch working, nothing to do." 122*cdf0e10cSrcweir sys.exit(0) 123*cdf0e10cSrcweir 124*cdf0e10cSrcweir# Open the header file for reading 125*cdf0e10cSrcweirinputfile = file(pchname, "r+") 126*cdf0e10cSrcweirinputdata = inputfile.read() 127*cdf0e10cSrcweirinputfile.close() 128*cdf0e10cSrcweir 129*cdf0e10cSrcweirsegments = inputdata.split(MARKER) 130*cdf0e10cSrcweirheader = segments[0] 131*cdf0e10cSrcweirfooter = segments[2] 132*cdf0e10cSrcweirlines = segments[1].split("\n") 133*cdf0e10cSrcweir 134*cdf0e10cSrcweirwritePch(pchname + "_backup", header, footer, lines, []) 135*cdf0e10cSrcweir 136*cdf0e10cSrcweir# test for corner case of no convergence possible 137*cdf0e10cSrcweirwritePch(pchname, header, footer, [], []) 138*cdf0e10cSrcweirif not testSequenceBuild(dirlist): 139*cdf0e10cSrcweir writePch(pchname, header, footer, lines, []) 140*cdf0e10cSrcweir print "Building with no candidate lines failed. Convergence questionable, aborting." 141*cdf0e10cSrcweir sys.exit(0) 142*cdf0e10cSrcweir 143*cdf0e10cSrcweir# Starting pruning 144*cdf0e10cSrcweirprint "Starting evaluation of " + str(len(lines)) + " lines" 145*cdf0e10cSrcweiracceptedlines = binaryTest(dirlist, lines, pchname, header, footer, [], "", 0) 146*cdf0e10cSrcweirwritePch(pchname, header, footer, acceptedlines, []) 147*cdf0e10cSrcweir 148*cdf0e10cSrcweir 149*cdf0e10cSrcweir 150