all repos — mgba @ 3f59175a8173214691f599feb6c959de90095b0c

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(), ".."))
 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")