Skip to content

Commit 23d85b1

Browse files
authored
Move dynamic linking docs from wiki to main site. NFC (#15598)
This was mostly generated directly from the wiki using `site/ource/get_wiki.py`.
1 parent 4f33bfe commit 23d85b1

File tree

3 files changed

+215
-2
lines changed

3 files changed

+215
-2
lines changed

site/source/docs/compiling/Building-Projects.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ final build stage). This is to ensure that the same dynamic library is not
271271
linked multiple times in intermediate build stages, which would result in
272272
duplicate symbol errors.
273273

274-
There is `experimental support <https://github.com/emscripten-core/emscripten/wiki/Linking>`_ for true dynamic libraries, loaded as runtime, either via dlopen or as a shared library. See that link for the details and limitations.
274+
There is :ref:`experimental support <Dynamic-Linking>` for true dynamic libraries, loaded as runtime, either via dlopen or as a shared library. See that link for the details and limitations.
275275

276276

277277
Configure may run checks that appear to fail
@@ -386,4 +386,4 @@ Troubleshooting
386386

387387
.. note:: You can use ``llvm-nm`` to see which symbols are defined in each object file.
388388

389-
One solution is to use the _`dynamic-linking` approach described above. This ensures that libraries are linked only once, in the final build stage.
389+
One solution is to use :ref:`dynamic-linking <Dynamic-Linking>`. This ensures that libraries are linked only once, in the final build stage.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
.. _Dynamic-Linking:
2+
3+
===============
4+
Dynamic Linking
5+
===============
6+
7+
.. note:: Dynamic linking in emscripten is still somewhat experimental and subject to change. This documentation is also curently somewhat outdated the in the process of being refreshed.
8+
9+
Emscripten supports linking object files (and ar archives that contain
10+
object files) statically. This lets most build systems work with Emscripten
11+
with little or no changes (see :ref:`Building-Projects`).
12+
13+
In addition, Emscripten also has support for a form of **dynamic** linking of
14+
WebAssembly modules. This can add overhead, so for best performance static
15+
linking should still be prefered. However, this overhead can can be reduced
16+
with the use of certain command line flags, see below for details.
17+
18+
Background
19+
==========
20+
21+
Before we get to dynamic linking, let’s talk about static linking.
22+
Emscripten’s linking model is a little different than most native
23+
platforms. To understand it, consider that native linking models work in
24+
a setting where the following facts are true:
25+
26+
1. The application runs directly on the local system, and has access to
27+
local system libraries, like C and C++ standard libraries, and
28+
others.
29+
2. Code size is not a big concern. In part this is because the system
30+
libraries already exist on the system, so “hello world” in C++ can be
31+
small, even if it uses a large amount of iostream code in the C++
32+
standard library. But also, code size is perhaps a matter that
33+
influences cold startup times, in that more code takes longer to load
34+
from disk, but the cost is general not significant, and modern OSes
35+
mitigate it in various ways, like caching apps they expect to be
36+
loaded.
37+
38+
In Emscripten’s case, code is typically going to run on the web. That
39+
means the following:
40+
41+
1. The application is running in a sandbox. It has no local system
42+
libraries to dynamically link to; it must ship its own system library
43+
code.
44+
2. Code size is a major concern, as the application’s code is being
45+
downloaded over the internet, which is many orders of magnitude
46+
slower than an installed native app on one’s local machine.
47+
48+
For that reason, Emscripten automatically handles system libraries for
49+
you and automatically does dead code elimination etc. to do the best
50+
possible job it can at getting them small.
51+
52+
An additional factor here is that Emscripten has “js libraries” - system
53+
libraries written in JavaScript. Such system libraries are the way we
54+
access APIs on the web. It’s also a convenient way for people to connect
55+
compiled code and handwritten code on the same page. This is another
56+
reason for Emscripten to handle system libraries in a special way, and
57+
in particular, in a way that lets it strip out as much of those js
58+
libraries as it can, leaving only what is actually used, and again, that
59+
works best in the context of statically linking a standalone app with no
60+
external dependencies.
61+
62+
Overview of Dynamic Linking
63+
===========================
64+
65+
Emscripten’s dynamic linking is fairly simple: you build several
66+
separate code “modules” containing JavaScript, and can link them at
67+
runtime. The linking basically connects up the unresolved symbols in
68+
each module with the implemented symbols in the others, in the simplest
69+
of ways. It does not currently support some corner cases.
70+
71+
System libraries do utilize some more advanced linking features that
72+
include such corner cases. For that reason, Emscripten tries to simplify
73+
the problem as follows: There are two types of shared modules:
74+
75+
1. **Main modules**, which have system libraries linked in.
76+
2. **Side modules**, which do not have system libraries linked in.
77+
78+
A project should contain **exactly one** main module. It can then be
79+
linked at runtime to multiple side modules. This model also makes other
80+
things simpler, like only the singleton main module has the general
81+
JavaScript environment setup code to connect to the web page and so
82+
forth; side modules contain just the pure compiled WebAssembly and
83+
nothing more.
84+
85+
The one tricky aspect to this design is that a side module might need a
86+
system library that the main doesn’t know about. See the section on
87+
system libraries, below, for how to handle that.
88+
89+
Note that the “main module” doesn’t need to contain the ``main()``
90+
function. It could just as easily be in a side module. What makes the
91+
main module the “main” module is just that there is only one main
92+
module, and only it has system libs linked in.
93+
94+
(Note that system libraries are linked in to the main module
95+
*statically*. We still have some optimizations from doing it that way,
96+
even if we can’t dead code eliminate as well as we’d like.)
97+
98+
Practical Details
99+
=================
100+
101+
If you want to jump to see running code, you can look in the test suite.
102+
There are ``test_dylink_*`` tests that test general dynamic linking, and
103+
``test_dlfcn_*`` tests that test ``dlopen()`` specifically. Otherwise,
104+
we describe the procedure now.
105+
106+
General Dynamic Linking
107+
-----------------------
108+
109+
- Build one part of your code as the main module, using
110+
``-s MAIN_MODULE=1``.
111+
- Build other parts of your code as side modules, using
112+
``-s SIDE_MODULE=1``.
113+
114+
Important: since 1.38.16 you need to set ``-s EXPORT_ALL=1`` (for
115+
SIDE_MODULEs, as well as the MAIN_MODULE if it exposes functions to the
116+
modules). Alternatively, use ``-s EXPORTED_FUNCTIONS`` to declare the
117+
exported functions. Without either of them, modules are useless.
118+
119+
Note that both should have suffix ``.js`` or ``.wasm`` (``emcc`` uses
120+
suffixes to know what to emit). If you want, you can then rename the
121+
side modules to ``.so`` or such (but it is just a superficial change.)
122+
123+
You then need to tell the main module to load the sides. You can do that
124+
using the ``Module`` object, with something like
125+
126+
::
127+
128+
Module.dynamicLibraries = ['libsomething.js'];
129+
130+
At runtime, when you run the main module, if it sees
131+
``dynamicLibraries`` on ``Module``, then it loads them one by one and
132+
links them. The running application then can access code from any of the
133+
modules linked together.
134+
135+
``dlopen()`` Dynamic Linking
136+
----------------------------
137+
138+
``dlopen()`` is slightly simpler than general dynamic linking. The
139+
procedure begins in the same way, with the same flags used to build the
140+
main and side modules. The difference is that you do not use
141+
``Module.dynamicLibraries``; instead, you must load the side module into
142+
the filesystem, so that ``dlopen`` (or ``fopen``, etc.) can access it
143+
(except for ``dlopen(NULL)`` which means to open the current executable,
144+
which just works without filesystem integration). That’s basically it -
145+
you can then use ``dlopen(), dlsym()``, etc. normally.
146+
147+
System Libraries
148+
================
149+
150+
As mentioned earlier, system libraries are handled in a special way by
151+
the Emscripten linker, and in dynamic linking, only the main module is
152+
linked against system libraries. A possible issue is if a side module
153+
needs a system library that the main does not. If so, you’ll get a
154+
runtime error. This section explains what to do to fix that.
155+
156+
To get around this, you can build the main module with
157+
``EMCC_FORCE_STDLIBS=1`` in the environment to force inclusion of all
158+
standard libs. A more refined approach is to build the side module with
159+
``-v`` in order to see which system libs are actually needed - look for
160+
``including lib[...]`` messages - and then building the main module with
161+
something like ``EMCC_FORCE_STDLIBS=libcxx,libcxxabi`` (if you need
162+
those two libs).
163+
164+
Code Size
165+
=========
166+
167+
By default, main modules disable dead code elimination. That means that
168+
all the code compiled remains in the output, including all system
169+
libraries linked in, and also all the JS library code.
170+
171+
That is the default behavior since it is the least surprising. But it is
172+
also possible to use normal dead code elimination, by building with
173+
``-s MAIN_MODULE=2`` (instead of 1). In that mode, the main module is
174+
built normally, with no special behavior for keeping code alive. It is
175+
then your responsibility to make sure that code that side modules need
176+
is kept alive. You can do this in the usual ways, like adding to
177+
``EXPORTED_FUNCTIONS``. See ``other.test_minimal_dynamic`` for an
178+
example of this in action. There is also the corresponding
179+
``-s SIDE_MODULE=2`` for side modules.
180+
181+
Miscellaneous Notes
182+
===================
183+
184+
Dynamic Checks
185+
--------------
186+
187+
Native linkers generally only run code when all symbols are resolved.
188+
Emscripten’s dynamic linker hooks up symbols to unresolved references to
189+
those symbols **dynamically**. As a result, we don’t check if any
190+
symbols remain unresolved, and code can start to run even if there are.
191+
It will run successfully if they are not called in practice. If they
192+
are, you will get a runtime error. What went wrong should be clear from
193+
the stack trace (in an unminified build); building with
194+
``-s ASSERTIONS=1`` can help some more.
195+
196+
Limitations
197+
-----------
198+
199+
- Chromium does not support compiling >4kB WASM on the main thread, and
200+
that includes side modules; you can use ``--use-preload-plugins`` (in
201+
``emcc`` or ``file_packager.py``) to make Emscripten compile them on
202+
startup
203+
`[doc] <https://emscripten.org/docs/porting/files/packaging_files.html#preloading-files>`__
204+
`[discuss] <https://groups.google.com/forum/#!topic/emscripten-discuss/cE3hUV3fDSw>`__.
205+
- See also `webAssembly standalone <https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone>`_` for more on side modules in this context.
206+
207+
Pthreads support
208+
----------------
209+
210+
Dynamic linking + pthreads is not supported. It would require new wasm
211+
spec features (a way to share the Table), or some serious workarounds in
212+
the toolchain.

site/source/docs/compiling/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This section contains topics about building projects and running the output.
1919

2020
Building-Projects
2121
WebAssembly
22+
Dynamic-Linking
2223
Running-html-files-with-emrun
2324
Travis
2425
Deploying-Pages

0 commit comments

Comments
 (0)