Overview

7 Dynamic linking: the basics

This chapter introduces dynamic linking for WebAssembly as the runtime process of connecting multiple modules so that unresolved symbols in one module resolve to definitions in another. It explains why teams might adopt this approach: faster iteration by rebuilding only changed parts, code sharing (for example, a reusable engine linked by several apps), reduced initial download via on-demand loading, and better use of the browser cache. It also cautions about trade-offs, including more complex builds, extra network requests, additional instantiation work, and potential performance overhead (often 5–10% or more), especially when many cross-module calls occur—reinforcing the need to measure whether dynamic linking fits a given scenario.

The chapter clarifies Emscripten’s module roles: side modules and a main module. Side modules omit Emscripten’s generated JavaScript and standard C library, assuming they will link against a single main module at runtime; the main module includes the necessary runtime and libraries and can be linked with multiple side modules (note that “main module” is unrelated to the presence of a main() function). It outlines the relevant build flags (SIDE_MODULE and MAIN_MODULE) and shows how side modules rely on the main module’s facilities, including I/O. Practical considerations—such as placing a .wasm on Emscripten’s in-memory filesystem when needed—are highlighted to make dynamic linking work in the browser.

Three dynamic linking techniques are compared. With the C/C++ dlopen approach, you programmatically open a side module, use dlsym to acquire function pointers, and can even call functions that have name collisions with your own, because resolution is done via the side module’s handle. With the dynamicLibraries approach, you declare side modules in Module.dynamicLibraries so Emscripten downloads and links them automatically at startup; calls look like normal function calls, but name collisions resolve to the local function. Finally, the WebAssembly JavaScript API path gives full frontend control: fetch and instantiate modules manually, then wire one module’s exports as another’s imports. The choice hinges on where you want control—backend code (dlopen), tooling (dynamicLibraries), or frontend JavaScript (manual API)—balanced against performance, complexity, and deployment needs.

At runtime, the logic from one module (Module 2 in this case) is linked to another module (Module 1 in this case) allowing the two to communicate and act as one.
Using Emscripten to generate a WebAssembly module as a side module. No standard C library functions are included in the module and the Emscripten JavaScript file is not generated in this case.
Using Emscripten to generate a WebAssembly module as a main module. The standard C library functions are included in the module and the Emscripten JavaScript file is also generated in this case.
The steps to modify calculate_primes.cpp so that it can be compiled into a WebAssembly side module. Then the steps to create a WebAssembly main module that will link to the side module by calling the dlopen function.
The first step in implementing dynamic linking using dlopen is to modify the calculate_primes.cpp file so that it can be compiled into a side module.
Use Emscripten to generate the WebAssembly file as a side module.
The third step of the process to implement dynamic linking using dlopen is to create the logic that will use dlopen to link to the side module.
The fourth step of the process to implement dynamic linking using dlopen is to use Emscripten to generate the WebAssembly module as a main module from the main.cpp file. In this case, you’ll also use Emscripten to generate the HTML file.
When the webpage is viewed, a link error is thrown about a missing _putchar function.
The prime numbers determined by the side module and displayed to the webpage using the printf function that’s part of the main module.
The steps to create the WebAssembly main module that will instruct Emscripten’s dynamicLibraries array about which side module you want it to dynamically link to.
The first step toward implementing dynamic linking using dynamicLibraries is to create the main.cpp file.
Your second step when implementing dynamic linking using dynamicLibraries is to create the JavaScript code that will instruct Emscripten to link to your side module.
The last step of the process when implementing dynamic linking using dynamicLibraries is to have Emscripten generate the WebAssembly module.
The prime numbers determined by the side module when both modules were linked together by using Emscripten’s dynamicLibraries array.
The steps to modify calculate_primes.c file so that it can be compiled into two WebAssembly side modules. The generated WebAssembly files are copied to the server and then the HTML and JavaScript files are created to load, link, and interact with the two WebAssembly modules.
The first step toward implementing manual dynamic linking using the WebAssembly JavaScript API is modify the calculate_primes.c file so that its logic is now part of two files.
Step two is to use Emscripten to generate the WebAssembly side modules from your two files.
The final steps are to create the HTML and JavaScript files that will load, link, and interact with the WebAssembly modules.
The prime numbers between 3 and 100 logged by the find_primes WebAssembly module

Summary

