Skip to content

Build Systems

C++ code needs to be compiled and linked. While you can use the compiler directly, build systems automate this process.

The Compilation Process

Understanding what happens when you run g++ main.cpp is crucial.

  1. Preprocessing (.cpp -> Translation Unit): - Handles directives like #include, #define, #ifdef. - The output is a pure C++ file with all headers pasted in. - Command: g++ -E main.cpp > main.i
  1. Compilation (Translation Unit -> Assembly .s): - Translates C++ code into assembly language for the target architecture. - Command: g++ -S main.i
  2. Assembly (Assembly -> Object File .o): - Translates assembly into machine code. - The object file contains code but unresolved symbols (functions defined elsewhere). - Command: g++ -c main.s
  3. Linking (Object Files + Libs -> Executable): - Combines multiple .o files and libraries. - Resolves symbols (e.g., connecting a call to std::cout to the standard library). - Command: g++ main.o utils.o -o my_program

Make

The classic build tool. It uses a Makefile to define rules.

Basic Makefile

CXX = g++
CXXFLAGS = -std=c++20 -Wall -Wextra

# Target: Dependencies
# [TAB] Command

all: my_program

# $@ = Target name (my_program)
# $^ = All dependencies (main.o utils.o)
my_program: main.o utils.o
    $(CXX) $(CXXFLAGS) -o $@ $^

# Pattern rule: How to build .o from .cpp
# $< = First dependency (%.cpp)
%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

clean:
    rm -f *.o my_program
.PHONY: clean all

CMake

The modern standard. It generates build files (like Makefiles or Ninja) for you. It is cross-platform and handles dependencies gracefully.

Modern CMake uses "Targets". Avoid global variables like include_directories.

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 1. Define the executable (The Target)
add_executable(my_program main.cpp utils.cpp)

# 2. Add include directories to the Target
# PRIVATE means only this target needs this include path
target_include_directories(my_program PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)

# 3. Link libraries to the Target
# target_link_libraries(my_program PRIVATE some_lib)

Building with CMake

1
2
3
4
mkdir build
cd build
cmake ..
cmake --build .

Libraries

  • Static Library (.a / .lib): Code is copied into your executable. Larger size, no runtime dependency.
  • Dynamic/Shared Library (.so / .dll): Code is loaded at runtime. Smaller executable, requires library to be present.