Building C++ Programs
Before working with CMake, it's useful to understand the tools it orchestrates. This lesson guides you through setting up a C++ toolchain.
If you're a C++ developer, you've likely encountered the challenge of building your projects. It seems simple at first - especially if you're using an IDE, where you can usually build your program from a single button press.
But for larger projects involving multiple developers, third-party libraries and platform-specific code, things get a lot more complicated.
This is where CMake comes in. It's not a compiler or a linker; it's a meta-build system. Its job is to manage the complexity of your build process for you. You tell CMake what your project looks like - its source files, libraries, and dependencies - and it generates the native build files for your specific platform. That might be Visual Studio solutions on Windows, or Makefiles on Linux, or a range of other possibilities.
This course is designed to take you from the absolute fundamentals of the C++ build process all the way to advanced, modern CMake practices for large, cross-platform projects.
But before we can write our first CMakeLists.txt file, we need to understand the world that CMake operates in. We'll first set up the fundamental tools that actually turn your code into an executable.
Before CMake: The Toolchain
CMake is like a project manager. It knows how to organize tasks, handle dependencies, and give the right instructions to the right people. But it doesn't do the physical work itself. For that, it needs a team of skilled workers. In the world of C++, that team is called a toolchain.
A toolchain is a set of programming tools used to create a software product. For a C++ project, the essential components of a toolchain are:
- A Compiler: A program that translates your human-readable C++ source code into low-level machine code that a computer's processor can understand.
- A Linker: A program that takes the machine code from one or more sources (your compiled files and any libraries) and combines them into a single executable program.
- Standard Libraries: A collection of pre-compiled code that provides fundamental functionality. Examples include input/output with
std::cout
, and containers likestd::vector
.
CMake's primary job is to find and control a toolchain. It needs to know which compiler to use, where to find libraries, and how to invoke the linker correctly for your target platform.
In this introductory lesson, we're going to assemble our "team" by installing a C++ compiler. Once we have that, we'll be ready to go into the nitty-gritty of the build process in the next lesson.
The Command Line
Before we start installing compilers, we need to introduce the primary environment where we'll be working: the command-line interface (CLI), also known as the terminal or console.
If you've spent most of your time in graphical user interfaces (GUIs), clicking on icons and menus, the terminal can seem intimidating. It's just a blank screen with a blinking cursor.

