From c1d8ec7ed4f9c538b9cd28271628fb9b7d1ec394 Mon Sep 17 00:00:00 2001 From: mohanson Date: Thu, 25 Sep 2025 11:38:47 +0800 Subject: [PATCH] Add a main entry for package --- .github/workflows/develop.yml | 1 + README.md | 1 + pywasm/__main__.py | 61 ++++++++++++++++++++++++++++++++ pywasm/core.py | 7 +++- script/wasi.py | 32 ----------------- script/wasi_testsuite_adapter.py | 30 ---------------- test/main.py | 10 ++++++ 7 files changed, 79 insertions(+), 63 deletions(-) create mode 100644 pywasm/__main__.py delete mode 100644 script/wasi.py delete mode 100644 script/wasi_testsuite_adapter.py create mode 100644 test/main.py diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 80bc24b..7d8d3b3 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -25,5 +25,6 @@ jobs: python script/build_spec.py python script/build_wasi.py python test/example.py + python test/main.py python test/spec.py python test/wasi.py diff --git a/README.md b/README.md index 908327f..4d32e13 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ $ python script/build_spec.py # Download spec tests at res/spec. $ python script/build_wasi.py # Download wasi tests at res/wasi-testsuite. $ python test/example.py # Test example. +$ python test/main.py # Test main. $ python test/spec.py # Test spec. $ python test/wasi.py # Test wasi. ``` diff --git a/pywasm/__main__.py b/pywasm/__main__.py new file mode 100644 index 0000000..6e66c31 --- /dev/null +++ b/pywasm/__main__.py @@ -0,0 +1,61 @@ +import argparse +import sys + +import pywasm + +parser = argparse.ArgumentParser() +parser.add_argument('--version', '-v', action='version', version=f'pywasm {pywasm.version}') +parser.add_argument('--func', default='_start', help='set func name') +parser.add_argument('--func-args', action='append', default=[], help='set func args, like arg') +parser.add_argument('--wasi-envs', action='append', default=[], help='set wasi envs, like key=val') +parser.add_argument('--wasi-dirs', action='append', default=[], help='set wasi dirs, like dir:dir(host)') +parser.add_argument('--wasi-args', action='append', default=[], help='set wasi args, like arg') +parser.add_argument('--wasi', choices=['preview1'], help='set wasi version') +parser.add_argument('file', help='wasm file') +args = parser.parse_args() + + +def main_wasi(): + wasi_args = [args.file] + args.wasi_args + wasi_dirs = {} + wasi_envs = {} + for e in args.wasi_dirs: + spes = e.split(':', 1) + wasi_dirs[spes[0]] = spes[1] + for e in args.wasi_envs: + spes = e.split('=', 1) + wasi_envs[spes[0]] = spes[1] + if args.wasi == 'preview1': + runtime = pywasm.core.Runtime() + wasi = pywasm.wasi.Preview1(wasi_args, wasi_dirs, wasi_envs) + wasi.bind(runtime) + inst = runtime.instance_from_file(args.file) + code = wasi.main(runtime, inst) + sys.exit(code) + + +def main_wasm(): + runtime = pywasm.core.Runtime() + inst = runtime.instance_from_file(args.file) + addr = [e for e in inst.exps if e.name == args.func][0].data.data + func = runtime.machine.store.func[addr] + assert len(func.type.args) == len(args.func_args) + func_args = [] + for e in zip(func.type.args, args.func_args): + if e[0] in [pywasm.ValType.i32(), pywasm.ValType.i64()]: + func_args.append(int(e[1])) + continue + if e[0] in [pywasm.ValType.f32(), pywasm.ValType.f64()]: + func_args.append(float(e[1])) + continue + if e[0] == pywasm.ValType.v128(): + func_args.append(bytearray.fromhex(e[1][2:])) + continue + assert 0 + rets = runtime.invocate(inst, args.func, func_args) + print(rets) + + +if args.wasi: + main_wasi() +main_wasm() diff --git a/pywasm/core.py b/pywasm/core.py index 4241b4e..ddb7bdd 100644 --- a/pywasm/core.py +++ b/pywasm/core.py @@ -4161,7 +4161,12 @@ def instance_from_file(self, path: str) -> ModuleInst: with open(path, 'rb') as f: return self.instance(ModuleDesc.from_reader(f)) - def invocate(self, module: ModuleInst, func: str, args: typing.List[int | float]) -> typing.List[int | float]: + def invocate( + self, + module: ModuleInst, + func: str, + args: typing.List[int | float | bytearray] + ) -> typing.List[int | float | bytearray]: # Once a module has been instantiated, any exported function can be invoked externally via its function address # in the store and an appropriate list of argument values. addr = [e for e in module.exps if e.name == func][0].data.data diff --git a/script/wasi.py b/script/wasi.py deleted file mode 100644 index 55079ba..0000000 --- a/script/wasi.py +++ /dev/null @@ -1,32 +0,0 @@ -import argparse -import sys - -import pywasm - -parser = argparse.ArgumentParser() -parser.add_argument('--version', '-v', action='version', version=f'pywasm {pywasm.version}') -parser.add_argument('--preview1', action='store_true', default=True, help='use wasi preview1') -parser.add_argument('file', help='wasm file to run') -parser.add_argument('args', nargs='*', help='arg ... dir(wasm):dir(host) ... env=val ...') -args = parser.parse_args() - -wasi_args = [args.file] -wasi_dirs = {} -wasi_envs = {} -for e in args.args: - if '=' in e: - spes = e.split('=', 1) - wasi_envs[spes[0]] = spes[1] - continue - if ':' in e: - spes = e.split(':', 1) - wasi_dirs[spes[0]] = spes[1] - continue - wasi_args.append(e) - -if args.preview1: - runtime = pywasm.core.Runtime() - wasi = pywasm.wasi.Preview1(wasi_args, wasi_dirs, wasi_envs) - wasi.bind(runtime) - exit = wasi.main(runtime, runtime.instance_from_file(args.file)) - sys.exit(exit) diff --git a/script/wasi_testsuite_adapter.py b/script/wasi_testsuite_adapter.py deleted file mode 100644 index c1b973a..0000000 --- a/script/wasi_testsuite_adapter.py +++ /dev/null @@ -1,30 +0,0 @@ -import argparse -import os -import sys - -import pywasm - -# Implemented the adapter here https://github.com/WebAssembly/wasi-testsuite/tree/main/adapters - -parser = argparse.ArgumentParser() -parser.add_argument("--version", action="store_true") -parser.add_argument("--test-file", action="store") -parser.add_argument("--arg", action="append", default=[]) -parser.add_argument("--env", action="append", default=[]) -parser.add_argument("--dir", action="append", default=[]) - -args = parser.parse_args() - -if args.version: - print('pywasm', pywasm.version) - sys.exit(0) - -runtime = pywasm.core.Runtime() -wasi = pywasm.wasi.Preview1( - [os.path.basename(args.test_file)] + args.arg, - {e: e for e in args.dir}, - dict([e.split('=') for e in args.env]), -) -wasi.bind(runtime) -exit = wasi.main(runtime, runtime.instance_from_file(args.test_file)) -sys.exit(exit) diff --git a/test/main.py b/test/main.py new file mode 100644 index 0000000..1a8cacb --- /dev/null +++ b/test/main.py @@ -0,0 +1,10 @@ +import subprocess + + +def call(cmd: str) -> subprocess.CompletedProcess[bytes]: + print(f'$ {cmd}') + return subprocess.run(cmd, shell=True, check=True) + + +call('python -m pywasm --func pi --func-args 7 example/pi/bin/pi.wasm') +call('python -m pywasm --wasi preview1 --wasi-dirs pywasm:pywasm example/wasi_ll/bin/wasi_ll.wasm')