Skip to main content

📝 Lesson 1: C++ Development Environment Setup

Set up your development environment on Windows, macOS, or Linux with step-by-step guidance, then compile and run your first C++ program.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Install a C++ compiler toolchain — MinGW-w64 on Windows, Xcode Command Line Tools on macOS, or GCC/build-essential on Linux.
  • Configure your system PATH so the command line can find your compiler.
  • Set up a code editor (Visual Studio Code) with C++ support.
  • Compile a C++ source file into an executable with g++, understanding that compiling and running are separate steps.
  • Correctly run your compiled program (./program on Linux/macOS, program.exe on Windows) and troubleshoot common "command not found" errors.

Estimated Time: 45–60 minutes

Project: Install a complete C++ toolchain for your operating system, then compile and run a "Hello, C++ World!" program from the command line.

In This Lesson

Understanding What We're Building

Think of setting up a C++ development environment like preparing a professional kitchen before cooking. Just as a chef needs the right tools - knives, pans, and ovens - a C++ programmer needs specific software tools to write, compile, and run programs.

graph TD A[Your Code<br/>recipe.cpp] --> B[Compiler<br/>The Oven] B --> C[Executable Program<br/>The Finished Dish] D[Text Editor/IDE<br/>Your Workspace] --> A E[Debugger<br/>Taste Testing Tools] --> C

💡 Key idea: you compile for a specific platform

A compiler doesn't produce some universal program — it produces native machine code aimed at one target: a specific operating system and CPU architecture (for example, "Windows on x86-64" or "Linux on x86-64").

Because of that, a program built on Linux (an ELF binary) will not run on Windows, and a Windows .exe won't run as-is on Linux or macOS. The raw instructions and the way each OS launches a program are different.

Building a program on the same kind of machine you intend to run it on is called native compilation — and that's exactly what every installation guide below does: you pick your operating system, install its toolchain, and build programs that run on that same system. (Building for a different platform than the one you're on is called cross-compilation — an optional bonus topic covered at the end of this lesson.)

Core Components You'll Need

Windows Installation Guide

On Windows, we'll use MinGW-w64 (Minimalist GNU for Windows) - think of it as bringing Unix-style development tools to Windows, like installing a Swiss Army knife for programming.

Step-by-Step Installation

Download MinGW-w64

Visit the MSYS2 website (msys2.org) and download the installer. MSYS2 is like a package manager - imagine it as an app store specifically for development tools.

Run the Installer

Execute the downloaded file and follow these steps:

  • Choose installation directory (default C:\msys64 is fine)
  • Let the installation complete
  • Check "Run MSYS2 now" when finished

Update Package Database

In the MSYS2 terminal that opens, type:

pacman -Syu

This updates the package database - like refreshing your app store to see the latest versions.

Install Development Tools

After restarting MSYS2, open the MSYS2 UCRT64 shell from the Start menu and install the C++ toolchain. UCRT64 is the environment MSYS2 recommends today — it targets the modern Universal C Runtime that ships with current Windows:

pacman -S mingw-w64-ucrt-x86_64-gcc
pacman -S mingw-w64-ucrt-x86_64-gdb
pacman -S mingw-w64-ucrt-x86_64-make

Configure System PATH

Add MinGW to your system PATH so Windows can find the compiler from anywhere:

  1. Right-click "This PC" → Properties → Advanced System Settings
  2. Click "Environment Variables"
  3. Under System Variables, find "Path" and click Edit
  4. Add: C:\msys64\ucrt64\bin
  5. Click OK to save

Install Visual Studio Code

Download VS Code from code.visualstudio.com - it's a modern text editor with excellent C++ support. Once it's installed, open the Extensions panel (Ctrl+Shift+X) and install Microsoft's C/C++ extension (ms-vscode.cpptools) for IntelliSense, syntax highlighting, and debugging. This same extension works on macOS and Linux too.

macOS Installation Guide

On macOS, development tools come through Xcode Command Line Tools - Apple's official development toolkit.

Installation Process

Install Xcode Command Line Tools

Open Terminal (found in Applications → Utilities) and type:

xcode-select --install

A dialog will appear. Click "Install" and agree to the license.

Verify Installation

Check that the compiler is installed:

g++ --version

You should see version information for Apple clang.

Install Homebrew (Optional but Recommended)

Homebrew is a package manager for macOS - like an app store for command-line tools:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Install Additional Tools

With Homebrew, you can install extra tools:

