WebAssembly Build Guide

This tutorial will show you how to build a Wasm (WebAssembly) version of MNE-CPP. In order to build a Wasm version we need to do three things:

  • Setup the emscripten compiler
  • Build a static wasm version of Qt (with thread support)
  • Compile MNE-CPP with the wasm flag

This tutorial runs on Ubuntu 18.04.03 64bit and assumes the following folder structure:

Git/
├── emsdk/
├── qt5/
├── qt5_shadow/
├── qt5_wasm_binaries/
├── mne-cpp/
└── mne-cpp_shadow/

Basic Information on Qt Wasm with MNE-CPP

According to the official Qt Wasm guide, the preferred emscripten versions are:

Qt 5.12: 1.38.16
Qt 5.13: 1.38.27 (multithreading: 1.38.30)
Qt 5.14: it's complicated (1.38.27)
Qt 5.15: 1.39.7
Please note: With the versions above some functions are not able to be linked and produce errors. It is possible that some MNE-CPP functions are not compatible with these emscripten versions. However, emscripten version 1.39.3 and 1.39.7 seem to be working with MNE-CPP code. The following setups should work: Qt5.13.2 compiled with em++ 1.39.3 with thread support, Qt5.14.2 compiled with em++ 1.39.3 with thread support and Qt5.15.0 compiled with em++ 1.39.7 with thread support.

Setup the Emscripten Compiler

Get the emscripten compiler:

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory and pull
cd emsdk
git pull

# Download and install the latest SDK tools.
./emsdk install 1.39.3

# Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
./emsdk activate 1.39.3

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh

Build Qt from Source with Wasm Support

This is needed since we want to have threading support which is deactivated for the pre-built QtWasm build. Also, the pre-built QtWasm binaries are build with emscripten version 1.38.30 which does not work with MNE-CPP code.

Make sure to activate and source the correct emscripten version since the compiler will be used when building qt against wasm. You could also add this to your .basrc file. For example:

./emsdk activate 1.39.3
source ./emsdk_env.sh

Install some dependencies (just to make sure)

sudo apt-get install build-essential libgl1-mesa-dev python

Clone the current Qt version. For example Qt 5.14.2:

git clone https://code.qt.io/qt/qt5.git -b 5.14.2      
cd qt5
./init-repository -f --module-subset=qtbase,qtcharts,qtsvg

Navigate to the parent directory, create a new shadow build folder and cd into it:

cd ..
mkdir qt5_shadow
cd qt5_shadow

Call configure from the new working directory in order to setup a shadow build (remove the -feature-thread flag if you want to build without multithread support):

../qt5/configure -opensource -confirm-license -xplatform wasm-emscripten -feature-thread -nomake examples -no-dbus -no-ssl -prefix $PWD/../qt5_wasm_binaries

Build Qt and install to target (prefix) location afterwards. For MNE-CPP we only need the qt charts, qtsvg and qtbase module (see https://wiki.qt.io/Qt_for_WebAssembly for officially supported modules):

make module-qtbase module-qtsvg module-qtcharts -j8
make install -j8

A static Qt Wasm version should now be setup in the qt5_wasm_binaries folder.

Building MNE-CPP Against QtWasm

MNE-CPP needs to be build statically. This is automatically done if the wasm flag is set. Create a shadow build folder, run qmake and build MNE-CPP:

mkdir mne-cpp_shadow
cd mne-cpp_shadow
../qt5_wasm_binaries/resources/qmake ../mne-cpp/mne-cpp.pro MNECPP_CONFIG=wasm
make -j8

This should build all Wasm enabled applications, e.g. MNE Analyze, to mne-cpp/out/Release.

Run an Application

Navigate to mne-cpp/out/Release and start a server:

python3 -m http.server

Start to a suitable web browser (Chromium based browsers and Mozilla seem to work the best) and type:

http://localhost:8000/mne_analyze.html

Example Builds

Example builds can be found here (Chromium based and Mozilla browsers seem to work the best):

https://mne-cpp.github.io/wasm/mne_analyze.html

General Notes and Helpful Information

Wasm References

https://www.qt.io/blog/2018/11/19/getting-started-qt-webassembly

https://doc.qt.io/qt-5/wasm.html

https://medium.com/@jimmychen009/qt-quick-on-the-browser-30d5349c11ec

https://dev.to/captainsafia/why-the-heck-is-everyone-talking-about-webassembly-455a

https://wiki.qt.io/Qt_for_WebAssembly

https://doc.qt.io/qt-5/qtwebassembly-platform-notes.html

https://www.qt.io/blog/2019/06/26/qt-webassembly-multithreading

https://forum.qt.io/topic/107689/building-qt-apps-to-wasm/18

https://doc-snapshots.qt.io/qtcreator-master/creator-setup-webassembly.html

https://github.com/msorvig/qt-webassembly-examples