But it's also the most powerful and direct way to interact with your computer's operating system and, more importantly, with the developer tools we're about to install.
Think of it this way: a GUI is like ordering from a restaurant menu. You're limited to the options presented to you. The terminal is like having a direct line to the kitchen - you can make specific, powerful requests that aren't on the menu. Compilers, linkers, and CMake are all "chefs" that take their orders through the terminal.
Even when you click the "Build" button in a fancy IDE like Visual Studio or CLion, what's happening behind the scenes? The IDE is simply generating and running terminal commands for you. By learning to use the terminal directly, you gain a fundamental understanding of what's really going on, which is invaluable for troubleshooting and for mastering your tools.
Opening Your Terminal
First, you need to know how to open a terminal on your system.
- On Windows: You have several options. You can search for Command Prompt (
cmd.exe
) or the more modern PowerShell. If you install Visual Studio, it provides a special Developer Command Prompt which is pre-configured with the environment variables needed to use the MSVC compiler. This is often the most convenient choice. For this course, any of them will work. - On macOS: The terminal application is simply called Terminal. You can find it in your Applications/Utilities folder, or just press Cmd + Space to open Spotlight and type "Terminal".
- On Linux: This is the native environment for most developers. Your distribution will have an application called Terminal, Konsole, or something similar. The keyboard shortcut Ctrl + Alt + T will often launch it on Ubuntu and related distributions.
Essential Commands for Navigation
You don't need to be a terminal expert, but you do need to know how to navigate the file system. Here are the three most important commands you'll use constantly.
Print Working Directory: pwd
This command tells you where you currently are in the file system. It's the "You are here" map.
pwd
/home/user/documents
In Windows' command prompt, the current location is always shown, so there is no equivalent command.
List: ls
This command lists all the files and folders in your current directory. It's how you see what's around you. On the Windows Command Prompt, the equivalent command is dir
.
ls
ProjectA/
notes.txt
images/
Change Directory: cd
This is how you move around. You can move into a sub-folder or go back up to a parent folder.
# Move into the ProjectA folder
cd ProjectA
# Check where you are now
pwd
/home/user/documents/ProjectA
To navigate up to the parent directory, we can use ..
cd ..
You can check where you are again using pwd
:
pwd
/home/user/documents
We'll introduce more commands later in the chapter, and the effect that these commands will have typically depends on where we are in the file system.
With these three commands - pwd
, ls
, and cd
- you have everything you need to navigate around your file system and project folders to ensure your running future commands in the correct location.
Now for the practical part: installing a compiler.
Meet the Compilers
There are several C++ compilers available, but three stand out as the most widely used in the industry - GCC, Clang, and MSVC. CMake is designed to work with all of them.
We'll use GCC in our examples in this introductory chapter, but the choice isn't that important. It's more important that you understand the concepts rather than the exact commands needed to use a specific compiler. CMake will soon be taking care of the compiler interactions for us anyway.
GCC (GNU Compiler Collection)
GCC is one of the oldest and most established compilers. It originated as part of the GNU Project and is the standard compiler on most Linux systems. When you see the g++
command, you're using GCC's C++ compiler. It's known for its broad platform support and adherence to standards.
Clang
Clang is a newer compiler front-end, developed as part of the LLVM project. It was designed to be faster and use less memory than GCC, but its most popular feature is its incredibly clear and helpful error messages.
Clang is the default compiler on macOS (via Apple's toolchain) and is widely used on other platforms, including Windows and Linux. Its command-line interface, clang++, is designed to be a drop-in replacement for g++.
MSVC (Microsoft Visual C++)
If you're a Windows developer, you're likely familiar with Visual Studio. The compiler that powers it is MSVC (cl.exe
). It's a highly optimizing compiler with excellent integration into the Windows ecosystem.
While we'll focus on setting up GCC or Clang for a consistent command-line experience across platforms, rest assured that CMake has first-class support for MSVC. In fact, installing Visual Studio is often the easiest way to get a complete C++ toolchain on Windows.
For this course, we'll primarily use g++ or clang++ in our command-line examples, as their syntax is consistent across all operating systems.
Setting Up a Build Environment on Windows
Windows is the most complex platform to set up. You have several choices.
Option 1: Visual Studio (Recommended for Beginners)
This is the "batteries-included" approach and the easiest way to get started.
- Download Visual Studio Installer: Go to the Visual Studio download page and get the "Community" edition, which is free for individuals and open-source projects.
- Run the Installer: When the installer launches, it will show a list of "Workloads."
- Select the C++ Workload: Check the box for "Desktop development with C++". This single click will install everything you need: the MSVC compiler, the Windows SDK (which contains system headers and libraries), and a recent version of CMake.
- Install: Click the install button and wait for the process to complete.
Once installed, you can access the compiler by opening the Developer Command Prompt for VS, which you can find in your Start Menu. This special terminal automatically configures the necessary environment variables.

Option 2: MSYS2 (A GNU/Linux-like Environment)
If you prefer a command-line experience similar to Linux, using GCC on Windows is a great option. The best way to do this is with MSYS2.
Install MSYS2: Go to the MSYS2 website and follow their installation instructions. This will install a package manager called pacman, and some terminals we can use. We'll use the MSYS2 UCRT64 terminal in this example
Update MSYS2: Open the MSYS2 UCRT64 terminal and run the following command to make sure everything is up to date:
pacman -Syu
You may need to close and reopen the terminal and run it again to complete all updates.
Install the Toolchain: Now, use pacman to install the MinGW-w64 toolchain, which includes GCC (g++), the linker, make, and other essential tools.
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain
This command is likely to install a lot of packages, as there's often a complex web of dependencies involved (that is, packages that require other packages to be installed)
That's it! We'll confirm everything is working correctly in the "Verifying Your Setup" section below.
Setting Up a Build Environment on macOS
macOS makes this process very easy. The operating system ships with stubs for common developer tools, and trying to use them will prompt an installation.
Open the Terminal: You can find it in Applications/Utilities.
Run the Installer Command: Type the following command and press Enter.
xcode-select --install
Confirm Installation: A dialog box will appear asking if you want to install the command line developer tools. Click "Install" and agree to the terms.
This will download and install Apple's Command Line Tools package, which includes clang, clang++, make, and other necessary utilities. It's the official, Apple-supported way to get a C++ compiler on macOS.
Setting Up a Build Environment on Linux (Debian/Ubuntu)
Linux is a developer's paradise. Getting a C++ toolchain is typically a single command away. The instructions here are for Debian-based distributions like Ubuntu, but the process is similar on other distros. This might involve using dnf on Fedora/CentOS or pacman on Arch.
Update Your Package Lists: It's always good practice to update your package manager's index first.
sudo apt update
Install build-essential: This is a special meta-package that installs everything you need for basic compilation, including gcc, g++, and make.
sudo apt install build-essential g++
That's it! You now have a complete GCC toolchain ready to go. If you prefer to use Clang, you can install it just as easily:
sudo apt install clang
Verifying Your Setup
Once you've completed the installation for your platform, it's a good idea to verify that the compiler is correctly installed and accessible from your terminal. Open a new terminal window and try one of the following commands, based on the compiler you installed:
To check for GCC:
g++ --version
gcc.exe (Rev6, Built by MSYS2 project) 15.1.0
Copyright (C) 2025 Free Software Foundation, Inc.
To check for Clang:
clang++ --version
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin24.5.0
If you're on Windows using the Visual Studio Developer Command Prompt, check for MSVC:
cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.43.34810 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
If you see output that includes a version number, congratulations! Your compiler is installed and ready.
An Introduction to Manual Builds
Now that we have a working compiler, let's see it in action. This will give us a taste of the manual build process and help us understand the problem that CMake was created to solve.
Let's create a new file named hello.cpp
and add the following code:
hello.cpp
#include <iostream>
int main() {
std::cout << "Hello World!\n";
return 0;
}
Now, from your terminal, in the same directory as the file, run the following command:
g++ hello.cpp -o hello
Let's break this down:
g++
: The C++ compiler program.hello.cpp
: The input source file we want to compile.-o hello
: An option that specifies the name of the output file. If you omit this, the compiler will default toa.out
on Linux/macOS ora.exe
on Windows.
If all goes well, there will be no output. Instead, you'll find a new file in your directory: hello
on Linux/macOS, or hello.exe
on Windows. This is your executable program!
We can run our program directly from the command line simply using it's name - hello
, in this example. We may need to prepend ./
(as in ./hello
) to clarify to our terminal that the program we're trying to run is in the current directory:
./hello
Hello World!
In this case, our program is a single source file, which makes it fairly easy to build. But let's create a project with two source files, and one header file:
Files
To build this, we now need to give both of our source files to the compiler:
g++ main.cpp greeter.cpp -o app
We don't need to provide our header file in this example, as its contents are already getting inserted into main.cpp
because of the #include
directive. We'll talk more about header files in the next lesson.
If our program compiled, we can run it in the usual way:
./app
Hello, second file!
Again, this tiny project with its two source files is manageable. But what if we had 20 files? Or 200? What if some files needed special compiler flags for optimization, while others needed flags for debugging? What if we wanted to build on Windows with MSVC, which uses completely different commands and flags?
The complexity spirals out of control. Manually maintaining build commands or writing platform-specific scripts (like Makefiles or batch files) is a tedious and error-prone nightmare.
This is the problem CMake solves.
What's Next?
We've successfully prepared our development environment and gotten a small taste of the build process. We have our tools, and we've seen a hint of the complexity that lies ahead.
Now, we're ready to peel back the layers. In the next lesson, we will go deeper into what actually happens when you run that g++
command.
We'll explore the C++ compilation pipeline step-by-step, from preprocessing and compilation to the role of the linker. Understanding these fundamentals is the key to mastering any build system, especially CMake.
The Compilation Pipeline
Walking through the steps of the C++ compilation process, from source code to machine code.