In this lesson, we’ll cover how to set up our project using the CMake build system. CMake is an industry-standard way of managing cross-platform C++ projects.
It is supported by most IDEs, so following this guide will work in a lot of contexts.
If you’re not using CMake, and trying to get your project setup in Xcode or Visual Studio instead, these tutorials will be more useful:
Rather than installing a prebuilt version of SDL, we’ll compile it ourselves from the source code. Building the project on our own machines minimizes any possible incompatibility issues, and SDL has included a few scripts that make it easy.
The first step is to acquire the source code for SDL2. The latest version is available from the Releases page on the official GitHub repository, here: https://github.com/libsdl-org/SDL/releases
At the bottom of the latest release, we should see links to download the source code, as either a .zip
or a .tar.gz
 file.
Once downloaded, we should extract the files somewhere on our hard drive where we can easily access them.
Once the source code is extracted, we should navigate to that folder, which will usually be called SDL-main
. Inside that folder, create a new directory called build
.
Next, open a terminal window in that location, and run ../configure
The main cause of this error is that the terminal window is not in the correct location. We want the build folder to be inside the folder that was decompressed from the GitHub download. Then, we want the terminal to be open inside that folder.
You can check for this using the command pwd
- the output is likely to be something like:
/Users/your-name/Downloads/SDL-main/build
Specifically, we want the ending of this output to be SDL-main/build
. If that is not the case, ensure you’re creating the correct folder hierarchy and try again
The configure
command will scan your system to better understand how SDL2 should be compiled. It should complete within a few seconds.
When it is complete, run the command make
in the same build
location. This command will take a little longer, as it is compiling SDL2.
When that process completes, we next need to install the software onto our machine. That can be done with the command: sudo make install
Finally, when that completes, we should run the following command, again from the build
folder: sdl2-config --libs --cflags
This command will show exactly where SDL2 was installed. Copy that output somewhere - we will need it later. The output will look something like this:
-L/usr/local/lib -lSDL2
-I/usr/local/include/SDL2 -D_THREAD_SAFE
In summary, the 4 commands we need to run, in order, from the build folder are:
../configure
make
sudo make install
sdl2-config --cflags --libs
With this step complete, it’s time to move over to our CMake project and add SDL2 to it
CMakeLists.txt
The primary way CMake projects are configured is with a CMakeLists.txt
file, stored at the root of our project.
It’s possible our editor already created one for us. But, if not, a basic CMakeLists.txt
file would look something like this:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
project(Sandbox VERSION 1.0.0)
add_executable(Sandbox main.cpp)
Here, we are setting up some configuration, like which version of the C++ standard we want to use. Then, we’re creating our project, and defining what source code files it has.
In this example, our project is called “Sandbox” and the only file it has is main.cpp
. Your project name is likely to be different, so you substitute your name into these steps instead. So, any time one of our steps has the word "Sandbox", you should replace that with your project name.
To update this configuration to include SDL2, we need to make two additions to our CMakeLists.txt
 file:
CMakeLists.txt
Our earlier call to sdl2-config --libs --cflags
should have given us two directories.
For example, my output was:
-L/usr/local/lib -lSDL2
-I/usr/local/include/SDL2 -D_THREAD_SAFE
We need to add the second directory - the one that has /include
as a target in our CMake project.
We do that by adding a call to target_include_directories
to our CMakeLists.txt
file. This call needs to come after the project
 call.
For example, in my case, it looks like this:
target_include_directories(
Sandbox PRIVATE /usr/local/include/SDL2
)
We have the name of our project, Sandbox
in my case (yours is likely different), we have the keyword PRIVATE
, then we have the path of our include directory. All three arguments are separated by spaces.
target_include_directories
in my CMakeLists.txt
fileThat’s not a problem - it’s safe to have multiple calls:
target_include_directories(
Sandbox PRIVATE /some/directory
)
target_include_directories(
Sandbox PRIVATE /usr/local/include/SDL2
)
You can combine them into a single call, if preferred, by separating each directory with a space, or a line break:
target_include_directories(
Sandbox
PRIVATE
/some/directory
/usr/local/include/SDL2
)
CMakeLists.txt
Adding the library is broadly similar to adding the include directory. However, I recommend linking the exact library file we want to use, rather than just the directory.
To find the file, navigate to the directory that was returned by sdl2-config --libs
In my case, that is /usr/local/lib
In that folder, we’re looking for our recently installed SDL2 library. It will have a .dll
extension (if on Windows) or a .dylib
file (if on MacOS)
On MacOS, there is likely to be two files. Either will work - one is just an alias of the other.
Once we have the path to our library, we need to add it to our CMakeLists.txt
file, just like we did with the include directory.
The only difference is we use target_link_libraries
instead, and pass the full path:
target_link_libraries(
Sandbox
PRIVATE
/usr/local/lib/libSDL2.dylib
)
My complete CMakeLists.txt
file looks like this:
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
project(Sandbox VERSION 1.0.0)
add_executable(Sandbox main.cpp)
target_include_directories(
Sandbox
PRIVATE
/usr/local/include/SDL2
)
target_link_libraries(
Sandbox
PRIVATE
/usr/local/lib/libSDL2.dylib
)
With everything set up, we should now be able to create windows. To confirm, paste the following code into our main.cpp
 file:
#include <SDL.h>
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* Window { SDL_CreateWindow(
"Hello Window", 0, 0, 800, 300, 0
) };
SDL_Surface* WindowSurface { SDL_GetWindowSurface(Window) };
SDL_FillRect(
WindowSurface,
nullptr,
SDL_MapRGB(WindowSurface->format, 40, 40, 40)
);
SDL_UpdateWindowSurface(Window);
SDL_Event event;
while(true) {
SDL_PollEvent(&event);
}
}
After compiling and running our program, we should see our blank window pop up:
In our Introduction to C++ course, we pick up from this successful installation. We first explain what every line of this code is doing. Then, we build upon it to create a complete application with SDL2.
You can view the first lesson of that chapter here:
Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games