【问题标题】:How to do file inputs via node.js using emscripten?如何使用 emscripten 通过 node.js 进行文件输入?
【发布时间】:2020-01-16 20:24:57
【问题描述】:

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

查看documentation 我发现有一种方法可以使用 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++ 项目能够毫无问题地打开文件,所以我知道文件本身没有问题。

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

【问题讨论】:

    标签: node.js webassembly emscripten


    【解决方案1】:

    说明

    WebAssembly 模块使用emscripten 构建,没有关于物理文件系统中文件的信息。相反,它使用虚拟文件系统。您所要做的就是在物理系统上的文件与模块虚拟系统上的文件之间创建链接。 NODEFS 给你这个机会。

    快速解决方案

    我们将从修改您的 C++ 代码开始,通过使用嵌入式 JS 代码(使用EM_ASM)在物理和虚拟文件系统之间添加上述链接。首先(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 模块中,我们使用的是虚拟文件系统,而不是物理文件系统,所以当前目录(根 '.')中的每个引用文件实际上都在先前链接的虚拟目录中(@ 987654331@)。因此,'/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所在的目录,然后相应地挂载真实到虚拟的目录。

    【讨论】:

    • 我们可以在JS中做到这一点,而不接触原始C文件吗? (就我而言,我有一个用 emconfigure 和 emmake 编译的大项目,生成的 output.js 正在寻找 /etc/path,我很想在 JavaScript for Node 中提供虚拟磁盘和真实磁盘之间的映射.js.)
    • 通过-s NODERAWFS=1 标志emcc 弄清楚如何做到这一点。
    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多