[PATCH v4 32/33] scripts: Add a script to run the wasm-compiled QEMU on node.js

Kohei Tokunaga posted 33 patches 1 week, 6 days ago
Maintainers: "Alex Bennée" <alex.bennee@linaro.org>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Thomas Huth <thuth@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, WANG Xuerui <git@xen0n.name>, Aurelien Jarno <aurelien@aurel32.net>, Huacai Chen <chenhuacai@kernel.org>, Jiaxun Yang <jiaxun.yang@flygoat.com>, Aleksandar Rikalo <arikalo@gmail.com>, Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <Alistair.Francis@wdc.com>, Stefan Weil <sw@weilnetz.de>, Kohei Tokunaga <ktokunaga.mail@gmail.com>
[PATCH v4 32/33] scripts: Add a script to run the wasm-compiled QEMU on node.js
Posted by Kohei Tokunaga 1 week, 6 days ago
run-emscripten.mjs is a Node.js script to quickly test the Wasm-compiled
QEMU. This runs directly from the terminal using the node command so the
HTTP server or the browser isn't needed.

Node.js 24 or newer is needed to run wasm64 binaries. Also note that QEMU's
"quit" monitor command doesn't work as of now because of the Emscripten's
atexit issue [1]. Send SIGINT or SIGTERM to the node process to exit QEMU.

[1] https://github.com/emscripten-core/emscripten/issues/26040

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
 scripts/run-emscripten.mjs | 66 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 scripts/run-emscripten.mjs

diff --git a/scripts/run-emscripten.mjs b/scripts/run-emscripten.mjs
new file mode 100644
index 0000000000..330e31cfe3
--- /dev/null
+++ b/scripts/run-emscripten.mjs
@@ -0,0 +1,66 @@
+#!/usr/bin/env node
+
+import path from 'node:path';
+import { parseArgs } from "node:util";
+
+function help() {
+  console.log(`Usage: run-emscripten.mjs [--preload FILE] [script.js] -- [arguments]
+
+Options:
+  --preload FILE: Load the package created by Emscripten's file_packager.py`);
+}
+
+const { values, positionals } = parseArgs({
+  allowPositionals: true,
+  options: {
+    'preload': { type: 'string' },
+    'help': { type: 'boolean' },
+  },
+})
+if (values.help) {
+  help();
+  process.exit(0);
+}
+const preload = values.preload;
+const moduleFile = positionals[0];
+const moduleArgs = positionals.slice(1);
+if ((!moduleFile) || (!moduleFile.match(/.*\.m?js$/))) {
+  console.error("module JS file must be specified as the first argument");
+  help();
+  process.exit(1);
+}
+
+const targetModule = await import(path.resolve(moduleFile));
+let preloadModule;
+if (preload) preloadModule = await import(path.resolve(preload));
+
+var Module = {
+  preRun: [],
+  arguments: moduleArgs,
+  mainScriptUrlOrBlob: path.resolve(moduleFile),
+};
+Module["preRun"].push((Module) => {
+  const decoder = new TextDecoder('utf-8');
+  Module.TTY.default_tty_ops.put_char = (tty, val) => {
+    process.stdout.write(decoder.decode(new Uint8Array([val])));
+  }
+  Module.TTY.default_tty1_ops.put_char = (tty, val) => {
+    process.stderr.write(decoder.decode(new Uint8Array([val])));
+  }
+});
+if (preloadModule) preloadModule.default(Module);
+
+if (process.stdin.isTTY) {
+  process.stdin.setRawMode(true);
+}
+function restoreTTY() {
+  if (process.stdin.isTTY) {
+    process.stdin.setRawMode(false);
+  }
+  process.exit(0);
+}
+process.on('exit', restoreTTY);
+process.on('SIGINT', restoreTTY);
+process.on('SIGTERM', restoreTTY);
+
+await targetModule.default(Module);
-- 
2.43.0
Re: [PATCH v4 32/33] scripts: Add a script to run the wasm-compiled QEMU on node.js
Posted by Pierrick Bouvier 1 week, 6 days ago
Hi Kohei,

