Appendix F

For Mac and Linux Users

This book builds its demos with Visual Studio, on Windows, because it's the smoothest start there is for C++ with SDL: one installer, and a debugger that's hard to beat. But nothing in the demos belongs to Windows. They're standard C++ and SDL, and SDL runs on macOS and Linux just as happily.

What changes is the tools around the code. Instead of Visual Studio, you'll write and debug in VS Code, a free editor from Microsoft that runs everywhere. And instead of Chapter 1's project settings, a tool called CMake builds the demos, and fetches SDL for you. This appendix takes you from a bare machine to building and running every demo, and a program of your own. Then it goes through the places where the book's Windows steps work differently for you.

In this appendix, we will:

  • Install a compiler, CMake and VS Code, on a Mac or on Linux
  • Build every demo in the book's repository with one CMakeLists.txt file
  • Run a demo from a terminal, and debug it from VS Code
  • Start a program of your own, from the skeleton
  • Translate the book's Visual Studio steps into their Mac and Linux equivalents

First, though, a look at how the pieces fit together.

How It Fits Together

On Windows, each demo's folder in the book's repository holds a Visual Studio project, and its settings tell it where SDL is. Visual Studio doesn't run on a Mac or on Linux, so the repository has one file that does that job there, for every demo at once: CMakeLists.txt, at its top.

CMake reads that file, and works out how to build each demo with whatever compiler your system has: Clang on a Mac, or GCC on Linux. It also checks whether SDL 3 and SDL_ttf are installed. If they aren't, it downloads their source code and builds them, once, the first time. After that, VS Code's CMake Tools extension puts the building behind a few commands.

So the plan is short. Install the tools, download the book's repository, open it in VS Code, and let CMake do the rest.

Setting Up a Mac

You need Apple's command-line developer tools, which include the Clang compiler and the LLDB debugger; Homebrew, which installs everything else; and VS Code.

  1. Open Terminal, from Applications > Utilities, and type this, then press Return:
xcode-select --install

A window asks whether to install the command line developer tools. Click Install. The tools are a few hundred megabytes, so they can take a while to arrive. When it's done, check that it worked:

clang --version

The answer should start with "Apple clang version", followed by a number.

  1. Go to https://brew.sh, and copy the one-line install command shown on the page into Terminal. It explains what it's about to do, and asks for your password. When it finishes, it may print two or three commands under "Next steps", to add Homebrew to your path, and you should run those too.

  2. Install CMake, and FreeType, which SDL_ttf uses to read fonts:

brew install cmake freetype

Then check CMake's version, which needs to be 3.24 or later:

cmake --version
  1. Download VS Code from https://code.visualstudio.com, open the download, and drag Visual Studio Code into your Applications folder. Start it, and click the Extensions icon on the left, the one made of four squares. Search for C/C++ Extension Pack, and install the one published by Microsoft. It brings the two extensions we need: C/C++, for editing and debugging, and CMake Tools, for building.
Tip

If you'd rather not wait for SDL to build the first time, Homebrew can install it ready-made, with brew install sdl3 sdl3_ttf. The CMakeLists.txt uses those whenever they're recent enough, and downloads its own copies when they aren't, so either way works.

That's the Mac ready. Skip ahead to Getting the Demos.

Setting Up Linux

On Linux, the package manager installs everything. That's the compiler and the debugger, CMake and FreeType, and the development files that SDL needs to open windows on your system. The commands here are for Ubuntu and Debian, and for Fedora. SDL lists the packages for other distributions, such as Arch and openSUSE, at https://github.com/libsdl-org/SDL/blob/main/docs/README-linux.md.

  1. Open a terminal, and install the tools and libraries. On Ubuntu or Debian, that's this one long command, which you can paste in as it is:
sudo apt install build-essential gdb git cmake ninja-build pkg-config \
    libfreetype-dev libasound2-dev libpulse-dev libaudio-dev libjack-dev \
    libsndio-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev \
    libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev \
    libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
    libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev \
    libfribidi-dev libthai-dev libpipewire-0.3-dev libwayland-dev \
    libdecor-0-dev liburing-dev

On Fedora, it's this one:

sudo dnf install gcc-c++ gdb git-core make cmake ninja-build freetype-devel \
    alsa-lib-devel fribidi-devel pulseaudio-libs-devel pipewire-devel \
    libX11-devel libXext-devel libXrandr-devel libXcursor-devel \
    libXfixes-devel libXi-devel libXScrnSaver-devel libXtst-devel \
    dbus-devel ibus-devel systemd-devel mesa-libGL-devel libxkbcommon-devel \
    mesa-libGLES-devel mesa-libEGL-devel vulkan-devel wayland-devel \
    wayland-protocols-devel libdrm-devel mesa-libgbm-devel libusb1-devel \
    libdecor-devel pipewire-jack-audio-connection-kit-devel libthai-devel \
    liburing-devel zlib-ng-compat-static

