C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
126: Build Systems with CMake
Why do I need CMake if I can just write a Makefile or use an IDE?
I get this a lot. If you're working on a small project on a single machine, a Makefile is fine. But the moment you share your code with someone using a different OS, or try to move from Linux to Windows, your Makefile becomes a liability. You'll spend more time fighting tabs and shell differences than writing C++.
Here is the key: CMake isn't actually a build system. It's a build system generator. It doesn't compile your code; it writes the instructions for the tool that does. If you're on Windows, it can generate a Visual Studio solution. On Linux, it can generate a Ninja file or a Makefile. It abstracts the "how" of the build so you can focus on the "what." Trust me, once you've tried to manually manage dependencies across three different platforms, you'll appreciate this abstraction.
How do I actually structure a project with multiple files and folders?
Don't just dump everything in the root directory. I usually prefer a structure where headers are separated from implementation. Let's say we're building a simple 2D physics engine. I'd set it up like this:
/include(Public headers)/src(Implementation files)CMakeLists.txt(The recipe)
In your CMakeLists.txt, you want to be explicit about your targets. Instead of listing every single file in one giant command, I recommend grouping them. Here is how I'd handle a physics library and a main simulation app:
cmake_minimum_required(VERSION 3.10)
project(PhysicsSim VERSION 1.0)
# Use C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Create a library from our physics logic
add_library(PhysicsEngine
src/Vector2D.cpp
src/RigidBody.cpp
)
# Tell CMake where the headers for this library are
target_include_directories(PhysicsEngine PUBLIC include)
# Create the actual executable
add_executable(SimApp main.cpp)
# Link the app to the physics library
target_link_libraries(SimApp PRIVATE PhysicsEngine)
What is the difference between PUBLIC, PRIVATE, and INTERFACE?
This is where most people get tripped up. These keywords tell CMake how dependencies should "propagate." Think of it as visibility.
If you mark an include directory or a linked library as PRIVATE, it means "I need this to build myself, but anyone who uses me doesn't need to know about it." For example, if your PhysicsEngine uses a private helper library for internal math, mark it PRIVATE.
If you mark it PUBLIC, you're saying "I need this, and anyone who links to me also needs this." This is common for headers. If SimApp links to PhysicsEngine, and PhysicsEngine has its headers marked PUBLIC, SimApp automatically knows where those headers are without you having to call target_include_directories again for the app.
INTERFACE is rarer—it's for header-only libraries where you don't actually compile anything, but you want to provide the include paths to whoever uses the target.
📋 Practical Task
Exercise: Building a Multi-Target Logger System
You need to create a small project that separates a logging utility from the main application logic. Your goal is to ensure the main application can use the logger without manually specifying the include paths.
Requirements:
- Create a directory structure:
/include,/src, and a rootCMakeLists.txt. - Implement a simple
Loggerclass (header in/include, implementation in/src) that prints messages to the console. - Create a
main.cppin the root that calls theLogger. - Write a
CMakeLists.txtthat:- Defines a library target named
LoggerLib. - Uses
target_include_directorieswith thePUBLICkeyword so that theincludefolder is shared with any target that links to it. - Defines an executable target named
App. - Links
ApptoLoggerLibusingtarget_link_libraries.
- Defines a library target named
Validation: Run cmake -B build followed by cmake --build build. If the App compiles without you having to add -I include to the executable's specific flags, you've mastered target-based dependency propagation.
There are no comments for now.