view Compilable.py @ 0:28b636105ed6

Working version of codeOptimizer. -Still needs to implement more finegrained control per file basis. -CXXFLAGS are hardcoded.
author Tom Fredrik Blenning Klaussen <bfg@blenning.no>
date Sat, 15 Sep 2012 20:34:39 +0200
parents
children a1224150b8f6
line wrap: on
line source

import subprocess, re

def tryCompileFile(file, compiler, flags):
    cmd = compiler + " -x c++ -o /dev/null " + flags + " -c " + file
    devnull = open('/dev/null', 'w')
    p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
                         stdout=devnull, stderr=None, shell=True)
    s = p.wait()
    devnull.close()
    return s == 0

def tryCompileBuffer(buffer, compiler, flags):
    cmd = compiler + " -x c++ -o /dev/null " + flags + " -c -"
    devnull = open('/dev/null', 'w')
    p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
                         stdout=devnull, stderr=devnull, shell=True)
    p.stdin.write(buffer)
    p.stdin.close()
    s = p.wait()
    devnull.close()
    return s == 0



class Compilable:
    def __init__(self, path):
        self.path = path
        self.flags = ''
        self.lines = None

    def setFlags(self, flags):
        self.flags = flags

    def worksWithoutModifications(self):
        return tryCompileFile(self.path, 'g++', self.flags)

    def activeBuffer(self):
        self.loadFile()
        str = ''
        for i in range(len(self.lines)):
            if not i in self.replace:
                str += self.lines[i]
            else:
                str += self.replace[i]
        return str

    def works(self):
        return tryCompileBuffer(self.activeBuffer(), 'g++', self.flags)

    def deactivateLine(self, i):
        self.replace[i] = "\n"

    def activateLine(self, i):
        del self.replace[i]

    def loadFile(self):
        if self.lines == None:
            f = open(self.path, 'r')
            self.lines = f.readlines()
            f.close()
            self.replace = {}

    def includeLines(self):
        self.loadFile()
        pattern = '^\s*#include '
        prog = re.compile(pattern)
        res = []
        for i in range(len(self.lines)):
            if prog.match(self.lines[i].rstrip()):
                res.append(i)
        return res

    def removeRemovableIncludes(self):
        l = self.includeLines()
        retVal = []
        for n in l:
            self.deactivateLine(n)
            print 'Trying to compile ' + self.path + ' without ' + self.getPathname(self.lines[n])
            if self.works():
                retVal.append(n)
            else:
                self.activateLine(n)

        return retVal
            
    @staticmethod
    def getPathname(str):
        pattern = '^\s*#include ["<]([^">]+)[">]'
        prog = re.compile(pattern)
        m = prog.search(str)
        include = m.group(1)
        return include
        

    @staticmethod
    def getClassname(str):
        include = Compilable.getPathname(str)

        pattern = '[^/]+$'
        prog = re.compile(pattern)
        m = prog.search(include)
        filename = m.group(0)

        pattern = '^[^.]+'
        prog = re.compile(pattern)
        m = prog.search(filename)
        basename = m.group(0)

        return basename

    def replaceIncludes(self):
        l = self.includeLines()
        retVal = []
        for n in l:
            if n not in self.replace:
                rstring = 'class ' + self.getClassname(self.lines[n]) + ';\n'
                self.replace[n] = rstring
                if self.works():
                    retVal.append(n)
                else:
                    self.activateLine(n)
        return retVal

    def dependencies(self):
        lines = self.includeLines()
        retVal = []
        for line in lines:
            retVal.append(self.getPathname(self.lines[line]))
        return retVal


    def __repr__(self):
        return self.path