Most of those packages are SDL's: they let it find your windowing system, whether it's X11 or Wayland, and your sound system, when it's built. The demos make no sound, but SDL is built with it all the same. The rest are the compiler (build-essential or gcc-c++) and the debugger (gdb), with CMake, and FreeType for SDL_ttf.

  1. Check CMake's version, which needs to be 3.24 or later:
cmake --version

Ubuntu 22.04's CMake is older than that. If yours is, swap it for a newer one: run sudo apt remove cmake, and then sudo snap install cmake --classic. Close the terminal, and open a new one before checking again. The old one has to go first, because Ubuntu looks for commands in the snap's folder last.

  1. Download VS Code from https://code.visualstudio.com, choosing the .deb package for Ubuntu or Debian, or the .rpm for Fedora, and open it to install it. Start VS Code, and click the Extensions icon on the left, the one made of four squares. Search for C/C++ Extension Pack, and install the one published by Microsoft. It brings the C/C++ extension, for editing and debugging, and CMake Tools, for building.

That's Linux ready.

Getting the Demos

The book's repository is at https://github.com/EliteIntegrity/Learning-C-by-Building-Games-Fundamentals-2nd-Edition. Choose Code > Download ZIP, and extract the zip anywhere you like. Inside, there's a folder for each demo, named after it, and the Skeleton folder. Beside them are the font, RobotoMono-Light.ttf, and the CMakeLists.txt file. The Windows copies of SDL are there too, and a Mac or Linux build ignores them.

If you're comfortable with Git, you can clone the repository instead, which makes it easy to fetch any fixes later.

The CMakeLists.txt File

The CMakeLists.txt file is in the repository, so you don't have to type it, but it's worth reading once. It's short, and it's the only thing standing between the demos' code and your system. It starts by saying what it's for, and what it needs:

# Builds every demo in this folder with CMake, on macOS, Linux, or Windows.
# Appendix F of the book, For Mac and Linux Users, explains it.
#
# Every folder here with a main.cpp in it becomes a program, named after
# the folder, with underscores for its spaces, and built into that folder.
# The font is copied beside each program, where it looks for it. A folder
# of your own works the same way: copy the Skeleton folder, give it a name
# of your own, and configure again.

cmake_minimum_required(VERSION 3.24)
project(Fundamentals LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Debug)
endif()

In the preceding code, the set lines ask for C++20, the same standard as Chapter 1's projects. The if asks for a Debug build, the kind that's easiest to investigate, unless you choose another. The next part points CMake at the Windows copies of SDL, and switches off the parts of SDL and SDL_ttf that the demos never use:

# On Windows, use the copies of SDL that sit beside the demos
if(WIN32)
    list(APPEND CMAKE_PREFIX_PATH
        "${CMAKE_CURRENT_SOURCE_DIR}/SDL3"
        "${CMAKE_CURRENT_SOURCE_DIR}/SDL3_ttf")
endif()

# Only what the demos need: no SDL tests, and none of SDL_ttf's extras
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
set(SDLTTF_HARFBUZZ OFF CACHE BOOL "" FORCE)
set(SDLTTF_PLUTOSVG OFF CACHE BOOL "" FORCE)
set(SDLTTF_SAMPLES OFF CACHE BOOL "" FORCE)

In the preceding code, the if(WIN32) part points CMake at the copies of SDL that come with the repository, and on a Mac or on Linux, it's skipped. The set lines switch off SDL's own test library, and SDL_ttf's text shaping and color emoji, which saves a good deal of building. Then comes SDL itself:

# SDL and SDL_ttf: if they're installed already, in new enough versions,
# CMake uses them, and if not, it downloads and builds them, the first time
# only
string(CONCAT sdl_url "https://github.com/libsdl-org/SDL/releases/download/"
    "release-3.4.4/SDL3-3.4.4.tar.gz")
string(CONCAT ttf_url "https://github.com/libsdl-org/SDL_ttf/releases/download/"
    "release-3.2.2/SDL3_ttf-3.2.2.tar.gz")
include(FetchContent)
FetchContent_Declare(SDL3
    URL ${sdl_url}
    DOWNLOAD_EXTRACT_TIMESTAMP TRUE
    FIND_PACKAGE_ARGS 3.4 CONFIG)
FetchContent_Declare(SDL3_ttf
    URL ${ttf_url}
    DOWNLOAD_EXTRACT_TIMESTAMP TRUE
    FIND_PACKAGE_ARGS 3.2 CONFIG)
FetchContent_MakeAvailable(SDL3 SDL3_ttf)

