The Big Picture: Two Ways to Use a Library
A programmer writes code, but does not write everything. To draw a window or read a file, they use ready-made library code. The question is: how does that library code get connected to the program? There are two answers.
An everyday picture: you are cooking a big dinner and need a recipe for sauce.
- Static linking = you copy the recipe onto your own page. It is always with you, but your page is longer and your copy never updates.
- Dynamic linking = you write "see the cookbook on the shelf, page 40". Your page stays short, but the cookbook must be on the shelf when you cook.
2.1 Static Linking: Code Copied In at Build Time
What it is: Linking is the last step of building a program. A tool called the linker joins your compiled code with the library code it needs. In static linking, the linker copies the needed library code into the EXE file.
Your code (.obj) ─┐
├──> LINKER ──> program.exe
Library (.lib) ─┘ (your code + a COPY of the library
code, all in one file)
Terms used here:
- Compiler: turns the programmer's text into machine code (
.objfiles). - Linker: joins
.objfiles and libraries into one finished program. .libfile: a library for the linker. A static.libholds the actual code to copy.
Good points:
- The program is self-contained. Copy the one file to another PC and it runs.
- No "missing DLL" surprise for that library.
- The code can be tuned for that program, since only the parts used are copied.
Bad points:
- The EXE is bigger.
- Ten programs using the same library hold ten copies on disk and in RAM.
- A bug fix in the library means rebuilding and re-shipping every program.
2.2 Dynamic Linking: Code Loaded Separately at Run Time
What it is: In dynamic linking, the EXE does not hold the library code. It only holds a note: "I need the function CreateFileW from kernel32.dll." When the program starts (or later), Windows finds the DLL and connects the two.
Your code (.obj) ─┐
├──> LINKER ──> program.exe
Import library ─┘ (your code + a list of
(small .lib file) "I need these functions" notes)
later, at run time:
program.exe + kernel32.dll ──> connected in memory by Windows
An import library is a small .lib file that has no code, only the names of the functions a DLL offers, so the linker can write the right notes.
Dynamic linking happens in two ways (details in Section 3):
| Kind | When the DLL is connected | How |
|---|---|---|
| Load-time (implicit) | When the program starts | The notes (the import table) are filled in by Windows before the program's first line runs |
| Run-time (explicit) | When the program asks | The code calls LoadLibrary and GetProcAddress itself |
Delay-load: a middle way. The linker can also produce a delay-load program. The DLL is listed in the import table, but Windows connects it only the first time a function from it is called. That way a rarely used DLL costs nothing at startup. (Hedge: this is a Microsoft linker feature; it is not used by every program.)
2.3 Trade-offs: Size, Updating and Sharing
What it is: Neither way is "better". Each fits different needs.
| Static linking | Dynamic linking | |
|---|---|---|
| EXE size | Bigger | Smaller |
| Disk use (many programs) | Each has a copy | One shared DLL |
| RAM use (many programs) | Each loads its own copy | Code pages shared (Section 1.2) |
| Updating the library | Rebuild every program | Replace one DLL |
| Start-up | A little faster (nothing to find) | Slightly slower (find and connect DLLs) |
| Missing file risk | None | "DLL not found" errors possible |
| Version conflicts | None, you ship your version | Possible ("DLL hell", Section 7) |
| Security fixes | You must ship them | Arrive through Windows Update |
| Portability | Copy one file | Must bring the right DLLs along |
A visual: three programs, same library.
STATIC DYNAMIC
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ App A │ │ App B │ │ App C │ │ App A │ │ App B │ │ App C │
│ +lib copy│ │ +lib copy│ │ +lib copy│ └───┬────┘ └───┬────┘ └───┬────┘
└──────────┘ └──────────┘ └──────────┘ └──────────┼──────────┘
3 copies of the library ┌──────┴──────┐
│ lib.dll │
└─────────────┘
1 shared copy
Real life on Windows: Most of the Windows API is dynamic. But many programs mix both. For example, a program may statically link a small helper library and dynamically use kernel32.dll. The Visual C++ runtime (the helper code every C/C++ program needs) can even be linked either way: dynamically, which requires the matching vcruntime DLLs to be installed, or statically, which makes a larger, self-contained EXE. (Hedge: the choice is a compiler setting.)
Windows-specific tip: Why do some programs come with an installer that adds "Microsoft Visual C++ Redistributable"? Because they were linked dynamically to the Visual C++ runtime DLLs. The installer makes sure those shared DLLs exist on your PC.
Which should you choose?
- Small tool you give to a friend, no installation: static is easy.
- Big program family sharing code: dynamic saves space and makes updates easy.
- Code that must get urgent security fixes: dynamic lets the fix arrive without a new build.
Summary
| Topic | Remember this |
|---|---|
| Static linking | The linker copies library code into the EXE at build time |
| Dynamic linking | The EXE holds notes; Windows connects the DLL at run time |
| Import library | A small .lib with names only, no code |
| Load-time vs run-time | Load-time uses the import table; run-time uses LoadLibrary and GetProcAddress |
| Delay-load | Connect on first call, not at start |
| Trade-off | Static = self-contained but big; dynamic = small, shared, easy to update, but can break if a DLL is missing |