Completed
Push — oop-api ( 92fa45...c1b2d1 )
by Kyle
01:00
created

get_ast()   A

Complexity

Conditions 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
dl 0
loc 22
rs 9.2
c 1
b 0
f 0
1
#!/usr/bin/env python3
2
3
import os
4
import sys
5
6
import platform
7
from pycparser import c_parser, c_ast, parse_file, c_generator
8
from cffi import FFI
9
10
BITSIZE, LINKAGE = platform.architecture()
11
12
def walk_sources(directory):
13
    for path, dirs, files in os.walk(directory):
14
        for source in files:
15
            if not source.endswith('.c'):
16
                continue
17
            yield os.path.join(path, source)
18
19
def find_sources(directory):
20
    return [os.path.join(directory, source)
21
            for source in os.listdir(directory)
22
            if source.endswith('.c')]
23
24
module_name = 'tcod._libtcod'
25
include_dirs = [
26
                'tcod/',
27
                'Release/tcod/',
28
                'libtcod/include/',
29
                'libtcod/src/png/',
30
                'libtcod/src/zlib/',
31
                '/usr/include/SDL2/',
32
                ]
33
34
extra_compile_args = []
35
extra_link_args = []
36
sources = []
37
38
sources += [file for file in walk_sources('libtcod/src')
39
            if 'sys_sfml_c' not in file
40
            and 'sdl12' not in file
41
            ]
42
43
libraries = []
44
library_dirs = []
45
define_macros = [('LIBTCOD_EXPORTS', None),
46
                 ('TCOD_SDL2', None),
47
                 ('NO_OPENGL', None),
48
                 ('TCOD_NO_MACOSX_SDL_MAIN', None),
49
                 ('_CRT_SECURE_NO_WARNINGS', None),
50
                 ]
51
52
sources += find_sources('tcod/')
53
54
if sys.platform == 'win32':
55
    libraries += ['User32', 'OpenGL32']
56
57
if 'linux' in sys.platform:
58
    libraries += ['GL']
59
60
if sys.platform == 'darwin':
61
    extra_link_args += ['-framework', 'OpenGL']
62
63
libraries += ['SDL2']
64
65
# included SDL headers are for whatever OS's don't easily come with them
66
67
if sys.platform in ['win32', 'darwin']:
68
    include_dirs += ['dependencies/SDL2-2.0.4/include']
69
70
    if BITSIZE == '32bit':
71
        library_dirs += [os.path.realpath('dependencies/SDL2-2.0.4/lib/x86')]
72
    else:
73
        library_dirs += [os.path.realpath('dependencies/SDL2-2.0.4/lib/x64')]
74
75
if sys.platform in ['win32', 'darwin']:
76
    include_dirs += ['libtcod/src/zlib/']
77
78
class CustomPostParser(c_ast.NodeVisitor):
79
80
    def __init__(self):
81
        self.ast = None
82
        self.typedefs = None
83
84
    def parse(self, ast):
85
        self.ast = ast
86
        self.typedefs = []
87
        self.visit(ast)
88
        return ast
89
90
    def visit_Typedef(self, node):
91
        start_node = node
92
        if node.name in ['wchar_t', 'size_t']:
93
            self.ast.ext.remove(node) # remove wchar_t placeholder
94
        else:
95
            self.generic_visit(node)
96
            if node.name in self.typedefs:
97
                print('%s redefined' % node.name)
98
            self.typedefs.append(node.name)
99
100
    def visit_EnumeratorList(self, node):
101
        """Replace enumerator expressions with stubs."""
102
        for type, enum in node.children():
103
            if enum.value is None:
104
                pass
105
            elif isinstance(enum.value, c_ast.BinaryOp):
106
                enum.value = c_ast.Constant('int', '...')
107
            else:
108
                enum.value = c_ast.Constant(enum.value.type, '...')
109
110
    def visit_FuncDecl(self, node):
111
        pass
112
113
    def visit_FuncDef(self, node):
114
        """Remvoe function definitions."""
115
        self.ast.ext.remove(node)
116
117
def get_cdef():
118
    generator = c_generator.CGenerator()
119
    return generator.visit(get_ast())
120
121
def get_ast():
122
    if 'win32' in sys.platform:
123
        sdl_include = r'-Idependencies/SDL2-2.0.4/include'
124
    else:
125
        sdl_include = r'-I/usr/include/SDL2'
126
    ast = parse_file(filename='tcod/tcod.h', use_cpp=True,
127
                     cpp_args=[r'-Idependencies/fake_libc_include',
128
                               r'-Ilibtcod/include',
129
                               sdl_include,
130
                               r'-DDECLSPEC=',
131
                               r'-DSDLCALL=',
132
                               r'-DTCODLIB_API=',
133
                               r'-DTCOD_NO_MACOSX_SDL_MAIN=',
134
                               r'-DTCOD_SDL2=',
135
                               r'-DNO_OPENGL',
136
                               r'-DSDL_FORCE_INLINE=',
137
                               r'-U__GNUC__',
138
                               r'-D_SDL_thread_h',
139
                               r'-DDOXYGEN_SHOULD_IGNORE_THIS',
140
                               r'-DSDL_MAIN_HANDLED',
141
                               ])
142
    return CustomPostParser().parse(ast)
143
144
def resolve_ast(ast, consts):
145
    if isinstance(ast, c_ast.Constant):
146
        return int(ast.value)
147
    elif isinstance(ast, c_ast.ID):
148
        return consts[ast.name]
149
    elif isinstance(ast, c_ast.BinaryOp):
150
        return resolve_ast(ast.left, consts) | resolve_ast(ast.right, consts)
151
    else:
152
        raise RuntimeError('Unexpected ast node: %r' % ast)
153
154
155
ffi = FFI()
156
try:
157
    ffi.cdef(get_cdef())
158
except Exception as exc:
159
    #print(dir(exc.args[1]))
160
    #print(exc.args[1].children()[0][1].name)
161
    #print(exc.args[1].show())
162
    raise
163
ffi.cdef('''
164
extern "Python" {
165
    static bool pycall_parser_new_struct(TCOD_parser_struct_t str,const char *name);
166
    static bool pycall_parser_new_flag(const char *name);
167
    static bool pycall_parser_new_property(const char *propname, TCOD_value_type_t type, TCOD_value_t value);
168
    static bool pycall_parser_end_struct(TCOD_parser_struct_t str, const char *name);
169
    static void pycall_parser_error(const char *msg);
170
171
    static bool _pycall_bsp_callback(TCOD_bsp_t *node, void *userData);
172
173
    static float _pycall_path_func( int xFrom, int yFrom, int xTo, int yTo, void *user_data );
174
175
    static bool _pycall_line_listener(int x, int y);
176
177
    static void _pycall_sdl_hook(void *);
178
}
179
''')
180
ffi.set_source(
181
    module_name, '#include <tcod.h>',
182
    include_dirs=include_dirs,
183
    library_dirs=library_dirs,
184
    sources=sources,
185
    libraries=libraries,
186
    extra_compile_args=extra_compile_args,
187
    extra_link_args=extra_link_args,
188
    define_macros=define_macros,
189
)
190
191
if __name__ == "__main__":
192
    ffi.compile()
193