You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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的隔离上下文里,默认没有暴露完整的宿主环境接口,因此需要:

  1. 编译时指定兼容环境,并配置输出重定向到自定义JS函数
  2. 在隔离上下文中注入自定义函数,将输出捕获到变量

步骤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));

问题原因说明

  1. 使用ENVIRONMENT=node编译时,Emscripten会依赖Node.js的process对象,但isolated-vm的隔离上下文默认未暴露process,因此触发环境不匹配错误。
  2. 使用ENVIRONMENT=shell时,默认输出指向shell终端,但隔离上下文未连接宿主终端,因此无法直接看到输出,必须通过自定义函数重定向捕获。

内容的提问来源于stack exchange,提问作者Rodrigo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:23:34