为 emscripten HTML 程序提供标准输入?
Posted
技术标签:
【中文标题】为 emscripten HTML 程序提供标准输入?【英文标题】:Providing stdin to an emscripten HTML program? 【发布时间】:2015-10-02 16:55:05 【问题描述】:我有一个 C 程序,它通过命令行获取一个参数(一个字符数组/字符串),并且还从标准输入中读取。我已经使用 emscripten 将其编译为 javascript。这很成功,我可以像使用 node.js 的普通 C 程序一样运行它:
emcc -O2 translate.c
node translate.js "foo" < bar.txt
如您所见,我将字符串“foo”作为参数提供,并将 bar.txt 的内容作为标准输入。现在我希望这是一个独立的 html 文件。
通过将输出更改为 HTML:
emcc -O2 translate.c -o trans.html
我将adding arguments: ['foo'],
的参数提供给var Module
中的定义。这按预期工作,程序正确接收参数。
现在,我如何为这个程序提供标准输入输入?我不需要动态地执行此操作。只需在 HTML 中的某处声明一个带有所需标准输入内容的字符串就可以了。
【问题讨论】:
对 emscripten 不太熟悉,但看起来--embed-file
可能符合要求。
@nrabinowitz 刚刚找到了解决方案。谢谢!
@minxomat 您应该将解决方案添加为答案(并将其视为正确),而不是作为问题的编辑
@AlvaroMontoro 我确信这实际上不是“正确”的解决方案。总的来说,我对 JS 或 emscripten 不够精通,无法判断这种方法的质量。
@mınxomaτ 更有理由将其添加为答案,因此其他人可以与所有其他答案一起对其进行投票...我将删除它,但欢迎您如果需要,请重新发布它作为答案。
【参考方案1】:
一种方法是使用 Emscripten 文件系统 API,例如在 Module preRun 函数中调用 FS.init,传递自定义函数以用于标准输入、输出和错误。
var Module =
preRun: function()
function stdin()
// Return ASCII code of character, or null if no input
function stdout(asciiCode)
// Do something with the asciiCode
function stderr(asciiCode)
// Do something with the asciiCode
FS.init(stdin, stdout, stderr);
;
这些函数是相当低级的:它们每次处理一个字符作为 ASCII 码。如果您有要传入的字符串,则必须自己迭代字符串的字符。我怀疑charCodeAt 会有所帮助。要从 stdout 或 stderr 输出字符串,我怀疑 fromCharCode 会有所帮助。
使用每个示例(没有经过很好的测试!)实现如下。
var input = "This is from the standard input\n";
var i = 0;
var Module =
preRun: function()
function stdin()
if (i < res.length)
var code = input.charCodeAt(i);
++i;
return code;
else
return null;
var stdoutBuffer = "";
function stdout(code)
if (code === "\n".charCodeAt(0) && stdoutBuffer !== "")
console.log(stdoutBuffer);
stdoutBuffer = "";
else
stdoutBuffer += String.fromCharCode(code);
var stderrBuffer = "";
function stderr(code)
if (code === "\n".charCodeAt(0) && stderrBuffer !== "")
console.log(stderrBuffer);
stderrBuffer = "";
else
stderrBuffer += String.fromCharCode(code);
FS.init(stdin, stdout, stderr);
;
【讨论】:
太棒了!我无法摆脱ReferenceError: FS is not defined
- github.com/kripken/emscripten/issues/… 任何想法?
我确认这适用于 emscripten 本身提供的 test_stdin.c 程序。谢谢!【参考方案2】:
你可以修改 Window 对象,而不是编辑 Emscripten 的输出
window.prompt = function()
return 'This will appear to come from standard input';
;
不太好,但我认为这与其说是编辑 Emscripten 生成的 Javascript 不如说是一种 hack。
【讨论】:
抱歉,没有理由阻止这个默认功能。与此相比,编辑输入处理程序是更安全、更简单的方法。这样我就可以使用stdInput = read('input');
来传递整个输入。查看here(第 86 行+)我如何调用 emscripten 脚本。 :)
@minxonat 我认为这是有原因的:让构建不那么容易受到 Emscripten 生成的输出变化的影响。我怀疑大多数项目不使用 window.prompt,但确实需要处理对其依赖项的更新。这是一个权衡:您失去了按设计使用 window.prompt 的能力,但获得了代码,因为更新 Emscripten / 其配置可能会破坏其输出的自动修补,因此更有可能表现得更好。注意:“有更好的机会”是基于我自己的判断,即修补生成的代码很脆弱:我无法提供任何证据来支持这一点。
我确实相信从标准 JS API 修补函数会更加脆弱。
您的脚本可以将window.prompt
保存在另一个变量中,然后调用它作为您的提示,并让原始的工作用于 wasm 而无需修改它。我同意 Michal 的观点,monkeypatching 比修改 wasm.js 更好,但是可以实现 window.readline
或自定义函数,然后在 wasm.js 中删除或重新排序 wasm 的 prompt
条件分支。如果readline
首先在get_char
中进行了测试,那么很容易推荐。【参考方案3】:
根据问题“编辑”,我做了我的功能,谢谢。
只是希望下面的代码可以帮助别人。
注释运行();在 emscript 结尾
// in my emscript
// shouldRunNow refers to calling main(), not run().
var shouldRunNow = true;
if (Module['noInitialRun'])
shouldRunNow = false;
//run(); // << here
// POST_RUN_ADDITIONS
result = areaInput();
// 如题所述
在您的 html 文件中添加以下代码以激活 emscript 中的 run()
<script>
var message;
var point = -1;
function getArea()
message = document.getElementById('input').value.split('\n');
function areaInput()
if(point >= message.length - 1)
return null;
point += 1;
return message[point];
function execEmscript()
window.console =
log: function(str)
document.getElementById("output").value += "\n" + str;
getArea();
run();
</script>
记住 html 中的 io textareas
<textarea id="input" cols="80" rows="30"></textarea>
<textarea id="output" cols="80" rows="30"></textarea>
还有一个按钮
<button onclick="execEmscript();">run</button>
【讨论】:
以上是关于为 emscripten HTML 程序提供标准输入?的主要内容,如果未能解决你的问题,请参考以下文章
Emscripten:提供下载/保存生成的 MEMFS 文件