如何使用 emscripten 通过 node.js 进行文件输入?

2024-03-24

我有一个 C++ 项目,我已使用 emscripten 将其转换为 javascript。我需要帮助通过节点实现文件输入到程序中。据我了解,emscripten 中的默认文件系统使用只能在网页或网络工作人员上完成的预加载数据。我需要我的在命令行上使用node.js。

看着文档 https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api-persist-data我发现有一种方法可以使用 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++ 项目能够打开该文件,没有任何问题,所以我知道文件本身没有问题。

我不确定我必须做什么才能使转换后的项目与文件输入一起工作,任何帮助将非常感激。


解释

网络组装 https://webassembly.org/模块,使用构建埃姆脚本 https://emscripten.org/,没有有关物理文件系统中文件的信息。相反,它使用虚拟文件系统。您所要做的就是在物理系统上的文件与模块虚拟系统上的文件之间创建链接。NODEFS https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api-nodefs给你这个机会。

快速解决方案

我们将开始修改您的 C++ 代码,通过使用嵌入式 JS 代码(使用EM_ASM https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-call-javascript-from-native)。首先(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 https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html (--bind) and NODEFS https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api-nodefs (-lnodefs.js):

emcc project.cpp -o project.js -s WASM_ASYNC_COMPILATION=0 -s EXIT_RUNTIME=1  --bind -lnodefs.js

Testing

要使用与您提到的相同的调用约定来测试 WebAssembly 模块,我们可以使用以下命令test.js script:

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

Comment

如果引用的文件位于当前工作目录中,则此方法效果很好。如果不是,您可以修改以下代码InputFile解压到其中的目录fileName是,然后相应地挂载实目录到虚拟目录。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 emscripten 通过 node.js 进行文件输入? 的相关文章

随机推荐