Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I load .wasm files stored in a subdirectory?

I am trying out a simple example to call a C function compiled to .wasm with JavaScript.

This is the counter.c file:

#include <emscripten.h>

int counter = 100;

EMSCRIPTEN_KEEPALIVE
int count() {  
    counter += 1;
    return counter;
}

I compiled it using emcc counter.c -s WASM=1 -o counter.js.

My main.js JavaScript file:

Module['onRuntimeInitialized'] = onRuntimeInitialized;
const count = Module.cwrap('count ', 'number');

function onRuntimeInitialized() {
    console.log(count());
}

My index.html file only loads both .js files in the body, nothing else:

<script type="text/javascript" src="counter.js"></script>
<script type="text/javascript" src="main.js"></script>

It works fine / prints 101 to the console, but when I move the counter.c file to a wasm subdirectory, recompile it with emscripten and update the script tag to src="wasm/counter.js", the counter.js script tries to load counter.wasm from the root directory instead of the wasm subdirectory and I get the error:

counter.js:190 failed to asynchronously prepare wasm: failed to load wasm binary file at 'counter.wasm'

I did some research, but I didn't find any way to tell emscripten to let the generated .js file load the .wasm from the same subdirectory.

like image 679
Kilian Batzner Avatar asked Sep 20 '17 22:09

Kilian Batzner


2 Answers

As explained by ColinE in the other answer, you should look at the integrateWasmJS() function generated by the emcc compiler (counter.js). The body of that function has changed recently and now it looks like this:

function integrateWasmJS() {
    ...
    var wasmBinaryFile = 'counter.wasm';

    if (typeof Module['locateFile'] === 'function') {
        ...
        if (!isDataURI(wasmBinaryFile)) {
          wasmBinaryFile = Module['locateFile'](wasmBinaryFile);
        }
        ...
    }
}

If this is the case, then you should add a "locateFile" function to the global Module variable. So in your HTML, you could add the following snippet before importing the counter.js file:

<script>
  var Module = {
    locateFile: function(s) {
      return 'wasm/' + s;
    }
  };
</script> 
like image 109
HugoTeixeira Avatar answered Nov 10 '22 05:11

HugoTeixeira


If you look at the generated 'loader' file that emscripten creates, it has an integrateWasmJS function as follows:

function integrateWasmJS(Module) {
  var method = Module['wasmJSMethod'] || 'native-wasm';
  Module['wasmJSMethod'] = method;

  var wasmTextFile = Module['wasmTextFile'] || 'hello.wast';
  var wasmBinaryFile = Module['wasmBinaryFile'] || 'hello.wasm';
  var asmjsCodeFile = Module['asmjsCodeFile'] || 'hello.temp.asm.js';

  ...
}

You can see that the wasmBinaryFile indicates the location of the binary. If it is not set it provides a default.

It looks like you should be able to override this in your main.js file as follows:

Module['wasmBinaryFile'] = 'wasm/counter.wasm';
like image 44
ColinE Avatar answered Nov 10 '22 05:11

ColinE