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.
This answer is about MinGW / GCC, and not Visual Studio.
This answer only applies to Windows.
The common errors are:
SDL.h: No such file or directory
(when compiling)SDL_main
problems: "undefined reference to SDL_main", "conflicting types for SDL_main" or "number of arguments doesn't match prototype", etc. (when compiling or linking)undefined reference
to other functions (when linking)'??.dll' was not found
procedure entry point ... could not be located in ...
, and other mysterious DLL-related errorsThis 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.
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 and/or build system 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.
The same applies to build systems, such as CMake.
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.
Extract it to any directory, preferably somewhere near your source code. Extracting into the compiler installation directory is often considered a bad practice (and so is copying them to C:\Windows
, which is a horrible idea).
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, e.g. 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. Those are "compiler flags" and "linker flags" respectively.
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 error related to including SDL.h
or SDL2/SDL.h
.
You need to tell your compiler where to look for SDL.h
. It's in the SDL files you've downloaded (see preamble).
Add -Ipath
to your compiler flags, where path
is the directory where SDL.h
is located.
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 path will be different depending on how you write the #include
:
#include <SDL.h>
, then the path should end with .../include/SDL2
(like above). This is the recommended way.#include <SDL2/SDL.h>
, then the path should end with .../include
.Note: SDL2_image (and probably other SDL addons) uses #include "SDL.h"
in its headers. So you must either use the former option, or copy SDL2_image's include
directory on top of SDL2's include
directory to have SDL_image.h
in the same directory as SDL.h
.
SDL_main
problemsYou can get several different errors mentioning SDL_main
, such as undefined reference to SDL_main
, or conflicting types for 'SDL_main'
, or number of arguments doesn't match prototype
, etc.
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 a quirk of SDL2, related to it doing #define main SDL_main
.
Adding parameter names is allowed (and is mandatory in C), 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.
Remove #define SDL_MAIN_HANDLED
and #undef main
if you have them, see preamble for explanation.
undefined reference to
various functionsundefined reference to SDL_...
The error message will mention various SDL_...
functions, and/or WinMain
. If it mentions SDL_main
, consult the section "Various SDL_main
problems" above. If the function names don't start with SDL_
, consult the section "undefined reference to other functions" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2 -Lpath
, where path
is the directory where libSDL2.dll.a
and libSDL2main.a
(which you've downloaded) are located. The order of the -l...
flags matters. They must appear AFTER any .c
/.cpp
/.o
files.
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
.
When you use -l???
, the linker will look for a file called lib???.dll.a
or lib???.a
(and some other variants), which is why we need to pass the location of those files. libmingw32.a
(corresponding to -lmingw32
) is shipped with your compiler, so it already knows where to find it.
I added all those flags and nothing changed, or I'm getting skipping incompatible X when searching for Y
:
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.
Some MinGW versions can be switched between 32-bit and 64-bit modes using -m32
and -m64
flags (add them to both compiler and linker flags).
I get undefined reference
to a specific function:
undefined reference to WinMain
onlyThere are several possibilities, all of which were covered in the previous section:
-lmingw32
and/or -lSDL2main
linker flags..c
/.cpp
/.o
files: -lmingw32 -lSDL2main -lSDL2
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
onlySee the section "Various SDL_main
problems" above.
undefined reference
to other functionsYour linker found and used libSDL2.a
, but it should be finding and using libSDL2.dll.a
. When both are available, it prefers the latter by default, meaning you didn't copy the latter to the directory you passed to -L
.
If you intended to perform static linking, see the section called "How do I distribute my app to others?" below.
If you get any of those:
??.dll was not found
procedure entry point ... could not be located in ...
and other cryptic DLL errorsConsult How to debug DLL issues in MinGW?
There is MSYS2.
It has a package manager that lets you download prebuilt libraries, and, as a bonus, a fresh version of the compiler.
Install SDL2 from its package manager. Use a tool called pkg-config
(also from the package manager) to automatically determine all necessary flags (pkg-config --cflags SDL2
for compiler flags, pkg-config --libs SDL2
for linker flags).
This is the same experience as you would have on Linux (maybe except for some DLL management hassle).
Q: My program always opens a console window when I run it, how do I hide it?
-mwindows
to the linker flags.Q: I get error 'SDL_VideoMode' wasn't declared in this scope
.
SDL_VideoMode
is from SDL1.2, it's not a part of the newer SDL2. Your code was written for the outdated version of SDL. Find a better tutorial that deals specifically with SDL2.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 with convert
instead of magick
).
Create a file with the .rc
extension (say, icon.rc
), with following contents MyIconName ICON "icon.ico"
(where MyIconName
is an arbitrary name, and "icon.ico"
is the path to the icon). Convert the file to an .o
using windres -O res -i icon.rc -o icon.o
(the windres
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
.