brew install cmake
# The debugger on macOS is lldb, already installed with the Xcode Command Line Tools — no separate install needed.
# (gdb is available via Homebrew but needs code signing and has limited Apple Silicon support, so prefer lldb.)

Linux Installation Guide

Linux is like the natural habitat for C++ development - most tools are readily available through your distribution's package manager.

Ubuntu/Debian Installation

Update Package List

sudo apt update

Install Build Essentials

sudo apt install build-essential

This installs gcc, g++, make, and other essential tools in one package.

Install Debugging Tools

sudo apt install gdb valgrind

Fedora/Red Hat Installation

Install Development Tools

sudo dnf groupinstall "Development Tools"
sudo dnf install gcc-c++ gdb

Arch Linux Installation

Install Base Development Package

sudo pacman -S base-devel gdb

Testing Your Installation

Let's verify everything works by creating your first C++ program!

Create a Test Program

Create a new file called hello_world.cpp with this content:

#include <iostream>

int main() {
    std::cout << "Hello, C++ World!" << std::endl;
    std::cout << "Your development environment is ready!" << std::endl;
    return 0;
}

Compile the Program

Open your terminal/command prompt in the file's directory and run:

g++ -std=c++23 -o hello_world hello_world.cpp

Important: This command tells g++ to compile hello_world.cpp and create (-o) an executable file named hello_world. It does NOT run the program - it only creates it!

💡 About -std=c++23: This flag tells the compiler which version of the C++ standard to use. C++23 is the current finalized standard, so we'll use it throughout the course to get modern language features. If your compiler is a little older, -std=c++20 works just as well for everything here. Without a -std flag, g++ falls back to an older default, so it's a good habit to always include it.

Think of it like this: g++ is like a factory that takes your source code (raw materials) and produces an executable file (finished product). The factory doesn't use the product - it just makes it.

Run Your Program (Separate Step!)

After compilation creates the executable, you must run it with a separate command:

⚠️ IMPORTANT - Avoiding "command not found" error:

You MUST specify the path to your executable. The system won't find it by just typing the filename!

On Windows:

.\hello_world.exe

OR just:

hello_world

(Windows searches the current directory by default)

On macOS/Linux and Ubuntu WSL:

./hello_world

The ./ is REQUIRED! It tells the system "look in the current directory"

Why do we need ./ on Linux/Mac?

For security reasons, Unix-like systems don't search the current directory for executables by default. Without ./, the system only looks in directories listed in the PATH environment variable.

Understanding the Compilation Process

graph LR A["Source Code<br/>hello_world.cpp"] --> B["Preprocessor<br/>#include processing"] B --> C[Compiler<br/>Syntax checking] C --> D[Assembler<br/>Machine code] D --> E[Linker<br/>Creates executable] E --> F[Executable<br/>hello_world.exe] F -.->|Separate Command!| G["Running Program<br/>./hello_world"]

The compilation process is like a factory assembly line where your code goes through multiple stages of transformation before becoming an executable program. Note that g++ stops after creating the executable - it doesn't run it!

Practice Exercises

🏋️ Exercise: Understanding Program Execution

Let's practice avoiding the "command not found" error:

  1. Create and compile a simple program:
    g++ -std=c++23 -o mytest hello_world.cpp
  2. Try running it the WRONG way (this will fail):
    mytest

    You should see "command not found" or similar error

  3. Now run it the CORRECT way:
    ./mytest     # Linux/Mac
    .\mytest.exe # Windows
  4. Experiment with absolute paths:
    pwd                    # Shows current directory (Linux/Mac)
    cd                     # Shows current directory (Windows)
    /full/path/to/mytest   # Run using full path

🏋️ Exercise: Multi-file Compilation

Create two files:

math_functions.cpp:

int add(int a, int b) {
    return a + b;
}

main.cpp:

#include <iostream>

int add(int a, int b);  // Function declaration

int main() {
    std::cout << "5 + 3 = " << add(5, 3) << std::endl;
    return 0;
}

Compile them together:

g++ -std=c++23 -o calculator main.cpp math_functions.cpp

🏋️ Exercise: Read and Fix a Compiler Error

One of the most useful skills at this stage isn't avoiding mistakes — it's learning to read what the compiler tells you when you make one. Let's break a program on purpose, read the error, and fix it.

  1. Create a file called broken.cpp with a deliberate typo — a missing semicolon:
    #include <iostream>
    
    int main() {
        std::cout << "Learning to read errors!" << std::endl   // ← missing ;
        return 0;
    }
  2. Try to compile it:
    g++ -std=c++23 -o broken broken.cpp

    The compiler refuses to build and prints something like:

    broken.cpp: In function 'int main()':
    broken.cpp:4:57: error: expected ';' before 'return'

    Read it as file : line : column : what's wrong. It's pointing you almost exactly at the missing semicolon on line 4.

  3. Fix it — add the ; at the end of the std::cout line — and compile again. This time it succeeds with no output at all (for a compiler, no news is good news).
  4. Now run your fixed program:
    ./broken     # Linux/Mac
    .\broken.exe # Windows

    You should see: Learning to read errors!

