Skip to content

Bundling a multithreading program, without public URL #23957

Closed
@Andonvr

Description

@Andonvr

I have a problem using multithreading and packaging the resulting WASM in a reusable node package.
But let's start with what works so far:

I have a C++ program that I compile with emscripten, utilizing a CMakeLists.txt. I then want to use the resulting WASM in an npm package, for me to later publish.
These are my compiler flags:

            -O0\
            --bind\
            --no-entry\
            -s ALLOW_MEMORY_GROWTH=1\
            -s MALLOC=emmalloc\
            -s EXPORT_ES6=1\
            -s MODULARIZE=1\
            -s EXPORT_NAME=${PROJECT_NAME}\
            -s SINGLE_FILE=1\
            -s ENVIRONMENT=web,worker,shell\
            --emit-tsd=${BUILD_FOLDER}/${PROJECT_NAME}.d.ts\

It outputs a .js and a .d.ts file, and I can use it like this:

import MainModule from "../wasm/wasmbuild/output/hello_world_web"

export const testHelloWorld = async () => {
  const myMainModule = await MainModule()
  return myMainModule._main(0, 0)
}

This works well!
However, now I want to add multithreading. I adjust my code, and add the following compiler flags to my CMakeLists.txt:

            -pthread\
            -s PTHREAD_POOL_SIZE=16\

When running the same way I do above, I get these errors in my console:

Image
I have the strong suspicion, that it is because of this block in the generated .js file:

 allocateUnusedWorker() {
    var worker;
    var workerOptions = {
      "type": "module",
      // This is the way that we signal to the Web Worker that it is hosting
      // a pthread.
      "name": "em-pthread"
    };
    // If we're using module output, use bundler-friendly pattern.
    // We need to generate the URL with import.meta.url as the base URL of the JS file
    // instead of just using new URL(import.meta.url) because bundler's only recognize
    // the first case in their bundling step. The latter ends up producing an invalid
    // URL to import from the server (e.g., for webpack the file:// path).
    worker = new Worker(new URL("hello_world_web.js", import.meta.url), workerOptions); // <------ THIS
    PThread.unusedWorkers.push(worker);
  },

As I said, I use this in a package, I don't host the hello_world_web.js in any specific place. How would "hello_world_web.js" actually be found? Is there any specific way of handling this?

I already gave "locateFile" a go, like this:

const myMainModule = await MainModule({
  locateFile: (path: string) => {
    console.log("Trying to locate:")
    return path
  },
})

But nothing was logged, and since I don't see any "locateFile" referenced in the codeblock I mentioned, I didn't pursue this any further.

I also looked into webpack, and whether it would solve my issues. But that feels like overkill for what I want to achieve, and I have no clue if that is even the right path. So I didn't get further into that yet either.

Any help would be highly appreciated! Here's a simple repo to try things out: https://github.com/Andonvr/emscripten-threading-example.
Cheers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions