问题描述
我想使用SDL2制作游戏,但是我无法编译和/或运行我的代码,请帮忙!
I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
众所周知,SDL2很难安装,并且通常是有志于游戏开发的第一个尝试使用该库的人.
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
这篇文章旨在作为有关设置SDL2常见问题的规范重复.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
推荐答案
此答案涉及MinGW/GCC,而不涉及Visual Studio.
This answer deals with MinGW / GCC, and not Visual Studio.
此答案主要针对Windows.在其他操作系统上,事情变得更容易了,请参阅答案的底部以获取摘要.
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.
您会遇到的常见错误是:
The common errors you can get are:
-
SDL.h:没有这样的文件或目录
(编译时) -
对各种功能的未定义引用
(链接时) - 与
.dll
有关的神秘错误(运行程序时).
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.
在纠正错误之前,我想告诉您一些事情.
Here's some things I want to tell you before we get to fixing the errors.
0.不要听不好的建议.
一些资源会建议您执行 #define SDL_MAIN_HANDLED
或 #undef main
.不要这样做.这些解决方案与SDL2的使用方式有所不同,并且通过正确的设置,它们永远都不需要.
Some resources will suggest you to do #define SDL_MAIN_HANDLED
or #undef main
. Don't do that. Those solutions deviate from how SDL2 is intended to be used, and with the right setup they are NEVER necessary.
有人认为这些方法比预期的方法要好,但是我建议先学习预期的方法,然后了解区别,然后然后做出有根据的决定.
Some argue that those are better than the intended way, but I suggest to learn the intended way first, then learn what the difference is, and then make an educated decision.
1.了解如何直接从控制台进行编译,以后可以开始使用IDE.如果您使用的是IDE,建议您首先确保您能够直接从控制台编译程序,以排除任何IDE配置问题.弄清楚之后,您可以在IDE中使用相同的编译器选项.
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.
我还建议您避免刚开始使用CMake,以排除任何与CMake相关的问题.您可以稍后再使用.
I also suggest avoiding CMake if you just started, to rule out any CMake-related problems. You can start using it later.
2.下载正确的SDL2文件.确保您拥有正确的文件.您需要来自SDL2-devel-2.0.x-mingw.tar.gz 的存档nofollow noreferrer>此处.
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.了解编译器标志和链接器标志之间的区别.是在构建程序时在命令行中指定的选项.当您使用单个命令(例如 g ++ foo.cpp -o foo.exe
)时,所有标志都添加到同一位置(此单个命令).
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
(编译) -
g ++ foo.o -o foo.exe
(链接)
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.
大多数IDE将要求您分别指定编译器和链接器标志,因此即使您使用单个命令 now ,也最好知道哪个标志在哪里.
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
或 SDL2/SDL.h
有关的任何类似错误.
Or any similar errors related to including SDL.h
or SDL2/SDL.h
.
您需要告诉编译器 SDL.h
所在的目录.它在您下载的SDL文件中(请参见前言).
You need to tell your compiler the directory where SDL.h
is. It's in the SDL files you've downloaded (see preamble).
在编译器标志中添加以下内容: -I
,后跟目录.
Add following to your compiler flags: -I
, followed by a directory.
示例: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2
.(相对路径也有效,例如 -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2
.)
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
.)
请注意,根据您编写 #include
的方式,标记可以有所不同:
Note that the flag can be different depending on how you write the #include
:
- 如果执行
#include< SDL.h>
,则路径应以.../include/SDL2
结尾(如上).这是推荐的方法. - 如果您执行
#include< SDL2/SDL.h>
,则路径应以.../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
.
该错误消息将提及各种 SDL _...
函数(通常是您在程序中使用的函数)和/或 WinMain
.如果提到 SDL_main
,请参阅仅对SDL_main
的未定义引用"部分.在下面.
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.
您需要添加以下链接器标志: -lmingw32 -lSDL2main -lSDL2
.顺序很重要.这些标记必须出现在任何 .c
/ .cpp
/ .o
文件之后.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2
. The order matters. The flags must appear AFTER any .c
/.cpp
/.o
files.
编写 -lSDL2main -lSDL2
告诉链接器使用名为 libSDL2main.a
, libSDL2.a
(或 libSDL2)的文件.dll.a
)包含在您下载的SDL文件中.您还需要一个标志,以告知链接器在何处查找这些 .a
文件.在链接器标志中添加以下内容: -L
,然后是目录.
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.
示例: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib
.(相对路径也有效,例如 -LSDL2-2.0.12/x86_64-w64-mingw32/lib
.)
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
.)
我添加了所有这些标志,但没有做任何更改:
如果这样做,仍然出现相同的 undefined reference
错误,则可能使用了错误的SDL .a
文件.您下载的归档文件包含两组文件: i686-w64-mingw32
(32位)和 x86_64-w64-mingw32
(64位).您必须使用与您的编译器匹配的文件,这些文件也可以是32位或64位.打印(8 * sizeof(void *))
来查看您的编译器是32位还是64位.即使您认为使用的文件正确,也请尝试其他文件.
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.
一些MinGW版本可以使用 -m32
和 -m64
标志在32位和64位模式之间切换(可能必须将其添加到编译器和链接器标志).您也可以尝试.
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:
一共有三种可能性,上一节已经讨论了所有这些可能性:
There are three possibilities, all of which were covered in the previous section:
- 您忘记了
-lSDL2main
标志. - 您使用的
libSDL2main.a
文件与您的编译器不匹配(32位文件和64位编译器不匹配,反之亦然). - 您将
-lSDL2main
标志放在某些.c
/.cpp
/.o
的左侧文件.它必须始终在右边.
- You forgot the
-lSDL2main
flag. - The
libSDL2main.a
file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa). - You put the
-lSDL2main
flag to the left of some.c
/.cpp
/.o
files. It must always be to the right.
在解决此问题时,尽量避免使用 #define SDL_MAIN_HANDLED
或 #undef main
,请参见前言以获取解释.
Try to avoid #define SDL_MAIN_HANDLED
or #undef main
when solving this issue, see preamble for explanation.
您需要具有 main
函数.您的 main
函数必须类似于 int main(int,char **)
.否 int main()
和否 void main()
.这是SDL2的怪癖之一.
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.
允许添加任何参数名称,例如 int main(int argc,char ** argv)
.第二个参数也可以写为 char * []
或使用名称: char * argv []
.不允许其他更改.
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.
在解决此问题时,尽量避免使用 #define SDL_MAIN_HANDLED
或 #undef main
,请参见前言以获取解释.
Try to avoid #define SDL_MAIN_HANDLED
or #undef main
when solving this issue, see preamble for explanation.
您已经成功构建了 .exe
,但由于提到某些 .dll
的神秘错误而无法运行.你快到了!
You've successfully built an .exe
, but can't run it because of mysterious errors mentioning some .dll
s. You're almost there!
您创建的 .exe
需要一些 .dll
才能运行.如果找不到它们,它将告诉您并拒绝运行.这很简单.它还可以找到已安装的其他程序遗留下来的错误版本,然后会出现一些非常隐秘的错误.
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.
您的程序将在不同位置查找 .dll
,但是最可靠的解决方案是将它们放在与 .exe
相同的目录中.首先会搜索该目录,因此您可能在其他地方使用的其他版本的 .dll
s不会造成干扰.
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.
您需要弄清楚程序需要哪个 .dll
,并将它们放在 .exe
所在的目录中(除了系统 .dll
s,您无需复制).
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).
您会遇到两种错误:
-
仅告诉您缺少什么
.dll
的错误.
An error that just tells you what
.dll
is missing.
-
SDL2.dll
丢失. —在您下载的SDL文件中.
SDL2.dll
is missing. — It's in the SDL files you've downloaded.
请注意,文件包含两个不同的 SDL2.dll
s:一个32位文件(在 i686-w64-mingw32
目录中)和一个64位文件一个(在 x86_64-w64-mingw32
中).找到正确的一个,如有必要,请尝试两者.
Be aware that the files contain two different SDL2.dll
s: a 32-bit one (in i686-w64-mingw32
directory), and a 64-bit one (in x86_64-w64-mingw32
). Get the right one, if necessary try both.
缺少其他 .dll
. —编译器随附.在您的 gcc.exe
所在的目录中查找.
Some other .dll
is missing. — It's shipped with your compiler. Look in the directory where your gcc.exe
is.
如果您复制一个 .dll
并要求更多,这很正常,则可能需要重复此操作约3次.
If you copy one .dll
and it asks for more, that's normal, you might need to repeat this ~3 times.
与 .dll
有关的神秘错误. —您的程序在系统中的某个位置发现了 .dll
的错误版本.
A cryptic .dll
-related error. — Your program found a wrong version of a .dll
somewhere in your system.
您需要将其需要的所有非系统 .dll
复制到您的 .exe
所在的目录.
You need to copy all non-system .dll
s it needs to the directory where your .exe
is.
首先,复制 SDL2.dll
(有关找到该文件的位置,请参见上面的" SDL2.dll
丢失"部分).
First, copy SDL2.dll
(see the section "SDL2.dll
is missing" above for where to find it).
然后,从编译器目录( gcc.exe
所在的目录)中复制以下 .dll
s:
Then, copy following .dll
s from your compiler directory (the directory where gcc.exe
is located):
-
libgcc_s_seh-1.dll
(名称可能因您的MinGW版本而异,但始终以libgcc
开头) -
libstdc ++-6.dll
(仅适用于C ++,如果您使用C编写,则跳过) -
libwinpthread-1.dll
(名称可能因您的MinGW版本而异,但始终会提及thread
;某些版本根本不使用此代码)
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)
那应该解决您所有的错误.如果您想了解更多或没有帮助:
That should fix all your errors. If you want to know more or it didn't help:
有关 .dll
s
More information about the .dll
s
通过使用 -static .dll
s的 .exe
>链接器标志,这称为静态链接".很少执行此操作,并且如果正确执行了上述步骤,则无需执行此操作.这需要与平常不同的链接器标志(大约20个),请参阅SDL随附的 sdl2.pc
文件以获取确切的标志(它们在 Libs.private
部分中)
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).
在上一节中,我告诉过您程序所依赖的 .dll
.我怎么知道有几种方法可以自己解决:
In the previous section I told you what .dll
s your program depends on. How did I know? There are several ways to figure it out for yourself:
-
粗略的方法:
The crude way:
打开控制台, cd
到 .exe
所在的目录,然后键入 set PATH =
(不用担心,这不会更改您的系统 PATH
设置,只会影响当前的控制台会话.
Open the console, cd
to the directory where your .exe
is, then type in set PATH=
(don't worry, this doesn't change your system PATH
setting and only affects the current console session).
删除您可能已经在其中复制的任何 .dll
.
Remove any .dll
s that you may have already copied there.
现在,如果您从此控制台运行 .exe
,它将只能找到系统 .dll
s.它将仅在当前目录(没有目录)中查找非系统目录.现在,您会收到清晰的错误消息,说明需要什么 .dll
,并且可以逐个复制它们,直到它开始工作为止.这样,您将知道程序使用的所有非系统 .dll
.
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.
请注意,此方法并非完全安全.即使在这种情况下,始终会搜索 C:\ Windows
和某些嵌套目录.通常情况下,是否只有系统目录中的 .dll 都没有关系,但是如果某些some脚的安装程序在其中复制了自定义 .dll
,则此方法会成功无法正常工作.
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.
最好在C:\ Windows 和嵌套目录中搜索不应存在的 .dll ,然后将其删除.查找 SDL2.dll
和编译器随附的任何 .dll
(在 gcc.exe
所在的目录中)
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 for SDL2.dll
and for any .dll
s that are also shipped with your compiler (in the directory where your gcc.exe
is).
文明的方式:
使用 Dependency Walker 或 ntldd
之类的工具.您必须查看它们的输出,并确定每个 .dll
是系统文件还是非系统文件.如果 .dll
随编译器一起提供或属于您使用的库( SDL2.dll
),则它是非系统库.其余的 .dll
都是系统文件,请忽略它们.
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.
-
问:我运行程序时,总是会打开一个控制台窗口,除了我使用SDL打开的任何窗口之外.我如何摆脱它?
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:将
-mwindows
添加到链接器标志.
- A: Add
-mwindows
to the linker flags.
问:我的程序具有默认的文件图标,但是我想要一个自定义的图标.
Q: My program has the default file icon, but I want a custom one.
-
A:您的图标必须为
.ico
格式.创建一个扩展名为.rc
的文件(假设为icon.rc
),然后在其中键入以下内容:MAINICON ICON"icon.ico"
(第一部分是任意名称,可以更改;第二部分必须始终为ICON
,第三部分是图标的路径).使用windres -i icon.rc -o icon.o
将文件转换为.o
(windres
程序随编译器一起提供).链接时指定生成的.o
文件,例如g ++ foo.cpp icon.o -o foo.exe
.
A: Your icon must be in the
.ico
format. 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
.
SDL2的最新版本具有与窗口图标使用相同的图标的不错的属性,因此您不必使用 SDL_SetWindowIcon
.
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
.
问:我收到错误在此范围内未声明"SDL_VideoMode"
.
Q: I get error 'SDL_VideoMode' wasn't declared in this scope
.
- A:SDL1.2中存在
SDL_VideoMode
,但它不是SDL2的一部分.您的代码是针对过时的SDL1.2编写的.查找有关新SDL2的更好的教程.
- 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.
以上整个答案主要针对MinGW和Windows.如果您不在Windows上,事情会变得更容易:
The whole answer above is primarily targeted at MinGW and Windows. If you're not on Windows, things become easier:
-
没有与
.dll
相关的问题.
无需手动下载SDL2,它应该在您的软件包管理器中.
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
将告诉您编译器标志.
pkg-config --libs sdl2
将告诉您链接器标志.如果需要用于静态链接的标志,请添加-static
.
pkg-config --libs sdl2
will tell you the linker flags. Add --static
if you want flags for static linking.
您不需要 -lSDL2main
,并且没有与 SDL_main
相关的问题.
You don't need -lSDL2main
, and there are no problems related to SDL_main
.
另一方面:
-
将程序分发给其他人变得越来越困难,您不能随程序附带一堆
.dll
.
设置自定义图标的过程不同.
The process of setting a custom icon is different.
上一节中有关安装库和自动确定编译器标志的部分听起来是否方便?您也可以在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.
下载MSYS2.您将拥有一个程序包管理器(可从中安装SDL),最新的编译器以及从Linux移植的一组通用实用程序(包括 pkg-config
).这解决了大多数Windows特定的问题.
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.
这篇关于如何在程序中正确使用SDL2?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!