$ g++ -c main.cpp$ g++ -c square.cpp$ nm -C main.oT mainU square(int)$ g++ main.o square.o -o app$ ./app49$ g++ main.o -o appundefined reference to square(int)$ g++ -c square.cpp$ g++ main.o square.o -o app$ ./app49appmain.odefines mainneeds square✓✗square.odefines square1#include <iostream>/* <iostream> text */2#include "square.h"int square(int x);3int main() {4 std::cout << square(7);5}1#pragma once2int square(int x);1#include "square.h"int square(int x);2int square(int x) {3 return x * x;4}01010101!
Violet cards: source files; italic lines are what an #include pastes inSand blocks: the compiler and the linker; plum cards: object files with their symbol tablesTokens: source text hopping in, machine code (01) hopping out, a red ! for a link errorIn front: the source files main.cpp, square.h (a header) and square.cpp. In the middle: the compiler. At the back: the terminal, the executable app, the linker and the object files main.o and square.o with their symbol tables. Each .cpp file plus the headers it includes is one translation unit, compiled on its own into an object file. The linker matches main.o's need for square with square.o's definition and writes app, which prints 49. Leave square.o out and the link fails with an undefined reference; define square twice and it fails with a multiple definition. The C++ standard describes nine phases of translation and calls a source file together with everything it includes, after preprocessing, a translation unit. The figure shows the preprocessor and compiler as one step, as g++ -c runs them.

Files and headers

  1. Real programs are split into many files. Here main.cpp calls a function named square, and square.cpp holds its code. The third file, square.h, is a header: a small file that other files include to learn what square looks like.

Compiling

Linking

Rules and speed

What happens

;; step 1/11 · files
square.h
  1  #pragma once
  2  int square(int x);
main.cpp
  1  #include <iostream>
  2  #include "square.h"
  3  int main() {
  4    std::cout << square(7);
  5  }
square.cpp
  1  #include "square.h"
  2  int square(int x) {
  3    return x * x;
  4  }

The C++ standard describes nine phases of translation and calls a source file together with everything it includes, after preprocessing, a translation unit. The figure shows the preprocessor and compiler as one step, as g++ -c runs them. nm output is shortened: real lines start with an address, and on macOS C++ symbols carry an extra leading underscore (__Z6squarei). -C (demangle) turns _Z6squarei back into square(int).