我有一个C++项目,我已经使用emscripten将其转换为javascript。我需要帮助通过节点将文件输入实现到程序中。据我了解,emscripten 中的默认文件系统使用只能在网页或 Web worker 上完成的预加载数据。我需要我的在命令行上使用 node.js。
查看文档,我发现有一种方法可以使用NODEFS而不是默认的MEMFS,这应该允许我这样做。但是,我不确定我应该如何去做。我真的不明白提供的测试代码。
以下是在原始C++项目中完成文件处理的方式:
void InputFile(std::string &fileName)
{
std::ifstream in(fileName);
if (in.fail())
{
std::cerr << "ERROR, Could not open " << fileName << std::endl;
exit(1);
}
}
但是当我尝试使用文件运行转换后的程序时,node project.js -f test.file
收到错误消息:ERROR, Could not open test.file
意味着打开文件失败。最初的C++项目能够毫无问题地打开文件,所以我知道文件本身没有问题。
我不确定我必须做什么才能使转换后的项目与文件输入一起工作,任何帮助将不胜感激。
解释
WebAssembly 模块,使用 emscripten 构建,没有关于物理文件系统中文件的信息。相反,它使用虚拟文件系统。您所要做的就是在物理系统上的文件与模块虚拟系统上的文件之间创建一个链接。NODEFS给你这个机会。
快速解决方案
我们将通过使用嵌入式 JS 代码(带 EM_ASM(在物理和虚拟文件系统之间添加上述链接来开始修改您的C++代码。首先(1(,我们在虚拟文件系统上创建一个目录'/temp'
,所有引用的文件都将位于该目录中。然后(2(,我们将这个新的虚拟目录链接到一个真实的物理位置(当前工作目录'.'
(,所有引用的文件都已经存在。
#include <emscripten.h>
#include <emscripten/bind.h>
#include <iostream>
#include <fstream>
void InputFile(const std::string &fileName)
{
EM_ASM(
FS.mkdir('/temp'); // (1)
FS.mount(NODEFS, {root : '.'}, '/temp');); // (2)
std::ifstream in(std::string("/temp/") + fileName);
if (in.fail())
{
std::cerr << "ERROR, Could not open " << fileName << std::endl;
exit(1);
}
}
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("InputFile", &InputFile);
}
现在,因为在 WebAssembly 模块中,我们使用的是虚拟文件系统,而不是物理文件系统,因此当前目录(根目录'.'
(中的每个引用文件实际上都在先前链接的虚拟目录中('/temp'
(。因此,'/temp'
目录位于引用文件的名称之前:std::ifstream in(std::string("/temp/") + fileName);
。
最后,我们可以编译这个文件。我们强制同步编译(以确保require
按时加载 WASM 模块(。此外,选项-s EXIT_RUNTIME=1
确保C++命令exit(1);
完成执行。另外,我们需要链接Embind(--bind
(和NODEFS(-lnodefs.js
(:
emcc project.cpp -o project.js -s WASM_ASYNC_COMPILATION=0 -s EXIT_RUNTIME=1 --bind -lnodefs.js
测试
要使用与您提到的相同的调用约定来测试 WebAssembly 模块,我们可以使用以下test.js
脚本:
var Module = require('./project.js');
if (process.argv[3] && process.argv[2] === '-f') {
const filename = process.argv[3];
Module.InputFile(filename);
} else {
console.log('Pass the file with -f flag!');
}
要运行该文件,您所要做的就是:node test.js -f test.file
评论
如果引用的文件位于当前工作目录中,则此方法非常有效。如果不是,则可以修改InputFile
的代码以提取fileName
所在的目录,然后相应地挂载实实时到虚拟目录。