Compiling and running

C++ · Essentials · 10 min

Every C++ program goes through this pipeline, and most confusing build errors make sense once you know its stages.

C++ is compiled ahead of time. You write source files (.cpp), a compiler turns each one into machine code in an object file (.o / .obj), and a linker joins the object files and libraries into an executable. The three mainstream compilers are GCC (g++), Clang (clang++) and MSVC (cl).

Each .cpp file is compiled on its own as a translation unit. First the preprocessor handles lines starting with #: #include <iostream> literally pastes the contents of that header into your file. Then the compiler checks and translates the code. Only at link time are calls into other files and libraries matched up with their definitions; an "undefined reference" error comes from the linker, not the compiler.

Always say which language standard you want with -std=c++20 (or -std=c++23; on MSVC /std:c++20), because compilers default to older or extended dialects. Then turn on help from the compiler:

  • -Wall -Wextra enable the warnings that flag most real mistakes; treat warnings as bugs (-Werror in CI).
  • -g adds debug info for gdb/lldb; -O2 optimises for release builds.
  • -fsanitize=address,undefined instruments the program to report out-of-bounds access, use-after-free and many kinds of undefined behaviour at run time. Use it in development and tests.

Compiling only what changed is the job of a build system (CMake, covered later); for a single file, one command is enough. Online, Compiler Explorer (godbolt.org) shows what any compiler does with a snippet.

Example

# hello.cpp contains a main() function
g++ -std=c++20 -Wall -Wextra -g hello.cpp -o hello
./hello

# development build with run-time bug detectors
clang++ -std=c++20 -Wall -Wextra -g -fsanitize=address,undefined hello.cpp -o hello

# optimised release build
g++ -std=c++20 -O2 hello.cpp -o hello

# several files: compile each to an object file, then link them
g++ -std=c++20 -c main.cpp -o main.o
g++ -std=c++20 -c util.cpp -o util.o
g++ main.o util.o -o app

# MSVC, from a Developer Command Prompt
cl /std:c++20 /EHsc /W4 hello.cpp

Remember

  • Source file -> preprocessor -> compiler -> object file -> linker -> executable
  • Always pass the standard explicitly: -std=c++20
  • Develop with -Wall -Wextra -g -fsanitize=address,undefined

Watch out for

  • Ignoring warnings: many real bugs (uninitialised variables, sign mismatches) show up as warnings first.

Check yourself

  1. You change only util.cpp in a project of main.cpp and util.cpp. What is the minimum work to rebuild?
  2. The build fails with "undefined reference to `parse(int)'". Which stage reported it?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: isocpp.org/get-started