In this post, I’ll break down the C++ build pipeline step-by-step — from preprocessing and compilation to linking and execution. Whether you’re revisiting the basics or deepening your systems-level knowledge, this guide will help demystify what actually happens when you hit “build”.
Initial Program
|
|
Step 1: Preprocessing
-
Purpose
- Preprocessor expands macros (#define INPUT 5)
- It would also process: #include headers, #ifdef, #pragma, etc.
- Comments are removed
-
Run
clang++ -E square.cpp -o square.i
Result
|
|
Step 2: Compile to Assembly
-
Purpose:
- Compiler translates C++ code into assembly code (human-readable, low-level instructions).
- This is architecture-specific (e.g., x86_64 or ARM).
-
Run
clang++ -S square.i -o square.s
Result
|
|
- You’ll now have a file square.s, which contains assembly instructions.
Step 3: Assemble to Object Code
-
Purpose:
- The assembler turns the assembly code into binary machine code
- This is stored in an object file (.o), which can’t run on its own
-
Run
clang++ -c square.s -o square.o
-
Disassemble with
objdump -SC square.o > square.lst
to see what’s going on withsquare.o
since we cannot open a binary file
Result
|
|
Step 4: Link to Executable
-
Purpose:
- The linker takes your object file, startup/runtime code (such as _start), and any required standard library functions (e.g., std::cout if used), and links them together into a single executable.
-
Run
clang++ square.o -o square
Result
|
|