使用 Emscripten 读写字符串到虚拟文件系统
Posted
技术标签:
【中文标题】使用 Emscripten 读写字符串到虚拟文件系统【英文标题】:Read and write string to virtual file system using Emscripten 【发布时间】:2021-11-15 19:11:57 【问题描述】:我有一个 C++ 程序,它接受两个文件作为输入并生成一个文件作为输出。这些文件包含字符串。我使用带有以下标志的 Emscripten 成功将此程序编译为 webassembly:
emcc program.bc -o program.js -s USE_ZLIB=1 -s EXPORTED_RUNTIME_METHODS="['FS', 'callMain']" -s ALLOW_MEMORY_GROWTH=1 -s ENVIRONMENT='web, worker'
然后我使用以下粘合代码将字符串(作为参数传递)写入 Emscripten 虚拟文件系统中的文件。这些文件然后用于运行program
的主要功能。然后从文件系统中读取输出文件并将其内容记录到控制台:
const Module = require('./program.js')
async function main(input1, input2)
Module.FS.writeFile('first_input.txt', input1)
Module.FS.writeFile('second_input.txt', input2)
Module.callMain(['-r', 'first_input.txt', '-q', 'second_input.txt', '-o', 'test.out', '-t', '1'])
const output = Module.FS.readFile('test.out', encoding: 'utf8' )
console.log(output)
module.exports = main
当尝试调用上面的主函数时,我得到了错误:
Unhandled Rejection (TypeError): Cannot read properties of undefined (reading 'writeFile')
当我console.log(Module.FS)
时,确实是未定义。此外,console.log(Module)
返回一个空对象。在
program.js
内部,似乎确实通过Module["FS"] = FS
启用了FS 模块。当我为节点环境编译它(使用-s ENVIRONMENT='node'
)时,它可以顺利运行。
为什么工作环境会失败,我可以做些什么来修复它?
编辑:我尝试将代码包装在 `onRuntimeInitialized' 函数中,但我得到了同样的错误:
const Module = require('./program.js')
async function main(input1, input2)
Module.onRuntimeInitialized = () =>
Module.FS.writeFile('first_input.txt', input1)
Module.FS.writeFile('second_input.txt', input2)
Module.callMain(['-r', 'first_input.txt', '-q', 'second_input.txt', '-o', 'test.out', '-t', '1'])
const output = Module.FS.readFile('test.out', encoding: 'utf8' )
console.log(output)
await Module.onRuntimeInitialized()
module.exports = main
EDIT2:上面的 main 函数实际上是在一个 worker 上运行,而不是在 html 文档中的 script 标签内。我无法直接编辑 HTML 文档,这就是我 require
Emscripten 输出 javascript 文件的原因。
【问题讨论】:
浏览器和节点的行为方式不同。你得到未定义的模块,因为它没有完全初始化。您应该将代码包装在 onRuntimeInitialized 中,如本常见问题文章 emscripten.org/docs/getting_started/… 中所述 你还应该为读取文件提供一个ajax(Promise)函数。例如阅读以下代码:github.com/kalwalt/Emscripten-JpegReader/blob/… @kalwalt 您能否详细说明包装代码(最好作为答案)?我检查了链接的文档,但对于如何修改我的代码仍然有些困惑。我尝试将代码包装在上述主函数中(见编辑),但它给了我同样的错误。 不,您的代码不正确。它应该首先被调用。我会尽可能发布详细的答案。我现在没时间,抱歉! @kalwalt 需要注意的一点是,我无法直接编辑 html,因此无法添加 【参考方案1】:解决办法是:
-
使用
MODULARIZE=1
标志编译程序
emcc program.bc -o program.js -s USE_ZLIB=1 -s EXPORTED_RUNTIME_METHODS="['FS', 'callMain']" -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME='createModule'
-
导入模块,然后等待生成的承诺
import createModule from './program.js'
async function main(input1, input2)
const Module = await createModule()
Module.FS.writeFile('first_input.txt', input1)
Module.FS.writeFile('second_input.txt', input2)
Module.callMain(['-r', 'first_input.txt', '-q', 'second_input.txt', '-o', 'test.out', '-t', '1'])
const output = Module.FS.readFile('test.out', encoding: 'utf8' )
console.log(output)
export default main
【讨论】:
很高兴你解决了,也许是最简单的一个。以上是关于使用 Emscripten 读写字符串到虚拟文件系统的主要内容,如果未能解决你的问题,请参考以下文章
如何使用库导入编译 C 文件到 webassembly 文件(Emscripten)
如何使用 emscripten 将文件从 C 保存到浏览器存储
使用 emscripten 将字符串从 C++ 传递给 JS