4 A simple utility that compares tool invocations and exit codes issued by
5 compiler drivers that support -### (e.g. gcc and clang).
31 def insertMinimumPadding(a, b, dist):
32 """insertMinimumPadding(a,b) -> (a',b')
34 Return two lists of equal length, where some number of Nones have
35 been inserted into the shorter list such that sum(map(dist, a',
38 Assumes dist(X, Y) -> int and non-negative.
42 return sum(map(dist, a + [None] * (len(b) - len(a)), b))
44 # Normalize so a is shortest.
46 b, a = insertMinimumPadding(b, a, dist)
49 # For each None we have to insert...
50 for i in range(len(b) - len(a)):
51 # For each position we could insert it...
54 for j in range(len(a) + 1):
55 a_0 = a[:j] + [None] + a[j:]
56 candidate = cost(a_0, b)
57 if best is None or candidate < best[0]:
58 best = (candidate, a_0, j)
62 class ZipperDiff(object):
63 """ZipperDiff - Simple (slow) diff only accommodating inserts."""
65 def __init__(self, a, b):
73 a,b = insertMinimumPadding(self.a, self.b, self.dist)
74 for aElt,bElt in zip(a,b):
75 if self.dist(aElt, bElt):
78 class DriverZipperDiff(ZipperDiff):
79 def isTempFile(self, filename):
80 if filename[0] != '"' or filename[-1] != '"':
82 return (filename.startswith('/tmp/', 1) or
83 filename.startswith('/var/', 1))
86 if a and b and self.isTempFile(a) and self.isTempFile(b):
88 return super(DriverZipperDiff, self).dist(a,b)
91 def __init__(self, out, err, res):
94 # Standard out isn't used for much.
98 # FIXME: Compare error messages as well.
99 for ln in err.split('\n'):
100 if (ln == 'Using built-in specs.' or
101 ln.startswith('Target: ') or
102 ln.startswith('Configured with: ') or
103 ln.startswith('Thread model: ') or
104 ln.startswith('gcc version') or
105 ln.startswith('clang version')):
107 elif ln.strip().startswith('"'):
108 self.commands.append(list(splitArgs(ln)))
110 self.stderr += ln + '\n'
112 self.stderr = self.stderr.strip()
115 def captureDriverInfo(cmd, args):
116 p = subprocess.Popen([cmd,'-###'] + args,
118 stdout=subprocess.PIPE,
119 stderr=subprocess.PIPE)
120 out,err = p.communicate()
122 return CompileInfo(out,err,res)
128 driverA = os.getenv('DRIVER_A') or 'gcc'
129 driverB = os.getenv('DRIVER_B') or 'clang'
131 infoA = captureDriverInfo(driverA, args)
132 infoB = captureDriverInfo(driverB, args)
137 if infoA.stdout != infoB.stdout:
138 print '-- STDOUT DIFFERS -'
139 print 'A OUTPUT: ',infoA.stdout
140 print 'B OUTPUT: ',infoB.stdout
143 diff = ZipperDiff(infoA.stdout.split('\n'),
144 infoB.stdout.split('\n'))
145 for i,(aElt,bElt) in enumerate(diff.getDiffs()):
147 print 'A missing: %s' % bElt
149 print 'B missing: %s' % aElt
151 print 'mismatch: A: %s' % aElt
152 print ' B: %s' % bElt
157 if infoA.stderr != infoB.stderr:
158 print '-- STDERR DIFFERS -'
159 print 'A STDERR: ',infoA.stderr
160 print 'B STDERR: ',infoB.stderr
163 diff = ZipperDiff(infoA.stderr.split('\n'),
164 infoB.stderr.split('\n'))
165 for i,(aElt,bElt) in enumerate(diff.getDiffs()):
167 print 'A missing: %s' % bElt
169 print 'B missing: %s' % aElt
171 print 'mismatch: A: %s' % aElt
172 print ' B: %s' % bElt
177 for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
179 print 'A MISSING:',' '.join(b)
183 print 'B MISSING:',' '.join(a)
187 diff = DriverZipperDiff(a,b)
188 diffs = list(diff.getDiffs())
190 print '-- COMMAND %d DIFFERS -' % i
191 print 'A COMMAND:',' '.join(a)
192 print 'B COMMAND:',' '.join(b)
194 for i,(aElt,bElt) in enumerate(diffs):
196 print 'A missing: %s' % bElt
198 print 'B missing: %s' % aElt
200 print 'mismatch: A: %s' % aElt
201 print ' B: %s' % bElt
204 # Compare result codes.
205 if infoA.exitCode != infoB.exitCode:
206 print '-- EXIT CODES DIFFER -'
207 print 'A: ',infoA.exitCode
208 print 'B: ',infoB.exitCode
214 if __name__ == '__main__':