blob: 137f60b9b2cb0cd47eae9f98680af81b64ec6c7d [file] [log] [blame]
Daniel Dunbarab130612009-01-13 07:38:29 +00001#!/usr/bin/python
2
3import subprocess
4
5def splitArgs(s):
6 it = iter(s)
7 current = ''
8 inQuote = False
9 for c in it:
10 if c == '"':
11 if inQuote:
12 inQuote = False
13 yield current + '"'
14 else:
15 inQuote = True
16 current = '"'
17 elif inQuote:
18 if c == '\\':
19 current += c
20 current += it.next()
21 else:
22 current += c
23 elif not c.isspace():
24 yield c
25
26def insertMinimumPadding(a, b, dist):
27 """insertMinimumPadding(a,b) -> (a',b')
28
29 Return two lists of equal length, where some number of Nones have
30 been inserted into the shorter list such that sum(map(dist, a',
31 b')) is minimized.
32
33 Assumes dist(X, Y) -> int and non-negative.
34 """
35
36 # Yay for simplicity over complexity.
37
38 def extend(aElt, bElt, solution):
39 d0,(a0,b0) = solution
40 return d0 + dist(aElt,bElt), (([aElt]+a0),([bElt]+b0))
41
42 def f(a, b):
43 if len(a) == len(b):
44 return (sum(map(dist, a, b)), (a, b))
45
46 if not a or not b:
47 if not a:
48 a += [None] * len(b)
49 else:
50 b += [None] * len(a)
51 return (sum(map(dist, a, b)), (a, b))
52
53 if int(dist(a[0], b[0])) == 0:
54 # Non-negative condition implies maximum is satisfied
55 # taking this.
56 return extend(a[0], b[0], f(a[1:], b[1:]))
57
58 if len(a) < len(b):
59 return min(f([None] + a, b),
60 extend(a[0], b[0], f(a[1:], b[1:])))
61 else:
62 return min(f(a, [None] + b),
63 extend(a[0], b[0], f(a[1:], b[1:])))
64
65 return f(a, b)[1]
66
67class ZipperDiff(object):
68 """ZipperDiff - Simple (slow) diff only accomodating inserts."""
69
70 def __init__(self, a, b):
71 self.a = a
72 self.b = b
73
74 def dist(self, a, b):
75 return a != b
76
77 def getDiffs(self):
78 a,b = insertMinimumPadding(self.a, self.b, self.dist)
79 for aElt,bElt in zip(a,b):
80 if self.dist(aElt, bElt):
81 yield aElt,bElt
82
83class DriverZipperDiff(ZipperDiff):
84 def isTempFile(self, filename):
85 if filename[0] != '"' or filename[-1] != '"':
86 return False
87 return (filename.startswith('/tmp/', 1) or
88 filename.startswith('/var/', 1))
89
90 def dist(self, a, b):
91 if a and b and self.isTempFile(a) and self.isTempFile(b):
92 return 0
93 return super(DriverZipperDiff, self).dist(a,b)
94
95class CompileInfo:
96 def __init__(self, out, err, res):
97 self.commands = []
98
99 # Standard out isn't used for much.
100 self.stdout = out
101 self.stderr = ''
102
103 # FIXME: Compare error messages as well.
104 for ln in err.split('\n'):
105 if (ln == 'Using built-in specs.' or
106 ln.startswith('Target: ') or
107 ln.startswith('Configured with: ') or
108 ln.startswith('Thread model: ') or
109 ln.startswith('gcc version')):
110 pass
111 elif ln.strip().startswith('"'):
112 self.commands.append(list(splitArgs(ln)))
113 else:
114 self.stderr += ln + '\n'
115
116 self.stderr = self.stderr.strip()
117 self.exitCode = res
118
119def captureDriverInfo(cmd, args):
120 p = subprocess.Popen([cmd,'-###'] + args,
121 stdin=None,
122 stdout=subprocess.PIPE,
123 stderr=subprocess.PIPE)
124 out,err = p.communicate()
125 res = p.wait()
126 return CompileInfo(out,err,res)
127
128def main():
129 import sys
130
131 args = sys.argv[1:]
132 driverA = 'gcc'
133 driverB = 'xcc'
134
135 infoA = captureDriverInfo(driverA, args)
136 infoB = captureDriverInfo(driverB, args)
137
138 # Compare stdout.
139 if infoA.stdout != infoB.stdout:
140 print '-- STDOUT DIFFERS -'
141 print 'A: ',infoA.stdout
142 print 'B: ',infoB.stdout
143
144 # Compare stderr.
145 if infoA.stderr != infoB.stderr:
146 print '-- STDERR DIFFERS -'
147 print 'A: ',infoA.stderr
148 print 'B: ',infoB.stderr
149
150 # Compare commands.
151 for i,(a,b) in enumerate(zip(infoA.commands, infoB.commands)):
152 diff = DriverZipperDiff(a,b)
153 diffs = list(diff.getDiffs())
154 if diffs:
155 print '-- COMMAND %d DIFFERS -' % i
156 print 'A COMMAND:',' '.join(a)
157 print 'B COMMAND:',' '.join(b)
158 print
159 for i,(aElt,bElt) in enumerate(diffs):
160 if aElt is None:
161 print 'A missing: %s' % bElt
162 elif bElt is None:
163 print 'B missing: %s' % aElt
164 else:
165 print 'mismatch: A: %s' % aElt
166 print ' B: %s' % bElt
167
168 # Compare result codes.
169 if infoA.exitCode != infoB.exitCode:
170 print '-- EXIT CODES DIFFER -'
171 print 'A: ',infoA.exitCode
172 print 'B: ',infoB.exitCode
173
174if __name__ == '__main__':
175 main()