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__':