all repos — mgba @ b6db8581dfc625e527b2c7041193e996497a5ff7

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", ""))
 16if __name__ == "__main__":
 17    cppflags.extend(sys.argv[1:])
 18cppflags.extend(["-I" + incdir, "-I" + srcdir, "-I" + bindir])
 19
 20ffi.set_source("mgba._pylib", """
 21#define static
 22#define inline
 23#include "flags.h"
 24#define OPAQUE_THREADING
 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/ds/ds.h>
 38#include <mgba/internal/ds/input.h>
 39#include <mgba/internal/gba/gba.h>
 40#include <mgba/internal/gba/input.h>
 41#include <mgba/internal/gba/renderers/cache-set.h>
 42#include <mgba/internal/lr35902/lr35902.h>
 43#include <mgba/internal/gb/gb.h>
 44#include <mgba/internal/gb/renderers/cache-set.h>
 45#include <mgba-util/png-io.h>
 46#include <mgba-util/vfs.h>
 47
 48#define PYEXPORT
 49#include "platform/python/core.h"
 50#include "platform/python/log.h"
 51#include "platform/python/sio.h"
 52#include "platform/python/vfs-py.h"
 53#undef PYEXPORT
 54""", include_dirs=[incdir, srcdir],
 55     extra_compile_args=cppflags,
 56     libraries=["medusa-emu"],
 57     library_dirs=[bindir],
 58     runtime_library_dirs=[libdir],
 59     sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "core.c", "log.c", "sio.c"]])
 60
 61preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)
 62
 63lines = []
 64for line in preprocessed.splitlines():
 65    line = line.strip()
 66    if line.startswith('#'):
 67        continue
 68    lines.append(line)
 69ffi.cdef('\n'.join(lines))
 70
 71preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "lib.h")], universal_newlines=True)
 72
 73lines = []
 74for line in preprocessed.splitlines():
 75    line = line.strip()
 76    if line.startswith('#'):
 77        continue
 78    lines.append(line)
 79ffi.embedding_api('\n'.join(lines))
 80
 81ffi.embedding_init_code("""
 82    import os, os.path
 83    venv = os.getenv('VIRTUAL_ENV')
 84    if venv:
 85        activate = os.path.join(venv, 'bin', 'activate_this.py')
 86        exec(compile(open(activate, "rb").read(), activate, 'exec'), dict(__file__=activate))
 87    from mgba._pylib import ffi, lib
 88    symbols = {}
 89    globalSyms = {
 90        'symbols': symbols
 91    }
 92    pendingCode = []
 93
 94    @ffi.def_extern()
 95    def mPythonSetDebugger(debugger):
 96        from mgba.debugger import NativeDebugger, CLIDebugger
 97        oldDebugger = globalSyms.get('debugger')
 98        if oldDebugger and oldDebugger._native == debugger:
 99            return
100        if oldDebugger and not debugger:
101            del globalSyms['debugger']
102            return
103        if debugger.type == lib.DEBUGGER_CLI:
104            debugger = CLIDebugger(debugger)
105        else:
106            debugger = NativeDebugger(debugger)
107        globalSyms['debugger'] = debugger
108
109    @ffi.def_extern()
110    def mPythonLoadScript(name, vf):
111        from mgba.vfs import VFile
112        vf = VFile(vf)
113        name = ffi.string(name)
114        source = vf.readAll().decode('utf-8')
115        try:
116            code = compile(source, name, 'exec')
117            pendingCode.append(code)
118        except:
119            return False
120        return True
121
122    @ffi.def_extern()
123    def mPythonRunPending():
124        global pendingCode
125        for code in pendingCode:
126            exec(code, globalSyms, {})
127        pendingCode = []
128
129    @ffi.def_extern()
130    def mPythonDebuggerEntered(reason, info):
131        debugger = globalSyms['debugger']
132        if not debugger:
133            return
134        if info == ffi.NULL:
135            info = None
136        for cb in debugger._cbs:
137            cb(reason, info)
138
139    @ffi.def_extern()
140    def mPythonLookupSymbol(name, outptr):
141        name = ffi.string(name).decode('utf-8')
142        if name not in symbols:
143            return False
144        sym = symbols[name]
145        val = None
146        try:
147            val = int(sym)
148        except:
149            try:
150                val = sym()
151            except:
152                pass
153        if val is None:
154            return False
155        try:
156            outptr[0] = ffi.cast('int32_t', val)
157            return True
158        except:
159            return False
160""")
161
162if __name__ == "__main__":
163    ffi.emit_c_code("lib.c")