Skip to content
Theory · Your First Program · lesson 5 of 7

Compiling and linking

Remember the translator and the bookbinder from the first lesson. A thick book is translated chapter by chapter, and the translator of each chapter sees only that chapter. If chapter 1 says "see chapter 3", the translator takes the reference on trust. Whether chapter 3 exists is checked by the bookbinder, who sews the whole book together.

A C++ program often consists of several .cpp files, the way a book consists of chapters. The compiler translates each file separately and, while reading one, does not see what the other files contain. But a function call compiles only if the compiler already knows that the function exists. Here is a program made of two files: main.cpp calls the function triple, and its body is in triple.cpp.

The file main.cpp:

C++
#include <iostream>

int triple(int x);

int main() {
    std::cout << triple(14) << '\n';  // 42
}

The file triple.cpp:

C++
int triple(int x) {
    return x * 3;
}

The two steps together—compiling both files and linking them into one program—are called the build.

Declaration and definition

The line int triple(int x); in main.cpp is a declaration—that very "see chapter 3" reference. It repeats the function's first line:

  • the return type;
  • the name;
  • what the function takes, in parentheses.

A semicolon stands in place of the body. The declaration is enough for the compiler to check the call triple(14): the function takes an int and returns an int.

triple.cpp holds the definition—the same first line together with the body in curly braces. A function can be declared in every file that calls it, but defined in only one.

How a call works

Let's go through what happens on the call triple(14):

  1. x in int triple(int x) is a parameter, the function's own variable. On the call it receives the value in the parentheses, here 14.
  2. return x * 3; computes 14 * 3 and ends the function.
  3. The result 42 goes back to the place of the call, and std::cout prints it.

Several parameters are separated by commas: int add(int a, int b). The operators +, - and * work on integers as in arithmetic.

Who reports the error

The compiler finds errors in the text of one file—for example, a missing semicolon, as in the Hello, world program. Thanks to the declaration, it also catches the call triple(14, 1) with an extra number. No object file appears in that case.

The linker sees the whole program and looks for a definition of every function that is called. If triple.cpp is left out of the build, main.cpp compiles without errors, but the linker stops—like a bookbinder who has no chapter 3:

TEXT
undefined reference to `triple(int)'

That is how GNU ld, the default linker on Linux, puts it. In the course exercises the same message reads differently: undefined symbol: triple(int).

Build the program below, then take triple.cpp out of the build and watch which object file defines the triple(int) that main.o needs and what the linker reports:

LiveA two-file buildnot built yet
source files
main.cppalways in the build
triple.cpp
object files
not built yet
linker
not built yet

The compiler translates each .cpp file on its own, and the linker joins the object files into a program. Press the build button.

Take triple.cpp out of the build and build again

A compiler message names a file and a line, such as main.cpp:6. A linker message names the function that has no definition.

Common mistake

The name in the definition must match the declared one exactly. Here, in triple.cpp, it starts with a capital letter:

C++
int Triple(int x) {  // ✗
    return x * 3;
}

Both files compile without errors, but the linker again cannot find triple(int). C++ tells uppercase and lowercase letters apart, so Triple is a different function, and the declared triple still has no definition.

Key points

  • The compiler translates each .cpp file separately, and a declaration is enough for it to compile a call.
  • The linker looks for a definition of every called function across the whole program.
  • No definition means the linker error undefined reference, even though every file compiled.
  • A parameter receives the value from the call, and return hands the result back to the place of the call.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way