#!/usr/bin/env python
#
# header_wrappers.py: Generates SWIG proxy wrappers around Subversion
# header files
#
import os, re, string, sys, glob, shutil
if __name__ == "__main__":
parent_dir = os.path.dirname(os.path.abspath(os.path.dirname(sys.argv[0])))
sys.path[0:0] = [ parent_dir, os.path.dirname(parent_dir) ]
from gen_base import unique, native_path, build_path_basename, build_path_join
import generator.swig
class Generator(generator.swig.Generator):
"""Generate SWIG proxy wrappers around Subversion header files"""
def __init__(self, conf, swig_path):
"""Initialize Generator object"""
generator.swig.Generator.__init__(self, conf, swig_path)
# Build list of header files
self.header_files = map(native_path, self.includes)
self.header_basenames = map(os.path.basename, self.header_files)
# Ignore svn_repos_parse_fns_t because SWIG can't parse it
_ignores = ["svn_repos_parse_fns_t"]
def write_makefile_rules(self, makefile):
"""Write makefile rules for generating SWIG wrappers for Subversion
header files."""
wrapper_fnames = []
python_script = '$(abs_srcdir)/build/generator/swig/header_wrappers.py'
makefile.write('GEN_SWIG_WRAPPER = cd $(top_srcdir) && $(PYTHON)' +
' %s build.conf $(SWIG)\n\n' % python_script)
for fname in self.includes:
wrapper_fname = build_path_join(self.proxy_dir,
self.proxy_filename(build_path_basename(fname)))
wrapper_fnames.append(wrapper_fname)
makefile.write(
'%s: %s %s\n' % (wrapper_fname, fname, python_script) +
'\t$(GEN_SWIG_WRAPPER) %s\n\n' % fname
)
makefile.write('SWIG_WRAPPERS = %s\n\n' % string.join(wrapper_fnames))
for short_name in self.short.values():
makefile.write('autogen-swig-%s: $(SWIG_WRAPPERS)\n' % short_name)
makefile.write('\n\n')
def proxy_filename(self, include_filename):
"""Convert a .h filename into a _h.swg filename"""
return string.replace(include_filename,".h","_h.swg")
def _write_nodefault_calls(self, structs):
"""Write proxy definitions to a SWIG interface file"""
self.ofile.write("\n/* No default constructors for opaque structs */\n")
self.ofile.write('#ifdef SWIGPYTHON\n');
for structName, structDefinition in structs:
if not structDefinition:
self.ofile.write('%%nodefault %s;\n' % structName)
self.ofile.write('#endif\n');
def _write_includes(self, includes, base_fname):
"""Write includes to a SWIG interface file"""
self.ofile.write('\n/* Includes */\n')
# Include dependencies
self.ofile.write('#ifdef SWIGPYTHON\n');
apr_included = None
self.ofile.write('%import proxy.swg\n')
for include in includes:
if include in self.header_basenames:
self.ofile.write('%%include %s\n' % self.proxy_filename(include))
elif include[:3] == "apr" and not apr_included:
apr_included = 1
self.ofile.write('%import apr.swg\n')
self.ofile.write('#endif\n');
# Include the headerfile itself
self.ofile.write('%%{\n#include "%s"\n%%}\n' % base_fname)
if base_fname not in self._ignores:
self.ofile.write('%%include %s\n' % base_fname)
def _write_callbacks(self, callbacks):
"""Write invoker functions for callbacks"""
self.ofile.write('\n/* Callbacks */\n')
self.ofile.write("\n%inline %{\n")
struct = None
for match in callbacks:
if match[0]:
struct = match[0]
elif struct not in self._ignores:
name, params = match[1:]
if params == "void":
param_names = ""
else:
param_names = string.join(self._re_param_names.findall(params), ", ")
params = string.join(string.split(params))
self.ofile.write(
"static svn_error_t *%s_invoke_%s(\n" % (struct[:-2], name) +
" %s *_obj, %s) {\n" % (struct, params) +
" return _obj->%s(%s);\n" % (name, param_names) +
"}\n\n")
self.ofile.write("%}\n")
def _write_proxy_definitions(self, structs):
"""Write proxy definitions to a SWIG interface file"""
self.ofile.write('\n/* Structure definitions */\n')
self.ofile.write('#ifdef SWIGPYTHON\n');
for structName, structDefinition in structs:
if structDefinition:
self.ofile.write('%%proxy(%s);\n' % structName)
else:
self.ofile.write('%%opaque_proxy(%s);\n' % structName)
self.ofile.write('#endif\n');
"""Regular expression for parsing includes from a C header file"""
_re_includes = re.compile(r'#\s*include\s*[<"]([^<">;\s]+)')
"""Regular expression for parsing structs from a C header file"""
_re_structs = re.compile(r'\btypedef\s+(?:struct|union)\s+'
r'(svn_[a-z_0-9]+)\b\s*(\{?)')
"""Regular expression for parsing callbacks from a C header file"""
_re_callbacks = re.compile(r'\btypedef\s+(?:struct|union)\s+'
r'(svn_[a-z_0-9]+)\b|'
r'\n\s*svn_error_t\s*\*\(\*(\w+)\)\s*\(([^)]+)\);')
"""Regular expression for parsing parameter names from a parameter list"""
_re_param_names = re.compile(r'\b(\w+)\s*\)*\s*(?:,|$)')
"""Regular expression for parsing comments"""
_re_comments = re.compile(r'/\*.*?\*/')
def _write_swig_interface_file(self, base_fname, includes, structs,
callbacks):
"""Convert a header file into a SWIG header file"""
# Calculate output filename from base filename
output_fname = os.path.join(self.proxy_dir,
self.proxy_filename(base_fname))
# Open the output file
self.ofile = open(output_fname, 'w')
self.ofile.write('/* Proxy classes for %s\n' % base_fname)
self.ofile.write(' * DO NOT EDIT -- AUTOMATICALLY GENERATED */\n')
# Write list of structs for which we shouldn't define constructors
# by default
self._write_nodefault_calls(structs)
# Write includes into the SWIG interface file
self._write_includes(includes, base_fname)
# Write proxy definitions into the SWIG interface file
self._write_proxy_definitions(structs)
# Write callback definitions into the SWIG interface file
self._write_callbacks(callbacks)
# Close our output file
self.ofile.close()
def process_header_file(self, fname):
"""Generate a wrapper around a header file"""
# Read the contents of the header file
contents = open(fname).read()
# Remove comments
contents = self._re_comments.sub("", contents)
# Get list of includes
includes = unique(self._re_includes.findall(contents))
# Get list of structs
structs = unique(self._re_structs.findall(contents))
# Get list of callbacks
callbacks = self._re_callbacks.findall(contents)
# Get the location of the output file
base_fname = os.path.basename(fname)
# Write the SWIG interface file
self._write_swig_interface_file(base_fname, includes, structs, callbacks)
def write(self):
"""Generate wrappers for all header files"""
for fname in self.header_files:
self.process_header_file(fname)
if __name__ == "__main__":
if len(sys.argv) < 3:
print """Usage: %s build.conf swig [ subversion/include/header_file.h ]
Generates SWIG proxy wrappers around Subversion header files. If no header
files are specified, generate wrappers for subversion/include/*.h. """
else:
gen = Generator(sys.argv[1], sys.argv[2])
if len(sys.argv) > 3:
for fname in sys.argv[3:]:
gen.process_header_file(fname)
else:
gen.write()
syntax highlighted by Code2HTML, v. 0.9.1