g++ -E file.cpp # preprocess
g++ -c file.cpp # compile to file.o
g++ file.o -o app # link
C++
Topics in this category
Casting & Conversions
Compilation & Linking
Concepts & Constraints
Concurrency
Const Correctness
Constexpr & Compile-Time
Coroutines
Enums & Enum Classes
Exception Handling
I/O Streams
Lambda Expressions
Memory Management
Modern C++
Move Semantics
Namespaces
OOP & Classes
Operator Overloading
Preprocessor & Macros
RAII & Smart Pointers
Ranges & Views
C++
Compilation & Linking
Building involves: preprocessing (handling #include/#define to produce a translation unit), compilation (translating each translation unit to an object file, checking syntax and types), and linking (combining object files and libraries, resolving symbol references, into an executable or library). Understanding the stages helps diagnose where an error (preprocessor, compiler, or linker) occurs.
Real-world example
A 'undefined reference' error is a linker error, not a compiler error—knowing the stages pinpoints the fix.
Preprocessor & Macros
Compilation & Linking
Compilation & Linking
A translation unit is a single source file after preprocessing—the .cpp file with all its #included headers textually expanded. The compiler processes one translation unit at a time into an object file. Concepts like internal linkage and the one-definition rule are defined in terms of translation units.
Real-world example
Each .cpp plus its expanded headers is one translation unit compiled independently into a .o file.
Preprocessor & Macros
Compilation & Linking
Compilation & Linking
A declaration introduces a name and its type (promising it exists somewhere); a definition also provides the implementation/storage. You can declare something many times but define it only once (per the ODR). Header files typically contain declarations; source files contain definitions. Using an undeclared name is a compile error; a missing definition is a link error.
extern int x; // declaration
int x = 5; // definition
void f(); // declaration
void f(){} // definition
Real-world example
A function declared in a header but never defined causes an 'undefined reference' at link time.
Compilation & Linking
Namespaces
Compilation & Linking
The ODR states that every entity (variable, function, class, template) must have exactly one definition across the whole program (with specific exceptions: inline functions/variables and templates may be defined identically in multiple translation units). Violating the ODR—e.g., two different definitions of the same function—is undefined behavior, often a link error or subtle bug.
Real-world example
Defining a non-inline function in a header included by two files causes an ODR-violation multiple-definition link error.
Compilation & Linking
Templates
Compilation & Linking
External linkage means a name is visible across translation units (can be referenced from other files)—the default for non-const globals and functions. Internal linkage confines a name to its translation unit—given by static at namespace scope or an anonymous namespace, or by const/constexpr namespace-scope variables. Linkage controls symbol visibility and helps avoid multiple-definition clashes.
static int helper(); // internal linkage
int globalCounter; // external linkage
Real-world example
Marking a file-local helper static (internal linkage) prevents a symbol clash with a same-named function elsewhere.
Namespaces
Compilation & Linking
Compilation & Linking
It means a symbol was declared and used but the linker couldn't find its definition: a missing source file/object, a library not linked, a function declared but never defined, a signature mismatch (name mangling differs), or forgetting extern "C" for C functions. The fix is to provide/link the definition or correct the declaration.
// declared void f(); used f(); but f never defined -> undefined reference
Real-world example
Forgetting to link the math library or a .cpp file yields an 'undefined reference' at link time.
Compilation & Linking
Namespaces
Compilation & Linking
Name mangling is how the C++ compiler encodes a function's name together with its namespace, class, and parameter types into a unique linker symbol—necessary because C++ supports overloading (same name, different parameters). It's why linker errors show decorated names and why calling C code needs extern "C" (which disables mangling for C-compatible names).
// void f(int) and void f(double) get different mangled symbols
Real-world example
A link error shows a mangled symbol; demangling it reveals the exact overloaded function that's missing.
Compilation & Linking
Namespaces
Compilation & Linking
A static library (.a/.lib) is copied into the executable at link time—larger binary, no runtime dependency, updates require relinking. A dynamic/shared library (.so/.dll) is linked at load/run time—smaller executables, shared across programs, updatable without relinking, but the library must be present at runtime and version compatibility matters. The choice trades deployment simplicity against flexibility and size.
g++ main.o -lmylib # link against libmylib (static or shared)
Real-world example
Shipping a plugin as a shared library lets it be updated without rebuilding the host application.
Compilation & Linking
Compilation & Linking
Compilation & Linking
Headers are textually included into every translation unit that uses them, potentially multiple times via transitive includes. Without guards, a header's declarations/definitions would be duplicated within one translation unit, causing redefinition compile errors. Guards ensure the header's contents appear once per translation unit, complementing the ODR across translation units.
Real-world example
An unguarded header included twice in one .cpp triggers 'redefinition' errors the guard prevents.
Preprocessor & Macros
Compilation & Linking
Compilation & Linking
Modules (C++20) are a new way to organize code that replaces textual #include with a compiled, importable unit (import mymod;). They avoid repeatedly re-parsing headers (faster builds), don't leak macros or private details, remove include-order fragility, and give better encapsulation. Adoption is gradual as tooling matures, but modules address longstanding header/preprocessor problems.
export module math;
export int add(int a, int b);
// user: import math;
Real-world example
Migrating heavy headers to modules cuts compile times by avoiding repeated header parsing.
Preprocessor & Macros
Modern C++
Compilation & Linking