1#!/usr/bin/env python
2
3"""
4
5(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
6Released under GNU LGPL license.
7
8version 0.xx
9
10"""
11
12
13import sys
14import os
15
16import cparse
17import ir
18
19def callcmd(cmd):
20    try:
21        from subprocess import call
22        try:
23            retcode = call(cmd, shell=True)
24            assert retcode == 0, "command failed: %s"%cmd
25        except OSError, e:
26            assert False, "command failed: %s"%e
27    except ImportError:
28        status = os.system( cmd )
29        assert status == 0, "command failed: %s"%cmd
30
31class WorkUnit(object):
32    def __init__(self, files, modname, filename,
33                 std=False, strip=False, mark_cb=None,
34                 extradefs="", use_header=None, CC="gcc", CPP="gcc -E",
35                 CPPFLAGS=""):
36        self.files = tuple(files)
37        self.modname = modname
38        self.filename = filename
39        self.CPPFLAGS = CPPFLAGS
40        self.CPP = CPP
41        if CC == 'g++':
42            self.CPPFLAGS += " -D__cplusplus"
43        self.std = std
44        self.strip = strip
45        self.mark_cb = mark_cb
46        self.node = None
47        self.extradefs = extradefs
48        self.CC = CC
49        self.use_header = use_header
50
51    def mkheader( self ):
52        if self.use_header:
53            return self.use_header
54        tmpname = str(abs(hash( (self.files,self.CPPFLAGS) )))
55        name = '.tmp/%s' % tmpname
56        ifile = open( name+'.h', "w" )
57        ifile.write( """
58#define __attribute__(...)
59#define __const const
60#define __restrict
61#define __extension__
62#define __asm__(...)
63#define __asm(...)
64#define __inline__
65#define __inline
66""" )
67        for filename in self.files:
68            if self.std:
69                line = '#include <%s>\n'%filename
70            else:
71                line = '#include "%s"\n'%filename
72            ifile.write( line )
73            print line,
74        ifile.close()
75        cmd = '%s %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.E')
76        sys.stderr.write( "# %s\n" % cmd )
77        callcmd( cmd )
78        assert open(name+'.E').read().count('\n') > 10, "failed to run preprocessor"
79        cmd = '%s -dM %s %s > %s'%(self.CPP,name+'.h',self.CPPFLAGS,name+'.dM')
80        sys.stderr.write( "# %s\n" % cmd )
81        callcmd( cmd )
82        assert open(name+'.dM').read().count('\n') > 10, "failed to run preprocessor with -dM"
83        return name
84
85    def parse(self, verbose=False):
86        sys.stderr.write( "# parse %s\n" % str(self.files) )
87        name = self.mkheader()
88        # read macros
89        f = open(name+'.dM')
90        macros = {}
91        for line in f.readlines():
92            if line:
93                macro = line.split()[1]
94                if macro.count('('):
95                    macro = macro[:macro.index('(')]
96                macros[macro] = None
97        #keys = macros.keys()
98        #keys.sort()
99        #for key in keys:
100            #print key
101        self.macros = macros
102        # parse preprocessed code
103        f = open(name+'.E')
104        s = f.read() + self.extradefs
105        self.node = cparse.TransUnit(verbose = verbose)
106        sys.stderr.write( "# parsing %s lines\n" % s.count('\n') )
107        self.node.parse( s )
108        if self.strip:
109            self.node.strip(self.files)
110
111    def transform(self, verbose=False, test_parse=False, test_types=False):
112        sys.stderr.write( "# processing...\n" )
113        self.node = ir.TransUnit( self.node )
114        self.node.transform(verbose, test_parse, test_types)
115        #self.node[0].psource()
116        if self.mark_cb is not None:
117            self.node.mark(self.mark_cb,verbose=False)
118
119    def output( self, func_cb = None ):
120        sys.stderr.write( "# pyxstr...\n" )
121        decls = self.node.pyx_decls(self.files, self.modname, macros = self.macros, func_cb = func_cb, names={}, cprefix="" )
122
123        name = self.filename
124        assert name.endswith(".pyx")
125
126        pxi = name[:-3]+'pxi'
127        file = open( pxi, "w" )
128        file.write(decls)
129        sys.stderr.write( "# wrote %s, %d lines\n" % (pxi,decls.count('\n')) )
130
131    def pprint(self):
132        for decl in self.node:
133            #decl.psource()
134            #cstr = decl.cstr()
135            #cstr = cstr.replace( '\n', '\n# ' )
136            print
137            #print '#', cstr
138            print decl.deepstr()
139
140def file_exists(path):
141    try:
142        os.stat(path)
143        return True
144    except OSError:
145        return False
146
147if sys.platform.count('darwin'):
148    shared_ext = '.dylib'
149else:
150    shared_ext = '.so'
151
152def get_syms(libs, libdirs):
153    # XX write interface to objdump -t XX
154    libnames = []
155    for lib in libs:
156        for ext in shared_ext,'.a':
157            libname = 'lib'+lib+ext
158            for libdir in libdirs:
159                path = libdir+'/'+libname
160                if file_exists(path):
161                    libnames.append(path)
162                    break
163            #else:
164                #print "cannot find %s lib as %s in %s" % ( lib, libname, libdir )
165    print 'libnames:', libnames
166    syms = {}
167    accept = [ ' %s '%c for c in 'TVWBCDGRS' ]
168    #f = open('syms.out','w')
169    for libname in libnames:
170        try:
171            from subprocess import Popen, PIPE
172            p = Popen(['nm', libname], bufsize=1, stdout=PIPE)
173            fout = p.stdout
174        except ImportError:
175            fin, fout = os.popen2( 'nm %s' % libname )
176        for line in fout.readlines():
177            for acc in accept:
178                if line.count(acc):
179                    left, right = line.split(acc)
180                    sym = right.strip()
181                    if sys.platform.count('darwin'):
182                        if sym[0] == '_':
183                            sym = sym[1:] # remove underscore prefix
184                        if sym.endswith('.eh'):
185                            sym = sym[:-len('.eh')]
186                    syms[sym] = None
187                    #f.write( '%s: %s %s\n' % (sym,line[:-1],libname) )
188                    break
189    return syms
190
191
192
193