Cleanup comment
[LibreOffice.git] / static / README.wasm.md
blob7bca790acf7abca315c88ad781d395cea03797d3
1 # Support for Emscripten Cross Build
3 This module provides support for emscripten cross build
5 ## Status
7 The build generates a Writer-only LO build. You should be able to run either
9     $ emrun --serve_after_close instdir/program/qt_soffice.html
10     $ emrun --serve_after_close workdir/LinkTarget/Executable/qt_vcldemo.html
11     $ emrun --serve_after_close workdir/LinkTarget/Executable/qt_wasm-qt5-mandelbrot.html
13 REMINDER: Always start new tabs in the browser, reload might fail / cache!
14 INFO: latest browser won't work anymore with 0.0.0.0 and need 127.0.0.1.
16 ## Setup for the LO WASM build (with Qt)
18 We're using Qt 5.15.2 with Emscripten 2.0.31. There are a bunch of Qt patches
19 to fix the most grave bugs. Also newer Emscripten versions have various bugs
20 with the FS image support.
22 - See below under Docker build for another build option
24 ### Setup emscripten
26 <https://emscripten.org/docs/getting_started/index.html>
28     git clone https://github.com/emscripten-core/emsdk.git
29     ./emsdk install 2.0.31
30     ./emsdk activate --embedded 2.0.31
32 Example `bashrc` scriptlet:
34     EMSDK_ENV=$HOME/Development/libreoffice/git_emsdk/emsdk_env.sh
35     [ -f "$EMSDK_ENV" ] && \. "$EMSDK_ENV" 1>/dev/null 2>&1
37 ### Setup Qt
39 <https://doc.qt.io/qt-5/wasm.html>
41 Most of the information from <https://doc.qt.io/qt-6/wasm.html> is still valid for Qt5;
42 generally the Qt6 WASM documentation is much better, because it incorporated many
43 information from the Qt Wiki.
45 FWIW: Qt 5.15 LTS is not maintained publicly and Qt WASM has quite a few bugs. Most
46 WASM fixes from Qt 6 are needed for Qt 5.15 too. They can mainly be cherry-picked from:
47 - git log origin/dev src/plugins/platforms/wasm/
48 - git log --grep wasm origin/dev
50 We will probably offer our own Qt repository clone at some point.
52 But even the public Qt 5.15 branch is still broken, so better start with the v5.15.2 tag.
54     git clone https://github.com/qt/qt5.git
55     cd qt5
56     git checkout v5.15.2
57     ./init-repository --module-subset=qtbase
58     ./configure -xplatform wasm-emscripten -feature-thread -prefix $PWD/install-5.15.2
59     make -j<CORES> module-qtbase
61 Optionally you can add the configure flag "-compile-examples". But then you also have to
62 patch at least mkspecs/wasm-emscripten/qmake.conf with EXIT_RUNTIME=0, otherwise they will
63 fail to run. In addition, building with examples will break with some of them, but at that
64 point Qt already works and also most examples.
65 Building with examples will break with some of them, but at that point Qt already works.
66 Or just skip them. Other interesting flags might be "-nomake tests -no-pch -ccache".
68 Linking takes quite a long time, because emscripten-finalize rewrites the whole WASM files
69 with some options. This way the LO WASM needs at least 64GB RAM. For faster link times add
70 "-s WASM_BIGINT=1", change to ASSERTIONS=1 nd use -g3 to prevent rewriting the WASM file
71 and generating source maps (see emscripten.py, finalize_wasm, and avoid modify_wasm = True).
72 This is just needed for Qt examples, as LO already uses the correct flags!
74 The install is not really needed, as LO currently just uses qtbase on its own. You can do
76     make -j<CORES> install
78     make -j8 -C qtbase/src install_subtargets
80 Current Qt fails to start the demo webserver: <https://bugreports.qt.io/browse/QTCREATORBUG-24072>
82 Use `emrun --serve_after_close` to run Qt WASM demos.
84 ### Setup LO
86 `autogen.sh` is patched to use emconfigure. That basically sets various
87 environment vars, especially `EMMAKEN_JUST_CONFIGURE`, which will create the
88 correct output file names, checked by `configure` (`a.out`).
90 There's a distro config for WASM, but it just provides --host=wasm32-local-emscripten, which
91 should be enough setup. The build itself is a cross build and the cross-toolset just depends
92 on a minimal toolset (gcc, libc-dev, flex, bison); all else is build from source, because the
93 final result is not depending on the build system at all.
95 Recommended configure setup is thusly:
97 * grab defaults
98     `--with-distro=LibreOfficeWASM32`
100 * local config
101     `QT5DIR=/dir/of/git_qt5/qtbase`
103 * if you want to use ccache on both sides of the build
104     `--with-build-platform-configure-options=--enable-ccache`
105     `--enable-ccache`
107 FWIW: it's also possible to build an almost static Linux LibreOffice by just using
108 --disable-dynloading --enable-customtarget-components. System externals are still
109 linked dynamically, but everything else is static.
111 #### Experimental (AKA currently broken) WASM exception + SjLj build
113 You can build LO with WASM exceptions, which should be "much" faster then the JS
114 based Emscripten EH handling. For setjmp / longjmp (SjLj) used by the PNG and JPEG
115 libraries error handling, this needs Emscripten 3.1.3+. That builds, but execution
116 still fails early with a signature mismatch call to Task::UpdateMinPeriod in LO's
117 job scheduler code. Unfortunately the build also needs a Qt build with
118 "-s SUPPORT_LONGJMP=wasm", which is incompatible with the JS EH + SjLj.
120 The LO configure flag is simply an additional --enable-wasm-exceptions. Qt5 can
121 be patched in qtbase/mkspecs/wasm-emscripten/qmake.conf with the addition of
123     QMAKE_CFLAGS += -s SUPPORT_LONGJMP=wasm
124     QMAKE_CXXFLAGS += -s SUPPORT_LONGJMP=wasm
126 ### "Deploying" soffice.wasm
128     tar -chf wasm.tar --xform 's/.*program/lo-wasm/' instdir/program/soffice.* \
129         instdir/program/qt*
131 Your HTTP server needs to provide additional headers:
132 * add_header Cross-Origin-Opener-Policy same-origin
133 * add_header Cross-Origin-Embedder-Policy require-corp
135 The default html to use should be qt_soffice.html
137 ### Debugging setup
139 Since a few months you can use DWARF information embedded by LLVM into the WASM
140 to debug WASM in Chrome. You need to enable an experimental feature and install
141 an additional extension. The whole setup is described in:
143 https://developer.chrome.com/blog/wasm-debugging-2020/
145 This way you don't need source maps (much faster linking!) and can resolve local
146 WASM variables to C++ names!
148 Per default, the WASM debug build splits the DWARF information into an additional
149 WASM file, postfixed '.debug.wasm'.
151 ### Using Docker to cross-build with emscripten
153 If you prefer a controlled environment (sadly emsdk install/activate
154 is _not_ stable over time, as e.g. nodejs versions evolve), that is
155 easy to replicate across different machines - consider the docker
156 images we're providing.
158 Config/setup file see
159 <https://git.libreoffice.org/lode/+/ccb36979563635b51215477455953252c99ec013>
163     docker-compose build
165 in the lode/docker dir to get the container prepared. Run
167     PARALLELISM=4 BUILD_OPTIONS= BUILD_TARGET=build docker-compose run --rm \
168         -e PARALLELISM -e BUILD_TARGET -e BUILD_OPTIONS builder
170 to perform an actual `srcdir != builddir` build; the container mounts
171 checked-out git repo and output dir via `docker-compose.yml` (so make
172 sure the path names there match your setup):
174 The lode setup expects, inside the lode/docker subdir, the following directories:
176 - core (`git checkout`)
177 - workdir (the output dir - gets written into)
178 - cache (`ccache tree`)
179 - tarballs (external project tarballs gets written and cached there)
182 ## Ideas for an UNO bridge implementation
184 My post to Discord #emscripten:
186 "I'm looking for a way to do an abstract call
187 from one WASM C++ object to another WASM C++ object, so like FFI / WebIDL,
188 just within WASM. All my code is C++ and normally I have bridge code, with
189 assembler to implement the function call /RTTI and exception semantics of the
190 specified platform. Code is at
191 <https://cgit.freedesktop.org/libreoffice/core/tree/bridges/source/cpp_uno>.
192 I've read a bit about `call_indirect` and stuff, but I don't have yet a good
193 idea, how I could implement this (and  there is an initial feature/wasm branch
194 for the interested). I probably need some fixed lookup table, like on iOS,
195 because AFAIK you can't dynamically generate code in WASM. So any pointers or
196 ideas for an implementation? I can disassemble some minimalistic WASM example
197 and read clang code for `WASM_EmscriptenInvoke`, but if there were some
198 standalone code or documentation I'm missing, that would be nice to know."
200 We basically would go the same way then the other backends. Write the bridge in
201 C++, which is probably largely boilerplate code, but the function call in WAT
202 (<https://github.com/WebAssembly/wabt>) based on the LLVM WASM calling
203 conventions in `WASM_EmscriptenInvoke`. I didn't get a reply to that question for
204 hours. Maybe I'll open an Emscripten issue, if we really have to implement
205 this.
207 WASM dynamic dispatch:
209 - <https://fitzgeraldnick.com/2018/04/26/how-does-dynamic-dispatch-work-in-wasm.html>
211 ## Tools for problem diagnosis
213 * `nm -s` should list the symbols in the archive, based on the index generated by ranlib.
214   If you get linking errors that archive has no index.
217 ## Emscripten filesystem access with threads
219 This is closed, but not really fixed IMHO:
221 - <https://github.com/emscripten-core/emscripten/issues/3922>
223 ## Dynamic libraries `/` modules in emscripten
225 There is a good summary in:
227 - <https://bugreports.qt.io/browse/QTBUG-63925>
229 Summary: you can't use modules and threads.
231 This is mentioned at the end of:
233 - <https://github.com/emscripten-core/emscripten/wiki/Linking>
235 The usage of `MAIN_MODULE` and `SIDE_MODULE` has other problems, a major one IMHO is symbol resolution at runtime only.
236 So this works really more like plugins in the sense of symbol resolution without dependencies `/` rpath.
238 There is some clang-level dynamic-linking in progress (WASM dlload). The following link is already a bit old,
239 but I found it a god summary of problems to expect:
241 - <https://iandouglasscott.com/2019/07/18/experimenting-with-webassembly-dynamic-linking-with-clang/>
244 ## Mixed information, links, problems, TODO
246 More info on Qt WASM emscripten pthreads:
248 - <https://wiki.qt.io/Qt_for_WebAssembly#Multithreading_Support>
250 WASM needs `-pthread` at compile, not just link time for atomics support. Alternatively you can provide
251 `-s USE_PTHREADS=1`, but both don't seem to work reliable, so best provide both.
252 <https://github.com/emscripten-core/emscripten/issues/10370>
254 The output file must have the prefix .o, otherwise the WASM files will get a
255 `node.js` shebang (!) and ranlib won't be able to index the library (link errors).
257 Qt with threads has further memory limit. From Qt configure:
258 ````
259 Project MESSAGE: Setting PTHREAD_POOL_SIZE to 4
260 Project MESSAGE: Setting TOTAL_MEMORY to 1GB
261 ````
263 You can actually allocate 4GB:
265 - <https://bugzilla.mozilla.org/show_bug.cgi?id=1392234>
267 LO uses a nested event loop to run dialogs in general, but that won't work, because you can't drive
268 the browser event loop. like VCL does with the system event loop in the various VCL backends.
269 Changing this will need some major work (basically dropping Application::Execute).
271 But with the know problems with exceptions and threads, this might change:
273 - <https://github.com/emscripten-core/emscripten/pull/11518>
274 - <https://github.com/emscripten-core/emscripten/issues/11503>
275 - <https://github.com/emscripten-core/emscripten/issues/11233>
276 - <https://github.com/emscripten-core/emscripten/issues/12035>
278 We're also using emconfigure at the moment. Originally I patched emscripten, because it
279 wouldn't create the correct a.out file for C++ configure tests. Later I found that
280 the `emconfigure` sets `EMMAKEN_JUST_CONFIGURE` to work around the problem.
282 ICU bug:
284 - <https://github.com/emscripten-core/emscripten/issues/10129>
286 Alternative, probably:
288 - <https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Intl>
290 There is a wasm64, but that still uses 32bit pointers!
292 Old outdated docs:
294 - <https://wiki.documentfoundation.org/Development/Emscripten>
296 Reverted patch:
298 - <https://cgit.freedesktop.org/libreoffice/core/commit/?id=0e21f6619c72f1e17a7b0a52b6317810973d8a3e>
300 Generally <https://emscripten.org/docs/porting>:
302 - <https://emscripten.org/docs/porting/guidelines/api_limitations.html#api-limitations>
303 - <https://emscripten.org/docs/porting/files/file_systems_overview.html#file-system-overview>
304 - <https://emscripten.org/docs/porting/pthreads.html>
305 - <https://emscripten.org/docs/porting/emscripten-runtime-environment.html>
307 This will be interesting:
309 - <https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-an-event-loop>
311 This didn't help much yet:
313 - <https://github.com/emscripten-ports>
315 Emscripten supports standalone WASI binaries:
317 - <https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone>
318 - <https://www.qt.io/qt-examples-for-webassembly>
319 - <http://qtandeverything.blogspot.com/2017/06/qt-for-web-assembly.html>
320 - <http://qtandeverything.blogspot.com/2020/>
321 - <https://emscripten.org/docs/api_reference/Filesystem-API.html>
322 - <https://discuss.python.org/t/add-a-webassembly-wasm-runtime/3957/12>
323 - <http://git.savannah.gnu.org/cgit/config.git>
324 - <https://webassembly.org/specs/>
325 - <https://developer.chrome.com/docs/native-client/>
326 - <https://emscripten.org/docs/getting_started/downloads.html>
327 - <https://github.com/openpgpjs/openpgpjs/blob/master/README.md#getting-started>
328 - <https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API>
329 - <https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-intro.md>
330 - <https://www.ip6.li/de/security/x.509_kochbuch/openssl-fuer-webassembly-compilieren>
331 - <https://emscripten.org/docs/introducing_emscripten/about_emscripten.html#about-emscripten-porting-code>
332 - <https://emscripten.org/docs/compiling/Building-Projects.html>