Takeaway: If a program won't compile, no executable was created — so there's nothing to run yet. The error message hands you the file, line, and column to look at. Fix, recompile, repeat. (Bugs that compile cleanly but behave wrong at runtime are a separate skill — tracked down with a debugger such as gdb — that you'll build as you write more code.)

Troubleshooting Common Issues

"command not found" After Compilation

This is the #1 beginner issue! Your program compiled successfully, but you get "command not found" when trying to run it.

Solution: Use ./program_name on Linux/Mac or .\program_name.exe on Windows

Why: The operating system doesn't search the current directory for security reasons.

graph TD A[Type: hello_world] --> B{System searches PATH} B --> C["/usr/bin ❌"] B --> D["/usr/local/bin ❌"] B --> E["/bin ❌"] B --> F[Not found!] G["Type: ./hello_world"] --> H{System searches} H --> I[Current directory ✓] I --> J[Found and runs!]

Windows: "g++ is not recognized"

This means the PATH wasn't set correctly. Double-check that C:\msys64\ucrt64\bin is in your system PATH and restart your command prompt.

macOS: "xcrun: error: invalid active developer path"

Run xcode-select --install again or try sudo xcode-select --reset

Linux: "g++: command not found"

Install the compiler: sudo apt install g++ (Ubuntu) or equivalent for your distribution.

"Permission denied" When Running

On Linux/Mac, your executable might not have execute permissions. Fix with:

chmod +x hello_world

Then run with ./hello_world

🎯 Quick Quiz

Question 1: After running g++ -o hello_world hello_world.cpp, what has actually happened?

Question 2: Why do you need to type ./hello_world instead of just hello_world on Linux or macOS?

Question 3: What does compiling with g++ -g -o buggy buggy.cpp do differently from a normal build?

Summary

🎉 Key Takeaways

  • ✓ Installed a C++ compiler (g++) for your operating system
  • ✓ Set up a text editor or IDE (Visual Studio Code)
  • ✓ Learned basic compilation commands like g++ -std=c++23 -o program source.cpp
  • ✓ Created and ran your first C++ program
  • Compiling and running are separate steps - g++ creates the executable, then you launch it yourself
  • Use ./program_name on Linux/macOS, since the current directory isn't searched by default for security reasons

📚 Additional Resources

🚀 What's Next?

Your C++ development environment is now ready. In the next lesson, Lesson 2: C++ Syntax Basics, we'll dive into the building blocks of the language itself and start writing more complex programs with the toolchain you just set up. Remember, setting up your environment is like tuning an instrument before playing - now you're ready to make beautiful code!

🧭 Going Further (Bonus): Building for a Different Platform

Optional — you don't need this to finish the course. Everything above is native compilation: you build on your OS, for your OS. But sometimes you want to produce a program for a different platform than the one you're working on — for example, creating a Windows .exe while you're working on Linux (or inside WSL on a Windows PC). That's cross-compilation, and it just means using a compiler that targets the other platform.

Here's the concrete case — producing a Windows .exe from Ubuntu/WSL using the MinGW-w64 cross-compiler:

Install the cross-compiler (targets Windows)

sudo apt install g++-mingw-w64-x86-64

Compile with the cross-compiler instead of g++

x86_64-w64-mingw32-g++ -std=c++17 -static hello_world.cpp -o hello_world.exe

Note the different compiler name. The -static flag bundles the C++ runtime into the .exe so it runs on a plain Windows machine without needing extra DLLs.

Confirm what you built

file hello_world.exe

You'll see PE32+ executable ... for MS Windows — compare that with a normal Linux build, which reports ELF ... executable. Two different targets from the same source code.

In VS Code you can add a build task per target (one calling g++, another calling x86_64-w64-mingw32-g++) so a keystroke builds for Linux or Windows on demand. The same idea generalizes: cross-compiling for macOS, ARM devices, or embedded boards each uses a compiler built to target that platform.

🎉 Your toolchain is ready!

Every great C++ program starts with a working compiler, and you've got yours dialed in. Time to start writing real C++ code!