Search code examples
webassemblyemscripten

Can't Bind C++ Class With Emscripten


Using emscripten with c++, trying to bind a simple class which has a static function and nothing else. Examples I've seen in the official docs and other places is very straightforward. So I don't get why this doesn't work:

EMSCRIPTEN_BINDINGS(LLWI_COLLECTION){ 
    emscripten::class_<LLWI>("LLWI")
        .class_function("prepare", &LLWI::prepare)
        ;
}

Intellisense gives the error: no instance of constructor "emscripten::class_<ClassType, BaseSpecifier>::class_ [with ClassType=LLWI, BaseSpecifier=emscripten::internal::NoBaseClass]" matches the argument list -- argument types are: (const char [5])

Which means this is not a valid constructor for class_ but, I went through bind.h, I've found the constructor and there shouldn't be any problem, it does take a const char* as an argument. And frankly, I don't understand how this doesn't work, every example I look at, is the same thing that I've done.

Btw, even though intellisense gives an error, emcc compiles without problem. But in the browser I get the error: wasm streaming compile failed: TypeError: Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.

And Module.LLWI.prepare() is undefined when I try to call it from the console.


Solution

  • Since you're missing a whole lot of information, let me just point out what I personally need to know in-order to cover bases.

    1. How are you loading the .wasm module? Are you using pure vanilla js with an index.html? Or using something like reactjs or nextjs to load? Webpack has specific options now for loading .wasm modules.

    2. What flags/options are you using to compile the module? Could you share the whole CLI command to compile?

    3. In terms of intellisense, the IDE sounds like the definite issue. I'm using vscode with CMakeLists.txt for emscripten and I don't have any issue with intellisense on that part. If that's your toolkit, I am writing a blog on how to set it up.

    If you're using vanilla js and serving with some sort of static server like python3 -m http.server, this particular commit has a working 2-classes-example folder which worked for me. WASM is loaded asynchronously so it needs to be called once it's loaded. Just follow the example and it should just work (fingers crossed).

    If you're using webpack with something like ReactJS, make sure you use these flags when compiling:

    ENVIRONMENT=web
    MODULARIZE=1
    EXPORT_ES6=1
    

    and optionally DEMANGLE_SUPPORT=1 (just because I'm using it and it works). For webpack.config.js, include the following:

    module.exports = {
        ...
        experiments: {
          asyncWebAssembly: true,
        },
        output: {
          ...
          webassemblyModuleFilename: "static/wasm/[modulehash].wasm",
        },
        ...
    }
    

    Now you can import [module].js which in turn will load [module].wasm in your react project.

    If you'd like to setup your C++ project using CMakeLists.txt please reach out to me in twitter and I'd be more than happy to help you setup.