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/gba/gba.h>
32#include <mgba/internal/gba/input.h>
33#include <mgba/internal/gba/renderers/tile-cache.h>
34#include <mgba/internal/lr35902/lr35902.h>
35#include <mgba/internal/gb/gb.h>
36#include <mgba/internal/gb/renderers/tile-cache.h>
37#include <mgba-util/png-io.h>
38#include <mgba-util/vfs.h>
39
40#define PYEXPORT
41#include "platform/python/core.h"
42#include "platform/python/log.h"
43#include "platform/python/sio.h"
44#include "platform/python/vfs-py.h"
45#undef PYEXPORT
46""", include_dirs=[incdir, srcdir],
47 extra_compile_args=cppflags,
48 libraries=["mgba"],
49 library_dirs=[bindir],
50 sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "core.c", "log.c", "sio.c"]])
51
52preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)
53
54lines = []
55for line in preprocessed.splitlines():
56 line = line.strip()
57 if line.startswith('#'):
58 continue
59 lines.append(line)
60ffi.cdef('\n'.join(lines))
61
62preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "lib.h")], universal_newlines=True)
63
64lines = []
65for line in preprocessed.splitlines():
66 line = line.strip()
67 if line.startswith('#'):
68 continue
69 lines.append(line)
70ffi.embedding_api('\n'.join(lines))
71
72ffi.embedding_init_code("""
73 from mgba._pylib import ffi
74 debugger = None
75 pendingCode = []
76
77 @ffi.def_extern()
78 def mPythonSetDebugger(_debugger):
79 from mgba.debugger import NativeDebugger
80 global debugger
81 if debugger and debugger._native == _debugger:
82 return
83 debugger = _debugger and NativeDebugger(_debugger)
84
85 @ffi.def_extern()
86 def mPythonLoadScript(name, vf):
87 from mgba.vfs import VFile
88 vf = VFile(vf)
89 name = ffi.string(name)
90 source = vf.readAll().decode('utf-8')
91 try:
92 code = compile(source, name, 'exec')
93 pendingCode.append(code)
94 except:
95 return False
96 return True
97
98 @ffi.def_extern()
99 def mPythonRunPending():
100 global pendingCode
101 for code in pendingCode:
102 exec(code)
103 pendingCode = []
104
105 @ffi.def_extern()
106 def mPythonDebuggerEntered(reason, info):
107 global debugger
108 if not debugger:
109 return
110 if info == ffi.NULL:
111 info = None
112 for cb in debugger._cbs:
113 cb(reason, info)
114""")
115
116if __name__ == "__main__":
117 ffi.emit_c_code("lib.c")