|
| 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. |
0 commit comments