In the preceding code, the two string(CONCAT ...) lines make the addresses of the releases the book was written with, each from two halves, so that neither line is too long to read. Each FetchContent_Declare names a library, and says where to download its source code from. The words FIND_PACKAGE_ARGS ask CMake to look for the library on your system first, in at least the version given, and only download it if it isn't there. Then FetchContent_MakeAvailable does whichever is needed, for both.

The last part is what makes the file work for every demo:

# One program for each folder with a main.cpp in it
file(GLOB folders LIST_DIRECTORIES true RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
    "${CMAKE_CURRENT_SOURCE_DIR}/*")
foreach(folder IN LISTS folders)
    set(dir "${CMAKE_CURRENT_SOURCE_DIR}/${folder}")
    if(NOT EXISTS "${dir}/main.cpp")
        continue()
    endif()
    file(GLOB sources CONFIGURE_DEPENDS "${dir}/*.cpp")
    file(GLOB headers CONFIGURE_DEPENDS "${dir}/*.h")

    # A program's name can't have spaces, so "Vector Lab" is Vector_Lab
    string(REGEX REPLACE "[^A-Za-z0-9_.+-]" "_" target "${folder}")
    add_executable(${target} ${sources} ${headers})
    target_link_libraries(${target} PRIVATE SDL3_ttf::SDL3_ttf SDL3::SDL3)
    set_target_properties(${target} PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${dir}"
        RUNTIME_OUTPUT_DIRECTORY_DEBUG "${dir}"
        RUNTIME_OUTPUT_DIRECTORY_RELEASE "${dir}")

    # The font goes beside the program, and on Windows, SDL's DLLs too
    add_custom_command(TARGET ${target} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/RobotoMono-Light.ttf" "${dir}")
    if(WIN32)
        add_custom_command(TARGET ${target} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                $<TARGET_RUNTIME_DLLS:${target}> "${dir}"
            COMMAND_EXPAND_LISTS)
    endif()
endforeach()

In the preceding code, the loop looks at every folder beside the file, and each one with a main.cpp in it becomes a program, built from its .cpp and .h files. The program is named after its folder, with an underscore where each space was, so the Vector Lab folder makes a program called Vector_Lab. It's built into its own folder. After each build, the font is copied beside it, since every demo looks for the font in the program's own folder. On Windows, SDL's two DLLs are copied there too. Mesh Viewer's pyramid.obj is in its folder already, beside the program.

The words CONFIGURE_DEPENDS make CMake look for new files at every build, so a file you add to a folder is built without any more fuss. The folders that hold SDL have no main.cpp, so they're skipped.

Building, Running and Debugging

The first time, building a demo takes four steps, and after that, one:

  1. Start VS Code, and open the repository's folder itself, the one with CMakeLists.txt in it, with File > Open Folder. If VS Code asks whether you trust the authors of the files in the folder, choose to trust them, since this is the book's code.
  2. CMake Tools notices the CMakeLists.txt file, and asks which kit to use, which means which compiler. On a Mac, choose the one that starts with Clang, and on Linux, the one that starts with GCC. If no question appears, press Cmd+Shift+P on a Mac, or Ctrl+Shift+P on Linux, for the Command Palette. Then run CMake: Select a Kit from there.
  3. CMake Tools then configures the project: it reads CMakeLists.txt. The first time, unless SDL is installed already, it also downloads SDL and SDL_ttf, about 17 MB in all. Watch the Output panel at the bottom of the window. It's done when the last lines say "Build files have been written to" a folder called build.
  4. Open the Command Palette, run CMake: Set Build Target, and choose the demo you want, such as Vector_Lab. Then run CMake: Build. The first build takes a few minutes, because SDL itself is being built, and later builds only rebuild what you've changed.

To run the demo, use a terminal. In VS Code, choose Terminal > New Terminal, and type this, for Vector Lab:

cd "Vector Lab"
./Vector_Lab

The quotes are there because the folder's name has a space in it. The demo finds its font beside the program, so it runs from any folder, as "Vector Lab/Vector_Lab" from the repository's folder, say. The messages that SDL_Log writes, which the console window shows on Windows, appear in the terminal.

To debug, VS Code needs to know how to start the demo: which program, and from which folder. Choose Run > Add Configuration, and if it offers a choice of debuggers, choose C++ (GDB/LLDB). It makes a file called launch.json, in a folder called .vscode. Replace everything in it with this, and save it:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug the demo",
            "type": "cppdbg",
            "request": "launch",
            "program": "${command:cmake.launchTargetPath}",
            "args": [],
            "cwd": "${command:cmake.getLaunchTargetDirectory}",
            "osx": { "MIMode": "lldb" },
            "linux": { "MIMode": "gdb" }
        }
    ]
}

In the preceding code, the two ${command:...} values are filled in by CMake Tools: the program of the demo you've chosen, and the folder it was built in, which is its own folder. Choose the demo with CMake: Set Launch/Debug Target, then press F5, and the demo starts in the debugger.

