WebAssembly C++ using JS value - Import #0 module="env": module is not an object or function

21 Views Asked by At

I'm new to WebAssembly and I'm doing some experiments.

I managed to create very simple examples.

Now I would like to try using JS objects within my C++ code. Specifically,

I would like to try printing elements retrieved from windows such as location in C++ code.

This is my C++ code:

#include <string>
#include <emscripten.h>
#include <emscripten/val.h>

using namespace emscripten;

EMSCRIPTEN_KEEPALIVE
std::string decode_request(val window) {
    val location = window["location"];
    std::string search = location["search"].as<std::string>();
    size_t pos = search.find('?');
    if (pos != std::string::npos) {
        return search.substr(pos + 1);
    } else {
        return "";
    }
}

extern "C" {
    EMSCRIPTEN_KEEPALIVE
    const char* myFunction() {
        val window = val::global("window");
        std::string query = decode_request(window);
        return query.c_str();
    }
}

To compile, I'm using this command:

emcc -o module.js module_2.cpp -s EXPORTED_RUNTIME_METHODS="['ccall']"  -lembind

And this is the result:

module_2.cpp:24:16: warning: address of stack memory associated with local variable 'query' returned [-Wreturn-stack-address]
   24 |         return query.c_str();
      |                ^~~~~
1 warning generated.
cache:INFO: generating system asset: symbol_lists/83809947191162c2d512457e4d02c5266930142b.json... (this will be cached in "/Users/myuser/Documents/Emscripten/emsdk/upstream/emscripten/cache/symbol_lists/83809947191162c2d512457e4d02c5266930142b.json" for subsequent builds)
cache:INFO:  - ok

This is my HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebAssembly Example</title>
</head>
<body>
    <h1>WebAssembly Example</h1>
    <p id="result">Result: </p>

    <button onclick="run()">Trigger</button>

    <script>
        function run() {
            WebAssembly.instantiateStreaming(
                fetch("wrapping.wasm"), {}
            ).then(result => {
                if (!result || !result.instance || !result.instance.exports) {
                    console.error("Failed to instantiate WebAssembly module.");
                    return;
                }

                var sum = result.instance.exports.myFunction();
                console.log("Result:", sum);

                document.getElementById("result").textContent = "Result: " + sum;
            }).catch(error => {
                console.error("Error loading WebAssembly module:", error);
            });
        }
    </script>
</body>
</html>

Unfortunately, I see this error in the console when I click on the button:

Error loading WebAssembly module: TypeError: WebAssembly.instantiate(): Import #0 module="env": module is not an object or function
(anonymous) @ (index):32
Promise.catch (async)
run @ (index):31
onclick @ (index):12

Any suggestions?

1

There are 1 best solutions below

1
sbc100 On

Normally with emscripten you have the compiler generate the code that loads the wasm module (i.e. -o wrapping.js). You then load that .js file into your html and it takes care of the loading the wasm file.

You can output a wasm file directly using -o wrapping.wasm but then you would have implement all the JS support code yourself. This is especially hard when using embind which relies a lot of generating JS support code.

For more information on standalone wasm mode see https://v8.dev/blog/emscripten-standalone-wasm. In short, it not really feasible to use embind in this mode.