all repos — mgba @ bcad1494541fd163edde5fd588f5399fdb43e0d3

mGBA Game Boy Advance Emulator

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