On 1/25/26 11:03 PM, Kohei Tokunaga wrote:
> run-emscripten.mjs is a Node.js script to quickly test the Wasm-compiled
> QEMU. This runs directly from the terminal using the node command so the
> HTTP server or the browser isn't needed.
> 
> Node.js 24 or newer is needed to run wasm64 binaries. Also note that QEMU's
> "quit" monitor command doesn't work as of now because of the Emscripten's
> atexit issue [1]. Send SIGINT or SIGTERM to the node process to exit QEMU.
> 
> [1] https://github.com/emscripten-core/emscripten/issues/26040
> 
> Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
> ---
>   scripts/run-emscripten.mjs | 66 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 66 insertions(+)
>   create mode 100644 scripts/run-emscripten.mjs
> 

I followed the instructions but could not get this running:

$ /usr/share/emscripten/tools/file_packager.py qemu-system-aarch64.data 
--preload pack/ > load.js
$ ~/node-v24.13.0-linux-x64/bin/node ./scripts/run-emscripten.mjs 
--preload ./load.js ./qemu-system-aarch64.js -- -nographic -m 512M -L pack
file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51
if (preloadModule) preloadModule.default(Module);
                                         ^
TypeError: preloadModule.default is not a function
     at file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51:41
Node.js v24.13.0

I don't mind having a nodejs, or python script with browser. The point 
about using emrun was that it was easy to get something running, without 
fiddling with those kind of details.

If you offer a python script that automate the creation of details and 
spawn a server, it would be acceptable also.

Regards,
Pierrick
Re: [PATCH v4 32/33] scripts: Add a script to run the wasm-compiled QEMU on node.js
Posted by Kohei Tokunaga 1 week, 6 days ago
Hi Pierrick,

> I followed the instructions but could not get this running:
>
> $ /usr/share/emscripten/tools/file_packager.py qemu-system-aarch64.data
> --preload pack/ > load.js
> $ ~/node-v24.13.0-linux-x64/bin/node ./scripts/run-emscripten.mjs
> --preload ./load.js ./qemu-system-aarch64.js -- -nographic -m 512M -L pack
> file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51
> if (preloadModule) preloadModule.default(Module);
>                                          ^
> TypeError: preloadModule.default is not a function
>      at file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51:41
> Node.js v24.13.0

Thank you for trying the script.

That script requires the --export-es6 flag to file_packager.py. This flag
was introduced in Emscripten 4.0.13 so please update the Emscripten tools if
it is not available. If you're using emsdk, it provides the way to intall
newer tools, such as "emsdk update" and "emsdk install 4.0.23" [1].

[1] https://emscripten.org/docs/tools_reference/emsdk.html#how-to-guides

Regards,
Kohei Tokunaga
Re: [PATCH v4 32/33] scripts: Add a script to run the wasm-compiled QEMU on node.js
Posted by Pierrick Bouvier 1 week, 5 days ago
On 1/26/26 6:36 PM, Kohei Tokunaga wrote:
> Hi Pierrick,
> 
>  > I followed the instructions but could not get this running:
>  >
>  > $ /usr/share/emscripten/tools/file_packager.py qemu-system-aarch64.data
>  > --preload pack/ > load.js
>  > $ ~/node-v24.13.0-linux-x64/bin/node ./scripts/run-emscripten.mjs
>  > --preload ./load.js ./qemu-system-aarch64.js -- -nographic -m 512M -L 
> pack
>  > file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51
>  > if (preloadModule) preloadModule.default(Module);
>  >                                          ^
>  > TypeError: preloadModule.default is not a function
>  >      at file:///home/user/.work/qemu/scripts/run-emscripten.mjs:51:41
>  > Node.js v24.13.0
> 
> Thank you for trying the script.
> 
> That script requires the --export-es6 flag to file_packager.py. This flag
> was introduced in Emscripten 4.0.13 so please update the Emscripten tools if
> it is not available. If you're using emsdk, it provides the way to intall
> newer tools, such as "emsdk update" and "emsdk install 4.0.23" [1].
> 
> [1] https://emscripten.org/docs/tools_reference/emsdk.html#how-to-guides 
> <https://emscripten.org/docs/tools_reference/emsdk.html#how-to-guides>
> 
> Regards,
> Kohei Tokunaga
> 

Thanks, this was missing indeed.