Hol*_*Cat 25
这个答案涉及 MinGW/GCC,而不是 Visual Studio。
该答案主要涉及 Windows。其他操作系统上的事情更容易,请参阅答案底部的摘要。
我试图让这个答案保持简单,这样即使是新手也可以使用它。
您可能会遇到的常见错误是:
SDL.h: No such file or directory (编译时)undefined reference to 各种功能(链接时).dll相关的错误(运行程序时)。此列表按从坏到好排序。如果您更改某些内容并得到不同的错误,请使用此列表来判断您是否使事情变得更好或更糟。
有关如何解决所有这些问题,请参阅下面的答案。
在我们修复错误之前,我想告诉您一些事情。
0. 不要听从不好的建议。
一些资源会建议你做#define SDL_MAIN_HANDLED或#undef main。不要那样做。这些解决方案偏离了 SDL2 的预期使用方式,并且通过正确的设置,它们从来都不是必需的。
有些人认为这些比预期的方式更好,但我建议先学习预期的方式,然后了解有什么不同,然后做出明智的决定。
1.弄清楚如何直接从控制台编译,你可以稍后开始使用IDE。 如果您使用的是 IDE,我建议首先确保您能够直接从控制台编译您的程序,以排除任何 IDE 配置问题。弄清楚之后,您可以在 IDE 中使用相同的编译器选项。
如果您刚开始使用 CMake,我还建议您避免使用 CMake,以排除任何与 CMake 相关的问题。您可以稍后开始使用它。
2. 下载正确的 SDL2 文件。确保您拥有正确的文件。您需要SDL2-devel-2.0.x-mingw.tar.gz从此处调用的存档。
将它解压到任何目录中,最好靠近源代码。直接解压到编译器目录通常被认为是一种不好的做法。
3. 了解编译器标志和链接器标志之间的区别。“标志”是您在构建程序时在命令行中指定的选项。当您使用单个命令时,例如g++ foo.cpp -o foo.exe,您的所有标志都会添加到同一位置(添加到此单个命令)。
但是当您分两步构建程序时,例如:
g++ foo.cpp -c -o foo.o (编译)g++ foo.o -o foo.exe (链接)您必须知道要向其中添加标志的两个命令中的哪一个。需要添加到第一个命令的标志是“编译器标志”,需要添加到第二个命令的标志是“链接器标志”。在下面的答案中,当告诉您添加标志时,我将指定它是编译器标志还是链接器标志。
大多数 IDE 会要求您分别指定编译器和链接器标志,因此即使您现在使用单个命令,也最好知道哪个标志放在哪里。
除非另有说明,否则标志的顺序无关紧要。
SDL.h: No such file or directory或任何与包含SDL.h或相关的类似错误SDL2/SDL.h。
您需要告诉编译器位于哪个目录SDL.h中。它位于您下载的 SDL 文件中(请参阅序言)。
将以下内容添加到您的编译器标志中:-I,后跟一个目录。
例子:-IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2。(相对路径也有效,例如-ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2。)
请注意,该标志可能会有所不同,具体取决于您编写 的方式#include:
#include <SDL.h>,则路径应以.../include/SDL2(如上)结尾。这是推荐的方式。#include <SDL2/SDL.h>,则路径应以.../include.undefined reference to 各种功能错误消息将提及各种SDL_...函数(通常是您在程序中使用的函数)和/或WinMain. 如果提到SDL_main,请参阅undefined reference to SDL_main下面的“仅”部分。
您需要添加以下链接器标志:-lmingw32 -lSDL2main -lSDL2. 顺序很重要。该标志必须出现在任何AFTER .c/ .cpp/.o文件。
写入-lSDL2main -lSDL2告诉链接器使用您下载的 SDL 文件中包含的名为libSDL2main.a, libSDL2.a(或libSDL2.dll.a)的文件。您还需要一个标志来告诉链接器在哪里查找这些.a文件。将以下内容添加到您的链接器标志中:-L,后跟目录。
例子:-LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib。(相对路径也有效,例如-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 位。即使您认为自己使用了正确的文件,也请尝试其他文件以确保。
一些 MinGW 版本可以使用-m32和-m64标志在 32 位和 64 位模式之间切换(那些可能必须添加到编译器和链接器标志中)。你也可以试试这些。
我得到undefined reference了一个特定的功能:
undefined reference to WinMain仅存在三种可能性,所有这些都在上一节中介绍过:
-lSDL2main国旗。libSDL2main.a您使用的文件与您的编译器不匹配(32 位文件与 64 位编译器,反之亦然)。-lSDL2main国旗一些左.c/ .cpp/.o文件。它必须始终在右侧。尽量避免#define SDL_MAIN_HANDLED或#undef main在解决此问题时,请参阅序言以获取解释。
undefined reference to SDL_main仅你需要有一个main功能。你的main函数必须看起来像int main(int, char **). 不是 int main()和不是 void main()。这是 SDL2 的怪癖之一。
允许添加任何参数名称,例如int main(int argc, char **argv). 此外,第二个参数可以写成char *[]或带有名称:char *argv[]。不允许进行其他更改。
如果您的项目有多个源文件,请确保包含SDL.h在定义main函数的文件中,即使它不直接使用 SDL。
尽量避免#define SDL_MAIN_HANDLED或#undef main在解决此问题时,请参阅序言以获取解释。
.dll-相关错误您已经成功构建了一个.exe,但由于提到某些.dlls的神秘错误而无法运行它。您快到了!
在.exe你需要做一些.dlls到运行。如果它没有找到它们,它会告诉你并拒绝运行。这很简单。它还可以找到您安装的其他一些程序遗留下来的错误版本,然后您会得到一些非常神秘的错误。
您的程序将.dll在不同位置查找s,但最可靠的解决方案是将它们与.exe. 首先搜索此目录,因此.dll您可能在别处拥有的s 的其他版本不会干扰。
你需要找出哪些.dll是你的程序的需求,并把他们的目录中的.exeIS(除系统.dllS,你不需要复制)。
您可能会遇到两种类型的错误:
一个错误只是告诉您.dll缺少什么。
SDL2.dll不见了。— 它位于您下载的 SDL 文件中。
请注意,这些文件包含两个不同的SDL2.dlls:一个 32 位的(在i686-w64-mingw32目录中)和一个 64 位的(在x86_64-w64-mingw32. 选择正确的一个,如有必要,请尝试两者。
还有一些.dll不见了。— 它随您的编译器一起提供。查看你所在的目录gcc.exe。
如果您复制一个.dll并要求更多,这是正常的,您可能需要重复约 3 次。
一个神秘的.dll相关错误。— 您的程序.dll在系统中某处发现了错误版本的 a 。
您需要将.dll它需要的所有非系统s复制到您所在的目录中.exe。
首先,复制SDL2.dll(有关在SDL2.dll哪里可以找到它,请参阅上面的“丢失”部分)。
然后,.dll从编译器目录(所在目录gcc.exe)复制以下s :
libgcc_s_seh-1.dll(名称可能因您的 MinGW 版本而异,但始终以 开头libgcc)libstdc++-6.dll (仅适用于 C++,如果您用 C 编写,请跳过)libwinpthread-1.dll(名称可能因您的 MinGW 版本而异,但会始终提及thread;有些版本根本不使用它)对于某些 MinGW 发行版,这些可能不是正确.dll的。如果您没有看到这些或复制它们没有帮助,请继续阅读。
那应该可以解决您的所有错误。如果您想了解更多信息或没有帮助:
有关.dlls 的更多信息
通过使用链接器标志可以创建.exe不依赖于任何(非系统).dlls 的 s -static,这称为“静态链接”。很少这样做,如果您正确地执行了上述步骤,则不需要这样做。这需要与通常不同的链接器标志(大约 20 个),请参阅sdl2.pcSDL 随附的文件以了解确切的标志(它们在Libs.private部分)。
在上一节中,我试图猜测.dll你的程序依赖什么。我怎么知道?有几种方法可以自己解决:
粗暴的方法:
打开控制台,cd到您所在的目录.exe,然后键入set PATH=(别担心,这不会更改您的系统PATH设置,只会影响当前的控制台会话)。
删除.dll您可能已经在那里复制的任何s。
现在,如果您.exe从此控制台运行,它将只能找到系统.dlls。它只会在当前目录(没有)中查找非系统目录。现在您将得到明确的错误消息,说明.dll需要什么,您可以一一复制它们,直到它开始工作。这样你就会知道.dll你的程序使用的所有非系统。
请注意,此方法并非完全万无一失。C:\Windows并且始终搜索某些嵌套目录,即使在这种情况下也是如此。通常情况下,系统中是否只有.dlls并不重要,但是如果某些蹩脚的安装程序.dll在其中复制了自定义,则此方法将无法正常工作。
最好在C:\Windows嵌套目录中搜索.dll不应该存在的 s,然后将其删除。查找与您的编译器一起提供的SDL2.dll任何.dlls(在您所在的目录中gcc.exe)。
文明方式:
使用像Dependency Walker或ntldd. 您必须查看他们的输出并确定每个输出.dll是系统还是非系统。如果 a.dll随您的编译器一起提供或属于您使用的库 ( SDL2.dll),则它是非系统的。任何剩余的.dlls 都是系统的,忽略它们。
问:除了我使用 SDL 打开的任何窗口之外,我的程序在运行时总是会打开一个控制台窗口。我该如何摆脱它?
-mwindows到链接器标志。问:我的程序有默认文件图标,但我想要一个自定义图标。
答:您的图标必须符合.ico格式。如果您的图形编辑器不支持它,请制作一系列.png常见尺寸的s(例如 16x16、32x32、48x48、64x64),然后.ico使用ImageMagick :(magick *.png result.ico或使用convert代替magick)将它们转换为单个。
创建一个带有.rc扩展名的文件(假设为icon.rc),在其中键入以下内容:(MAINICON ICON "icon.ico"第一部分是任意名称,您可以更改它;第二部分必须始终是ICON,第三部分是图标的路径)。将文件转换为.ousing windres -i icon.rc -o icon.o(该windres程序随您的编译器一起提供)。.o链接时指定生成的文件,例如g++ foo.cpp icon.o -o foo.exe.
最新版本的 SDL2 有一个很好的特性,即使用与窗口图标相同的图标,因此您不必使用SDL_SetWindowIcon.
问:我收到错误'SDL_VideoMode' wasn't declared in this scope。
SDL_VideoMode存在于 SDL1.2 中,但不是 SDL2 的一部分。您的代码是为过时的 SDL1.2 编写的。查找处理新 SDL2 的更好教程。上面的整个答案主要针对 MinGW 和 Windows。如果您不在 Windows 上,事情会变得更简单:
无.dll相关问题。
无需手动下载 SDL2,它应该在您的包管理器中。
无需考虑使用哪个编译器或链接器标志:
pkg-config --cflags sdl2 会告诉你编译器标志。
pkg-config --libs sdl2会告诉你链接器标志。--static如果您想要静态链接的标志,请添加。
您不需要-lSDL2main,并且没有与SDL_main.
另一方面:
将您的程序分发给其他人变得更加困难,您不能.dll随程序一起发送一堆s。
设置自定义图标的过程是不同的。
上一节关于安装库和确定编译器标志的部分听起来是否很方便?你也可以在 Windows 上使用它。
下载 MSYS2。您将拥有一个包管理器(您可以从中安装 SDL)、最新的编译器和一组从 Linux 移植的常用实用程序(包括pkg-config)。这解决了大多数特定于 Windows 的问题。