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:
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__')
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user