brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.3 KiB · 0732baa Raw
217 lines · plain
1#!/usr/bin/env python2 3"""4A simple utility that compares tool invocations and exit codes issued by5compiler drivers that support -### (e.g. gcc and clang).6"""7 8from itertools import zip_longest9import subprocess10 11def splitArgs(s):12    it = iter(s)13    current = ''14    inQuote = False15    for c in it:16        if c == '"':17            if inQuote:18                inQuote = False19                yield current + '"'20            else:21                inQuote = True22                current = '"'23        elif inQuote:24            if c == '\\':25                current += c26                current += next(it)27            else:28                current += c29        elif not c.isspace():30            yield c31 32def insertMinimumPadding(a, b, dist):33    """insertMinimumPadding(a,b) -> (a',b')34 35    Return two lists of equal length, where some number of Nones have36    been inserted into the shorter list such that sum(map(dist, a',37    b')) is minimized.38 39    Assumes dist(X, Y) -> int and non-negative.40    """41    42    def cost(a, b):43        return sum(map(dist, a + [None] * (len(b) - len(a)), b))44 45    # Normalize so a is shortest.46    if len(b) < len(a):47        b, a = insertMinimumPadding(b, a, dist)48        return a,b49 50    # For each None we have to insert...51    for i in range(len(b) - len(a)):52        # For each position we could insert it...53        current = cost(a, b)54        best = None55        for j in range(len(a) + 1):56            a_0 = a[:j] + [None] + a[j:]57            candidate = cost(a_0, b)58            if best is None or candidate < best[0]:59                best = (candidate, a_0, j)60        a = best[1]61    return a,b62 63class ZipperDiff(object):64    """ZipperDiff - Simple (slow) diff only accommodating inserts."""65    66    def __init__(self, a, b):67        self.a = a68        self.b = b69 70    def dist(self, a, b):71        return a != b72 73    def getDiffs(self):74        a,b =  insertMinimumPadding(self.a, self.b, self.dist)75        for aElt,bElt in zip(a,b):76            if self.dist(aElt, bElt):77                yield aElt,bElt78 79class DriverZipperDiff(ZipperDiff):80    def isTempFile(self, filename):81        if filename[0] != '"' or filename[-1] != '"':82            return False83        return (filename.startswith('/tmp/', 1) or84                filename.startswith('/var/', 1))85 86    def dist(self, a, b):87        if a and b and self.isTempFile(a) and self.isTempFile(b):88            return 089        return super(DriverZipperDiff, self).dist(a,b)        90 91class CompileInfo:92    def __init__(self, out, err, res):93        self.commands = []94        95        # Standard out isn't used for much.96        self.stdout = out97        self.stderr = ''98 99        # FIXME: Compare error messages as well.100        for ln in err.split('\n'):101            if (ln == 'Using built-in specs.' or102                ln.startswith('Target: ') or103                ln.startswith('Configured with: ') or104                ln.startswith('Thread model: ') or105                ln.startswith('gcc version') or106                ln.startswith('clang version')):107                pass108            elif ln.strip().startswith('"'):109                self.commands.append(list(splitArgs(ln)))110            else:111                self.stderr += ln + '\n'112        113        self.stderr = self.stderr.strip()114        self.exitCode = res115 116def captureDriverInfo(cmd, args):117    p = subprocess.Popen([cmd,'-###'] + args,118                         stdin=None,119                         stdout=subprocess.PIPE,120                         stderr=subprocess.PIPE)121    out,err = p.communicate()122    res = p.wait()123    return CompileInfo(out,err,res)124 125def main():126    import os, sys127 128    args = sys.argv[1:]129    driverA = os.getenv('DRIVER_A') or 'gcc'130    driverB = os.getenv('DRIVER_B') or 'clang'131 132    infoA = captureDriverInfo(driverA, args)133    infoB = captureDriverInfo(driverB, args)134 135    differ = False136 137    # Compare stdout.138    if infoA.stdout != infoB.stdout:139        print('-- STDOUT DIFFERS -')140        print('A OUTPUT: ',infoA.stdout)141        print('B OUTPUT: ',infoB.stdout)142        print()143 144        diff = ZipperDiff(infoA.stdout.split('\n'),145                          infoB.stdout.split('\n'))146        for i,(aElt,bElt) in enumerate(diff.getDiffs()):147            if aElt is None:148                print('A missing: %s' % bElt)149            elif bElt is None:150                print('B missing: %s' % aElt)151            else:152                print('mismatch: A: %s' % aElt)153                print('          B: %s' % bElt)154 155        differ = True156 157    # Compare stderr.158    if infoA.stderr != infoB.stderr:159        print('-- STDERR DIFFERS -')160        print('A STDERR: ',infoA.stderr)161        print('B STDERR: ',infoB.stderr)162        print()163 164        diff = ZipperDiff(infoA.stderr.split('\n'),165                          infoB.stderr.split('\n'))166        for i,(aElt,bElt) in enumerate(diff.getDiffs()):167            if aElt is None:168                print('A missing: %s' % bElt)169            elif bElt is None:170                print('B missing: %s' % aElt)171            else:172                print('mismatch: A: %s' % aElt)173                print('          B: %s' % bElt)174 175        differ = True176 177    # Compare commands.178    for i,(a,b) in enumerate(zip_longest(infoA.commands, infoB.commands, fillvalue=None)):179        if a is None:180            print('A MISSING:',' '.join(b))181            differ = True182            continue183        elif b is None:184            print('B MISSING:',' '.join(a))185            differ = True186            continue187 188        diff = DriverZipperDiff(a,b)189        diffs = list(diff.getDiffs())190        if diffs:191            print('-- COMMAND %d DIFFERS -' % i)192            print('A COMMAND:',' '.join(a))193            print('B COMMAND:',' '.join(b))194            print()195            for i,(aElt,bElt) in enumerate(diffs):196                if aElt is None:197                    print('A missing: %s' % bElt)198                elif bElt is None:199                    print('B missing: %s' % aElt)200                else:201                    print('mismatch: A: %s' % aElt)202                    print('          B: %s' % bElt)203            differ = True204    205    # Compare result codes.206    if infoA.exitCode != infoB.exitCode:207        print('-- EXIT CODES DIFFER -')208        print('A: ',infoA.exitCode)209        print('B: ',infoB.exitCode)210        differ = True211 212    if differ:213        sys.exit(1)214 215if __name__ == '__main__':216    main()217