Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/python/pyste/src/Pyste/pyste.py @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 13.7 KB
Line 
1# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
2# distribution is subject to the Boost Software License, Version 1.0.
3# (See accompanying file LICENSE_1_0.txt or copy at
4# http:#www.boost.org/LICENSE_1_0.txt)
5
6"""
7Pyste version %s
8
9Usage:
10    pyste [options] interface-files
11
12where options are:
13    --module=<name>         The name of the module that will be generated;
14                            defaults to the first interface filename, without
15                            the extension.
16    -I <path>               Add an include path   
17    -D <symbol>             Define symbol   
18    --multiple              Create various cpps, instead of only one
19                            (useful during development)                       
20    --out=<name>            Specify output filename (default: <module>.cpp)
21                            in --multiple mode, this will be a directory
22    --no-using              Do not declare "using namespace boost";
23                            use explicit declarations instead
24    --pyste-ns=<name>       Set the namespace where new types will be declared;
25                            default is the empty namespace
26    --debug                 Writes the xml for each file parsed in the current
27                            directory
28    --cache-dir=<dir>       Directory for cache files (speeds up future runs)
29    --only-create-cache     Recreates all caches (doesn't generate code).
30    --generate-main         Generates the _main.cpp file (in multiple mode)
31    --file-list             A file with one pyste file per line. Use as a
32                            substitute for passing the files in the command
33                            line.
34    --gccxml-path=<path>    Path to gccxml executable (default: gccxml)
35    --no-default-include    Do not use INCLUDE environment variable for include
36                            files to pass along gccxml.
37    -h, --help              Print this help and exit
38    -v, --version           Print version information                         
39"""
40
41import sys
42import os
43import getopt
44import exporters
45import SingleCodeUnit
46import MultipleCodeUnit
47import infos
48import exporterutils
49import settings
50import gc
51import sys
52from policies import *
53from CppParser import CppParser, CppParserError
54import time
55import declarations
56
57__version__ = '0.9.30'
58
59def RecursiveIncludes(include):
60    'Return a list containg the include dir and all its subdirectories'
61    dirs = [include]
62    def visit(arg, dir, names):
63        # ignore CVS dirs
64        if os.path.split(dir)[1] != 'CVS':
65            dirs.append(dir)
66    os.path.walk(include, visit, None)
67    return dirs
68
69   
70def GetDefaultIncludes():
71    if 'INCLUDE' in os.environ:
72        include = os.environ['INCLUDE']
73        return include.split(os.pathsep)
74    else:
75        return []
76
77
78def ProcessIncludes(includes):
79    if sys.platform == 'win32':
80        index = 0
81        for include in includes:
82            includes[index] = include.replace('\\', '/')
83            index += 1
84
85
86def ReadFileList(filename):
87    f = file(filename)
88    files = []
89    try:
90        for line in f:
91            line = line.strip()
92            if line:
93                files.append(line)
94    finally:
95        f.close()
96    return files
97
98       
99def ParseArguments():
100
101    def Usage():
102        print __doc__ % __version__
103        sys.exit(1)
104       
105    try:
106        options, files = getopt.getopt(
107            sys.argv[1:], 
108            'R:I:D:vh', 
109            ['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=', 
110             'only-create-cache', 'version', 'generate-main', 'file-list=',  'help',
111             'gccxml-path=', 'no-default-include'])
112    except getopt.GetoptError, e:
113        print
114        print 'ERROR:', e
115        Usage()
116   
117    default_includes = GetDefaultIncludes()
118    includes = []
119    defines = []
120    module = None
121    out = None
122    multiple = False
123    cache_dir = None
124    create_cache = False
125    generate_main = False
126    gccxml_path = 'gccxml'
127   
128    for opt, value in options:
129        if opt == '-I':
130            includes.append(value)
131        elif opt == '-D':
132            defines.append(value)
133        elif opt == '-R':
134            includes.extend(RecursiveIncludes(value))
135        elif opt == '--module':
136            module = value
137        elif opt == '--out':
138            out = value
139        elif opt == '--no-using':
140            settings.namespaces.python = 'boost::python::'
141            settings.USING_BOOST_NS = False
142        elif opt == '--pyste-ns':
143            settings.namespaces.pyste = value + '::'
144        elif opt == '--debug':
145            settings.DEBUG = True
146        elif opt == '--multiple':
147            multiple = True
148        elif opt == '--cache-dir':
149            cache_dir = value
150        elif opt == '--only-create-cache':
151            create_cache = True
152        elif opt == '--file-list':
153            files += ReadFileList(value)
154        elif opt in ['-h', '--help']:
155            Usage()
156        elif opt in ['-v', '--version']:
157            print 'Pyste version %s' % __version__
158            sys.exit(2)
159        elif opt == '--generate-main':
160            generate_main = True
161        elif opt == '--gccxml-path':
162            gccxml_path = value
163        elif opt == '--no-default-include':
164            default_includes = [] 
165        else:
166            print 'Unknown option:', opt
167            Usage()
168
169    includes[0:0] = default_includes
170    if not files:
171        Usage() 
172    if not module:
173        module = os.path.splitext(os.path.basename(files[0]))[0]
174    if not out:
175        out = module
176        if not multiple:
177            out += '.cpp'
178    for file in files:
179        d = os.path.dirname(os.path.abspath(file))
180        if d not in sys.path:
181            sys.path.append(d) 
182
183    if create_cache and not cache_dir:
184        print 'Error: Use --cache-dir to indicate where to create the cache files!'
185        Usage()
186        sys.exit(3)
187
188    if generate_main and not multiple:
189        print 'Error: --generate-main only valid in multiple mode.'
190        Usage()
191        sys.exit(3)
192
193    ProcessIncludes(includes)
194    return includes, defines, module, out, files, multiple, cache_dir, create_cache, \
195        generate_main, gccxml_path
196
197
198def PCHInclude(*headers):
199    code = '\n'.join(['#include <%s>' % x for x in headers])
200    infos.CodeInfo(code, 'pchinclude')
201
202   
203def CreateContext():
204    'create the context where a interface file will be executed'
205    context = {}
206    context['Import'] = Import
207    # infos
208    context['Function'] = infos.FunctionInfo
209    context['Class'] = infos.ClassInfo
210    context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include')
211    context['PCHInclude'] = PCHInclude
212    context['Template'] = infos.ClassTemplateInfo
213    context['Enum'] = infos.EnumInfo
214    context['AllFromHeader'] = infos.HeaderInfo
215    context['Var'] = infos.VarInfo
216    # functions
217    context['rename'] = infos.rename
218    context['set_policy'] = infos.set_policy
219    context['exclude'] = infos.exclude
220    context['set_wrapper'] = infos.set_wrapper
221    context['use_shared_ptr'] = infos.use_shared_ptr
222    context['use_auto_ptr'] = infos.use_auto_ptr
223    context['holder'] = infos.holder
224    context['add_method'] = infos.add_method
225    context['final'] = infos.final
226    context['export_values'] = infos.export_values
227    # policies
228    context['return_internal_reference'] = return_internal_reference
229    context['with_custodian_and_ward'] = with_custodian_and_ward
230    context['return_value_policy'] = return_value_policy
231    context['reference_existing_object'] = reference_existing_object
232    context['copy_const_reference'] = copy_const_reference
233    context['copy_non_const_reference'] = copy_non_const_reference
234    context['return_opaque_pointer'] = return_opaque_pointer
235    context['manage_new_object'] = manage_new_object
236    context['return_by_value'] = return_by_value
237    context['return_self'] = return_self
238    # utils
239    context['Wrapper'] = exporterutils.FunctionWrapper
240    context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')
241    context['module_code'] = lambda code: infos.CodeInfo(code, 'module')
242    context['class_code'] = infos.class_code
243    return context                                       
244
245   
246def Begin():
247    # parse arguments
248    includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments()
249    # run pyste scripts
250    for interface in interfaces:
251        ExecuteInterface(interface)
252    # create the parser
253    parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path)
254    try:
255        if not create_cache:
256            if not generate_main:
257                return GenerateCode(parser, module, out, interfaces, multiple)
258            else:
259                return GenerateMain(module, out, OrderInterfaces(interfaces))
260        else:
261            return CreateCaches(parser)
262    finally:
263        parser.Close()
264
265
266def CreateCaches(parser):
267    # There is one cache file per interface so we organize the headers
268    # by interfaces.  For each interface collect the tails from the
269    # exporters sharing the same header.
270    tails = JoinTails(exporters.exporters)
271
272    # now for each interface file take each header, and using the tail
273    # get the declarations and cache them.
274    for interface, header in tails:       
275        tail = tails[(interface, header)]
276        declarations = parser.ParseWithGCCXML(header, tail)
277        cachefile = parser.CreateCache(header, interface, tail, declarations)
278        print 'Cached', cachefile
279   
280    return 0
281       
282
283_imported_count = {}  # interface => count
284
285def ExecuteInterface(interface):
286    old_interface = exporters.current_interface
287    if not os.path.exists(interface):
288        if old_interface and os.path.exists(old_interface):
289            d = os.path.dirname(old_interface)
290            interface = os.path.join(d, interface)
291    if not os.path.exists(interface):
292        raise IOError, "Cannot find interface file %s."%interface
293   
294    _imported_count[interface] = _imported_count.get(interface, 0) + 1
295    exporters.current_interface = interface
296    context = CreateContext()
297    context['INTERFACE_FILE'] = os.path.abspath(interface)
298    execfile(interface, context)
299    exporters.current_interface = old_interface
300
301
302def Import(interface):
303    exporters.importing = True
304    ExecuteInterface(interface)
305    exporters.importing = False
306
307   
308def JoinTails(exports):
309    '''Returns a dict of {(interface, header): tail}, where tail is the
310    joining of all tails of all exports for the header. 
311    '''
312    tails = {}
313    for export in exports:
314        interface = export.interface_file
315        header = export.Header()
316        tail = export.Tail() or ''
317        if (interface, header) in tails:
318            all_tails = tails[(interface,header)]
319            all_tails += '\n' + tail
320            tails[(interface, header)] = all_tails
321        else:
322            tails[(interface, header)] = tail         
323
324    return tails
325
326
327
328def OrderInterfaces(interfaces):
329    interfaces_order = [(_imported_count[x], x) for x in interfaces]
330    interfaces_order.sort()
331    interfaces_order.reverse()
332    return [x for _, x in interfaces_order]
333
334
335
336def GenerateMain(module, out, interfaces):
337    codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
338    codeunit.GenerateMain(interfaces)
339    return 0
340   
341
342def GenerateCode(parser, module, out, interfaces, multiple):   
343    # prepare to generate the wrapper code
344    if multiple:
345        codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
346    else:
347        codeunit = SingleCodeUnit.SingleCodeUnit(module, out) 
348    # stop referencing the exporters here
349    exports = exporters.exporters
350    exporters.exporters = None 
351    exported_names = dict([(x.Name(), None) for x in exports])
352
353    # order the exports
354    order = {}
355    for export in exports:
356        if export.interface_file in order:
357            order[export.interface_file].append(export)
358        else:
359            order[export.interface_file] = [export]
360    exports = []
361    interfaces_order = OrderInterfaces(interfaces)
362    for interface in interfaces_order:
363        exports.extend(order[interface])
364    del order
365    del interfaces_order
366
367    # now generate the code in the correct order
368    #print exported_names
369    tails = JoinTails(exports)
370    for i in xrange(len(exports)):
371        export = exports[i]
372        interface = export.interface_file
373        header = export.Header()
374        if header:
375            tail = tails[(interface, header)]
376            declarations, parsed_header = parser.Parse(header, interface, tail)
377        else:
378            declarations = []
379            parsed_header = None
380        ExpandTypedefs(declarations, exported_names)
381        export.SetDeclarations(declarations)
382        export.SetParsedHeader(parsed_header)
383        if multiple:
384            codeunit.SetCurrent(export.interface_file, export.Name())
385        export.GenerateCode(codeunit, exported_names)
386        # force collect of cyclic references
387        exports[i] = None
388        del declarations
389        del export
390        gc.collect()
391    # finally save the code unit
392    codeunit.Save()
393    if not multiple:
394        print 'Module %s generated' % module
395    return 0
396
397
398def ExpandTypedefs(decls, exported_names):
399    '''Check if the names in exported_names are a typedef, and add the real class
400    name in the dict.
401    '''
402    for name in exported_names.keys():
403        for decl in decls:
404            if isinstance(decl, declarations.Typedef):
405                exported_names[decl.type.FullName()] = None
406
407def UsePsyco():
408    'Tries to use psyco if possible'
409    try:
410        import psyco
411        psyco.profile()
412    except: pass         
413
414
415def main():
416    start = time.clock()
417    UsePsyco()
418    status = Begin()
419    print '%0.2f seconds' % (time.clock()-start)
420    sys.exit(status) 
421
422   
423if __name__ == '__main__':
424    main()
Note: See TracBrowser for help on using the repository browser.