Explanation
WebAssembly module, built using emscripten, has no information about files in your physical file system. Instead, it uses a virtual file system. All you have to do is to create a link between files on your physical system to the files on the module's virtual system. NODEFS gives you this opportunity.
Quick solution
We will start at modifying your C++ code by adding the aforementioned link between physical and virtual file systems using embedded JS code (with EM_ASM). First (1), we create a directory '/temp'
on the virtual file system where all referenced files will be located in. Then (2), we link this new virtual directory with a real physical location (the current working directory '.'
) where all the referenced files are already.
#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);
}
Now, because in the WebAssembly module, we are working with the virtual file systems, and not the physical one, each referenced file from the current directory (the root '.'
) is actually in the virtual directory previously linked ('/temp'
). Hence, '/temp'
directory precedes the name to the referenced file: std::ifstream in(std::string("/temp/") + fileName);
.
Finally, we can compile this file. We force the synchronized compilation (to make sure the require
loads the WASM module on time). Moreover, the option -s EXIT_RUNTIME=1
makes sure that the C++ command exit(1);
finishes the execution. Also, we need to link Embind (--bind
) and NODEFS (-lnodefs.js
):
emcc project.cpp -o project.js -s WASM_ASYNC_COMPILATION=0 -s EXIT_RUNTIME=1 --bind -lnodefs.js
Testing
To test the WebAssembly module with the same calling convention as you have mentioned, we can use the following 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!');
}
To run the file, all you have to do is this: node test.js -f test.file
Comment
This approach works well if the referenced files are in the current working directory. In the case they are not, you could modify the code of the InputFile
to extract the directory in which the fileName
is, and then, mount the real-to-virtual directory accordingly.