Kilian Obermeier
Kilian Obermeier

Reputation: 7168

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.

Upvotes: 9

Views: 5549

Answers (2)

HugoTeixeira
HugoTeixeira

Reputation: 4884

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> 

Upvotes: 12

ColinE
ColinE

Reputation: 70160

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';

Upvotes: 6

Related Questions