static versus dynamic linking
When your program uses a library, there is a choice about when the library's code gets joined to your program. You can bake it in at build time, copying the library code right into your executable, or you can leave a reference and have the library found and connected only when the program runs. These two answers are static linking and dynamic linking. The cookbook analogy: either photocopy every recipe you need into your own binder (static), or just write down which shared cookbook on the shelf to grab when you actually cook (dynamic).
With static linking, the linker copies the needed library routines into the final executable. The result is a single self-contained file that carries everything it needs; it runs with no external dependencies and the library version is frozen at build time. With dynamic linking, the executable instead records the names of shared libraries it needs; at run time the dynamic loader finds those libraries (files like .so on Linux or .dll on Windows), maps them into memory, and fixes up the references. Many running programs can then share one copy of a library in memory, and updating the shared library (say, a security fix) upgrades every program that uses it without rebuilding them.
Each choice is an honest trade-off, not a winner. Static linking gives bigger executables and duplicated code across programs, but maximum portability and no surprise about which library version runs. Dynamic linking gives smaller executables and shared, updatable libraries, but introduces run-time dependencies (the dreaded missing-shared-library error) and the possibility that an updated library subtly changes behavior. Neither is universally right; the choice depends on whether you value self-containment and predictability or smaller size and easy shared updates.
Two builds of the same program using a math library: Static : the math routines are copied inside the executable. One big file, no external needs, frozen library version. Dynamic: the executable just says 'I need libm'. At launch the dynamic loader maps libm into memory and links it. Smaller file, shared in memory, but it fails to start if libm is missing.
Static bakes the library in at build time; dynamic finds and links it at run time. Each trades size against dependencies.
Neither is simply better. Dynamic linking saves space and lets one security patch fix every program, but adds run-time dependencies; static linking is self-contained but freezes the library version and bloats every binary.