2008-08-18 07:10:52 -05:00
|
|
|
#!/usr/bin/python
|
2007-05-10 09:10:04 -05:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Hacky little delta debug tool to figure out the proper includes for a pch file
|
|
|
|
#
|
|
|
|
# Usage:
|
|
|
|
#
|
|
|
|
# pchdelta.py <pch_target> <dir1> [<dir2> <dir3> ...]
|
|
|
|
#
|
|
|
|
# <pch_target> File to perform delta debugging on. The section to test
|
|
|
|
# is delimeted by '//---MARKER---' lines.
|
|
|
|
# <dir1> .. <dirn> Sequence of directories to run dmake in to test if the
|
|
|
|
# modification works
|
|
|
|
#
|
|
|
|
# Examples:
|
|
|
|
#
|
|
|
|
# pchdelta.py inc/pch/precompiled_sfx2.hxx inc source/dialog
|
|
|
|
#
|
|
|
|
# Run pchdelta inside sfx2 first building the pch files and then files in
|
|
|
|
# source/dialog
|
|
|
|
#
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import sys
|
|
|
|
|
|
|
|
# C++
|
|
|
|
MARKER="//---MARKER---\n"
|
|
|
|
|
|
|
|
# dmake
|
|
|
|
#MARKER="#---MARKER---\n"
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Sequentially build all argument directories from scratch
|
|
|
|
|
|
|
|
def testSequenceBuild(dirlist):
|
|
|
|
cwd = os.path.abspath(os.getcwd())
|
|
|
|
for path in dirlist:
|
|
|
|
os.chdir(path)
|
|
|
|
buildcommand = "dmake -u"
|
|
|
|
buildcommand += " >>" + cwd + "/buildlog.txt 2>&1"
|
|
|
|
buildresult = os.system(buildcommand)
|
|
|
|
os.chdir(cwd)
|
|
|
|
if buildresult != 0:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Dump out the delta file with corresponding markers
|
|
|
|
|
|
|
|
def writePch(pchname, header, footer, acceptedlines, testlines):
|
|
|
|
outputfile = file(pchname, "w")
|
|
|
|
outputfile.write(header)
|
|
|
|
outputfile.write(MARKER)
|
|
|
|
outputfile.write("\n".join(acceptedlines))
|
|
|
|
if len(testlines) > 0:
|
|
|
|
outputfile.write("\n\n//---Candidate marker---\n")
|
|
|
|
outputfile.write("\n".join(testlines) + "\n")
|
|
|
|
outputfile.write("//---Candidate marker end---\n")
|
|
|
|
outputfile.write(MARKER)
|
|
|
|
outputfile.write(footer)
|
|
|
|
outputfile.close()
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Recursive tester routine. Test the segment given and if an error is
|
|
|
|
# encountered splits the segment into <fanout> subsegment and recurses. Failing
|
|
|
|
# one liners are rejected. The set of accepted lines are built sequentially from
|
|
|
|
# the beginning.
|
|
|
|
|
|
|
|
def binaryTest(dirlist, lines, pchname, header, footer, acceptedlines, indent, startpoint):
|
|
|
|
linecount = len(lines)
|
|
|
|
if linecount == 0:
|
|
|
|
return
|
|
|
|
# Test if this slice passes the buildtest
|
|
|
|
writePch(pchname, header, footer, acceptedlines, lines)
|
|
|
|
if testSequenceBuild(dirlist):
|
|
|
|
return acceptedlines + lines
|
|
|
|
|
|
|
|
# Reject one liners
|
|
|
|
if linecount == 1:
|
|
|
|
print indent + "Rejected: " + lines[0]
|
|
|
|
return acceptedlines
|
|
|
|
|
|
|
|
# Recurse with multiline slices
|
|
|
|
fanout = 4
|
|
|
|
splits = []
|
|
|
|
for i in range(3):
|
|
|
|
splits.append(linecount * (i + 1) / fanout)
|
|
|
|
splits.append(linecount)
|
|
|
|
|
|
|
|
splitstart = 0
|
|
|
|
for splitend in splits:
|
|
|
|
# avoid splitting in case we have no resulting lines
|
|
|
|
if (splitend - splitstart) == 0:
|
|
|
|
continue
|
|
|
|
splitslice = lines[splitstart:splitend]
|
|
|
|
print indent + "[" + str(startpoint + splitstart) + ":" + str(startpoint + splitend) + "] (" + str(splitend - splitstart) + ")"
|
|
|
|
acceptedlines = binaryTest(dirlist, splitslice, pchname, header, footer, acceptedlines, indent + " ", startpoint + splitstart)
|
|
|
|
splitstart = splitend
|
|
|
|
|
|
|
|
return acceptedlines
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Main entry point
|
|
|
|
|
|
|
|
if len(sys.argv) < 3:
|
|
|
|
print "Usage: " + sys.argv[0] + " <pch_target> <dir1> [<dir2> <dir3> ...]"
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
pchname = os.path.abspath(sys.argv[1])
|
|
|
|
dirlist = sys.argv[2:]
|
|
|
|
|
|
|
|
# remove old build log file
|
|
|
|
if os.path.exists("buildlog.txt"):
|
|
|
|
os.remove("buildlog.txt")
|
|
|
|
|
|
|
|
# test for corner case of everything working from the start
|
|
|
|
if testSequenceBuild(dirlist):
|
|
|
|
print "pch working, nothing to do."
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
# Open the header file for reading
|
|
|
|
inputfile = file(pchname, "r+")
|
|
|
|
inputdata = inputfile.read()
|
|
|
|
inputfile.close()
|
|
|
|
|
|
|
|
segments = inputdata.split(MARKER)
|
|
|
|
header = segments[0]
|
|
|
|
footer = segments[2]
|
|
|
|
lines = segments[1].split("\n")
|
|
|
|
|
|
|
|
writePch(pchname + "_backup", header, footer, lines, [])
|
|
|
|
|
|
|
|
# test for corner case of no convergence possible
|
|
|
|
writePch(pchname, header, footer, [], [])
|
|
|
|
if not testSequenceBuild(dirlist):
|
|
|
|
writePch(pchname, header, footer, lines, [])
|
|
|
|
print "Building with no candidate lines failed. Convergence questionable, aborting."
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
# Starting pruning
|
|
|
|
print "Starting evaluation of " + str(len(lines)) + " lines"
|
|
|
|
acceptedlines = binaryTest(dirlist, lines, pchname, header, footer, [], "", 0)
|
|
|
|
writePch(pchname, header, footer, acceptedlines, [])
|
|
|
|
|
|
|
|
|
|
|
|
|