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

Compiling and linking

A C++ program often consists of several .cpp files. 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. It repeats the function's first line: the return type, the name and what the function takes. 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.

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:

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).

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.