Building with CMake
A single
g++ file.cpp -o app command works fine for one file, but real projects have dozens or hundreds of source files, external libraries to link, and need to build on Windows, macOS, and Linux with different compilers. Typing out every source file and flag by hand doesn't scale — that's the job of a build system.Why CMake specifically
CMake has become the de facto standard build tool for C++ projects. Rather than compiling code directly, CMake is a build system generator: you describe your project once, in a file called
CMakeLists.txt, and CMake generates the actual platform-native build files — Makefiles on Linux, Visual Studio project files on Windows, Ninja files, and more — from that single description.A minimal CMakeLists.txt
CMakeLists.txt
Text
cmake_minimum_required(VERSION 3.16) project(MyApp VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(my_app main.cpp helpers.cpp)
cmake_minimum_requireddeclares the oldest CMake version the project supports.project()names the project and declares which languages it uses.set(CMAKE_CXX_STANDARD 17)picks the C++ standard version to compile against.add_executable(name file1.cpp file2.cpp ...)declares an executable target built from those source files.
The typical build workflow
CMake projects are built out-of-source — generated build files and object files live in a separate directory, keeping your source tree clean.
terminal
Bash
# Configure: generate build files into a "build" directory cmake -B build # Build: actually compile, using whichever generator CMake picked cmake --build build # Run the resulting binary ./build/my_app
cmake -B build reads CMakeLists.txt and writes out Makefiles (or another generator's files) into build/. cmake --build build then invokes the right underlying tool (make, ninja, MSBuild, etc.) to actually compile — you don't need to know or care which one is being used underneath.Linking a library
Most non-trivial projects depend on other libraries, whether third-party or another target within the same project.
target_link_libraries() connects an executable (or library) target to the libraries it needs.CMakeLists.txt (with a library)
Text
cmake_minimum_required(VERSION 3.16) project(MyApp LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) add_library(math_utils math_utils.cpp) add_executable(my_app main.cpp) target_link_libraries(my_app PRIVATE math_utils)
Here
math_utils is compiled as its own library target, and my_app is linked against it. The same function works for linking external packages found with find_package(), such as Boost or a system library.CMake generates build files — it doesn't build directly
This is the core mental model to keep: running
cmake never compiles a single line of your code by itself. It only produces the platform-native project files. The actual compilation happens in the second step (cmake --build), delegated to whatever native build tool CMake generated files for.