In this chapter, you learned the following:

  • Like with most things, there are pros and cons to using dynamic linking. Before pursuing this approach, you should decide if the advantages outweigh the disadvantages for your application.
  • Dynamic linking can be performed as needed by your WebAssembly’s code using the dlopen function.
  • It’s possible to tell the Emscripten generated JavaScript that you want certain side modules linked to your main module. Emscripten will automatically link the modules together during instantiation.
  • Through the use of the WebAssembly JavaScript API, it’s possible to manually download, instantiate, and link multiple side modules together.
  • You can control the execution of Emscripten’s generated JavaScript by creating a Module object before Emscripten’s JavaScript file is included on the webpage. You can also adjust the Module object by including your own JavaScript in Emscripten’s generated JavaScript file by using the --pre-js command line flag when compiling the WebAssembly module.

FAQ

What is dynamic linking in WebAssembly, and what problem does it solve?Dynamic linking lets two or more WebAssembly modules resolve and call each other’s symbols at runtime, without merging them into a single binary. It helps you reuse shared logic (for example, a game engine) across multiple modules, reduces initial download by loading only what’s needed, speeds up development by rebuilding just changed modules, and benefits from browser caching so unchanged modules aren’t redownloaded.
What are the main downsides or performance costs of dynamic linking?It adds build and deployment complexity because you now manage multiple modules. Page load can involve more network requests and extra work at instantiation time to link modules. Cross-module function calls are typically slower than calls within a single module, and Emscripten notes a 5–10% (or more) overhead depending on code structure.
How do “main” and “side” modules differ in Emscripten?A main module (built with -s MAIN_MODULE=1) includes the Emscripten runtime glue and system libraries needed for dynamic linking. Side modules (built with -s SIDE_MODULE=2) omit those libraries and depend on a main module at runtime. You can link multiple side modules to one main module, and the placement of your program’s main() function is independent of being a “main” module.
What dynamic linking options does Emscripten support?There are three: 1) In C/C++, call dlopen/dlsym/dlclose to load and bind side modules. 2) Use the Module['dynamicLibraries'] array so Emscripten automatically downloads and links specified side modules at startup. 3) Use the WebAssembly JavaScript API yourself to fetch, instantiate, and wire exports from one module as imports to another.
When should I prefer the dlopen approach?Choose dlopen when you want linking control inside your C/C++ code or you must call a function in a side module that has the same name as a function in your main module (dlopen resolves by handle + symbol, avoiding collisions). With dlopen, the side module must exist in Emscripten’s virtual file system; you can download it with emscripten_async_wget, then use dlopen to load, dlsym to look up functions, and dlclose to release.
How do I compile modules as side or main modules with Emscripten?Build a side module with a command like: emcc file.c -s SIDE_MODULE=2 -O1 -o file.wasm. Build a main module with: emcc main.cpp -s MAIN_MODULE=1 -o main.html. If you hit missing symbols at runtime (for example, _putchar), export them explicitly via -s EXPORTED_FUNCTIONS=['_putchar','_main'] rather than using -s EXPORT_ALL=1, which can bloat output.
How does the dynamicLibraries approach work in practice?Specify your side module filenames in Module['dynamicLibraries'] before the Emscripten runtime initializes (for example via --pre-js pre.js). Emscripten will download and link those side modules automatically during startup. You then declare and call side-module functions like normal C/C++ functions; however, if a function name exists in both modules, your module’s own symbol wins (you can’t disambiguate like dlopen can).
How do I manually link modules using the WebAssembly JavaScript API?Fetch and instantiate the first side module (for example, one exporting _IsPrime). Then build an import object for the second module that includes the needed exports from the first module and any JS callbacks (for example, _LogPrime). Instantiate the second module with that import object, and then call its exported functions. Both modules should be compiled as side modules (no Emscripten runtime or libc expected).
Why does dlopen need Emscripten’s file system and how do I use it?dlopen loads a file by path, so the side module must be visible to the module in its virtual file system. Emscripten provides an in-memory FS by default, accessible from the generated JS via FS; you can download files into it at runtime using emscripten_async_wget and then open them via dlopen. Remember that this default FS is not persistent across page reloads.
How should I choose between dlopen, dynamicLibraries, and manual JS API linking?Use dlopen if you need in-module control or must call a side-module function that shares a name with one in your main module. Use dynamicLibraries for simplest integration where Emscripten handles downloading and linking at startup. Use the WebAssembly JS API when you want full frontend control (custom download timing, fine-grained wiring of imports/exports, or when not relying on Emscripten’s runtime).

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free