Note

On a Mac, the first time you debug, macOS may ask for your password so that the debugger can take control of the program. That's normal: it's the permission that every debugger on a Mac needs.

The debugger works just like Visual Studio's, with the same keys. Click in the margin beside a line's number, or press F9, to set a breakpoint. When the demo stops on it, the Variables view on the left shows every variable, as Visual Studio's Locals and Autos windows do. F10 steps over a line, F11 steps into a function, and F5 carries on.

Names Must Match Exactly

Windows doesn't care whether you write Vec2.h or vec2.h: it finds the same file either way. Linux does care, and treats them as two different names, so an #include "vec2.h" that works on Windows stops the build on Linux, when the file is called Vec2.h. Most Macs don't care either, until code written on one moves to Linux.

Every name in the book's code matches its file exactly, letter for letter, and so does every file the demos open, such as the font and pyramid.obj. Keep to that in your own code, and a program you build on one system builds on all three.

A Program of Your Own

Every demo started as a copy of the skeleton, and a program of your own can start the same way. Any folder with a main.cpp in it becomes a program, so yours is a folder beside the demos':

  1. In VS Code's Explorer, right-click the Skeleton folder, and choose Copy. Then right-click the empty space below the folders, and choose Paste. Right-click the copy, choose Rename, and give it a name of your own, such as My Demo.
  2. Wherever a chapter adds a header, such as Vec2.h, copy it from that chapter's demo into your folder. Any .cpp or .h file you make in your folder is built with it.

The first time, open the Command Palette and run CMake: Configure, so that CMake finds your folder. Then choose My_Demo with CMake: Set Build Target and CMake: Set Launch/Debug Target. After that, your program builds and runs just as the demos do.

Where the Book's Windows Steps Differ

Most of the book reads exactly the same on a Mac or on Linux, but the steps that belong to Visual Studio or to Windows have their own equivalents:

  • Chapter 1's Getting the Code and A Project of Your Own. Finding SDL, the project's settings, and copying the font are all the CMakeLists.txt file's job. There's no DLL to copy on a Mac or on Linux: the build tells each program where SDL's libraries are.
  • F5. Running a demo is ./ and its program's name in a terminal, in its folder. Debugging it is F5, with the launch.json file from Building, Running and Debugging.
  • The console window. Where Chapter 1 sends you to the console window for a message, such as "Font not found", read the terminal instead.
  • Chapter 1's settings for a console-free program. The SubSystem setting is Windows' alone. On a Mac or on Linux, a program started from a terminal writes to it, and one started any other way has no console to hide.
  • The right button. On a Mac trackpad, a right-click is a click with two fingers. Matrix Sandbox's probe and Camera's tile picker need one. Vector Lab's b, and the erasing in Flood and A-Star Explorer, need the right button held while the mouse moves, which is far easier with a mouse.
  • The mouse wheel. On a trackpad, the wheel is two fingers sliding up and down. On a Mac with natural scrolling, as Macs have unless it's switched off, the wheel's directions in the book are the other way round for you.

Everything else in the chapters, the code above all, is the same on all three systems.

When Something Goes Wrong

CMake says it needs version 3.24 or later. Your CMake is too old. Install a newer one, as in Setting Up a Mac or Setting Up Linux, and configure again.

Configuring stops with "Could NOT find Freetype". SDL_ttf needs FreeType to read fonts, and it isn't installed. Run brew install freetype on a Mac, sudo apt install libfreetype-dev on Ubuntu or Debian, or sudo dnf install freetype-devel on Fedora. Then run CMake: Delete Cache and Reconfigure.

On Linux, configuring stops because SDL can't find X11 or Wayland, or the demo opens no window. SDL was built without the packages it needs for your windowing system. Install the whole list from Setting Up Linux, then run CMake: Delete Cache and Reconfigure, so that SDL is built again with them.

Configuring fails while downloading. The first configure needs an internet connection, to download SDL. Once it has succeeded, the downloads are kept in the build folder, and it doesn't need the internet again, unless you delete that folder.

The window opens, but there's no text, and the terminal says the font wasn't found. The font isn't beside the program. Run CMake: Clean Rebuild, which builds the program afresh and copies the font beside it. If the font is still missing, check that RobotoMono-Light.ttf is at the top of the repository.

The build can't find a header, such as SDL3_ttf/SDL_ttf.h. The configure step didn't finish. Read the Output panel from the top, fix the first problem it reports, and configure again.

Everything was working, and now it isn't. Run CMake: Delete Cache and Reconfigure. It starts CMake's bookkeeping afresh, which cures most of the strange problems that come from moving folders around or changing tools.

With that, you're set up the way the rest of the book assumes: a demo open, a program running, and a debugger ready when you need it. Every chapter, from the first point on the screen to the tumbling slab of the last, is yours to build, on whichever computer you have.