diff options
Diffstat (limited to 'clang/utils/CmpDriver')
| -rwxr-xr-x | clang/utils/CmpDriver | 210 | 
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()  | 
