HTML5
Exporting to HTML5 works just like exporting to other platforms, however there are some things that can make the process a bit tricky and require extra attention.
What you need (to know)
The Godot HTML5 export templates are built with Emscripten, so you need to build your Rust code for the wasm32-unknown-emscripten
target (wasm32-unknown-unknown
will not work). Since Emscripten does not offer a stable ABI between versions, your code and the Godot export template have to be built with the same Emscripten version, which also needs to be compatible with the Rust compiler version you are using.
In practice, this means you probably have to do some or all of these things:
- install a specific version of Emscripten
- build the HTML5 export template yourself
- use a specific version of Rust
You can check which versions of Emscripten/Rust you are using like this:
emcc -v
rustc --version --verbose
A list of compatible Rust and Emscripten versions are given in the next section.
Emscripten uses a cache to store build artifacts and header files. This means that the order in which steps are completed matters. In particular, Godot export template should be built before the GDNative library.
Also note that wasm32-unknown-emscripten
is a 32-bit target, which can cause problems with crates incorrectly assuming that usize
is 64 bits wide.
Limitations
- Multi-threading is not supported. See this issue for more details and instructions for failing experimental build.
- Debug builds may not work due to their large size. See the corresponding issue.
- As a workaround, you can set
opt-level = 1
in debug builds, which reduces the build size. Add the following to your workspace's/project'sCargo.toml
:
- As a workaround, you can set
[profile.dev]
opt-level = 1
Godot 3.5
Disclaimer: Currently, the following steps are only tested and confirmed to work on Linux.
Godot 3.5's prebuilt HTML5 export template is built with Emscripten 3.1.10. It might be possible to use it if build your Rust code with that exact version, but extra compiler flags may be needed. This guide focuses on building the export template yourself with a recent version of Emscripten.
As of 2023-01-28 you also need to use a Rust nightly build.
Confirmed working versions are:
- Rust toolchain
nightly-2023-01-27
andEmscripten 3.1.21 (f9e81472f1ce541eddece1d27c3632e148e9031a)
- This combination will be used in the following sections of this tutorial.
rustc 1.65.0-nightly (8c6ce6b91 2022-09-02)
andEmscripten 3.1.21-git (3ce1f726b449fd1b90803a6150a881fc8dc711da)
The compatibility problems between Rust and Emscripten versions are assumed to stem from differing LLVM versions. You can use the following commands to check the LLVM versions of the currently installed nightly toolchain and the currently active emcc:
rustc +nightly --version --verbose
emcc -v
emcc -v
reports the version number of clang
, which is equal to the version number of the overall LLVM release.
Install Rust toolchain
Following bash commands install nightly-2023-01-27
toolchain with wasm32-unknown-emscripten
target:
# Install the specific version of Rust toolchain.
rustup toolchain install nightly-2023-01-27
# Add wasm32-unknown-emscripten target to this toolchain.
rustup +nightly-2023-01-27 target add wasm32-unknown-emscripten
Installing and configuring Emscripten
Use the following bash commands to install Emscripten 3.1.21, which is known to be compatible with Rust nightly-2023-01-27
:
# Get the emsdk repo.
git clone https://github.com/emscripten-core/emsdk.git
# Enter the cloned directory.
cd emsdk
# Download and install a compatible SDK version.
./emsdk install 3.1.21
# Make this SDK version "active" for the current user. (writes .emscripten file)
./emsdk activate 3.1.21
# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
Building Godot
Build the Godot Export template according to the instructions:
source "/path/to/emsdk-portable/emsdk_env.sh"
scons platform=javascript tools=no gdnative_enabled=yes target=release
mv bin/godot.javascript.opt.gdnative.zip bin/webassembly_gdnative_release.zip
Since this is a web build, you might want to disable unused modules and optimize your build for size as shown in Godot documentation.
Set the newly built export template as a custom template in Godot and be sure to set the export type as GDNative. When exporting, uncheck "Export With Debug".
Building your Rust code
In your project's .cargo/config.toml
(see Cargo Docs), add the following:
[target.wasm32-unknown-emscripten]
rustflags = [
"-Clink-arg=-sSIDE_MODULE=2", # build a side module that Godot can load
"-Zlink-native-libraries=no", # workaround for a wasm-ld error during linking
"-Cpanic=abort", # workaround for a runtime error related to dyncalls
]
Build like this:
source "/path/to/emsdk-portable/emsdk_env.sh"
export C_INCLUDE_PATH=$EMSDK/upstream/emscripten/cache/sysroot/include
cargo +nightly-2023-01-27 build --target=wasm32-unknown-emscripten --release
This will produce a .wasm
file in target/wasm32-unknown-emscripten/release/
directory. Add this file to GDNativeLibrary
properties under entry/HTML5.wasm32
, just like you would add a .so
or a .dll
for Linux or Windows.
Errors you might encounter
Compile time:
failed to run custom build command for gdnative-sys v0.10.1
,fatal error: 'wchar.h' file not found
: Emscripten cache not populated, build Godot export template firstundefined symbol: __cxa_is_pointer_type
: You need to build with-Clink-arg=-sSIDE_MODULE=2
error: undefined symbol: main/__main_argc_argv (referenced by top-level compiled C/C++ code)
: Your.cargo/config.toml
was not loaded. See Cargo Docs and verify its location.
Runtime:
indirect call signature mismatch
: Possibly due to Emscripten version mismatch between Godot and Rustneed the dylink section to be first
: Same as aboveWebAssembly.Module(): Compiling function #1 failed: invalid local index
: You need to build with-Cpanic=abort
ERROR: Can't resolve symbol godot_gdnative_init. Error: Tried to lookup unknown symbol "godot_gdnative_init" in dynamic lib
: Possibly because Emscripten version is not compatible with Rust toolchain version. See the compatible version list above.wasm validation error: at offset 838450: too many locals
: Binary size is too big. See limitations section for a workaround.WebAssembly.instantiate(): Compiling function #2262:"gdnative_sys::GodotApi::from_raw::..." failed: local count too large
: Binary size is too big. See limitations section for a workaround.
Further reading
In the future, some of this will probably not be needed, for more info see:
- Tracking issue for godot-rust wasm support
- Rust and Emscripten issues that explain the need for
-Zlink-native-libraries=no
- Emscripten PR that should have obsoleted
-Cpanic=abort
- Rust PR that would obsolete
-Clink-arg=-sSIDE_MODULE=2