简体   繁体   中英

How do I successfully compile and run a rust program with threading and SDL2 for webassembly via emscripten?

I'm trying to compile my game engine for WebAssembly with Emscripten. The engine is powered by Rust and SDL2.

The config.toml file says:

[target.wasm32-unknown-emscripten]
ar = "/home/alexis/.exe/emsdk/upstream/emscripten/emar"
linker = "/home/alexis/.exe/emsdk/upstream/emscripten/emcc"
rustflags = ["-L/home/alexis/Desktop/game/target/libs", "-lSDL2", "-lSDL2_image", "-lpthread"]

The index.html file says:

<!DOCTYPE html>
<html lang="en-US">
    <head>
        <meta charset="utf-8" />
        <title>Catgirl Engine</title>
        <!-- https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm -->
    </head>
    <body>
        <script src="./catgirl-engine.js"></script>
    </body>
</html>

The lib.rs portion relevant to the wasm entry point is below. I have multiple different entry points for my engine due to different methods of starting up the engine. The 3 examples are c bindings for SDL to call (named SDL_main), the regular old main function, and the wasm function below. They all call game::start();

// Run as Library (e.g. Webassembly)
#[wasm_bindgen(start)]
fn wasm_init() -> Result<(), JsValue> {
    game::start();

    Ok(())
}

catgirl-engine.js and catgirl_engine.wasm are both generated by emcc.

My build command is

# The EMCC_CFLAGS exist because the engine wouldn't compile without them
EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry" cargo build -j 4 --verbose --target wasm32-unknown-emscripten --release

引用我与线程相关的代码行的错误消息

The alt text for the image error is

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 6, kind: WouldBlock, message: "Resource temporarily unavailable" }', src/game.rs:31:59

The line of code that is referenced by the error message is:

let physics_thread: JoinHandle<()> = thread::Builder::new().name("physics".to_string())
                    .spawn(|| physics::start(rptx, sprx)).unwrap();  // Server

It is one of the three threads that exist in the engine. The other two threads are the main thread and the render thread. The render thread (logical client) is the next line after this one.

I tried to add explicit support for pthreads by adding the -pthread flag as per https://emscripten.org/docs/porting/pthreads.html , however it seems to make no difference.

This of course doesn't even cover problems like my being unable to get SDL_ttf and SDL_mixer to compile for this platform or the other problems with trying to setup the output format (eg -oformat=html ) within the RUST_FLAGS. This is after manually creating the html file and working with the generation I do get.

With the specific EMCC_CFLAGS I have set, it generates the files:

  • main.wasm
  • catgirl_engine.wasm
  • catgirl-engine.js

catgirl-engine.js calls catgirl_engine.wasm and entirely ignores main.wasm (which is a slightly different file that I have not determined why it's generated yet.

Edit: I should mention, I've seen this exact same error message on both firefox and nodejs

There's a lot of stuff that went into making multi-threading working at all with Rust pthreads and Emscripten. This doesn't solve issues such as writing to a canvas from a non-main thread, but it does make it possible to run more than one thread.

First, you must make sure SharedArrayBuffer is available. All this requires is a couple of CORS headers and an if statement to check that it was successfully enabled. As there's already a StackOverflow answer related to this, see https://stackoverflow.com/a/65675390 .

After that, you want to make sure to compile with WASM threads enabled. I originally found instructions at https://web.dev/wasm-threads , however, I changed the instructions to be up to date in my setup.

In my build.rs file, I create the EMCC_CFLAGS environment variable in order to tell Rust how to build with threading.

// NOTICE FOR STACKOVERFLOW: I removed most of my EMCC_CFLAGS from this example just to
//   show the ones relevant for this particular answer, see the settings.js file for
//   more info on other flags you may need.

// Flags to Make Emscripten Compile This Correctly (Combined With RUSTFLAGS)
// https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
println!("cargo:rustc-env=EMCC_CFLAGS=-O3 \
                -pthread \
                -s PTHREAD_POOL_SIZE=3
         ");

Lastly, I modify my RUSTFLAGS environment variable by setting the config.toml file so it can tell what Rust features to enable. The original instructions are at https://github.com/wngr/wasm-futures-executor#sample-usage .

# NOTICE FOR STACKOVERFLOW: I removed most of my RUSTFLAGS from this example just to
#   show the ones relevant for this particular answer.

[target.wasm32-unknown-emscripten]
linker = "path/to/emsdk/upstream/emscripten/emcc"
rustflags = ["-Ctarget-feature=+atomics,+bulk-memory,+mutable-globals"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM