Lesson 2 of 6
g++ hello.cpp -o hello looks like one step. It's actually four programs running in sequence,
and knowing which is which is how you'll diagnose build problems for the rest of your career.
hello.cpp
│ 1. preprocessor handles #include, #define — pure text substitution
▼
hello.i (expanded C++ source, still text)
│ 2. compiler C++ → assembly, and where type errors are found
▼
hello.s (assembly, still text)
│ 3. assembler assembly → machine code
▼
hello.o (object file — machine code, but incomplete)
│ 4. linker stitch object files + libraries together
▼
hello (executable)
You can stop g++ after any stage and look at what it produced. That's the rest of this lesson.
Stage 1: the preprocessor
The preprocessor handles every line starting with #. It doesn't understand C++ at all — it
does text substitution and nothing more. #include <iostream> means, quite literally, "paste the
entire contents of the iostream header here."
Run this to see the result:
g++ -E hello.cpp -o hello.i
wc -l hello.i
-E means "stop after preprocessing." wc -l counts lines. Your six-line program becomes tens of
thousands of lines — that's <iostream> and everything it includes, pasted in.
This is why C++ build times get bad: every file that includes a big header pays for the whole thing, every time it's compiled.
Stage 2: the compiler
This is the stage people mean when they say "the compiler." It parses the expanded source, checks types, applies optimizations, and emits assembly — a human-readable text form of machine instructions.
g++ -S hello.cpp -o hello.s
-S means "stop after compiling." Open hello.s and you'll see lines like movq, call,
ret. You don't need to read assembly, but it's worth looking at once: this is the shape of what
your CPU actually does.
Nearly every error you meet as a beginner comes from this stage — type mismatches, undeclared names, missing semicolons.
Stage 3: the assembler
The assembler translates that assembly text into actual machine code bytes, producing an object file.
g++ -c hello.cpp -o hello.o
-c means "compile and assemble, but don't link." The result is real machine code — but it's not
runnable yet. Your hello.o contains the compiled body of main, and a note saying "I call
something named operator<<, and I don't know where it lives."
This stage almost never fails. If your code assembled, the hard part is behind you.
Stage 4: the linker
The linker resolves those notes. It takes all your object files, plus the libraries you use (like
the C++ standard library, which supplies std::cout), and connects every call to the actual code
that implements it. Then it writes the final executable.
g++ hello.o -o hello
The linker knows nothing about C++ types or syntax. It works with names and addresses. That's why linker errors look so different from compiler errors — the subject of lesson 2.6.
Why this matters
When a build fails, the message alone tells you which stage broke, and each stage fails for completely different reasons:
| Stage | Typical failure |
| --- | --- |
| Preprocessor | fatal error: foo.h: No such file or directory |
| Compiler | error: 'x' was not declared in this scope |
| Assembler | (essentially never) |
| Linker | undefined reference to 'foo()' |
Knowing "this is a linker error, not a compiler error" cuts your search space enormously before you've even read the details.
Try it
Run all four commands above on your hello.cpp, then look at the sizes of what came out:
ls -l hello.cpp hello.i hello.s hello.o hello. Which file is biggest, and why is that
surprising at first?
Cleaning up
Those intermediate files aren't needed. Remove them:
rm -f hello.i hello.s hello.o
Checkpoint
- A build is four stages: preprocessor → compiler → assembler → linker.
-E,-S, and-cstop after stages 1, 2, and 3 so you can inspect the output.- The preprocessor is pure text substitution;
#includeliterally pastes a file in. - Type errors come from the compiler; "undefined reference" comes from the linker.
- Identifying the failing stage narrows a build problem before you read any details.
Questions about this lesson
Log in to ask a question.