PacktPublishing / Learn-WebAssembly

Learn WebAssembly, published by Packt
MIT License
73 stars 26 forks source link

Not loading without-glue code due to mime type wasm. #5

Closed MahbbRah closed 4 years ago

MahbbRah commented 4 years ago

Because of proper mime-type the load-wasm.js file is not loading. and due to that the sample is not working. what should we do on that? image

MahbbRah commented 4 years ago

@mikerourke

MahbbRah commented 4 years ago

I was trying to come up with a solution. then I took everything inline. and now a different errors!

    const canvas = document.querySelector('#myCanvas');
    const ctx = canvas.getContext('2d');

    const env = {
        table: new WebAssembly.Table({ initial: 8, element: 'anyfunc' }),
        _jsFillRect: function (x, y, w, h) {
            ctx.fillStyle = '#0000ff';
            ctx.fillRect(x, y, w, h);
        },
        _jsClearRect: function () {
            ctx.fillStyle = '#ff0000';
            ctx.fillRect(0, 0, 255, 255);
        },
    };

    const getDefaultEnv = () => ({
            __memory_base: 0,
            __table_base: 0,
            memory: new WebAssembly.Memory({ initial: 256 }),
            table: new WebAssembly.Table({ initial: 2, element: 'anyfunc' }),
            abort: console.log
    });
    var importObject = { imports: { imported_func: arg => console.log(arg) } };
    const allEnv = Object.assign({}, getDefaultEnv(), env);
    const allImports = Object.assign({}, importObject, { env: allEnv });

    fetch('without-glue.wasm')
    .then(response => {
        if (response.ok) return response.arrayBuffer();
        throw new Error(`Unable to fetch WebAssembly file ${fileName}`);
    })
    .then(bytes => WebAssembly.instantiate(bytes, allImports))
    .then(instance => {
            const m = instance.exports;
            m._init();

            // Move the rectangle by 1px in the nx and y every 20 milliseconds:
            const loopRectMotion = () => {
                setTimeout(() => {
                    m._moveRect();
                    if (m._getIsRunning()) loopRectMotion();
                }, 20)
            };

            // Enable you to pause and resume the rectangle movement:
            document.querySelector('#actionButton')
                .addEventListener('click', event => {
                    const newIsRunning = !m._getIsRunning();
                    m._setIsRunning(newIsRunning);
                    event.target.innerHTML = newIsRunning ? 'Pause' : 'Start';
                    if (newIsRunning) loopRectMotion();
                });

            loopRectMotion();

        })

image

mikerourke commented 4 years ago

@MahbbRah Let me take a look at it today. I've run into the mime type issue before because of the NPM library I was using to serve up the page. I had to switch from http-server to serve. I'll try running the examples in a newer browser. I'll let you know when it's fixed.

MahbbRah commented 4 years ago

@MahbbRah Let me take a look at it today. I've run into the mime type issue before because of the NPM library I was using to serve up the page. I had to switch from http-server to serve. I'll try running the examples in a newer browser. I'll let you know when it's fixed.

I tried few still faces that issue, serve, http-server, python httpserver, emrun server as well. But still no luck :/

and then I inlined all the codes as you saw up. then I got a error, which is: image

mikerourke commented 4 years ago

@MahbbRah FYI, I didn’t get a chance to look into that issue yesterday, but I’ll work on it tonight. I apologize for the delay. Were you working on macOS, Windows, or Linux?

mikerourke commented 4 years ago

@MahbbRah I figured out the issue! It looks like you need to explicitly specify which functions get exported from the .c file you're compiling when running emcc. So for the example you're trying to run, you need to use the EXPORTED_FUNCTIONS flag with an array of functions (prefixed with an underscore).

In the Makefile located at /chapter-05-create-load-module/Makefile, you need to change the without-glue step to the following:

without-glue: clean
    emcc without-glue.c -Os -s WASM=1 -s SIDE_MODULE=1 \
    -s "EXPORTED_FUNCTIONS=['_init', '_setIsRunning', '_getIsRunning', '_moveRect', '_updateRectLocation']" \
    -s BINARYEN_ASYNC_COMPILATION=0 -o without-glue.wasm

Notice the -s "EXPORTED_FUNCTIONS... flag on the second line. Going forward, if you continue to run into the issue, just add this flag with the exported functions and you should be good to go. I apologize for the issues. Let me know if you have any other questions.

MahbbRah commented 4 years ago

I did exported functions. But still the same issue. Not working! Can you share your updated implementation with commands for the wasm? image

mikerourke commented 4 years ago

Huh, that's odd, so I have 2 questions:

  1. Are you still using the inline version that you commented with, or are you using the example from the book?
  2. Which version of Emscripten do you have installed? Due to breaking API changes, you need to have v1.38.37. You can get the version by running emcc --version in the console.
MahbbRah commented 4 years ago

I'm using 1.39.6 version, How to go back to a specific version as you said? But I don't think this is a proper solution to going back.

mikerourke commented 4 years ago

@MahbbRah So I installed the latest version (1.39.6) and I was able to get it working by doing the following:

  1. Change the without-glue step in the Makefile to the following:
without-glue: clean
    emcc without-glue.c -Os -s STANDALONE_WASM \
    -s "EXPORTED_FUNCTIONS=['_init', '_setIsRunning', '_getIsRunning', '_moveRect', '_updateRectLocation']" \
    -s BINARYEN_ASYNC_COMPILATION=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -o without-glue.wasm
  1. Remove the _ prefix from the _jsFillRect and _jsClearRect functions in the env object:
