1

I've been toying with the usage of WebAssembly in a project as an importable function module (with hope to eventually use in a React/Electron app), so I've set myself up with Emscripten and got to work using C++.

No issues implementing functions, but I have been unsuccessful with classes. I want to be able to expose and instantiate a class in JS and call the methods on it, persisting until the "task" is complete.

Below is an example from Emscripten's own website, which builds but throws an error when trying to run (likely due to my build command and JS importing process)

The error message is [TypeError: WebAssembly.instantiate(): Import #13 module="GOT.func" error: module is not an object or function].

Is what I'm trying to achieve sensible and possible?

#include <stdio.h>
#include <string>
#include <iostream>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>

using namespace emscripten;

class MyClass
{
public:
    MyClass(int x, std::string y)
        : x(x), y(y)
    {
    }

    void incrementX()
    {
        ++x;
    }

    int getX() const { return x; }
    void setX(int x_) { x = x_; }

    static std::string getStringFromInstance(const MyClass &instance)
    {
        return instance.y;
    }

private:
    int x;
    std::string y;
};

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example)
{
    class_<MyClass>("MyClass")
        .constructor<int, std::string>()
        .function("incrementX", &MyClass::incrementX)
        .property("x", &MyClass::getX, &MyClass::setX)
        .class_function("getStringFromInstance", &MyClass::getStringFromInstance);
};
const util = require('util');
const fs = require('fs');
var source = fs.readFileSync('./dist/module.wasm');
const env = {
    memoryBase: 0,
    tableBase: 0,
    memory: new WebAssembly.Memory({
        initial: 256
    }),
    table: new WebAssembly.Table({
        initial: 0,
        element: 'anyfunc'
    }),
}



var typedArray = new Uint8Array(source);

WebAssembly.instantiate(typedArray, {
    env: env
}).then(result => {
    console.log('MODULE: ', result.instance.exports)

}).catch(e => {
    // error caught
    console.log(e);
});
{
  "name": "wasm-js-test",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "build-test": "rm -rf ./dist && mkdir ./dist && em++ ./src/module.cpp -O2 -s WASM=1 -s SIDE_MODULE=1 --no-entry --bind -o ./dist/module.wasm && node test.js"
  },
  "author": "",
  "license": "ISC"
}

1 Answer 1

1

You probably don't want to use -s SIDE_MODULE. Using SIDE_MODULE enables emscripten dynamic linking (PIC) ABI which you probably don't want.

Building with --no-entry and with an output file ending in .wasm should be enough to build something that is as sand-alone as possible. However remember that emscripten's output is really designed to be run by emscripten-generated JS so you may run into complications trying to load it yourself like this.

Sign up to request clarification or add additional context in comments.

4 Comments

Hi, thanks for a fast reply! Tried removing -s SIDE_MODULE=1 and I am receiving error [TypeError: WebAssembly.instantiate(): Import #13 module="wasi_snapshot_preview1" error: module is not an object or function]
Now you are running up against the fact that you need to implement the APIs that the module depends on. You can use wasm-objdump or wasm-dis to see what imports it requires. You will then need to provide implementations of each of the imports. Normally with emscirpten you build with -o <something>.js and emscripten will provide those for you.
When I started doing tutorials I started off having Emscripten output its JS file which I import via require(), but now I am trying to export a class I never see any reference to "MyClass" in the file at all. Though I can see strings in the .wasm file that correspond. I feel I am missing something
PROGRESS UPDATE: So I was able to build the class with command em++ ./src/testing.cpp -s --no-entry --bind -o ./dist/testing.js and run the methods through the JS file using onRuntimeInitialized event. I haven't actually seen this referenced in many places. Changes how I wanted to require() my WASM code, is there any way to avoid this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.