SimplifyC++ Article

Has the Age of DLLs Ended?

By Ayman AlherakiReads: 5Today: 5

Why modern applications should be self-contained, and dynamic linking should be a justified exception.

A new application should not begin with a hunt for a missing file. Users expect to download, copy, or install software and run it—not search for foo.dll on Windows, libfoo.so on Linux, or libfoo.dylib on macOS. When an application fails because a library is missing, a newer version broke compatibility, or the loader chose the wrong copy, that is not the user’s problem. It is a deployment-design problem.

Dynamic linking was created when memory and storage were scarce, and sharing one copy of a library made perfect economic sense. Today, saving a few megabytes is usually less important than ensuring that an application runs exactly as tested—on every machine and years later.

Platform Shared library Loader
Windows .dll Windows Loader
Linux and other ELF systems .so ld.so / ld-linux
macOS .dylib or a framework dyld

Static linking incorporates library code into the executable at build time. Dynamic linking leaves the application with information about an external library that the operating system must locate at startup or during execution. Microsoft’s documentation describes this distinction directly.

Dynamic linking still has legitimate strengths: centrally updating a component, sharing some code pages, and supporting plug-ins, drivers, and extensible platforms. But it becomes fragile when a self-contained application depends more on the host environment than on its own package: an ABI mismatch, an unexpected search path, an operating-system update, or a package manager removing a dependency it considered unused.

It is also a security concern. On Windows, DLL lookup involves multiple locations, and Microsoft warns that control of one searched directory can allow an attacker to place a malicious DLL there. See the Windows DLL search-order guidance. On Linux, library selection can be affected by RPATH, RUNPATH, LD_LIBRARY_PATH, and system paths; locating private libraries next to the application through a relative path such as $ORIGIN reduces that uncertainty. See ld.so(8).

Is the Hidden Motive Monopoly?

The mere use of a DLL, .so, or .dylib is not evidence of a conspiracy or monopoly; these are legitimate technologies. Yet dynamic dependency can become a form of technical control when a product runs only with a runtime, version, or service owned by one party that also controls its updates and distribution. That is not necessarily legal monopoly, but it can limit the user’s practical freedom to run, preserve, and reproduce software.

Static Linking: A Sound Default, Not a Blind Doctrine

Static linking is a sound default for deployment because what the developer tested is what the user receives. It reduces the chance of missing files and wrong versions. However, it is not a universal remedy: a security fix in a statically included library requires rebuilding and republishing the application, and system components—as well as platforms such as macOS—do not lend themselves to fully static deployment.

The right question is therefore not “static or dynamic?” but “does the application own everything it needs to run safely and predictably?”

A Practical Policy

  1. Statically link private, stable application libraries whenever practical and license-compatible.
  2. When dynamic linking is needed, ship the exact library version with the application: beside the executable on Windows, in a private lib directory on Linux, or inside a signed .app bundle on macOS.
  3. Do not require users to modify PATH or LD_LIBRARY_PATH, and do not scatter product libraries through system directories.
  4. Reserve dynamic linking for true extension points: a small, stable C ABI, an explicit version, and a trusted or signed source.
  5. Test the final package on a clean system and ship a clear component list, version information, and signed updates.

Dynamic linking has not ended, but it should no longer be the automatic choice for an independent application. The default should be a program that runs from its own package, with dynamic linking used only when it provides a real capability—not when it transfers an old dependency problem to the user.

A good application owns what it needs to run; it does not require users to become experts in DLL, SO, and DYLD before its first window can open.

Technical References

Actual visitors 85,173
Visitors today 765
Total page views 1,729,855
Page views today 1,069
Book downloads 17,414