Completed
Push — oop-api ( c1b2d1...007516 )
by Kyle
01:09
created

CustomPostParser.visit_FuncDef()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
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
                'libtcod/include/',
28
                'libtcod/src/png/',
29
                'libtcod/src/zlib/',
30
                '/usr/include/SDL2/',
31
                ]
32
33
extra_compile_args = []
34
extra_link_args = []
35
sources = []
36
37
sources += [file for file in walk_sources('libtcod/src')
38
            if 'sys_sfml_c' not in file
39
            and 'sdl12' not in file
40
            ]
41
42
libraries = []
43
library_dirs = []
44
define_macros = [('LIBTCOD_EXPORTS', None),
45
                 ('TCOD_SDL2', None),
46
                 ('NO_OPENGL', None),
47
                 ('TCOD_NO_MACOSX_SDL_MAIN', None),
48
                 ('_CRT_SECURE_NO_WARNINGS', None),
49
                 ]
50
51
sources += find_sources('tcod/')
52
53
if sys.platform == 'win32':
54
    libraries += ['User32', 'OpenGL32']
55
56
if 'linux' in sys.platform:
57
    libraries += ['GL']
58
59
if sys.platform == 'darwin':
60
    extra_link_args += ['-framework', 'OpenGL']
61
62
libraries += ['SDL2']
63
64
# included SDL headers are for whatever OS's don't easily come with them
65
66
if sys.platform in ['win32', 'darwin']:
67
    include_dirs += ['dependencies/SDL2-2.0.4/include']
68
69
    if BITSIZE == '32bit':
70
        library_dirs += [os.path.realpath('dependencies/SDL2-2.0.4/lib/x86')]
71
    else:
72
        library_dirs += [os.path.realpath('dependencies/SDL2-2.0.4/lib/x64')]
73
74
if sys.platform in ['win32', 'darwin']:
75
    include_dirs += ['libtcod/src/zlib/']
76
77
class CustomPostParser(c_ast.NodeVisitor):
78
79
    def __init__(self):
80
        self.ast = None
81
        self.typedefs = None
82
83
    def parse(self, ast):
84
        self.ast = ast
85
        self.typedefs = []
86
        self.visit(ast)
87
        return ast
88
89
    def visit_Typedef(self, node):
90
        start_node = node
91
        if node.name in ['wchar_t', 'size_t']:
92
            # remove fake typedef placeholders
93
            self.ast.ext.remove(node)
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, c_ast.UnaryOp)):
106
                enum.value = c_ast.Constant('int', '...')
107
            else:
108
                enum.value = c_ast.Constant(enum.value.type, '...')
109
110
    def visit_Decl(self, node):
111
        if node.name is None:
112
            self.generic_visit(node)
113
        elif (node.name and 'vsprint' in node.name or
114
              node.name in ['SDL_vsscanf',
115
                            'SDL_vsnprintf',
116
                            'SDL_LogMessageV']):
117
            # exclude va_list related functions
118
            self.ast.ext.remove(node)
119
        elif node.name in ['screen']:
120
            # exclude outdated 'extern SDL_Surface* screen;' line
121
            self.ast.ext.remove(node)
122
        else:
123
            self.generic_visit(node)
124
125
    def visit_FuncDef(self, node):
126
        """Exclude function definitions.  Should be declarations only."""
127
        self.ast.ext.remove(node)
128
129
def get_cdef():
130
    generator = c_generator.CGenerator()
131
    return generator.visit(get_ast())
132
133
def get_ast():
134
    if 'win32' in sys.platform:
135
        sdl_include = r'-Idependencies/SDL2-2.0.4/include'
136
    else:
137
        sdl_include = r'-I/usr/include/SDL2'
138
    ast = parse_file(filename='tcod/tcod.h', use_cpp=True,
139
                     cpp_args=[r'-Idependencies/fake_libc_include',
140
                               r'-Ilibtcod/include',
141
                               sdl_include,
142
                               r'-DDECLSPEC=',
143
                               r'-DSDLCALL=',
144
                               r'-DTCODLIB_API=',
145
                               r'-DTCOD_NO_MACOSX_SDL_MAIN=',
146
                               r'-DTCOD_SDL2=',
147
                               r'-DNO_OPENGL',
148
                               r'-DSDL_FORCE_INLINE=',
149
                               r'-U__GNUC__',
150
                               r'-D_SDL_thread_h',
151
                               r'-DDOXYGEN_SHOULD_IGNORE_THIS',
152
                               r'-DSDL_MAIN_HANDLED',
153
                               ])
154
    ast = CustomPostParser().parse(ast)
155
    return ast
156
157
ffi = FFI()
158
ffi.cdef(get_cdef())
159
ffi.cdef('''
160
extern "Python" {
161
    static bool pycall_parser_new_struct(TCOD_parser_struct_t str,const char *name);
162
    static bool pycall_parser_new_flag(const char *name);
163
    static bool pycall_parser_new_property(const char *propname, TCOD_value_type_t type, TCOD_value_t value);
164
    static bool pycall_parser_end_struct(TCOD_parser_struct_t str, const char *name);
165
    static void pycall_parser_error(const char *msg);
166
167
    static bool _pycall_bsp_callback(TCOD_bsp_t *node, void *userData);
168
169
    static float _pycall_path_func( int xFrom, int yFrom, int xTo, int yTo, void *user_data );
170
171
    static bool _pycall_line_listener(int x, int y);
172
173
    static void _pycall_sdl_hook(void *);
174
}
175
''')
176
ffi.set_source(
177
    module_name, '#include <tcod.h>',
178
    include_dirs=include_dirs,
179
    library_dirs=library_dirs,
180
    sources=sources,
181
    libraries=libraries,
182
    extra_compile_args=extra_compile_args,
183
    extra_link_args=extra_link_args,
184
    define_macros=define_macros,
185
)
186
187
if __name__ == "__main__":
188
    ffi.compile()
189