如何在isolated-vm中捕获Emscripten生成的WASM模块的stdout/stderr
问题描述
我有如下C++代码:
#include <iostream> int main() { std::cout << "Hello World!" << std::endl; return 0; }
使用以下命令编译:
emcc -s ENVIRONMENT=shell -s WASM=1 -s MODULARIZE=1 main.cpp -o main.js
该命令会生成main.js和main.wasm文件。
随后,我安装了isolated-vm:
npm install isolated-vm
并编写了如下JavaScript代码:
const fs = require("fs"); const ivm = require("isolated-vm"); const isolate = new ivm.Isolate({ memoryLimit: 128 }); const context = isolate.createContextSync(); const jail = context.global; jail.setSync("global", jail.derefInto()); const hostile = isolate.compileScriptSync(fs.readFileSync("main.js", "utf8")); hostile.run(context).catch((err) => console.error(err));
运行node index.js后,程序无报错但未输出stdout/stderr内容。
我的问题是:如何使用isolated-vm将WASM模块的stdout/stderr捕获到JavaScript变量中?我曾查找相关代码但均无效。
编辑补充
若使用以下编译命令:
emcc -s ENVIRONMENT=node -s WASM=1 main.cpp -o main.js && node main.js
终端会显示"Hello World!",但按照上述index.js的方式运行时,会出现错误:
错误:未针对当前环境编译(你是否构建了HTML版本却不在网页运行,或是将ENVIRONMENT设置为某个环境比如node,却在其他环境比如网页运行?)
解决方案
核心思路
Emscripten编译的WASM模块,其stdout/stderr默认依赖宿主环境的输出能力。在isolated-vm的隔离上下文里,默认没有暴露完整的宿主环境接口,因此需要:
- 编译时指定兼容环境,并配置输出重定向到自定义JS函数
- 在隔离上下文中注入自定义函数,将输出捕获到变量
步骤1:修改Emscripten编译命令
使用ENVIRONMENT=shell保证兼容性,同时添加输出重定向和必要的运行时配置:
emcc -s ENVIRONMENT=shell -s WASM=1 -s MODULARIZE=1 -s FORCE_FILESYSTEM=1 -s "EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" -s "STDOUT_FUNC='customStdout'" -s "STDERR_FUNC='customStderr'" main.cpp -o main.js
关键参数说明:
STDOUT_FUNC='customStdout':指定C++的std::cout会调用名为customStdout的JS函数STDERR_FUNC='customStderr':指定std::cerr对应调用customStderr函数FORCE_FILESYSTEM=1:确保shell环境下文件系统API可用EXPORTED_RUNTIME_METHODS:导出Emscripten运行时的必要方法,保证模块正常初始化
步骤2:修改isolated-vm的JavaScript代码
在隔离上下文中注入自定义输出函数,将WASM的输出捕获到变量:
const fs = require("fs"); const ivm = require("isolated-vm"); // 创建隔离环境 const isolate = new ivm.Isolate({ memoryLimit: 128 }); const context = isolate.createContextSync(); const jail = context.global; // 注入基础全局对象 jail.setSync("global", jail.derefInto()); // 用于捕获输出的变量 let capturedStdout = ''; let capturedStderr = ''; // 向隔离上下文注入自定义stdout处理函数 jail.setSync("customStdout", new ivm.Reference((text) => { capturedStdout += text; })); // 向隔离上下文注入自定义stderr处理函数 jail.setSync("customStderr", new ivm.Reference((text) => { capturedStderr += text; })); // 编译并运行WASM模块的JS包装代码 const wasmScript = isolate.compileScriptSync(fs.readFileSync("main.js", "utf8")); wasmScript.run(context).then(() => { // 运行完成后输出捕获的内容 console.log("捕获的stdout:", capturedStdout); console.log("捕获的stderr:", capturedStderr); }).catch((err) => console.error(err));
问题原因说明
- 使用
ENVIRONMENT=node编译时,Emscripten会依赖Node.js的process对象,但isolated-vm的隔离上下文默认未暴露process,因此触发环境不匹配错误。 - 使用
ENVIRONMENT=shell时,默认输出指向shell终端,但隔离上下文未连接宿主终端,因此无法直接看到输出,必须通过自定义函数重定向捕获。
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

