Link-time optimization (LTO) (-flto) defers optimization until link time, when the compiler has the entire program visible. This enables optimizations across translation units—inlining functions from other files, eliminating unused code globally, and whole-program analysis.
gcc -O3 -flto -o app a.c b.c c.c
With -flto, each .c file is compiled to intermediate representation (not native code), then optimized and linked together at the end. This takes longer to compile but can produce significantly faster code.
Compilation process with LTO:
gcc -O3 -flto -c a.c -o a.o # intermediate representation, not native code gcc -O3 -flto -c b.c -o b.o gcc -O3 -flto -c c.c -o c.o gcc -O3 -flto a.o b.o c.o -o app # link and optimize together
Each object file is intermediate code. The linker (with -flto) reoptimizes and produces the final native code.
Advantages:
1. Cross-file inlining—functions defined in a.c can be inlined into b.c
2. Whole-program dead code elimination—unused functions across the entire program are removed
3. Global data flow analysis—the compiler understands how data flows through the entire program
4. Smaller binary—unused code is completely eliminated
Disadvantages: 1. Slower compilation—optimization happens at link time, which can take minutes 2. More memory—the compiler loads the entire program's intermediate code 3. Linker complexity—requires LTO-capable linker (usually available on modern systems)
Use cases: LTO is most valuable for large programs with many files and clear unused code. For small programs or embedded systems with size constraints, it can be worth the extra compilation time.
File size reduction: LTO often produces smaller binaries than -O3 without LTO because it eliminates unused functions globally:
gcc -O3 -o app a.c b.c c.c # ~5MB gcc -O3 -flto -o app a.c b.c c.c # ~3.5MB (dead code removed)
Performance trade-off: Sometimes LTO produces faster code (better inlining, dead code removal). Sometimes it produces slower code if aggressive inlining increases code size and hurts cache behavior. Measure both.
Incremental builds: With LTO, every link operation requires optimization. -flto=thin (thin LTO) speeds up this by doing parallel optimization:
gcc -O3 -flto=thin -o app a.c b.c c.c
Thin LTO is faster than full LTO but produces less optimal code. Good compromise for development builds.