Module 35: CMake
Introduction
CMake is the most widely used cross-platform build system for C++ projects. Instead of manually writing compiler commands, you describe your project in a CMakeLists.txt file, and CMake generates build files for your chosen build system (such as Make, Ninja, or Visual Studio).
CMake supports:
- Linux
- Windows
- macOS
- Visual Studio
- GCC
- Clang
- MSVC
- Ninja
Large projects such as LLVM, OpenCV, Qt, PyTorch, and VTK use CMake.
Learning Objectives
After completing this module, you will understand:
- What is CMake?
- Project Structure
- CMakeLists.txt
- Building Projects
- Installing Applications
- Creating Libraries
- Static vs Shared Libraries
- Best Practices
What is CMake?
CMake is a build system generator.
Instead of compiling manually:
1g++ main.cpp math.cpp -o app
You write:
1CMakeLists.txt 2 3↓ 4 5CMake 6 7↓ 8 9Makefile / Ninja / Visual Studio Project 10 11↓ 12 13Executable
Typical Project Structure
1Calculator/ 2│ 3├── CMakeLists.txt 4├── include/ 5│ └── calculator.h 6├── src/ 7│ ├── calculator.cpp 8│ └── main.cpp 9├── build/ 10└── install/
Installing CMake
Ubuntu
1sudo apt install cmake
Verify Installation
1cmake --version
Example Output
1cmake version 3.30.0
Your First CMake Project
main.cpp
1#include <iostream> 2 3int main() 4{ 5 std::cout << "Hello CMake!" << std::endl; 6 7 return 0; 8}
Basic CMakeLists.txt
1cmake_minimum_required(VERSION 3.20) 2 3project(HelloCMake) 4 5add_executable(app main.cpp)
Build the Project
Create a build directory.
1mkdir build
Move into it.
1cd build
Generate build files.
1cmake ..
Compile.
1cmake --build .
Run.
Linux/macOS
1./app
Windows
1app.exe
Output
1Hello CMake!
Understanding CMakeLists.txt
1cmake_minimum_required(VERSION 3.20) 2 3project(MyProject VERSION 1.0) 4 5add_executable(app main.cpp)
Explanation
| Command | Purpose |
|---|---|
cmake_minimum_required() | Minimum CMake version |
project() | Defines project name and version |
add_executable() | Creates an executable |
Multiple Source Files
Project
1project/ 2│ 3├── main.cpp 4├── math.cpp 5└── math.h
math.h
1#pragma once 2 3int add(int a, int b);
math.cpp
1#include "math.h" 2 3int add(int a, int b) 4{ 5 return a + b; 6}
main.cpp
1#include <iostream> 2#include "math.h" 3 4int main() 5{ 6 std::cout << add(5, 8); 7 8 return 0; 9}
CMakeLists.txt
1cmake_minimum_required(VERSION 3.20) 2 3project(MathProject) 4 5add_executable( 6 app 7 main.cpp 8 math.cpp 9)
Using Include Directories
Project
1project/ 2 3include/ 4 math.h 5 6src/ 7 math.cpp 8 main.cpp
CMake
1cmake_minimum_required(VERSION 3.20) 2 3project(MathProject) 4 5add_executable( 6 app 7 src/main.cpp 8 src/math.cpp 9) 10 11target_include_directories(app PRIVATE include)
Build Types
1cmake -DCMAKE_BUILD_TYPE=Debug ..
or
1cmake -DCMAKE_BUILD_TYPE=Release ..
Common Build Types
| Type | Purpose |
|---|---|
| Debug | Debugging with symbols |
| Release | Optimized build |
| RelWithDebInfo | Optimized + debug symbols |
| MinSizeRel | Optimize for small binaries |
Creating a Static Library
Project
1project/ 2 3include/ 4 math.h 5 6src/ 7 math.cpp
CMake
1add_library(math STATIC 2 src/math.cpp 3) 4 5target_include_directories(math PUBLIC include)
Using the Static Library
1add_executable(app src/main.cpp) 2 3target_link_libraries(app PRIVATE math)
Creating a Shared Library
1add_library(math SHARED 2 src/math.cpp 3) 4 5target_include_directories(math PUBLIC include)
Static vs Shared Libraries
| Feature | Static | Shared |
|---|---|---|
| Extension (Linux) | .a | .so |
| Extension (Windows) | .lib | .dll |
| Linked | Compile time | Runtime |
| Executable Size | Larger | Smaller |
| Memory Sharing | No | Yes |
Installing Targets
Install executable.
1install(TARGETS app 2 DESTINATION bin)
Install library.
1install(TARGETS math 2 DESTINATION lib)
Install headers.
1install(FILES 2 include/math.h 3 DESTINATION include)
Run installation.
1cmake --install .
Installed structure
1install/ 2 3bin/ 4 app 5 6lib/ 7 libmath.a 8 9include/ 10 math.h
Variables
1set(CMAKE_CXX_STANDARD 20) 2 3message(STATUS "Using C++20")
Compiler Options
1target_compile_options(app PRIVATE 2 -Wall 3 -Wextra 4)
For MSVC, use the appropriate warning flags such as /W4.
Linking Multiple Libraries
1target_link_libraries(app 2 PRIVATE 3 math 4 pthread 5)
Modern CMake Example
1cmake_minimum_required(VERSION 3.20) 2 3project(MyProject VERSION 1.0 LANGUAGES CXX) 4 5set(CMAKE_CXX_STANDARD 20) 6set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 8add_library(math STATIC 9 src/math.cpp 10) 11 12target_include_directories(math 13 PUBLIC 14 include 15) 16 17add_executable(app 18 src/main.cpp 19) 20 21target_link_libraries(app 22 PRIVATE 23 math 24)
Out-of-Source Builds
Recommended workflow
1mkdir build 2cd build 3cmake .. 4cmake --build .
Advantages
- Keeps source files clean
- Easy to delete build artifacts
- Supports multiple build configurations
Build Workflow
1Source Code 2 │ 3 ▼ 4CMakeLists.txt 5 │ 6 ▼ 7cmake .. 8 │ 9 ▼ 10Build Files 11 │ 12 ▼ 13cmake --build . 14 │ 15 ▼ 16Executable
Common CMake Commands
| Command | Purpose |
|---|---|
project() | Create project |
add_executable() | Create executable |
add_library() | Create library |
target_link_libraries() | Link libraries |
target_include_directories() | Add include paths |
install() | Install files |
set() | Define variables |
message() | Print messages |
Common Errors
Missing Source File
1Cannot find source file
Solution
Verify the file path in add_executable() or add_library().
Missing Header
1fatal error: 2math.h: 3No such file
Solution
Add the include directory using:
1target_include_directories(app PRIVATE include)
Undefined Reference
1undefined reference to add()
Solution
Ensure the implementation file is compiled or the library is linked with:
1target_link_libraries(app PRIVATE math)
Best Practices
- Use out-of-source builds.
- Prefer target-based commands (
target_link_libraries,target_include_directories). - Set the required C++ standard explicitly.
- Organise code into
src/,include/, andtests/. - Keep
CMakeLists.txtsimple and modular. - Build libraries separately from executables.
Interview Questions
1. What is CMake?
A cross-platform build system generator that creates build files for tools such as Make, Ninja, and Visual Studio.
2. What is a CMakeLists.txt file?
The main configuration file that describes how a C++ project should be built.
3. What is the difference between a static and shared library?
A static library is linked into the executable at compile time, while a shared library is loaded at runtime.
4. Why use an out-of-source build?
It keeps generated build files separate from source code and makes cleanup easier.
5. What does target_link_libraries() do?
It links libraries required by an executable or another library.
6. Why use target_include_directories()?
To specify where the compiler should search for header files.
7. What is the purpose of install()?
It copies executables, libraries, and headers into a structured installation directory.
8. Why is Modern CMake preferred?
Because it uses target-based commands, resulting in cleaner, more maintainable, and less error-prone build configurations.
Module Summary
In this module, you learned:
- The purpose and advantages of CMake
- How to organise a C++ project structure
- Writing and understanding
CMakeLists.txt - Building projects using CMake
- Creating executables and libraries
- Working with static and shared libraries
- Installing applications and headers
- Using Modern CMake best practices
- Troubleshooting common build issues
CMake is the industry-standard build system for modern C++ development and is used in projects ranging from small applications to large frameworks such as LLVM, OpenCV, Qt, and PyTorch.