Building for WebAssembly

CXX-Qt and applications written with it can be compiled for WebAssembly, with a few limitations. Below you will find detailed instructions regarding how to build for the WASM target.

You will need to have Qt for WebAssembly installed. The next section shows versions that have been tested.

Additionally, if you haven't already, clone the emsdk git repo from here.

Using Correct Versions

The version of Emscripten used to build CXX-Qt and programs using it should match the one that was used to build Qt for WebAssembly. This is because Emscripten does not guarantee ABI compatibility between versions, so using different versions is not guaranteed to work fully or even at all.

Here are the associated Qt and Emscripten versions, and whether they are currently working with CXX-Qt for WebAssembly:

QtEmscripten
6.22.0.14
6.33.0.0
6.43.1.14
6.53.1.25
6.63.1.37

Info about other Qt and emscripten versions can be found in the Qt documentation.

Setting Up emsdk

Once you know which Qt and Emscripten versions you will use, navigate to the root directory of the emsdk repo and run the following commands:

$ ./emsdk install <emscripten version>
$ ./emsdk activate <emscripten version>
$ source ./emsdk_env.sh

For example, if you are going to use Qt 6.4, the corresponding version of Emscripten is 3.1.14, so the first command will be:

$ ./emsdk install 3.1.14

On Windows, the third step, which sets up environment variables (source command above on Unix-like environments) is unnecessary because the required environment setup will already be done.

Toolchains

When configuring with CMake, the CMAKE_TOOLCHAIN_FILE variable needs to be set to the correct toolchain file; for example, if using Qt 6.4.2 on WebAssembly, the toolchain file is typically located at /path/to/Qt/6.4.2/wasm_32/lib/cmake/Qt6/qt.toolchain.cmake. This will set CMake up to use the correct Qt path, compiler, linker, and so forth.

Generally, this does not need to be done manually. Using the qt-cmake binary bundled with your selected version of Qt WASM will set the toolchain file for you.

For example, if using Qt 6.4.2:

$ /path/to/Qt/6.4.2/wasm_32/bin/qt-cmake -B build .

However, in Qt 6.3 and below, the bundled CMake is version 3.22, while CXX-Qt requires at least version 3.24. For these versions of Qt, a more up-to-date CMake binary needs to be used to configure, so CMAKE_TOOLCHAIN_FILE needs to be passed into the cmake command.

If using a different CMake binary, instead do this:

$ cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/qt.toolchain.cmake -B build .

For Qt 6.5 or later, use the wasm_singlethread toolchain. For versions earlier than 6.5 use wasm_32.

The wasm_multithread toolchain available in 6.5 and later is currently not supported. For more information, see the Known Issues section at the bottom of this page.

Compiling Your Project for WebAssembly

To build for WebAssembly in a project that uses CXX-Qt crates, first follow the instructions in the Using Correct Versions and Setting Up emsdk sections.

CMakeLists.txt

When compiling a CXX-Qt project for wasm, the Rust target must be set to wasm32-unknown-emscripten, and the project must be configured to use POSIX threads. Make sure you have the Emscripten target for rustc with rustup target add wasm32-unknown-emscripten.

set(Rust_CARGO_TARGET wasm32-unknown-emscripten)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

Using CMake, add_executable will not output an HTML file when targeting wasm. In order to render an HTML file, one must use qt_add_executable in its place. Assuming a project has a CMake flag BUILD_WASM to toggle wasm and native builds, one could write the following:

if(BUILD_WASM)
    qt_add_executable(${APP_NAME} ${SOURCE_FILES})
else()
    add_executable(${APP_NAME} ${SOURCE_FILES})
endif()

Configure, Build, and Run

Configure your build directory following the instructions in the Toolchains section.

Now, run cmake --build on the build directory to compile and link the project. This can be any CMake binary; here the OS package works just fine:

$ cmake --build build

You can then run your built application like so:

$ emrun ./build/path/to/<appname>.html

Compiling CXX-Qt WASM from Source

If you are compiling CXX-Qt from source, the workflow is similar. First, follow the instructions in the Using Correct Versions and Setting Up emsdk sections.

The CMakeLists.txt file at the root of the CXX-Qt repository has an option BUILD_WASM to toggle WebAssembly builds. Simply compiling with the correct emsdk and toolchain and flipping this option ON should build the libraries and examples for WebAssembly.

Building

Read the Toolchains section before proceeding. Then navigate to the root directory of the CXX-Qt repo.

If using the qt-cmake binary packaged with your version of Qt for WebAssembly, run the following command to configure CXX-Qt:

$ /path/to/qt-cmake -DBUILD_WASM=ON -B build .

If using a different CMake binary, instead do this:

$ <cmake binary> -DCMAKE_TOOLCHAIN_FILE=/path/to/qt.toolchain.cmake -DBUILD_WASM=ON -B build .

Finally, run cmake --build on the configured build directory to compile and link the project and examples. This can be any CMake binary; here the OS package works just fine:

$ cmake --build build

Then you can run the qml_minimal example like so:

$ emrun ./build/examples/qml_minimal/example_qml_minimal.html

Working Examples

Not all of the examples are currently supported for WASM builds.

ExampleWorking
qml-minimal-no-cmake❌ broken
demo_threading❌ broken
qml_features✅ working
qml_minimal✅ working

For more information, see the Known Issues section at the bottom of this page.

Known Issues

wasm_multithread toolchain

CXX-Qt will currently not build with wasm_multithread versions of Qt.

wasm-ld: error: --shared-memory is disallowed by qml_minimal-e6f36338b0e1fa5c.17g6vcid2nczsjj0.rcgu.o 
            because it was not compiled with 'atomics' or 'bulk-memory' features.

This issue is related to pthread in the libc crate. It is possible that manually compiling cxx and libc crates with -pthread may solve this.

cargo-only builds

The example qml-minimal-no-cmake will not build for WebAssembly with cargo, and attempts to build with cargo without cmake will not work. This is due to an upstream issue with the libc crate, which does not support wasm and can cause breakage.

cannot find function `pthread_kill` in crate `libc`

demo_threading example

The example demo_threading will not build for WebAssembly due to an upstream issue with async-std, which does not support wasm. On Linux, the observed breakage is due to socket2 using its unix.rs file to target a Unix rather than wasm environment, resulting in error messages from unix.rs like the following:

error[E0433]: failed to resolve: use of undeclared type `IovLen`

socket2 is a dependency of async-io, which is a dependency of async-std.

There is discussion around supporting wasm in the GitHub repository for async-std, and the progress is being tracked here.