Skip to content

Static vs. Dynamic Linking

The previous section covered how the linking stage combines object files with the libraries they depend on. Libraries themselves come in two forms — static and dynamic — and the two differ entirely in when and how they end up linked into the final program, which is the root of their respective tradeoffs.

Static libraries: bundled in wholesale at compile time

Section titled “Static libraries: bundled in wholesale at compile time”

A static library (typically a .a file on Linux) is essentially a bundle of object files packaged together. When linking against a static library, the linker copies the portion of code actually used from it directly into the final executable being produced.

This means the resulting executable is fully self-contained — the static library file itself doesn’t need to exist at runtime, since the code it needed has already been copied in. The tradeoff is a noticeably larger executable, and if multiple programs on the same machine all statically link the same library, that code gets duplicated on disk and in memory across each of them rather than being shared.

Dynamic libraries: loaded on demand at runtime

Section titled “Dynamic libraries: loaded on demand at runtime”

A dynamic library (typically a .so, or Shared Object, file on Linux) doesn’t get its code copied into the executable at link time — instead, the executable just records reference information: which dynamic library needs to be loaded at runtime, and which symbols (function/variable names) from it are needed. The actual code loading happens the moment the program starts running, handled by the operating system’s dynamic linker, which locates the corresponding .so file and maps the needed code into the program’s memory space.

This brings two direct benefits: the executable is noticeably smaller, since the library’s code isn’t copied in; and if the same dynamic library is depended on by multiple programs running at once, the operating system can let them share a single in-memory copy of that code instead of each holding its own separate copy.

Dimension Static linking Dynamic linking
When linking happens At compile/build time When the program starts
Executable size Larger (includes library code) Smaller (only reference info)
Distributing dependencies No extra library files to distribute Must ensure a matching version of the library exists in the runtime environment
Updating a library Requires recompiling the whole program Just replace the .so file — no recompile needed

The update advantage of dynamic linking comes with a matching risk: if the runtime environment is missing a dynamic library, or has a version that doesn’t match what the program was compiled against, the program fails outright at startup, unable to find the expected symbols. This class of problem is commonly called “dependency hell,” and it’s a category of issue that shows up far more often with dynamic linking than with static linking.

Checking which dynamic libraries an executable depends on

Section titled “Checking which dynamic libraries an executable depends on”
Terminal window
ldd /usr/bin/some-program

ldd lists every dynamic library a program depends on at runtime, along with whether the system can actually locate the corresponding file. If a line shows => not found, the program is missing that dependency and will very likely fail to start — this is a common first step when troubleshooting a program that “installed fine but won’t open.”

This topic is an important part of building a reliable Linux development workflow. Understanding it clearly will make later tasks easier, because it reduces guesswork and helps you recognize when a step is missing or misapplied.

  • Try the commands or configuration shown here in a safe test environment.
  • Compare how the concepts apply across different distributions or tools.
  • Keep a short note of what worked and what failed so you can diagnose future problems faster.
  • Revisit the related article in the series to deepen the connections between topics.
  • Skipping verification steps and assuming the system is configured correctly.
  • Copying commands without adapting paths, package names, or tool versions for your environment.
  • Treating this topic as an isolated tip rather than part of a larger workflow.