1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
'''
Use CppHeaderParser to parse some C++ headers, and generate binding code for them.
Usage:
bindings_generator.py BASENAME HEADER1 HEADER2 ...
BASENAME is the name used for output files (with added suffixes).
HEADER1 etc. are the C++ headers to parse
We generate the following:
* BASENAME.c: C bindings file, with generated C wrapper functions. You will
need to build this with your project, and make sure it compiles
properly by adding the proper #includes etc. You can also just
#include this file itself in one of your existing project files.
* BASENAME.js: JavaScript bindings file, with generated JavaScript wrapper
objects. This is a high-level wrapping, using native JS classes.
'''
import os, sys, glob
abspath = os.path.abspath(os.path.dirname(__file__))
def path_from_root(*pathelems):
return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems)))
exec(open(path_from_root('tools', 'shared.py'), 'r').read())
# Find ply and CppHeaderParser
sys.path = [path_from_root('third_party', 'ply'), path_from_root('third_party', 'CppHeaderParser')] + sys.path
import CppHeaderParser
#print glob.glob(path_from_root('tests', 'bullet', 'src', 'BulletCollision', 'CollisionDispatch', '*.h'))
basename = sys.argv[1]
# First pass - read everything
classes = {}
for header in sys.argv[2:]:
#[('tests', 'bullet', 'src', 'BulletCollision/CollisionDispatch/btCollisionWorld.h')]:
parsed = CppHeaderParser.CppHeader(header)
#header = CppHeaderParser.CppHeader(path_from_root('tests', 'bullet', 'src', 'btBulletDynamicsCommon.h'))
#print header.classes.keys()
#print dir(header.classes['btCollisionShape'])
#print header.classes['btCollisionWorld']['methods']['public']
for cname, clazz in parsed.classes.iteritems():
if len(clazz['methods']['public']) > 0: # Do not notice stub classes
print 'Seen', cname
classes[cname] = clazz
# Second pass - generate bindings
funcs = []
gen_c = open(basename + '.c', 'w')
gen_js = open(basename + '.js', 'w')
gen_c.write('extern "C" {\n')
for cname, clazz in classes.iteritems():
print 'Generating', cname
# TODO: Generate all parent class (recursively) data too
constructor_counter = 0
for method in clazz['methods']['public']:
#print ' ', method['name'], method
mname = method['name']
args = method['parameters']
constructor = mname == cname
# C
ret = (cname + ' *') if constructor else method['rtnType']
callprefix = 'new ' if constructor else 'self->'
typedargs = ', '.join( ([] if constructor else [cname + ' * self']) + map(lambda arg: arg['type'] + ' ' + arg['name'], args) )
justargs = ', '.join(map(lambda arg: arg['name'], args))
fullname = cname + '__' + mname
gen_c.write('''
%s emscripten_bind_%s(%s) {
return %s%s(%s);
}
''' % (ret, fullname, typedargs, callprefix, mname, justargs))
funcs.append('emscripten_bind_' + fullname)
# JS
if constructor:
gen_js.write('''
function %s(%s) {
this.ptr = _emscripten_bind_%s(%s);
}
''' % (cname + (str(constructor_counter) if constructor_counter > 0 else ''), justargs, fullname, justargs))
constructor_counter += 1
else: # TODO: handle case of multiple constructors
gen_js.write('''
%s.prototype.%s = function(%s) {
%s_emscripten_bind_%s(this.ptr%s);
}
''' % (cname, mname, justargs, 'return ' if ret != 'void' else '', fullname, (', ' if len(justargs) > 0 else '') + justargs))
# Finish up
gen_c.write('''
}
#include <stdio.h>
struct EmscriptenEnsurer
{
EmscriptenEnsurer() {
// Actually use the binding functions, so DFE will not eliminate them
int sum = 0;
void *seen = (void*)%s;
''' % funcs[0])
for func in funcs[1:]:
gen_c.write(''' sum += (void*)%s == seen;
''' % func)
gen_c.write(''' printf("(%d)\\n", sum);
}
};
EmscriptenEnsurer emscriptenEnsurer;
''')
gen_c.close()
gen_js.close()
|