Build Systems & Modern CMake
বিল্ড সিস্টেম ও আধুনিক CMake
1. Why CMake?
Real C++ projects span hundreds of files, third-party libraries, multiple platforms, and multiple compilers. Hand-written Makefiles don't scale. CMake generates platform-specific build files (Makefiles, Ninja, MSBuild, Xcode) from one declarative spec.
2. A Minimal CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(myapp
src/main.cpp
src/utils.cpp)
target_include_directories(myapp PRIVATE include)
target_compile_options(myapp PRIVATE -Wall -Wextra -Wpedantic)
3. Build Workflow
# Configure (once per build dir)
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build -j
# Run
./build/myapp
# Clean rebuild
cmake --build build --clean-first
4. Libraries & Linking
add_library(mathlib STATIC src/math.cpp)
target_include_directories(mathlib PUBLIC include)
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE mathlib)
- PUBLIC: this and consumers see it
- PRIVATE: only this target sees it
- INTERFACE: only consumers see it (header-only libs)
5. find_package for Third-Party Libs
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)
find_package(fmt CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE fmt::fmt)
For dependency management, modern projects use vcpkg or Conan alongside CMake.
6. Modern CMake Rules
- Target-based, not variable-based. Set properties on targets, not globally.
- Use
target_*commands (target_link_libraries,target_include_directories). - Avoid
include_directories,link_libraries(old style). - Pin a minimum version >= 3.20.
- Use generator expressions
$<CONFIG:Debug>for build-type specific options.
7. Practice Problems
- Write a CMakeLists.txt for a 2-file project.
✨ Show Answer
See section 2 above.
- Difference between
add_library STATICandSHARED?✨ Show Answer
STATIC:
.a/.liblinked into executable. SHARED:.so/.dllloaded at runtime — smaller exe, more dependencies. - Why prefer target_* commands?
✨ Show Answer
Properties propagate correctly via PUBLIC/PRIVATE/INTERFACE. Old-style globals leak everywhere and cause subtle bugs.
- Configure a Release build.
✨ Show Answer
cmake -B build -DCMAKE_BUILD_TYPE=Release - Add the C++20 standard requirement.
✨ Show Answer
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) - Find and link the Threads library.
✨ Show Answer
find_package(Threads REQUIRED) target_link_libraries(myapp PRIVATE Threads::Threads) - Why use a separate
build/directory?✨ Show Answer
Out-of-source builds keep generated files separate from sources. Easy to
rm -rf buildfor a fresh start. - What is
cmake --install?✨ Show Answer
Copies built artifacts (executables, libraries, headers) to install prefix. Set in CMakeLists with
install(TARGETS ...).
Summary
CMake is the de-facto C++ build system. Use modern, target-based CMake (3.x+).
Set properties with target_* commands. Use PUBLIC/PRIVATE/INTERFACE correctly.
For dependencies, use find_package with vcpkg/Conan.