2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 06:02:14 +00:00

- incremental code and some fixes

[SVN r19499]
This commit is contained in:
Bruno da Silva de Oliveira
2003-08-09 21:18:12 +00:00
parent 7fa6a29814
commit 168476382a
13 changed files with 418 additions and 201 deletions

View File

@@ -48,25 +48,23 @@ class ClassExporter(Exporter):
return makeid(self.class_.FullName()) + '_scope'
def Unit(self):
return makeid(self.class_.name)
def Name(self):
return self.class_.FullName()
return self.info.name
def SetDeclarations(self, declarations):
Exporter.SetDeclarations(self, declarations)
decl = self.GetDeclaration(self.info.name)
if isinstance(decl, Typedef):
self.class_ = self.GetDeclaration(decl.type.name)
if not self.info.rename:
self.info.rename = decl.name
if self.declarations:
decl = self.GetDeclaration(self.info.name)
if isinstance(decl, Typedef):
self.class_ = self.GetDeclaration(decl.type.name)
if not self.info.rename:
self.info.rename = decl.name
else:
self.class_ = decl
self.class_ = copy.deepcopy(self.class_)
else:
self.class_ = decl
self.class_ = copy.deepcopy(self.class_)
self.class_ = None
def ClassBases(self):
@@ -82,7 +80,8 @@ class ClassExporter(Exporter):
bases' bases. Do this because base classes must be instantialized
before the derived classes in the module definition.
'''
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
num_bases = len(self.ClassBases())
return num_bases, self.class_.FullName()
def Export(self, codeunit, exported_names):
@@ -101,7 +100,7 @@ class ClassExporter(Exporter):
self.ExportSmartPointer()
self.ExportOpaquePointerPolicies()
self.Write(codeunit)
exported_names[self.class_.FullName()] = 1
exported_names[self.Name()] = 1
def InheritMethods(self, exported_names):
@@ -131,7 +130,7 @@ class ClassExporter(Exporter):
break
def IsValid(member):
return isinstance(member, valid_members) and member.visibility == Scope.public
self.public_members = [x for x in self.class_ if IsValid(x)]
self.public_members = [x for x in self.class_ if IsValid(x)]
def Write(self, codeunit):
@@ -196,14 +195,9 @@ class ClassExporter(Exporter):
def ExportBasics(self):
'''Export the name of the class and its class_ statement.
Also export the held_type if specified.'''
'''Export the name of the class and its class_ statement.'''
class_name = self.class_.FullName()
self.Add('template', class_name)
held_type = self.info.held_type
if held_type:
held_type = held_type % class_name
self.Add('template', held_type)
name = self.info.rename or self.class_.name
self.Add('constructor', '"%s"' % name)
@@ -211,14 +205,14 @@ class ClassExporter(Exporter):
def ExportBases(self, exported_names):
'Expose the bases of the class into the template section'
hierarchy = self.class_.hierarchy
exported = []
for level in hierarchy:
exported = []
for base in level:
if base.visibility == Scope.public and base.name in exported_names:
exported.append(base.name)
if exported:
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
self.Add('template', code)
if exported:
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
self.Add('template', code)
def ExportConstructors(self):
@@ -408,13 +402,19 @@ class ClassExporter(Exporter):
has_virtual_methods = True
break
holder = self.info.holder
if has_virtual_methods:
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
self.Add('template', generator.FullName())
if holder:
self.Add('template', holder(generator.FullName()))
else:
self.Add('template', generator.FullName())
for definition in generator.GenerateDefinitions():
self.Add('inside', definition)
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
else:
if holder:
self.Add('template', holder(self.class_.FullName()))
# operators natively supported by boost
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -='\
@@ -610,7 +610,7 @@ class ClassExporter(Exporter):
if smart_ptr:
class_name = self.class_.FullName()
smart_ptr = smart_ptr % class_name
self.Add('scope', '%s::register_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
def ExportOpaquePointerPolicies(self):

View File

@@ -2,16 +2,25 @@ from GCCXMLParser import ParseDeclarations
import tempfile
import shutil
import os
import sys
import os.path
import settings
import shutil
import shelve
from cPickle import dump, load
#==============================================================================
# exceptions
#==============================================================================
class CppParserError(Exception): pass
#==============================================================================
# CppParser
#==============================================================================
class CppParser:
'Parses a header file and returns a list of declarations'
def __init__(self, includes=None, defines=None):
def __init__(self, includes=None, defines=None, cache_dir=None):
'includes and defines ar the directives given to gcc'
if includes is None:
includes = []
@@ -19,9 +28,26 @@ class CppParser:
defines = []
self.includes = includes
self.defines = defines
#if cache_dir is None:
# cache_dir = tempfile.mktemp()
# self.delete_cache = True
#else:
# self.delete_cache = False
self.delete_cache = False
self.cache_dir = cache_dir
self.cache_files = []
# create the cache dir
if cache_dir:
try:
os.makedirs(cache_dir)
except OSError: pass
def _includeparams(self, filename):
def __del__(self):
self.Close()
def _IncludeParams(self, filename):
includes = self.includes[:]
filedir = os.path.dirname(filename)
if not filedir:
@@ -31,64 +57,153 @@ class CppParser:
return ' '.join(includes)
def _defineparams(self):
def _DefineParams(self):
defines = ['-D "%s"' % x for x in self.defines]
return ' '.join(defines)
def FindFileName(self, include):
if os.path.isfile(include):
return include
def FindHeader(self, header):
if os.path.isfile(header):
return header
for path in self.includes:
filename = os.path.join(path, include)
filename = os.path.join(path, header)
if os.path.isfile(filename):
return filename
name = os.path.basename(include)
raise RuntimeError, 'Header file "%s" not found!' % name
else:
name = os.path.basename(header)
raise RuntimeError, 'Header file "%s" not found!' % name
def parse(self, include, tail=None, decl_name=None):
'''Parses the given filename, and returns (declaration, header). The
header returned is normally the same as the given to this method,
except if tail is not None: in this case, the header is copied to a temp
filename and the tail code is appended to it before being passed on to gcc.
This temp filename is then returned.
'''
filename = self.FindFileName(include)
# copy file to temp folder, if needed
def AppendTail(self, filename, tail):
'''Creates a temporary file, appends the text tail to it, and returns
the filename of the file.
'''
temp = tempfile.mktemp('.h')
shutil.copyfile(filename, temp)
f = file(temp, 'a')
f.write('\n\n'+tail)
f.close()
return temp
def ParseWithGCCXML(self, header, tail):
'''Parses the given header using gccxml and GCCXMLParser.
'''
header = self.FindHeader(header)
if tail:
tempfilename = tempfile.mktemp('.h')
infilename = tempfilename
shutil.copyfile(filename, infilename)
f = file(infilename, 'a')
f.write('\n\n'+tail)
f.close()
filename = self.AppendTail(header, tail)
else:
infilename = filename
filename = header
xmlfile = tempfile.mktemp('.xml')
try:
# get the params
includes = self._includeparams(filename)
defines = self._defineparams()
includes = self._IncludeParams(filename)
defines = self._DefineParams()
# call gccxml
cmd = 'gccxml %s %s %s -fxml=%s' \
% (includes, defines, infilename, xmlfile)
if decl_name is not None:
cmd += ' "-fxml-start=%s"' % decl_name
status = os.system(cmd)
cmd = 'gccxml %s %s %s -fxml=%s'
status = os.system(cmd % (includes, defines, filename, xmlfile))
if status != 0 or not os.path.isfile(xmlfile):
raise CppParserError, 'Error executing gccxml'
# parse the resulting xml
declarations = ParseDeclarations(xmlfile)
# make the declarations' location to point to the original file
if tail:
for decl in declarations:
decl_filename = os.path.normpath(os.path.normcase(decl.location[0]))
filename = os.path.normpath(os.path.normcase(filename))
if decl_filename == filename:
decl.location = header, decl.location[1]
# return the declarations
return declarations, infilename
return declarations
finally:
if settings.DEBUG and os.path.isfile(xmlfile):
filename = os.path.basename(include)
shutil.copy(xmlfile, os.path.splitext(filename)[0] + '.xml')
filename = os.path.basename(header)
filename = os.path.splitext(filename)[0] + '.xml'
shutil.copy(xmlfile, filename)
# delete the temporary files
try:
os.remove(xmlfile)
if tail:
os.remove(tempfilename)
except OSError: pass
os.remove(filename)
except OSError: pass
def Parse(self, header, interface, tail=None):
'''Parses the given filename related to the given interface and returns
the (declarations, headerfile). The header returned is normally the
same as the given to this method (except that it is the full path),
except if tail is not None: in this case, the header is copied to a temp
filename and the tail code is appended to it before being passed on to
gccxml. This temp filename is then returned.
'''
if tail is None:
tail = ''
tail.strip()
declarations = self.GetCache(header, interface, tail)
if declarations is None:
declarations = self.ParseWithGCCXML(header, tail)
if self.cache_dir is not None:
self.CreateCache(header, interface, tail, declarations)
return declarations, header
def CacheFileName(self, interface):
interface_name = os.path.basename(interface)
cache_file = os.path.splitext(interface_name)[0] + '.pystec'
cache_file = os.path.join(self.cache_dir, cache_file)
return cache_file
def GetCache(self, header, interface, tail):
if self.cache_dir is None:
return None
header = self.FindHeader(header)
cache_file = self.CacheFileName(interface)
if os.path.isfile(cache_file):
f = file(cache_file, 'rb')
try:
cache = load(f)
key = (header, interface, tail)
if cache.has_key(key):
self.cache_files.append(cache_file)
return cache[key]
else:
return None
finally:
f.close()
else:
return None
def CreateCache(self, header, interface, tail, declarations):
header = self.FindHeader(header)
cache_file = self.CacheFileName(interface)
if os.path.isfile(cache_file):
f = file(cache_file, 'rb')
try:
cache = load(f)
finally:
f.close()
else:
cache = {}
key = (header, interface, tail)
cache[key] = declarations
self.cache_files.append(cache_file)
f = file(cache_file, 'wb')
try:
dump(cache, f, 1)
finally:
f.close()
return cache_file
def Close(self):
if self.delete_cache and self.cache_files:
for filename in self.cache_files:
try:
os.remove(filename)
except OSError:
pass
self.cache_files = []
shutil.rmtree(self.cache_dir)

View File

@@ -14,7 +14,10 @@ class EnumExporter(Exporter):
def SetDeclarations(self, declarations):
Exporter.SetDeclarations(self, declarations)
self.enum = self.GetDeclaration(self.info.name)
if self.declarations:
self.enum = self.GetDeclaration(self.info.name)
else:
self.enum = None
def Export(self, codeunit, exported_names):
@@ -34,12 +37,8 @@ class EnumExporter(Exporter):
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
code += indent + ';\n\n'
codeunit.Write('module', code)
exported_names[self.enum.FullName()] = 1
exported_names[self.Name()] = 1
def Unit(self):
return utils.makeid(self.info.include)
def Order(self):
def Name(self):
return self.info.name

View File

@@ -12,10 +12,11 @@ class Exporter(object):
self.info = info
self.parser_tail = parser_tail
self.interface_file = None
self.declarations = []
def Name(self):
return self.info.name
raise NotImplementedError(self.__class__.__name__)
def Tail(self):
@@ -73,12 +74,15 @@ class Exporter(object):
'''Returns a string that uniquely identifies this instance. All
exporters will be sorted by Order before being exported.
'''
raise NotImplementedError
def Unit(self):
return self.info.include
return 0, self.info.name
def Header(self):
return self.info.include
def __eq__(self, other):
return self.Name() == other.Name()
def __ne__(self, other):
return self.Name() != other.Name()

View File

@@ -24,7 +24,7 @@ class FunctionExporter(Exporter):
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
self.ExportOpaquePointer(decl, codeunit)
self.GenerateOverloads(decls, codeunit)
exported_names[decl.FullName()] = 1
exported_names[self.Name()] = 1
def ExportDeclaration(self, decl, unique, codeunit):
@@ -82,9 +82,6 @@ class FunctionExporter(Exporter):
if macro:
codeunit.Write('declaration-outside', macro)
def Order(self):
def Name(self):
return self.info.name
def Unit(self):
return utils.makeid(self.info.include)

View File

@@ -66,17 +66,11 @@ class HeaderExporter(Exporter):
exporter.SetDeclarations(self.declarations)
exporter.SetParsedHeader(self.parser_header)
if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit):
codeunit.SetCurrent(self.interface_file, exporter.Unit())
codeunit.SetCurrent(self.interface_file, exporter.Name())
else:
codeunit.SetCurrent(exporter.Unit())
codeunit.SetCurrent(exporter.Name())
exporter.GenerateCode(codeunit, exported_names)
def Unit(self):
return None # doesn't write anything by itself
def Order(self):
def Name(self):
return self.info.include

View File

@@ -17,11 +17,8 @@ class IncludeExporter(Exporter):
def Parse(self, parser):
pass
def Order(self):
return self.info.include
def Unit(self):
return '__all__' # include it in all generated cpps (multiple mode)
def Name(self):
return '__all__'
def Header(self):
return None # means "don't try to parse me!"

View File

@@ -22,8 +22,9 @@ class MultipleCodeUnit(object):
self.all = SingleCodeUnit(None, None)
def _FunctionName(self, export_name):
return 'Export_%s' % utils.makeid(export_name)
def _FunctionName(self, interface_file):
name = os.path.splitext(interface_file)[0]
return 'Export_%s' % utils.makeid(name)
def _FileName(self, interface_file):
@@ -40,13 +41,13 @@ class MultipleCodeUnit(object):
self._current = self.all
else:
filename = self._FileName(interface_file)
function = self._FunctionName(export_name)
function = self._FunctionName(interface_file)
try:
codeunit = self.codeunits[(filename, function)]
codeunit = self.codeunits[filename]
except KeyError:
codeunit = SingleCodeUnit(None, filename)
codeunit.module_definition = 'void %s()' % function
self.codeunits[(filename, function)] = codeunit
self.codeunits[filename] = codeunit
if function not in self.functions:
self.functions.append(function)
self._current = codeunit
@@ -84,7 +85,7 @@ class MultipleCodeUnit(object):
# unit in the list of code units is used as the main unit
# which dumps all the include, declaration and
# declaration-outside sections at the top of the file.
for (filename, _), codeunit in self.codeunits.items():
for filename, codeunit in self.codeunits.items():
if filename not in codeunits:
# this codeunit is the main codeunit.
codeunits[filename] = [codeunit]
@@ -103,20 +104,24 @@ class MultipleCodeUnit(object):
codeunit.Save(append)
if not append:
append = True
def GenerateMain(self, interfaces):
# generate the main cpp
filename = os.path.join(self.outdir, '_main.cpp')
fout = SmartFile(filename, 'w')
fout.write(utils.left_equals('Include'))
fout.write('#include <boost/python.hpp>\n\n')
fout.write('#include <boost/python/module.hpp>\n\n')
fout.write(utils.left_equals('Exports'))
for function in self.functions:
functions = [self._FunctionName(x) for x in interfaces]
for function in functions:
fout.write('void %s();\n' % function)
fout.write('\n')
fout.write(utils.left_equals('Module'))
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
fout.write('{\n')
indent = ' ' * 4
for function in self.functions:
for function in functions:
fout.write(indent)
fout.write('%s();\n' % function)
fout.write('}\n')

View File

@@ -85,13 +85,14 @@ class SingleCodeUnit:
fout.write(declaration_outside + '\n\n')
if declaration:
pyste_namespace = namespaces.pyste[:-2]
fout.write('namespace %s {\n\n\n' % pyste_namespace)
fout.write('namespace %s {\n\n' % pyste_namespace)
fout.write(declaration)
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
fout.write('\n}// namespace %s\n' % pyste_namespace)
fout.write(space)
# module
fout.write(left_equals('Module'))
fout.write(self.module_definition + '\n')
fout.write('{\n')
fout.write(self.code['module'])
fout.write('}\n')
fout.write('}\n\n')
fout.close()

View File

@@ -28,8 +28,8 @@ class VarExporter(Exporter):
def Order(self):
return 0, self.info.name
def Name(self):
return self.info.name
def Unit(self):
return utils.makeid(self.info.include)

View File

@@ -58,7 +58,8 @@ class FunctionInfo(DeclarationInfo):
self._Attribute('exclude', False)
# create a FunctionExporter
exporter = FunctionExporter(InfoWrapper(self), tail)
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -74,7 +75,8 @@ class ClassInfo(DeclarationInfo):
self._Attribute('exclude', False)
# create a ClassExporter
exporter = ClassExporter(InfoWrapper(self), tail)
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -87,7 +89,8 @@ class IncludeInfo(DeclarationInfo):
DeclarationInfo.__init__(self)
self._Attribute('include', include)
exporter = IncludeExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -137,7 +140,8 @@ class EnumInfo(DeclarationInfo):
self._Attribute('include', include)
self._Attribute('exclude', False)
exporter = EnumExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -150,7 +154,8 @@ class HeaderInfo(DeclarationInfo):
DeclarationInfo.__init__(self)
self._Attribute('include', include)
exporter = HeaderExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -164,7 +169,8 @@ class VarInfo(DeclarationInfo):
self._Attribute('name', name)
self._Attribute('include', include)
exporter = VarExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
if exporter not in exporters.exporters:
exporters.exporters.append(exporter)
exporter.interface_file = exporters.current_interface
@@ -215,11 +221,10 @@ def use_shared_ptr(info):
def use_auto_ptr(info):
info._Attribute('smart_ptr', 'std::auto_ptr< %s >')
def hold_with_shared_ptr(info):
info._Attribute('held_type', 'boost::shared_ptr< %s >')
def hold_with_auto_ptr(info):
info._Attribute('held_type', 'std::auto_ptr< %s >')
def holder(info, function):
msg = "Expected a callable that accepts one string argument."
assert callable(function), msg
info._Attribute('holder', function)
def add_method(info, name, rename=None):
added = info._Attribute('__added__')

View File

@@ -2,7 +2,6 @@ import profile
import pstats
import pyste
import psyco
import elementtree.XMLTreeBuilder as XMLTreeBuilder
import GCCXMLParser
@@ -12,6 +11,6 @@ if __name__ == '__main__':
#psyco.bind(XMLTreeBuilder.fixname)
#psyco.bind(XMLTreeBuilder.TreeBuilder)
#psyco.bind(GCCXMLParser.GCCXMLParser)
profile.run('pyste.Main()', 'profile')
profile.run('pyste.main()', 'profile')
p = pstats.Stats('profile')
p.strip_dirs().sort_stats(-1).print_stats()
p.strip_dirs().sort_stats('cumulative').print_stats()

View File

@@ -1,28 +1,31 @@
'''
"""
Pyste version %s
Usage:
pyste [options] interface-files
where 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 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
-h, --help print this help and exit
-v, --version print version information
'''
--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)
-h, --help Print this help and exit
-v, --version Print version information
"""
import sys
import os
@@ -70,16 +73,22 @@ def ParseArguments():
options, files = getopt.getopt(
sys.argv[1:],
'R:I:D:vh',
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'version', 'help'])
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=',
'only-create-cache', 'version', 'generate-main', 'help'])
except getopt.GetoptError, e:
print
print 'ERROR:', e
Usage()
includes = GetDefaultIncludes()
defines = []
module = None
out = None
multiple = False
cache_dir = None
create_cache = False
generate_main = False
for opt, value in options:
if opt == '-I':
includes.append(value)
@@ -100,11 +109,17 @@ def ParseArguments():
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 in ['-h', '--help']:
Usage()
elif opt in ['-v', '--version']:
print 'Pyste version %s' % __VERSION__
sys.exit(2)
elif opt == '--generate-main':
generate_main = True
else:
print 'Unknown option:', opt
Usage()
@@ -122,12 +137,23 @@ def ParseArguments():
if d not in sys.path:
sys.path.append(d)
return includes, defines, module, out, files, multiple
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)
return includes, defines, module, out, files, multiple, cache_dir, create_cache, generate_main
def CreateContext():
'create the context where a interface file will be executed'
context = {}
context['Import'] = ExecuteInterface
# infos
context['Function'] = infos.FunctionInfo
context['Class'] = infos.ClassInfo
@@ -143,8 +169,7 @@ def CreateContext():
context['set_wrapper'] = infos.set_wrapper
context['use_shared_ptr'] = infos.use_shared_ptr
context['use_auto_ptr'] = infos.use_auto_ptr
context['hold_with_shared_ptr'] = infos.hold_with_shared_ptr
context['hold_with_auto_ptr'] = infos.hold_with_auto_ptr
context['holder'] = infos.holder
context['add_method'] = infos.add_method
context['final'] = infos.final
# policies
@@ -162,70 +187,146 @@ def CreateContext():
def Begin():
includes, defines, module, out, interfaces, multiple = ParseArguments()
# execute the interface files
# parse arguments
includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main = ParseArguments()
# run pyste scripts
for interface in interfaces:
exporters.current_interface = interface
context = CreateContext()
execfile(interface, context)
ExecuteInterface(interface)
# create the parser
parser = CppParser(includes, defines)
parser = CppParser(includes, defines, cache_dir)
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 => count
def 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()
execfile(interface, context)
exporters.current_interface = old_interface
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 tails
def 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)
# group exporters by header files
groups = {}
for export in exporters.exporters:
header = export.Header()
if header in groups:
groups[header].append(export)
else:
groups[header] = [export]
# stop referencing the exporters here
exports = exporters.exporters
exporters.exporters = None
# export all the exporters in each group, releasing memory as doing so
while len(groups) > 0:
# get the first group
header = groups.keys()[0]
exports = groups[header]
del groups[header]
# gather all tails into one
all_tails = []
for export in exports:
if export.Tail():
all_tails.append(export.Tail())
all_tails = '\n'.join(all_tails)
# parse header (if there's one)
exported_names = dict([(x.Name(), None) for x in exports])
# order the exports
interfaces_order = OrderInterfaces(interfaces)
order = {}
for export in exports:
if export.interface_file in order:
order[export.interface_file].append(export)
else:
order[export.interface_file] = [export]
exports = []
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:
try:
declarations, parsed_header = parser.parse(header, all_tails)
except CppParserError, e:
print>>sys.stderr, '\n\n***', e, ': exitting'
return 2
tail = tails[(interface, header)]
declarations, parsed_header = parser.Parse(header, interface, tail)
else:
declarations = []
parsed_header = None
# first set the declarations and parsed_header for all the exporters
for export in exports:
export.SetDeclarations(declarations)
export.SetParsedHeader(parsed_header)
# sort the exporters by their order
exports = [(x.Order(), x) for x in exports]
exports.sort()
exports = [x for _, x in exports]
# maintain a dict of exported_names for this group
exported_names = {}
for export in exports:
if multiple:
codeunit.SetCurrent(export.interface_file, export.Unit())
export.GenerateCode(codeunit, 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()
print 'Module %s generated' % module
codeunit.Save()
if not multiple:
print 'Module %s generated' % module
return 0