145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#!/usr/bin/env python
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org"""
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgReleased under GNU LGPL license.
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgversion 0.xx
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org"""
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgimport sys
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgimport os
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgimport cparse
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgimport ir
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
19a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgdef callcmd(cmd):
20a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    try:
21a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        from subprocess import call
22a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        try:
23a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            retcode = call(cmd, shell=True)
24a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            assert retcode == 0, "command failed: %s"%cmd
25a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        except OSError, e:
26a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            assert False, "command failed: %s"%e
27a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    except ImportError:
28a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        status = os.system( cmd )
29a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        assert status == 0, "command failed: %s"%cmd
30a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgclass WorkUnit(object):
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def __init__(self, files, modname, filename,
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 std=False, strip=False, mark_cb=None,
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 extradefs="", use_header=None, CC="gcc", CPP="gcc -E",
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 CPPFLAGS=""):
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.files = tuple(files)
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.modname = modname
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.filename = filename
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.CPPFLAGS = CPPFLAGS
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.CPP = CPP
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if CC == 'g++':
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            self.CPPFLAGS += " -D__cplusplus"
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.std = std
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.strip = strip
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.mark_cb = mark_cb
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.node = None
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.extradefs = extradefs
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.CC = CC
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.use_header = use_header
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def mkheader( self ):
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if self.use_header:
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return self.use_header
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        tmpname = str(abs(hash( (self.files,self.CPPFLAGS) )))
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        name = '.tmp/%s' % tmpname
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ifile = open( name+'.h', "w" )
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ifile.write( """
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __attribute__(...)
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __const const
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __restrict
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __extension__
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __asm__(...)
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __asm(...)
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __inline__
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define __inline
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org""" )
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for filename in self.files:
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if self.std:
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                line = '#include <%s>\n'%filename
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else:
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                line = '#include "%s"\n'%filename
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ifile.write( line )
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            print line,
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ifile.close()
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        cmd = '%s %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.E')
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# %s\n" % cmd )
77a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        callcmd( cmd )
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        assert open(name+'.E').read().count('\n') > 10, "failed to run preprocessor"
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        cmd = '%s -dM %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.dM')
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# %s\n" % cmd )
81a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        callcmd( cmd )
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        assert open(name+'.dM').read().count('\n') > 10, "failed to run preprocessor with -dM"
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return name
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def parse(self, verbose=False):
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# parse %s\n" % str(self.files) )
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        name = self.mkheader()
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        # read macros
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        f = open(name+'.dM')
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        macros = {}
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for line in f.readlines():
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if line:
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                macro = line.split()[1]
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if macro.count('('):
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    macro = macro[:macro.index('(')]
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                macros[macro] = None
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        #keys = macros.keys()
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        #keys.sort()
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        #for key in keys:
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #print key
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.macros = macros
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        # parse preprocessed code
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        f = open(name+'.E')
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s = f.read() + self.extradefs
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.node = cparse.TransUnit(verbose = verbose)
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# parsing %s lines\n" % s.count('\n') )
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.node.parse( s )
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if self.strip:
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            self.node.strip(self.files)
11045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def transform(self, verbose=False, test_parse=False, test_types=False):
11245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# processing...\n" )
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.node = ir.TransUnit( self.node )
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        self.node.transform(verbose, test_parse, test_types)
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        #self.node[0].psource()
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if self.mark_cb is not None:
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            self.node.mark(self.mark_cb,verbose=False)
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def output( self, func_cb = None ):
12045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# pyxstr...\n" )
12145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        decls = self.node.pyx_decls(self.files, self.modname, macros = self.macros, func_cb = func_cb, names={}, cprefix="" )
12245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        name = self.filename
12445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        assert name.endswith(".pyx")
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        pxi = name[:-3]+'pxi'
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        file = open( pxi, "w" )
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        file.write(decls)
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sys.stderr.write( "# wrote %s, %d lines\n" % (pxi,decls.count('\n')) )
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    def pprint(self):
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for decl in self.node:
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #decl.psource()
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #cstr = decl.cstr()
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #cstr = cstr.replace( '\n', '\n# ' )
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            print
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #print '#', cstr
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            print decl.deepstr()
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgdef file_exists(path):
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    try:
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        os.stat(path)
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return True
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    except OSError:
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return False
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgif sys.platform.count('darwin'):
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    shared_ext = '.dylib'
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgelse:
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    shared_ext = '.so'
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
15245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgdef get_syms(libs, libdirs):
15345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    # XX write interface to objdump -t XX
15445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    libnames = []
15545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for lib in libs:
15645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for ext in shared_ext,'.a':
15745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            libname = 'lib'+lib+ext
15845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for libdir in libdirs:
15945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                path = libdir+'/'+libname
16045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if file_exists(path):
16145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    libnames.append(path)
16245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break
16345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            #else:
16445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                #print "cannot find %s lib as %s in %s" % ( lib, libname, libdir )
16545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    print 'libnames:', libnames
16645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    syms = {}
16745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    accept = [ ' %s '%c for c in 'TVWBCDGRS' ]
16845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    #f = open('syms.out','w')
16945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for libname in libnames:
170a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        try:
171a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            from subprocess import Popen, PIPE
172a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            p = Popen(['nm', libname], bufsize=1, stdout=PIPE)
173a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            fout = p.stdout
174a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        except ImportError:
175a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            fin, fout = os.popen2( 'nm %s' % libname )
17645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for line in fout.readlines():
17745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for acc in accept:
17845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if line.count(acc):
17945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    left, right = line.split(acc)
18045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    sym = right.strip()
18145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if sys.platform.count('darwin'):
18245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if sym[0] == '_':
18345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            sym = sym[1:] # remove underscore prefix
18445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if sym.endswith('.eh'):
18545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            sym = sym[:-len('.eh')]
18645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    syms[sym] = None
18745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    #f.write( '%s: %s %s\n' % (sym,line[:-1],libname) )
18845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break
18945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return syms
19045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
19145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
19245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
193