In [142]:
import sys
sys.path.insert(0,'/Users/jon/DEV/clang-llvm-git/llvm/tools/clang/bindings/python/')
import clang.cindex
if not clang.cindex.Config.library_file:
clang.cindex.Config.set_library_file('/opt/local/libexec/llvm-3.7/lib/libclang.dylib')
In [143]:
import uuid
testfile='/tmp/{}.cpp'.format(uuid.uuid1())
In [207]:
%%writefile $testfile
#define C_API __attribute__((annotate("GENERATE_C_API")))
struct Shape
{
virtual ~Shape() {}
virtual double area(double r) const = 0;
virtual double perimeter(double r) const = 0;
} C_API;
static const double pi = 3.14159265359;
class Circle : public Shape
{
const double radius_;
public:
double area() const override { return pi * radius_ * radius_; }
double perimeter() const override { return 2 * pi * radius_; }
Circle(double r) : radius_(r) {}
};
class Square : public Shape
{
const double side_;
public:
double area() const override { return side_ * side_; }
double perimeter() const override { return 4.0 * side_; }
Square(double s) : side_(s) {}
};
In [208]:
def get_annotations(node):
return [c.displayname for c in node.get_children()
if c.kind == clang.cindex.CursorKind.ANNOTATE_ATTR]
class MemberData:
def __repr__(self):
return str(self.type)+":\""+str(self.name)+"\""
def __init__(self,cursor):
self.name = cursor.spelling
self.type = cursor.type.spelling
class FunctionArgument:
def __repr__(self):
return str(self.type)+":\""+str(self.name)+"\""
def __init__(self, type, name):
self.type = type
self.name = name
class Function(object):
def __repr__(self):
return "Function:"+str(self.name)
def __init__(self, cursor):
self.function_cursor = cursor
self.name = cursor.spelling
arguments = [x.spelling for x in cursor.get_arguments()]
argument_types = [x.spelling for x in cursor.type.argument_types()]
self.type = cursor.type.spelling
self.arguments = []
self.annotations = get_annotations(cursor)
for t,n in zip(argument_types,arguments):
self.arguments.append(FunctionArgument(t,n))
class Class(object):
def __repr__(self):
return "Class:%s"%str(self.name)
def __init__(self, cursor):
self.name = cursor.spelling
self.functions = []
self.members = []
self.annotations = get_annotations(cursor)
self.base_classes = []
for c in cursor.get_children():
if (c.kind == clang.cindex.CursorKind.FIELD_DECL):
m = MemberData(c)
self.members.append(m)
elif (c.kind == clang.cindex.CursorKind.CXX_METHOD):
f = Function(c)
self.functions.append(f)
elif (c.kind == clang.cindex.CursorKind.CONSTRUCTOR):
f = Function(c)
self.functions.append(f)
elif (c.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER):
self.base_classes.append(c.type.spelling)
self.constructors = [x for x in self.functions if x.name == self.name]
def build_classes(cursor):
result = []
for c in cursor.get_children():
if c.kind == clang.cindex.CursorKind.CLASS_DECL:
a_class = Class(c)
result.append(a_class)
elif c.kind == clang.cindex.CursorKind.STRUCT_DECL:
a_class = Class(c)
result.append(a_class)
elif c.kind == clang.cindex.CursorKind.NAMESPACE:
child_classes = build_classes(c)
result.extend(child_classes)
return result
In [209]:
index = clang.cindex.Index.create()
translation_unit = index.parse(testfile, ['-x', 'c++', '-std=c++11'])
classes = build_classes(translation_unit.cursor)
In [210]:
from django.template import Context, Template
import django
In [211]:
if not django.conf.settings.configured : django.conf.settings.configure()
In [235]:
t_api = Template(""" {{ class.name }}_delete(const void* my{{class.name}})
{
delete ((const {{class.name}}*)(my{{class.name}}));
}{% for function in class.functions %}
{{ class.name }}_{{function.name}}(const void* my{{class.name}}{% for arg in function.arguments %}, {{arg.type}} {{arg.name}}{% endfor %})
{
return ((const {{class.name}}*)(my{{class.name}}))->{{function.name}}({% for arg in function.arguments %}{% if not forloop.first %}, {% endif %}{{arg.type}} {{arg.name}}{% endfor %});
}{% endfor %}""")
In [236]:
t_obj = Template("""{% for function in class.constructors %}
const void* {{base}}_{{ class.name }}_new({% for arg in function.arguments %}{% if not forloop.first %}, {% endif %}{{arg.type}} {{arg.name}}{% endfor %})
{
return new (std::nothrow) {{ class.name }}({% for arg in function.arguments %}{% if not forloop.first %}, {% endif %}{{arg.name}}{% endfor %});
}{% endfor %}""")
In [237]:
api_classes = []
api_classes.extend([c for c in classes if 'GENERATE_C_API' in c.annotations])
obj_classes = []
for c in classes:
for b in c.base_classes:
if b in [x.name for x in api_classes]:
obj_classes.append((c,b))
In [238]:
print """extern "C"
{"""
for c in api_classes:
print(t_api.render(Context({"class": c})))
for c,b in obj_classes:
print(t_obj.render(Context({"class": c, "base": b})))
print "}"