How do I use SDL2 in my programs correctly?
I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
Solution 1:
This answer deals with MinGW / GCC, and not Visual Studio.
This answer deals primarily with Windows. Things are easier on other OSes, see the bottom of the answer for a summary.
I tried to keep this answer dead simple, so that even a newbie can use it.
Common errors
The common errors you can get are:
-
SDL.h: No such file or directory
(when compiling) -
undefined reference to
various functions (when linking) - Mysterious
.dll
-related errors (when running your program).
This list is sorted from bad to good. If you change something and get a different error, use this list to tell if you made things better or worse.
See the answer below for how to fix all of those.
The preamble
Here's some things I want to tell you before we get to fixing the errors.
0. Don't follow bad advice.
Some resources will suggest you to do #define SDL_MAIN_HANDLED
or #undef main
. Don't blindly follow that advice, it's not how SDL2 is intended to be used.
If you do everything correcty, it will never be necessary. Learn the intended approach first. Then you can research what exactly that does, and make an educated decision.
1. Figure out how to compile directly from the console, you can start using an IDE later. If you're using an IDE, I suggest to first make sure you're able to compile your program directly from the console, to rule out any IDE configuration problems. After you figure that out, you can use the same compiler options in your IDE.
I also suggest avoiding CMake if you just started, to rule out any CMake-related problems. You can start using it later.
2. Download the right SDL2 files. Make sure you have the right files. You need the archive called SDL2-devel-2.0.x-mingw.tar.gz
from here.
Unpack it in any directory, preferably somewhere near your source code. Unpacking directly into the compiler directory is often considered a bad practice.
3. Know the difference between compiler flags and linker flags. A "flag" is an option you specify in the command line when building your program. When you use a single command, like g++ foo.cpp -o foo.exe
, all your flags are added to the same place (to this single command).
But when you build your program in two steps, e.g.:
-
g++ foo.cpp -c -o foo.o
(compiling) -
g++ foo.o -o foo.exe
(linking)
you have to know which of the two commands to add a flag to. The flags that need to be added to the first command are "compiler flags" and the flags that need to be added to the second are "linker flags". In the answer below, when telling you to add a flag, I'll specify if it's a compiler flag or a linker flag.
Most IDEs will require you to specify compiler and linker flags separately, so even if you use a single command now, it's good to know which flag goes where.
Unless specified otherwise, the order of the flags doesn't matter.
SDL.h: No such file or directory
Or any similar errors related to including SDL.h
or SDL2/SDL.h
.
You need to tell your compiler in which directory SDL.h
is located. It's in the SDL files you've downloaded (see preamble).
Add following to your compiler flags: -I
, followed by a directory.
Example: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2
. (Relative paths work too, e.g. -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2
.)
Note that the flag can be different depending on how you write the #include
:
- If you do
#include <SDL.h>
, then the path should end with.../include/SDL2
(like above). This is the recommended way. - If you do
#include <SDL2/SDL.h>
, then the path should end with.../include
.
undefined reference to
various functions
The error message will mention various SDL_...
functions (often the ones you use in your program), and/or WinMain
. If it mentions SDL_main
, consult the section "undefined reference to SDL_main
only" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2
. The order matters. The flags must appear AFTER any .c
/.cpp
/.o
files.
Writing -lSDL2main -lSDL2
tells the linker to use files called libSDL2main.a
, libSDL2.a
(or libSDL2.dll.a
) that are included in the SDL files you downloaded. You need one more flag to tell the linker where to look for those .a
files. Add following to your linker flags: -L
, followed by the directory.
Example: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib
. (Relative paths work too, e.g. -LSDL2-2.0.12/x86_64-w64-mingw32/lib
.)
I added all those flags and nothing changed:
If you did that and still get the same undefined reference
errors, you probably use the wrong SDL .a
files. The archive you downloaded contains two sets of files: i686-w64-mingw32
(32-bit) and x86_64-w64-mingw32
(64-bit). You must use the files matching your compiler, which can also be either 32-bit or 64-bit. Print (8*sizeof(void*))
to see if your compiler is 32-bit or 64-bit. Even if you think you use the right files, try the other ones to be sure.
A few of the MinGW versions can be switched between 32-bit and 64-bit modes using -m32
and -m64
flags (those probably have to be added to both compiler and linker flags). You can try those too.
I get undefined reference
to a specific function:
• undefined reference to WinMain
only
There are several possibilities, all of which were covered in the previous section:
- You forgot
-lmingw32
and/or-lSDL2main
flags.
You must use following linker flags, in this exact order, after any.c
/.cpp
/.o
files:-lmingw32 -lSDL2main -lSDL2
- The
libSDL2main.a
file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa).
Try to avoid #define SDL_MAIN_HANDLED
or #undef main
when solving this issue, see preamble for explanation.
• undefined reference to SDL_main
only
You need to have a main
function. Your main
function must look like int main(int, char **)
. NOT int main()
and NOT void main()
. This is one of the SDL2 quirks.
Adding any parameter names is allowed, e.g. int main(int argc, char **argv)
. Also the second parameter can be written as char *[]
or with a name: char *argv[]
. No other changes are allowed.
If your project has multiple source files, make sure to include SDL.h
in the file that defines the main
function, even if it doesn't otherwise use SDL directly.
Try to avoid #define SDL_MAIN_HANDLED
or #undef main
when solving this issue, see preamble for explanation.
.dll
-related errors
You've successfully built an .exe
, but can't run it because of mysterious errors mentioning some .dll
s. You're almost there!
The .exe
you made needs some .dll
s to run. If it doesn't find them, it will tell you and refuse to run. This is easy. It can also find wrong versions of them left over from some other programs you've installed, then you'll get some very cryptic errors.
Your program will look for the .dll
s in different locations, but the most reliable solution is to put them in the same directory as the .exe
. This directory is searched first, so other versions of the .dll
s you might have elsewhere won't interfere.
You need to figure out which .dll
s your program needs and put them in the directory where your .exe
is (except for the system .dll
s, which you don't need to copy).
There are two types of errors you can get:
-
An error that just tells you what
.dll
is missing.-
SDL2.dll
is missing. — It's in the SDL files you've downloaded.Be aware that the files contain two different
SDL2.dll
s: a 32-bit one (ini686-w64-mingw32
directory), and a 64-bit one (inx86_64-w64-mingw32
). Get the right one, if necessary try both. -
Some other
.dll
is missing. — It's shipped with your compiler. Look in the directory where yourgcc.exe
is.If you copy one
.dll
and it asks for more, that's normal, you might need to repeat this ~3 times.
-
-
A cryptic
.dll
-related error. — Your program found a wrong version of a.dll
somewhere in your system.You need to copy all non-system
.dll
s it needs to the directory where your.exe
is.First, copy
SDL2.dll
(see the section "SDL2.dll
is missing" above for where to find it).Then, copy following
.dll
s from your compiler directory (the directory wheregcc.exe
is located):-
libgcc_s_seh-1.dll
(the name can vary depending on your MinGW version, but will always start withlibgcc
) -
libstdc++-6.dll
(for C++ only, skip if you're writing in C) -
libwinpthread-1.dll
(the name can vary depending on your MinGW version, but will always mentionthread
; some versions don't use this at all)
For some MinGW distributions, those may not be the right
.dll
s. If you don't see those or copying them doesn't help, continue reading. -
That should fix all your errors. If you want to know more or it didn't help:
More information about the .dll
s
It's possible to make an .exe
that doesn't depend on any (non-system) .dll
s by using the -static
linker flag, this is called "static linking". This is rarely done, and you shouldn't need to do this if you did the above steps correctly. This requires different linker flags than usual (around 20 of them), see sdl2.pc
file shipped with SDL for the exact flags (they are in the Libs.private
section).
In the previous section I tried to guess what .dll
s your program depends on. How did I know? There are several ways to figure it out for yourself:
-
The crude way:
Open the console,
cd
to the directory where your.exe
is located, then typeset PATH=
(don't worry, this doesn't change your systemPATH
setting and only affects the current console session).Remove any
.dll
s that you may have already copied there.Now if you run the
.exe
from this console, it will only be able to find the system.dll
s. It will look for non-system ones only in the current directory (which has none). Now you'll get clear error messages saying what.dll
s are required, and you can copy them one by one until it starts working. This way you'll know all non-system.dll
s your program uses.Note that this method is not completely fool-proof.
C:\Windows
and some of the nested directories are always searched, even in this case. Normally it doesn't matter if the only.dll
s in there are the system ones, but if some crappy installer copied a custom.dll
in there, then this method won't work correctly.It's a good idea to search through
C:\Windows
and nested directories for.dll
s that shouldn't be there, and delete them. Look forSDL2.dll
and for any.dll
s that are also shipped with your compiler (in the directory where yourgcc.exe
is located). -
The civilized way:
Use a tool like Dependency Walker or
ntldd
. You'll have to go through their output and determine if each.dll
is a system or non-system one. If a.dll
is shipped with your compiler or belongs to a library you use (SDL2.dll
), then it's a non-system one. Any remaining.dll
s are system ones, ignore them.
Other problems
-
Q: My program always opens a console window when I run it, in addition to any windows I open using SDL. How do I get rid of it?
- A: Add
-mwindows
to the linker flags.
- A: Add
-
Q: My program has the default file icon, but I want a custom one.
-
A: Your icon must be in the
.ico
format. If your graphics editor doesn't support it, make a series of.png
s of common sizes (e.g. 16x16, 32x32, 48x48, 64x64), then convert them to a single.ico
using ImageMagick:magick *.png result.ico
(or withconvert
instead ofmagick
).Create a file with
.rc
extension (let's sayicon.rc
), type following into it:MAINICON ICON "icon.ico"
(the first part is an arbitrary name, you can change it; the second part must always beICON
, the third part is the path to the icon). Convert the file to an.o
usingwindres -i icon.rc -o icon.o
(thewindres
program is shipped with your compiler). Specify the resulting.o
file when linking, e.g.g++ foo.cpp icon.o -o foo.exe
.Recent versions of SDL2 have a nice property of using the same icon as the window icon, so you don't have to use
SDL_SetWindowIcon
.
-
-
Q: I get error
'SDL_VideoMode' wasn't declared in this scope
.- A:
SDL_VideoMode
existed in SDL1.2, but isn't a part of SDL2. Your code was written for the outdated SDL1.2. Find a better tutorial that deals with the new SDL2.
- A:
I'm not on Windows, what do I do differently?
The whole answer above is primarily targeted at MinGW and Windows. If you're not on Windows, things become easier:
-
No
.dll
-related problems. -
No need to manually download SDL2, it should be in your package manager.
-
No need to think about which compiler or linker flags to use:
-
pkg-config --cflags sdl2
will tell you the compiler flags. -
pkg-config --libs sdl2
will tell you the linker flags. Add--static
if you want flags for static linking.
-
-
You don't need
-lSDL2main
, and there are no problems related toSDL_main
.
On the other hand:
-
Distributing your programs to other people becomes harder, you can't just ship a bunch of
.dll
s with your program. -
The process of setting a custom icon is different.
Alternative approach: use a Linux-like enviroment on Windows
Does the part of the previous section about installing libraries and determining compiler flags automatically sound convenient? You can have that on Windows too.
Download MSYS2. You'll have a package manager (from which you can install SDL), up-to-date compilers, and a set of common utilities ported from Linux (including pkg-config
). This solves most of the Windows-specific problems.
Solution 2:
On Mac this is what I follow for XCode (must install g++):
sdl linking:
g++ main.cpp -o main $(sdl2-config --cflags --libs)
XCODE project steps:
-
open terminal app (macOS)
-
BUILD SETTINGS (select 'all' and 'combined' search bar enter: "search")
-
click on "header search paths(way right side click)
-
add:
/usr/local/include
-
BUILD PHASES --> LINK BINARY LIBRARIES (click plus)
-
type in
SDL
--> click "add other" -
press: command+SHIFT+g (to bring search bar)
-
type in:
usr/local/Cellar
-
navigate to: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (make sure not shortcut)