SDL3 Introduction
The Simple DirectMedia Layer (SDL) library provides a “cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D” (https://www.libsdl.org/). This library is used in games (and other software), particularly where the developers want a cross-platform solution. Even though it is powerful enough for production-quality code (such as some of Valve’s titles), it is easy enough for us to use in our projects as well. This post is a recap of the official documentation; I include it here for your convenience.
The newest version of SDL - version 3 - was released in 2025, and it is easier than ever to include it in your own codebases. While there are multiple ways we can add it to a project, we will concentrate on using the powerful CMake build system in this tutorial. For those of you that don’t know what CMake is, I will try to cover that in a later blog post. For now just know that it is a tool that helps us use other tools to build our code. If you don’t have CMake installed on your system, do that first. You can do so with your system’s package manager, or from the website at https://cmake.org/. Make sure you add it to your system’s PATH variable when you install. You may need to log out and back in again to ensure the PATH is updated.
Once CMake is installed and you can find it on your system, create a new project folder. In that folder, use the command git clone https://github.com/libsdl-org/SDL.git vendored/SDL to download the current version of SDL. This will put the code in a directory called vendored, which is where we will be putting all of our third-party libraries this semester. Now, we need to make a file called CMakeLists.txt. This is a file that tells CMake what we are trying to accomplish. Inside of it, add the code
cmake_minimum_required(VERSION 3.16)
project(hello)
# set the output directory for built objects.
# This makes sure that the dynamic library goes into the build directory automatically.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
# This assumes the SDL source is available in vendored/SDL
add_subdirectory(vendored/SDL EXCLUDE_FROM_ALL)
# Create your game executable target as usual
add_executable(hello WIN32 hello.c)
# Link to the actual SDL3 library.
target_link_libraries(hello PRIVATE SDL3::SDL3)
Now, create a file called hello.c. Place the code
/*
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
/* Create the window */
if (!SDL_CreateWindowAndRenderer("Hello World", 800, 600, SDL_WINDOW_FULLSCREEN, &window, &renderer)) {
SDL_Log("Couldn't create window and renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE;
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_KEY_DOWN ||
event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE;
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
const char *message = "Hello World!";
int w = 0, h = 0;
float x, y;
const float scale = 4.0f;
/* Center the message and scale it up */
SDL_GetRenderOutputSize(renderer, &w, &h);
SDL_SetRenderScale(renderer, scale, scale);
x = ((w / scale) - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(message)) / 2;
y = ((h / scale) - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) / 2;
/* Draw the message */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, x, y, message);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
}
We will go over all of this in class. It is simply a “Hello World”-style program for SDL3. Save this file. Now, to create the build system, type
cmake -S . -B build
cmake --build build
This will create a new directory called build where the generated and compiled code will go. You should now be able to go into the build directory and enter
./hello
or
./hello.exe
if you are on Windows to run the example. You should see a window pop up. Barring any errors, you now have SDL3 included in your project and are ready to take advantage of its (many) powerful features.