pyste.py

来自「Boost provides free peer-reviewed portab」· Python 代码 · 共 425 行

PY
425
字号
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and # distribution is subject to the Boost Software License, Version 1.0.# (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt)"""Pyste version %sUsage:    pyste [options] interface-fileswhere options are:    --module=<name>         The name of the module that will be generated;                            defaults to the first interface filename, without                            the extension.    -I <path>               Add an include path        -D <symbol>             Define symbol        --multiple              Create various cpps, instead of only one                             (useful during development)                            --out=<name>            Specify output filename (default: <module>.cpp)                            in --multiple mode, this will be a directory    --no-using              Do not declare "using namespace boost";                            use explicit declarations instead    --pyste-ns=<name>       Set the namespace where new types will be declared;                            default is the empty namespace    --debug                 Writes the xml for each file parsed in the current                            directory    --cache-dir=<dir>       Directory for cache files (speeds up future runs)    --only-create-cache     Recreates all caches (doesn't generate code).    --generate-main         Generates the _main.cpp file (in multiple mode)    --file-list             A file with one pyste file per line. Use as a                             substitute for passing the files in the command                            line.    --gccxml-path=<path>    Path to gccxml executable (default: gccxml)    --no-default-include    Do not use INCLUDE environment variable for include                            files to pass along gccxml.    -h, --help              Print this help and exit    -v, --version           Print version information                         """import sysimport osimport getoptimport exportersimport SingleCodeUnitimport MultipleCodeUnitimport infosimport exporterutilsimport settingsimport gcimport sysfrom policies import *from CppParser import CppParser, CppParserErrorimport timeimport declarations__version__ = '0.9.30'def RecursiveIncludes(include):    'Return a list containg the include dir and all its subdirectories'    dirs = [include]    def visit(arg, dir, names):        # ignore CVS dirs        if os.path.split(dir)[1] != 'CVS':            dirs.append(dir)    os.path.walk(include, visit, None)    return dirs    def GetDefaultIncludes():    if 'INCLUDE' in os.environ:        include = os.environ['INCLUDE']        return include.split(os.pathsep)    else:        return []def ProcessIncludes(includes):    if sys.platform == 'win32':        index = 0        for include in includes:            includes[index] = include.replace('\\', '/')            index += 1def ReadFileList(filename):    f = file(filename)    files = []    try:        for line in f:            line = line.strip()            if line:                files.append(line)    finally:        f.close()    return files        def ParseArguments():    def Usage():        print __doc__ % __version__        sys.exit(1)            try:        options, files = getopt.getopt(            sys.argv[1:],             'R:I:D:vh',             ['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=',              'only-create-cache', 'version', 'generate-main', 'file-list=',  'help',             'gccxml-path=', 'no-default-include'])    except getopt.GetoptError, e:        print        print 'ERROR:', e        Usage()        default_includes = GetDefaultIncludes()    includes = []    defines = []    module = None    out = None    multiple = False    cache_dir = None    create_cache = False    generate_main = False    gccxml_path = 'gccxml'        for opt, value in options:        if opt == '-I':            includes.append(value)        elif opt == '-D':            defines.append(value)        elif opt == '-R':            includes.extend(RecursiveIncludes(value))        elif opt == '--module':            module = value        elif opt == '--out':            out = value         elif opt == '--no-using':            settings.namespaces.python = 'boost::python::'            settings.USING_BOOST_NS = False        elif opt == '--pyste-ns':            settings.namespaces.pyste = value + '::'        elif opt == '--debug':            settings.DEBUG = True        elif opt == '--multiple':            multiple = True        elif opt == '--cache-dir':            cache_dir = value        elif opt == '--only-create-cache':            create_cache = True        elif opt == '--file-list':            files += ReadFileList(value)        elif opt in ['-h', '--help']:            Usage()        elif opt in ['-v', '--version']:            print 'Pyste version %s' % __version__            sys.exit(2)        elif opt == '--generate-main':            generate_main = True        elif opt == '--gccxml-path':            gccxml_path = value        elif opt == '--no-default-include':            default_includes = []         else:            print 'Unknown option:', opt            Usage()    includes[0:0] = default_includes    if not files:        Usage()     if not module:        module = os.path.splitext(os.path.basename(files[0]))[0]    if not out:        out = module        if not multiple:            out += '.cpp'    for file in files:        d = os.path.dirname(os.path.abspath(file))        if d not in sys.path:            sys.path.append(d)     if create_cache and not cache_dir:        print 'Error: Use --cache-dir to indicate where to create the cache files!'        Usage()        sys.exit(3)    if generate_main and not multiple:        print 'Error: --generate-main only valid in multiple mode.'        Usage()        sys.exit(3)    ProcessIncludes(includes)    return includes, defines, module, out, files, multiple, cache_dir, create_cache, \        generate_main, gccxml_pathdef PCHInclude(*headers):    code = '\n'.join(['#include <%s>' % x for x in headers])    infos.CodeInfo(code, 'pchinclude')    def CreateContext():    'create the context where a interface file will be executed'    context = {}    context['Import'] = Import    # infos    context['Function'] = infos.FunctionInfo    context['Class'] = infos.ClassInfo    context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include')    context['PCHInclude'] = PCHInclude    context['Template'] = infos.ClassTemplateInfo    context['Enum'] = infos.EnumInfo    context['AllFromHeader'] = infos.HeaderInfo    context['Var'] = infos.VarInfo    # functions    context['rename'] = infos.rename    context['set_policy'] = infos.set_policy    context['exclude'] = infos.exclude    context['set_wrapper'] = infos.set_wrapper    context['use_shared_ptr'] = infos.use_shared_ptr    context['use_auto_ptr'] = infos.use_auto_ptr    context['holder'] = infos.holder    context['add_method'] = infos.add_method    context['final'] = infos.final    context['export_values'] = infos.export_values    # policies    context['return_internal_reference'] = return_internal_reference    context['with_custodian_and_ward'] = with_custodian_and_ward    context['return_value_policy'] = return_value_policy    context['reference_existing_object'] = reference_existing_object    context['copy_const_reference'] = copy_const_reference    context['copy_non_const_reference'] = copy_non_const_reference    context['return_opaque_pointer'] = return_opaque_pointer    context['manage_new_object'] = manage_new_object    context['return_by_value'] = return_by_value    context['return_self'] = return_self    # utils    context['Wrapper'] = exporterutils.FunctionWrapper    context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')    context['module_code'] = lambda code: infos.CodeInfo(code, 'module')    context['class_code'] = infos.class_code    return context                                            def Begin():    # parse arguments    includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments()    # run pyste scripts    for interface in interfaces:        ExecuteInterface(interface)    # create the parser    parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path)    try:        if not create_cache:            if not generate_main:                return GenerateCode(parser, module, out, interfaces, multiple)            else:                return GenerateMain(module, out, OrderInterfaces(interfaces))        else:            return CreateCaches(parser)    finally:        parser.Close()def CreateCaches(parser):    # There is one cache file per interface so we organize the headers    # by interfaces.  For each interface collect the tails from the    # exporters sharing the same header.    tails = JoinTails(exporters.exporters)    # now for each interface file take each header, and using the tail    # get the declarations and cache them.    for interface, header in tails:                tail = tails[(interface, header)]        declarations = parser.ParseWithGCCXML(header, tail)        cachefile = parser.CreateCache(header, interface, tail, declarations)        print 'Cached', cachefile        return 0        _imported_count = {}  # interface => countdef ExecuteInterface(interface):    old_interface = exporters.current_interface    if not os.path.exists(interface):        if old_interface and os.path.exists(old_interface):            d = os.path.dirname(old_interface)            interface = os.path.join(d, interface)    if not os.path.exists(interface):        raise IOError, "Cannot find interface file %s."%interface        _imported_count[interface] = _imported_count.get(interface, 0) + 1    exporters.current_interface = interface    context = CreateContext()    context['INTERFACE_FILE'] = os.path.abspath(interface)    execfile(interface, context)    exporters.current_interface = old_interfacedef Import(interface):    exporters.importing = True    ExecuteInterface(interface)    exporters.importing = False    def JoinTails(exports):    '''Returns a dict of {(interface, header): tail}, where tail is the    joining of all tails of all exports for the header.      '''    tails = {}    for export in exports:        interface = export.interface_file        header = export.Header()        tail = export.Tail() or ''        if (interface, header) in tails:            all_tails = tails[(interface,header)]            all_tails += '\n' + tail            tails[(interface, header)] = all_tails        else:            tails[(interface, header)] = tail             return tailsdef OrderInterfaces(interfaces):    interfaces_order = [(_imported_count[x], x) for x in interfaces]    interfaces_order.sort()    interfaces_order.reverse()    return [x for _, x in interfaces_order]def GenerateMain(module, out, interfaces):    codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)    codeunit.GenerateMain(interfaces)    return 0    def GenerateCode(parser, module, out, interfaces, multiple):        # prepare to generate the wrapper code    if multiple:        codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)    else:        codeunit = SingleCodeUnit.SingleCodeUnit(module, out)     # stop referencing the exporters here    exports = exporters.exporters    exporters.exporters = None     exported_names = dict([(x.Name(), None) for x in exports])    # order the exports    order = {}    for export in exports:        if export.interface_file in order:            order[export.interface_file].append(export)        else:            order[export.interface_file] = [export]    exports = []    interfaces_order = OrderInterfaces(interfaces)    for interface in interfaces_order:        exports.extend(order[interface])    del order    del interfaces_order    # now generate the code in the correct order     #print exported_names    tails = JoinTails(exports)    for i in xrange(len(exports)):        export = exports[i]        interface = export.interface_file        header = export.Header()        if header:            tail = tails[(interface, header)]            declarations, parsed_header = parser.Parse(header, interface, tail)        else:            declarations = []            parsed_header = None        ExpandTypedefs(declarations, exported_names)        export.SetDeclarations(declarations)        export.SetParsedHeader(parsed_header)        if multiple:            codeunit.SetCurrent(export.interface_file, export.Name())        export.GenerateCode(codeunit, exported_names)        # force collect of cyclic references        exports[i] = None        del declarations        del export        gc.collect()    # finally save the code unit    codeunit.Save()    if not multiple:        print 'Module %s generated' % module    return 0def ExpandTypedefs(decls, exported_names):    '''Check if the names in exported_names are a typedef, and add the real class     name in the dict.    '''    for name in exported_names.keys():        for decl in decls:            if isinstance(decl, declarations.Typedef):                exported_names[decl.type.FullName()] = Nonedef UsePsyco():    'Tries to use psyco if possible'    try:        import psyco        psyco.profile()    except: pass         def main():    start = time.clock()    UsePsyco()    status = Begin()    print '%0.2f seconds' % (time.clock()-start)    sys.exit(status)     if __name__ == '__main__':    main()

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?