src/platform/python/_builder.py (view raw)
1import cffi
2import os, os.path
3import shlex
4import subprocess
5import sys
6
7ffi = cffi.FFI()
8pydir = os.path.dirname(os.path.abspath(__file__))
9srcdir = os.path.join(pydir, "..", "..")
10incdir = os.path.join(pydir, "..", "..", "..", "include")
11bindir = os.environ.get("BINDIR", os.path.join(os.getcwd(), ".."))
12
13cpp = shlex.split(os.environ.get("CPP", "cc -E"))
14cppflags = shlex.split(os.environ.get("CPPFLAGS", ""))
15if __name__ == "__main__":
16 cppflags.extend(sys.argv[1:])
17cppflags.extend(["-I" + incdir, "-I" + srcdir, "-I" + bindir])
18
19ffi.set_source("mgba._pylib", """
20#include "flags.h"
21#define OPAQUE_THREADING
22#include <mgba-util/common.h>
23#include <mgba/core/core.h>
24#include <mgba/core/log.h>
25#include <mgba/core/mem-search.h>
26#include <mgba/core/thread.h>
27#include <mgba/core/tile-cache.h>
28#include <mgba/core/version.h>
29#include <mgba/debugger/debugger.h>
30#include <mgba/internal/arm/arm.h>
31#include <mgba/internal/debugger/cli-debugger.h>
32#include <mgba/internal/ds/ds.h>
33#include <mgba/internal/ds/input.h>
34#include <mgba/internal/gba/gba.h>
35#include <mgba/internal/gba/input.h>
36#include <mgba/internal/gba/renderers/tile-cache.h>
37#include <mgba/internal/lr35902/lr35902.h>
38#include <mgba/internal/gb/gb.h>
39#include <mgba/internal/gb/renderers/tile-cache.h>
40#include <mgba-util/png-io.h>
41#include <mgba-util/vfs.h>
42
43#define PYEXPORT
44#include "platform/python/core.h"
45#include "platform/python/log.h"
46#include "platform/python/sio.h"
47#include "platform/python/vfs-py.h"
48#undef PYEXPORT
49""", include_dirs=[incdir, srcdir],
50 extra_compile_args=cppflags,
51 libraries=["medusa-emu"],
52 library_dirs=[bindir],
53 sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "core.c", "log.c", "sio.c"]])
54
55preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)
56
57lines = []
58for line in preprocessed.splitlines():
59 line = line.strip()
60 if line.startswith('#'):
61 continue
62 lines.append(line)
63ffi.cdef('\n'.join(lines))
64
65preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "lib.h")], universal_newlines=True)
66
67lines = []
68for line in preprocessed.splitlines():
69 line = line.strip()
70 if line.startswith('#'):
71 continue
72 lines.append(line)
73ffi.embedding_api('\n'.join(lines))
74
75ffi.embedding_init_code("""
76 from mgba._pylib import ffi, lib
77 symbols = {}
78 globalSyms = {
79 'symbols': symbols
80 }
81 pendingCode = []
82
83 @ffi.def_extern()
84 def mPythonSetDebugger(debugger):
85 from mgba.debugger import NativeDebugger, CLIDebugger
86 oldDebugger = globalSyms.get('debugger')
87 if oldDebugger and oldDebugger._native == debugger:
88 return
89 if oldDebugger and not debugger:
90 del globalSyms['debugger']
91 return
92 if debugger.type == lib.DEBUGGER_CLI:
93 debugger = CLIDebugger(debugger)
94 else:
95 debugger = NativeDebugger(debugger)
96 globalSyms['debugger'] = debugger
97
98 @ffi.def_extern()
99 def mPythonLoadScript(name, vf):
100 from mgba.vfs import VFile
101 vf = VFile(vf)
102 name = ffi.string(name)
103 source = vf.readAll().decode('utf-8')
104 try:
105 code = compile(source, name, 'exec')
106 pendingCode.append(code)
107 except:
108 return False
109 return True
110
111 @ffi.def_extern()
112 def mPythonRunPending():
113 global pendingCode
114 for code in pendingCode:
115 exec(code, globalSyms, {})
116 pendingCode = []
117
118 @ffi.def_extern()
119 def mPythonDebuggerEntered(reason, info):
120 debugger = globalSyms['debugger']
121 if not debugger:
122 return
123 if info == ffi.NULL:
124 info = None
125 for cb in debugger._cbs:
126 cb(reason, info)
127
128 @ffi.def_extern()
129 def mPythonLookupSymbol(name, outptr):
130 name = ffi.string(name).decode('utf-8')
131 if name not in symbols:
132 return False
133 sym = symbols[name]
134 val = None
135 try:
136 val = int(sym)
137 except:
138 try:
139 val = sym()
140 except:
141 pass
142 if val is None:
143 return False
144 try:
145 outptr[0] = ffi.cast('int32_t', val)
146 return True
147 except:
148 return False
149""")
150
151if __name__ == "__main__":
152 ffi.emit_c_code("lib.c")