summaryrefslogtreecommitdiff
path: root/clang/utils/CmpDriver
diff options
context:
space:
mode:
authorZancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au>2012-09-24 09:58:17 +1000
committerZancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au>2012-09-24 09:58:17 +1000
commit222e2a7620e6520ffaf4fc4e69d79c18da31542e (patch)
tree7bfbc05bfa3b41c8f9d2e56d53a0bc3e310df239 /clang/utils/CmpDriver
parent3d206f03985b50beacae843d880bccdc91a9f424 (diff)
Add the clang library to the repo (with some of my changes, too).
Diffstat (limited to 'clang/utils/CmpDriver')
-rwxr-xr-xclang/utils/CmpDriver210
1 files changed, 210 insertions, 0 deletions
diff --git a/clang/utils/CmpDriver b/clang/utils/CmpDriver
new file mode 100755
index 0000000..2533f54
--- /dev/null
+++ b/clang/utils/CmpDriver
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+
+import subprocess
+
+def splitArgs(s):
+ it = iter(s)
+ current = ''
+ inQuote = False
+ for c in it:
+ if c == '"':
+ if inQuote:
+ inQuote = False
+ yield current + '"'
+ else:
+ inQuote = True
+ current = '"'
+ elif inQuote:
+ if c == '\\':
+ current += c
+ current += it.next()
+ else:
+ current += c
+ elif not c.isspace():
+ yield c
+
+def insertMinimumPadding(a, b, dist):
+ """insertMinimumPadding(a,b) -> (a',b')
+
+ Return two lists of equal length, where some number of Nones have
+ been inserted into the shorter list such that sum(map(dist, a',
+ b')) is minimized.
+
+ Assumes dist(X, Y) -> int and non-negative.
+ """
+
+ def cost(a, b):
+ return sum(map(dist, a + [None] * (len(b) - len(a)), b))
+
+ # Normalize so a is shortest.
+ if len(b) < len(a):
+ b, a = insertMinimumPadding(b, a, dist)
+ return a,b
+
+ # For each None we have to insert...
+ for i in range(len(b) - len(a)):
+ # For each position we could insert it...
+ current = cost(a, b)
+ best = None
+ for j in range(len(a) + 1):
+ a_0 = a[:j] + [None] + a[j:]
+ candidate = cost(a_0, b)
+ if best is None or candidate < best[0]:
+ best = (candidate, a_0, j)
+ a = best[1]
+ return a,b
+
+class ZipperDiff(object):
+ """ZipperDiff - Simple (slow) diff only accommodating inserts."""
+
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+
+ def dist(self, a, b):
+ return a != b
+
+ def getDiffs(self):
+ a,b = insertMinimumPadding(self.a, self.b, self.dist)
+ for aElt,bElt in zip(a,b):
+ if self.dist(aElt, bElt):
+ yield aElt,bElt
+
+class DriverZipperDiff(ZipperDiff):
+ def isTempFile(self, filename):
+ if filename[0] != '"' or filename[-1] != '"':
+ return False
+ return (filename.startswith('/tmp/', 1) or
+ filename.startswith('/var/', 1))
+
+ def dist(self, a, b):
+ if a and b and self.isTempFile(a) and self.isTempFile(b):
+ return 0
+ return super(DriverZipperDiff, self).dist(a,b)
+
+class CompileInfo:
+ def __init__(self, out, err, res):
+ self.commands = []
+
+ # Standard out isn't used for much.
+ self.stdout = out
+ self.stderr = ''
+
+ # FIXME: Compare error messages as well.
+ for ln in err.split('\n'):
+ if (ln == 'Using built-in specs.' or
+ ln.startswith('Target: ') or
+ ln.startswith('Configured with: ') or
+ ln.startswith('Thread model: ') or
+ ln.startswith('gcc version') or
+ ln.startswith('clang version')):
+ pass
+ elif ln.strip().startswith('"'):
+ self.commands.append(list(splitArgs(ln)))
+ else:
+ self.stderr += ln + '\n'
+
+ self.stderr = self.stderr.strip()
+ self.exitCode = res
+
+def captureDriverInfo(cmd, args):
+ p = subprocess.Popen([cmd,'-###'] + args,
+ stdin=None,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out,err = p.communicate()
+ res = p.wait()
+ return CompileInfo(out,err,res)
+
+def main():
+ import os, sys
+
+ args = sys.argv[1:]
+ driverA = os.getenv('DRIVER_A') or 'gcc'
+ driverB = os.getenv('DRIVER_B') or 'clang'
+
+ infoA = captureDriverInfo(driverA, args)
+ infoB = captureDriverInfo(driverB, args)
+
+ differ = False
+
+ # Compare stdout.
+ if infoA.stdout != infoB.stdout:
+ print '-- STDOUT DIFFERS -'
+ print 'A OUTPUT: ',infoA.stdout
+ print 'B OUTPUT: ',infoB.stdout
+ print
+
+ diff = ZipperDiff(infoA.stdout.split('\n'),
+ infoB.stdout.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+
+ differ = True
+
+ # Compare stderr.
+ if infoA.stderr != infoB.stderr:
+ print '-- STDERR DIFFERS -'
+ print 'A STDERR: ',infoA.stderr
+ print 'B STDERR: ',infoB.stderr
+ print
+
+ diff = ZipperDiff(infoA.stderr.split('\n'),
+ infoB.stderr.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+
+ differ = True
+
+ # Compare commands.
+ for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
+ if a is None:
+ print 'A MISSING:',' '.join(b)
+ differ = True
+ continue
+ elif b is None:
+ print 'B MISSING:',' '.join(a)
+ differ = True
+ continue
+
+ diff = DriverZipperDiff(a,b)
+ diffs = list(diff.getDiffs())
+ if diffs:
+ print '-- COMMAND %d DIFFERS -' % i
+ print 'A COMMAND:',' '.join(a)
+ print 'B COMMAND:',' '.join(b)
+ print
+ for i,(aElt,bElt) in enumerate(diffs):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+ differ = True
+
+ # Compare result codes.
+ if infoA.exitCode != infoB.exitCode:
+ print '-- EXIT CODES DIFFER -'
+ print 'A: ',infoA.exitCode
+ print 'B: ',infoB.exitCode
+ differ = True
+
+ if differ:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()