Move CompilerInstance::LLVMContext and LLVMContext ownership to CodeGenAction
[clang.git] / utils / CmpDriver
blob16b108117d3e933e75cb1f14491c7823789f2e0d
1 #!/usr/bin/env python
3 import subprocess
5 def 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
26 def insertMinimumPadding(a, b, dist):
27 """insertMinimumPadding(a,b) -> (a',b')
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.
33 Assumes dist(X, Y) -> int and non-negative.
34 """
36 def cost(a, b):
37 return sum(map(dist, a + [None] * (len(b) - len(a)), b))
39 # Normalize so a is shortest.
40 if len(b) < len(a):
41 b, a = insertMinimumPadding(b, a, dist)
42 return a,b
44 # For each None we have to insert...
45 for i in range(len(b) - len(a)):
46 # For each position we could insert it...
47 current = cost(a, b)
48 best = None
49 for j in range(len(a) + 1):
50 a_0 = a[:j] + [None] + a[j:]
51 candidate = cost(a_0, b)
52 if best is None or candidate < best[0]:
53 best = (candidate, a_0, j)
54 a = best[1]
55 return a,b
57 class ZipperDiff(object):
58 """ZipperDiff - Simple (slow) diff only accomodating inserts."""
60 def __init__(self, a, b):
61 self.a = a
62 self.b = b
64 def dist(self, a, b):
65 return a != b
67 def getDiffs(self):
68 a,b = insertMinimumPadding(self.a, self.b, self.dist)
69 for aElt,bElt in zip(a,b):
70 if self.dist(aElt, bElt):
71 yield aElt,bElt
73 class DriverZipperDiff(ZipperDiff):
74 def isTempFile(self, filename):
75 if filename[0] != '"' or filename[-1] != '"':
76 return False
77 return (filename.startswith('/tmp/', 1) or
78 filename.startswith('/var/', 1))
80 def dist(self, a, b):
81 if a and b and self.isTempFile(a) and self.isTempFile(b):
82 return 0
83 return super(DriverZipperDiff, self).dist(a,b)
85 class CompileInfo:
86 def __init__(self, out, err, res):
87 self.commands = []
89 # Standard out isn't used for much.
90 self.stdout = out
91 self.stderr = ''
93 # FIXME: Compare error messages as well.
94 for ln in err.split('\n'):
95 if (ln == 'Using built-in specs.' or
96 ln.startswith('Target: ') or
97 ln.startswith('Configured with: ') or
98 ln.startswith('Thread model: ') or
99 ln.startswith('gcc version') or
100 ln.startswith('clang version')):
101 pass
102 elif ln.strip().startswith('"'):
103 self.commands.append(list(splitArgs(ln)))
104 else:
105 self.stderr += ln + '\n'
107 self.stderr = self.stderr.strip()
108 self.exitCode = res
110 def captureDriverInfo(cmd, args):
111 p = subprocess.Popen([cmd,'-###'] + args,
112 stdin=None,
113 stdout=subprocess.PIPE,
114 stderr=subprocess.PIPE)
115 out,err = p.communicate()
116 res = p.wait()
117 return CompileInfo(out,err,res)
119 def main():
120 import os, sys
122 args = sys.argv[1:]
123 driverA = os.getenv('DRIVER_A') or 'gcc'
124 driverB = os.getenv('DRIVER_B') or 'clang'
126 infoA = captureDriverInfo(driverA, args)
127 infoB = captureDriverInfo(driverB, args)
129 differ = False
131 # Compare stdout.
132 if infoA.stdout != infoB.stdout:
133 print '-- STDOUT DIFFERS -'
134 print 'A OUTPUT: ',infoA.stdout
135 print 'B OUTPUT: ',infoB.stdout
136 print
138 diff = ZipperDiff(infoA.stdout.split('\n'),
139 infoB.stdout.split('\n'))
140 for i,(aElt,bElt) in enumerate(diff.getDiffs()):
141 if aElt is None:
142 print 'A missing: %s' % bElt
143 elif bElt is None:
144 print 'B missing: %s' % aElt
145 else:
146 print 'mismatch: A: %s' % aElt
147 print ' B: %s' % bElt
149 differ = True
151 # Compare stderr.
152 if infoA.stderr != infoB.stderr:
153 print '-- STDERR DIFFERS -'
154 print 'A STDERR: ',infoA.stderr
155 print 'B STDERR: ',infoB.stderr
156 print
158 diff = ZipperDiff(infoA.stderr.split('\n'),
159 infoB.stderr.split('\n'))
160 for i,(aElt,bElt) in enumerate(diff.getDiffs()):
161 if aElt is None:
162 print 'A missing: %s' % bElt
163 elif bElt is None:
164 print 'B missing: %s' % aElt
165 else:
166 print 'mismatch: A: %s' % aElt
167 print ' B: %s' % bElt
169 differ = True
171 # Compare commands.
172 for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
173 if a is None:
174 print 'A MISSING:',' '.join(b)
175 differ = True
176 continue
177 elif b is None:
178 print 'B MISSING:',' '.join(a)
179 differ = True
180 continue
182 diff = DriverZipperDiff(a,b)
183 diffs = list(diff.getDiffs())
184 if diffs:
185 print '-- COMMAND %d DIFFERS -' % i
186 print 'A COMMAND:',' '.join(a)
187 print 'B COMMAND:',' '.join(b)
188 print
189 for i,(aElt,bElt) in enumerate(diffs):
190 if aElt is None:
191 print 'A missing: %s' % bElt
192 elif bElt is None:
193 print 'B missing: %s' % aElt
194 else:
195 print 'mismatch: A: %s' % aElt
196 print ' B: %s' % bElt
197 differ = True
199 # Compare result codes.
200 if infoA.exitCode != infoB.exitCode:
201 print '-- EXIT CODES DIFFER -'
202 print 'A: ',infoA.exitCode
203 print 'B: ',infoB.exitCode
204 differ = True
206 if differ:
207 sys.exit(1)
209 if __name__ == '__main__':
210 main()