const env = {
  table: new WebAssembly.Table({ initial: 8, element: 'anyfunc' }),
  jsFillRect: function (x, y, w, h) { // <- Removed underscore
    ctx.fillStyle = '#0000ff';
    ctx.fillRect(x, y, w, h);
  },
  jsClearRect: function() { // <- Removed underscore
    ctx.fillStyle = '#ff0000';
    ctx.fillRect(0, 0, 255, 255);
  },
};
  1. Removed the _ from the methods called from the Wasm module:
loadWasm('without-glue.wasm', { env }).then(({ instance }) => {
  const m = instance.exports;
  m.init(); // <- Removed _ from init

  // Move the rectangle by 1px in the x and y every 20 milliseconds:
  const loopRectMotion = () => {
    setTimeout(() => {
      m.moveRect();  // <- Removed _ from moveRect
      if (m.getIsRunning()) loopRectMotion(); // <- Removed _ from getIsRunning
    }, 20)
  };

  // Enable you to pause and resume the rectangle movement:
  document.querySelector('#actionButton')
    .addEventListener('click', event => {
      const newIsRunning = !m.getIsRunning(); // <- Removed _ from getIsRunning
      m.setIsRunning(newIsRunning); // <- Removed _ from setIsRunning
      event.target.innerHTML = newIsRunning ? 'Pause' : 'Start';
      if (newIsRunning) loopRectMotion();
    });

  loopRectMotion();
});

This will fix the issue for this particular example, but it will also require you to update the examples for the rest of the book. I would recommend installing version v1.38.15 for the remainder of the book examples. That way you should be able to get around adding EXPORTED_FUNCTIONS to all of the Makefile steps. You can do this by running these commands:

./emsdk install sdk-1.38.15-64bit

Once the installation is complete, run this command:

./emsdk activate sdk-1.38.15-64bit

Using an older version may not be ideal, but the breaking API changes weren't implemented until after the book was published. There's a good chance you may run into other unexpected issues if you continue to use 1.39.6.

MahbbRah commented 4 years ago

Thank you so much! It worked, Really appreciate your help.

BTW, can you help my giving resources/instructions how to port existing libraries for video/audio encoder decoder, and files manipulation/handling like library. How I can convert these to Wasm. this seems to be a not a easy way. need in-depth understanding and capabilites to handling error message while the migration. I need few practicals conversation examples with proper explanations. only a games conversion is not enough here.

Thank you so much.

mikerourke commented 4 years ago

@MahbbRah No problem, I'm glad it worked. The chapter on integrating Wasm with a web app might help you understand Wasm's capabilities a little better. Video and audio encoding/decoding is a little out of scope for an introductory book. I know Google built Squoosh in WebAssembly, which is an image compression library. There's a lot of really cool things happening with Wasi and the Bytecode Alliance. If you want to see a full blown app that uses WebAssembly, you should check out wasmboy. It uses AssemblyScript to emulate a GameBoy. Hopefully that helps!

kalwalt commented 3 years ago

@mikerourke It seems that is not possible to install anymore v1.38.15 if i try to install i get this error:

./emsdk install sdk-1.38.15-64bit
Error: No tool or SDK found by name 'sdk-1.38.15-64bit'.

i think it is not more available... tryed with 2.0.9 and your suggested mods but i got this error in the console:

without-glue.html:1 Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #2 module="wasi_snapshot_preview1" error: module is not an object or function

mikerourke commented 3 years ago

Hi @kalwalt, it looks like they moved that version to a "legacy" group in the emsdk repo. I'm looking into how to install it now. I'll try to have an answer for you by tomorrow. I imagine it might be a little more complex to get it up and running now.

I apologize for the delay (and your issues). WebAssembly and the corresponding tooling have undergone a lot of changes since the book release, and backwards compatibility isn't a top priority. It's good for the community because they keep adding new features and improvements, but bad for me because it breaks the examples in my book.

kalwalt commented 3 years ago

Hi @kalwalt, it looks like they moved that version to a "legacy" group in the emsdk repo. I'm looking into how to install it now. I'll try to have an answer for you by tomorrow. I imagine it might be a little more complex to get it up and running now.

Thank you @mikerourke! They moved maybe because the upstream version is now the official version?

I apologize for the delay (and your issues). WebAssembly and the corresponding tooling have undergone a lot of changes since the book release, and backwards compatibility isn't a top priority. It's good for the community because they keep adding new features and improvements, but bad for me because it breaks the examples in my book.

Yes i know that WebAssembly has a lot of changes, and Emscripten/emsdk too, i have a bit of experience with jsartoolkit5. One idea for the book would be create a dedicated branch for version that works for a specific emsdk version. Anyway i was able to run other exemples with emsdk 2.0.8 making some tweaks. I can share this when i have time...

mikerourke commented 3 years ago

In retrospect, I should have just put everything in a Docker container, but I suck at Docker. I know I got the older version working on one of my other laptops, but I can't remember what the heck I did. I'm going to get this sorted out today. Hopefully I'll be back with another update in an hour or so with instructions to get the older version up and running.

mikerourke commented 3 years ago

@kalwalt I figured it out!

  1. Make sure you have the latest version of the git repo:
    cd emsdk
    git pull
  2. Run the following command to install the required version (make sure you're in the emsdk directory):
    ./emsdk install sdk-fastcomp-1.38.15-64bit
  3. Once that's done, activate that version:
    ./emsdk activate sdk-fastcomp-1.38.15-64bit
  4. Make sure you run the source <emsdk Directory>/emsdk_env.sh before trying to run any make commands.

If for some reason, you're having issues, I would recommend just deleting the emsdk repo directory and re-cloning it. Let me know if that gets you back up and running.