|
| 1 | +import os |
| 2 | +import sys |
| 3 | +import wasmtime |
| 4 | +import pathlib |
| 5 | +import hashlib |
| 6 | +import appdirs |
| 7 | +try: |
| 8 | + from importlib import resources as importlib_resources |
| 9 | + try: |
| 10 | + importlib_resources.files # py3.9+ stdlib |
| 11 | + except AttributeError: |
| 12 | + import importlib_resources # py3.8- shim |
| 13 | +except ImportError: |
| 14 | + import importlib_resources # py3.6- shim |
| 15 | + |
| 16 | + |
| 17 | +def _run_wasm_app(wasm_filename, argv): |
| 18 | + module_binary = importlib_resources.read_binary(__package__, wasm_filename) |
| 19 | + module_digest = hashlib.sha1(module_binary).digest() |
| 20 | + |
| 21 | + wasi_cfg = wasmtime.WasiConfig() |
| 22 | + wasi_cfg.argv = argv |
| 23 | + wasi_cfg.preopen_dir(str(importlib_resources.files(__package__) / "share"), "/share") |
| 24 | + wasi_cfg.preopen_dir("/", "/") |
| 25 | + wasi_cfg.preopen_dir(".", ".") |
| 26 | + wasi_cfg.inherit_stdin() |
| 27 | + wasi_cfg.inherit_stdout() |
| 28 | + wasi_cfg.inherit_stderr() |
| 29 | + |
| 30 | + engine = wasmtime.Engine() |
| 31 | + cache_path = pathlib.Path(os.getenv("YOWASP_CACHE_DIR", appdirs.user_cache_dir("yowasp"))) |
| 32 | + cache_path.mkdir(parents=True, exist_ok=True) |
| 33 | + cache_filename = (cache_path / "{}-cache".format(wasm_filename)) |
| 34 | + digest_filename = (cache_path / "{}-digest".format(wasm_filename)) |
| 35 | + try: |
| 36 | + with digest_filename.open("rb") as digest_file: |
| 37 | + if digest_file.read() != module_digest: |
| 38 | + raise Exception("cache miss") |
| 39 | + with cache_filename.open("rb") as cache_file: |
| 40 | + module = wasmtime.Module.deserialize(engine, cache_file.read()) |
| 41 | + except: |
| 42 | + print("Preparing to run {}. This might take a while...".format(argv[0]), file=sys.stderr) |
| 43 | + module = wasmtime.Module(engine, module_binary) |
| 44 | + with cache_filename.open("wb") as cache_file: |
| 45 | + cache_file.write(module.serialize()) |
| 46 | + with digest_filename.open("wb") as digest_file: |
| 47 | + digest_file.write(module_digest) |
| 48 | + |
| 49 | + store = wasmtime.Store(engine) |
| 50 | + linker = wasmtime.Linker(store) |
| 51 | + wasi = linker.define_wasi(wasmtime.WasiInstance(store, |
| 52 | + "wasi_snapshot_preview1", wasi_cfg)) |
| 53 | + app = linker.instantiate(module) |
| 54 | + try: |
| 55 | + app.exports["_start"]() |
| 56 | + return 0 |
| 57 | + except wasmtime.ExitTrap as trap: |
| 58 | + return trap.code |
| 59 | + |
| 60 | + |
| 61 | +def run_prjoxide(argv): |
| 62 | + return _run_wasm_app("prjoxide.wasm", ["yowasp-prjoxide", *argv]) |
| 63 | + |
| 64 | + |
| 65 | +def _run_prjoxide_argv(): |
| 66 | + sys.exit(run_prjoxide(sys.argv[1:])) |
| 67 | + |
| 68 | + |
| 69 | +def run_nextpnr_nexus(argv): |
| 70 | + return _run_wasm_app("nextpnr-nexus.wasm", ["yowasp-nextpnr-nexus", *argv]) |
| 71 | + |
| 72 | + |
| 73 | +def _run_nextpnr_nexus_argv(): |
| 74 | + sys.exit(run_nextpnr_nexus(sys.argv[1:])) |
0 commit comments