The recipe
A real project has many files. Typing a compiler command for each one is slow and easy to get wrong. With CMake you describe the project once, in a file called CMakeLists.txt, and CMake works out the commands.
A target is one thing to build. Line 4 makes a library, greet, from greet.cpp. Line 5 makes the program app from main.cpp. Line 6 says app uses greet, so greet must be built first and linked in.
Configure
Step one: cmake -S . -B build. CMake reads the recipe, finds your C++ compiler and writes a build system into a separate folder, build/. Your source folder stays clean: to start over, delete build/.
The build system holds a graph: each output file and the files it is made from. greet.o comes from greet.cpp and greet.h. app comes from main.o and libgreet.a. This graph decides what to build, and in what order.
Build
Step two: cmake --build build. The build tool walks the graph. greet.cpp and main.cpp do not need each other, so with Ninja (-G Ninja) the compiler can turn them into greet.o and main.o at the same time, on two CPU cores.
Next greet.o is packed into the library libgreet.a. Then the linker joins main.o with libgreet.a into the program app. The graph sets the order: no file is made before the files it is made from.
The program is in the build folder: run ./build/app and it prints Hello, CMake! Build again straight away and nothing happens: every output is newer than its inputs, so all is up to date.
Rebuild fast
Change greet.cpp and build again. The build tool compares file times: greet.cpp is now newer than greet.o, so greet.o is rebuilt, then libgreet.a and app. main.o is still up to date, so main.cpp is not compiled.
Change greet.h instead. Both .cpp files include it, so greet.o and main.o are both out of date and all four files are rebuilt. You never listed greet.h: the compiler reports each file's headers to the build tool.
Fast code
How fast the program runs is a setting too. With CMAKE_BUILD_TYPE=Release, CMake adds -O3 -DNDEBUG for GCC and Clang: optimised code, assert checks off. Debug adds -g for the debugger. Give each build type its own folder.
What happens
;; step 1/10 · recipe CMakeLists.txt the recipe, next to the source files 1 cmake_minimum_required(VERSION 3.20) 2 project(hello CXX) 3 set(CMAKE_CXX_STANDARD 20) 4 add_library(greet greet.cpp) 5 add_executable(app main.cpp) 6 target_link_libraries(app greet) project folder: CMakeLists.txt main.cpp greet.cpp greet.h
The build graph card is a simplified view. CMake writes it as Makefiles (the default on Linux and macOS) or as build.ninja (with -G Ninja), with more rules and longer names: the object files are really build/CMakeFiles/greet.dir/greet.cpp.o and build/CMakeFiles/app.dir/main.cpp.o. Header dependencies (greet.h) are not written in the recipe or in the generated files: the compiler reports them during the first build (GCC and Clang -MD depfiles), and the build tool remembers them.